Index: gp-plugins/wporg-routes/routes/wp-plugins.php
===================================================================
--- gp-plugins/wporg-routes/routes/wp-plugins.php	(revision 2089)
+++ gp-plugins/wporg-routes/routes/wp-plugins.php	(working copy)
@@ -88,4 +88,71 @@

 		$this->tmpl( 'projects-wp-plugins', get_defined_vars() );
 	}
+
+	private function get_project_contributors( $project_id ) {
+		global $gpdb;
+
+		$sql = $gpdb->prepare( '
+			SELECT ts.`locale`, ts.`slug` AS `locale_slug`, t.`user_id`, COUNT(*) AS `translation_count`
+			FROM `' . $gpdb->translations .'` t, `'. $gpdb->translation_sets . '` ts
+			WHERE t.`translation_set_id` = ts.`id`
+			    AND t.`user_id` IS NOT NULL AND t.`user_id` != 0
+			    AND ts.`project_id` = %d
+			GROUP BY ts.`locale`, ts.`slug`, t.`user_id`
+		', $project_id );
+
+		return $gpdb->get_results( $sql );
+	}
+
+	function get_plugin_project_contributors( $project_slug ) {
+		global $gpdb;
+
+		$project_path = 'wp-plugins/' . $project_slug;
+		$project = GP::$project->by_path( $project_path );
+		if ( ! $project ) {
+			return $this->die_with_404();
+		}
+
+		$sub_projects = $gpdb->get_results( $gpdb->prepare( "
+			SELECT id
+			FROM {$gpdb->prefix}projects
+			WHERE parent_project_id = %d
+		", $project->id ) );
+
+		// also include the main project in the count
+		$sub_projects[] = $project;
+
+		$project_contributors = array();
+		foreach ( $sub_projects as $sub_project ) {
+
+			foreach( $this->get_project_contributors( $sub_project->id ) as $row ) {
+				$locale_key = $row->locale;
+				if ( 'default' != $row->locale_slug ) {
+					$locale_key = $row->locale . '/' . $row->locale_slug;
+				}
+
+				if ( ! isset( $project_contributors[ $locale_key ] ) ) {
+					$project_contributors[ $locale_key ] = array();
+				}
+
+				if ( ! isset( $project_contributors[ $locale_key ][ $row->user_id ] ) ) {
+					$project_contributors[ $locale_key ][ $row->user_id ] = 0;
+				}
+
+				// sum up translations per user over all (sub-)projects
+				$project_contributors[ $locale_key ][ $row->user_id ] += $row->translation_count;
+			}
+		}
+
+		// sort by locales for display
+		ksort( $project_contributors );
+
+		if ( function_exists( 'wporg_get_plugin_icon' ) ) {
+			$project->icon = wporg_get_plugin_icon( $project->slug, 64 );
+		} else {
+			$project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
+		}
+
+		$this->tmpl( 'contributors-project', get_defined_vars() );
+	}
 }


Index: gp-plugins/wporg-routes/wporg-routes.php
===================================================================
--- gp-plugins/wporg-routes/wporg-routes.php	(revision 2088)
+++ gp-plugins/wporg-routes/wporg-routes.php	(working copy)
@@ -43,8 +43,9 @@
 		GP::$router->prepend( "/locale/$locale/$path/$path", array( 'GP_WPorg_Route_Locale', 'get_locale_projects' ) );
 		GP::$router->prepend( "/locale/$locale/$path/$path/$path", array( 'GP_WPorg_Route_Locale', 'get_locale_project' ) );

-		$project = '([^/]*)/?';
-		GP::$router->prepend( "/projects/wp-plugins/$project", array( 'GP_WPorg_Route_WP_Plugins', 'get_plugin_projects' ) );
+		$project = '([^/]*)';
+		GP::$router->prepend( "/projects/wp-plugins/$project/?", array( 'GP_WPorg_Route_WP_Plugins', 'get_plugin_projects' ) );
+		GP::$router->prepend( "/projects/wp-plugins/$project/contributors/?", array( 'GP_WPorg_Route_WP_Plugins', 'get_plugin_project_contributors' ) );
 	}
 }

Index: gp-templates/contributors-project.php
===================================================================
--- gp-templates/contributors-project.php	(revision 0)
+++ gp-templates/contributors-project.php	(working copy)
@@ -0,0 +1,89 @@
+<?php
+$edit_link = gp_link_project_edit_get( $project, __( '(edit)' ) );
+
+gp_title( sprintf( __( 'Contributors &lt; %s &lt; GlotPress' ), esc_html( $project->name ) ) );
+gp_breadcrumb_project( $project );
+
+wp_enqueue_script( 'common' );
+wp_enqueue_script( 'tablesorter' );
+
+gp_tmpl_header();
+?>
+
+<div class="project-header">
+	<p class="project-description"><?php echo apply_filters( 'project_description', $project->description, $project ); ?></p>
+
+	<div class="project-box">
+		<div class="project-box-header">
+			<div class="project-icon">
+				<?php echo $project->icon; ?>
+			</div>
+
+			<ul class="project-meta">
+				<li class="project-name"><?php echo $project->name; ?> <?php echo $edit_link; ?></li>
+			</ul>
+		</div>
+	</div>
+</div>
+
+<div class="stats-table">
+	<table id="contributors-table" class="table">
+		<thead>
+			<tr>
+				<th class="locale"><?php echo _( 'Locale' ); ?></th>
+				<th class="username"><?php echo _( 'Username' ); ?></th>
+				<th class="translations"><?php echo _( 'Translations' ); ?></th>
+			</tr>
+		</thead>
+		<tbody>
+			<?php
+			foreach ( $project_contributors as $locale => $contributors ) :
+				$gp_locale = GP_Locales::by_slug( $locale );
+
+				$set_slug  = 'default';
+
+				// Variants (de/formal for example) don't have GP_Locales in this context
+				if ( ! $gp_locale && ( list( $base_locale_slug, $set_slug ) = explode( '/', $locale_slug ) ) ) :
+					$gp_locale = clone GP_Locales::by_slug( $base_locale_slug );
+
+					// Just append it for now..
+					$gp_locale->wp_locale .= '/' . $set_slug;
+					$gp_locale->english_name .=  ' (' . ucfirst( $set_slug ) . ')';
+				endif;
+
+				if ( ! $gp_locale || ! $gp_locale->wp_locale ) :
+					continue;
+				endif;
+
+				foreach ( $contributors as $contributor => $translation_count ):
+					$user = GP::$user->get( $contributor );
+					?>
+					<tr>
+						<th title="<?php echo esc_attr( $gp_locale->wp_locale ); ?>">
+							<a href="<?php echo gp_url( gp_url_join( 'locale', $gp_locale->slug, $set_slug, $project->path ) ); ?>">
+								<?php echo esc_html( $gp_locale->english_name ); ?>
+							</a>
+						</th>
+						<td><?php echo $user->user_login; ?></td>
+						<td><?php echo $translation_count; ?></td>
+					</tr>
+				<?php endforeach; ?>
+			<?php endforeach; ?>
+		</tbody>
+	</table>
+</div>
+
+<script type="text/javascript">
+jQuery( function( $ ) {
+	$( '#contributors-table' ).tablesorter( {
+		textExtraction: function( node ) {
+			var cellValue = $( node ).text(),
+				sortValue = $( node ).data( 'sortValue' );
+
+			return ( undefined !== sortValue ) ? sortValue : cellValue;
+		}
+	});
+});
+</script>
+
+<?php gp_tmpl_footer();
