Ticket #340: 340.4.diff
File 340.4.diff, 17.7 KB (added by , 10 years ago) |
---|
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/wp-i18n-teams/css/front-end.css
1 /* todo remove any unused Bootstrap rules */ 2 3 /* 4 * Table of all locales 5 */ 6 7 .i18n-label.latest { 8 color: #468847; 9 } 10 .i18n-label.minor-behind { 11 color: #F7D708; 12 } 13 .i18n-label.major-behind-one { 14 color: #E6A45A; 15 } 16 .i18n-label.major-behind-many { 17 color: #e38587; 18 } 19 20 .version.latest { 21 background: #d2e7ca; 22 } 23 .version.minor-behind { 24 background: #fef0c1; 25 } 26 .version.major-behind-one { 27 background: #E6A45A; 28 } 29 .version.major-behind-many { 30 background: #e38587; 31 } 32 33 34 /* 35 * Details page for an individual locale 36 */ 37 38 #locale-header { 39 padding: 0 20px; 40 background-color: #F5F5F5; 41 border: 1px solid #E3E3E3; 42 border-radius: 4px; 43 box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05) inset; 44 } 45 #locale-header ul, 46 #main ul#postlist .postcontent #locale-header ul { 47 overflow: auto; 48 margin-left: 0 !important; /* !important is necessary here to override P2's use of !important in .postcontent ul */ 49 } 50 #locale-header ul li { 51 list-style-type: none; 52 } 53 #locale-header ul#locale-details { 54 margin-bottom: 0 !important; /* !important is necessary here to override P2's use of !important in .postcontent ul */ 55 } 56 #locale-header ul li.download-button, 57 #main ul#postlist .postcontent #locale-header ul li.download-button { 58 float: left; 59 height: 34px; 60 margin: 8px 12px 0 0; 61 padding: 6px 12px; 62 } 63 #locale-header ul li.download-button a { 64 font-size: 1.1em; 65 color: white; 66 } 67 68 .validators, 69 #main ul#postlist .postcontent ul.validators { 70 overflow: auto; 71 margin: 0 !important; /* !important is necessary here to override P2's use of !important in .postcontent ul */ 72 padding: 0; 73 } 74 .validators li { 75 float: left; 76 width: 280px; 77 padding-bottom: 15px; 78 list-style-type: none; 79 } 80 .validators .gravatar { 81 float: left; 82 margin: 0 10px 10px 0; 83 padding: 2px; 84 } 85 .validators a.web { 86 display: block; 87 margin: 6px 0 2px; 88 font-size: 16px; 89 text-decoration: none; 90 } 91 92 .translators-info table { 93 width: 100%; 94 margin: .7em 0 1.5em; 95 border: 1px solid #ccc; 96 border-width: 1px 1px 1px 0; 97 border-spacing: 0; 98 } 99 .translators-info th { 100 background: #ccc; 101 border: 1px solid #ccc; 102 border-width: 1px 0 0 1px; 103 padding: 6px 15px; 104 } 105 .translators-info td { 106 border: 1px solid #ccc; 107 border-width: 1px 0 0 1px; 108 padding: 6px 15px; 109 } 110 .become-a-translator { 111 background-color: #D9EDF7; 112 border-color: #BCE8F1; 113 color: #31708F; 114 padding: 15px; 115 margin-bottom: 20px; 116 border: 1px solid transparent; 117 border-radius: 4px; 118 } 119 No newline at end of file -
sites/trunk/wordpress.org/public_html/wp-content/plugins/wp-i18n-teams/views/all-locales.php
1 <?php if ( $locale_data ) : ?> 2 3 <div class="translators-info"> 4 <p> 5 <?php printf( 6 __( '%s locales up-to-date. %s locales behind by one minor version. %s locales behind by one major version. %s locales behind by two or more major versions. %s locales do not yet have a package available.', 'wporg' ), 7 '<strong class="i18n-label latest">' . $locale_data['status_counts']['latest'] . '</strong>', 8 '<strong class="i18n-label minor-behind">' . $locale_data['status_counts']['minor-behind'] . '</strong>', 9 '<strong class="i18n-label major-behind-one">' . $locale_data['status_counts']['major-behind-one'] . '</strong>', 10 '<strong class="i18n-label major-behind-many">' . $locale_data['status_counts']['major-behind-many'] . '</strong>', 11 '<strong class="i18n-label no-site no-releases">' . ( $locale_data['status_counts']['no-site'] + $locale_data['status_counts']['no-releases'] ) . '</strong>' 12 ); ?> 13 </p> 14 15 <table> 16 <thead> 17 <tr> 18 <th><?php _e( 'Locale Name', 'wporg' ); ?></th> 19 <th><?php _e( 'Native Name', 'wporg' ); ?></th> 20 <th><?php _e( 'Locale Code', 'wporg' ); ?></th> 21 <th><?php _e( 'WordPress Locale', 'wporg' ); ?></th> 22 <th><?php _e( 'Version', 'wporg' ); ?></th> 23 <th><!-- intentionally blank --></th> 24 </tr> 25 </thead> 26 27 <tbody> 28 <?php foreach ( $locales as $locale ) : ?> 29 <tr class="version <?php echo esc_attr( $locale_data[ $locale->wp_locale ]['status'] ); ?>"> 30 <td><?php echo esc_html( $locale->english_name ); ?></td> 31 <td><?php echo esc_html( $locale->native_name ); ?></td> 32 33 <td> 34 <?php if ( $locale_data[ $locale->wp_locale ]['rosetta_site_url'] ) : ?> 35 <a href="<?php echo esc_url( $locale_data[ $locale->wp_locale ]['rosetta_site_url'] ); ?>"> 36 <?php echo esc_html( $locale->slug ); ?> 37 </a> 38 <?php else : ?> 39 <?php echo esc_html( $locale->slug ); ?> 40 <?php endif; ?> 41 </td> 42 43 <td><?php echo esc_html( $locale->wp_locale ); ?></td> 44 45 <td> 46 <?php 47 if ( $locale_data[ $locale->wp_locale ]['rosetta_site_url'] ) { 48 if ( $locale_data[ $locale->wp_locale ]['latest_release'] ) { 49 echo esc_html( $locale_data[ $locale->wp_locale ]['latest_release'] ); 50 } else { 51 _e( 'None', 'wporg' ); 52 } 53 } else { 54 _e( 'No site', 'wporg' ); 55 } 56 ?> 57 </td> 58 59 <td> 60 <a href="<?php echo esc_url( add_query_arg( 'locale', $locale->wp_locale ) ); ?>"> 61 <?php _e( 'More', 'wporg' ); ?> 62 </a> 63 </td> 64 </tr> 65 <?php endforeach; ?> 66 </tbody> 67 </table> 68 </div> <!-- /.translators-info --> 69 70 <?php else : ?> 71 72 <p class="become-a-translator" role="alert"> <!-- todo rename to something more generic that can be reused across wporg --> 73 <?php _e( 'Localization data is not available.', 'wporg' ); ?> 74 </p> 75 76 <?php endif; ?> -
sites/trunk/wordpress.org/public_html/wp-content/plugins/wp-i18n-teams/views/locale-details.php
1 <?php if ( $locale_data && is_a( $locale, 'GP_Locale' ) ) : ?> 2 <?php $locale_data = $locale_data[ $locale->wp_locale ]; ?> 3 4 <div id="locale-header"> <!-- todo change to #books? --> 5 <h1> 6 <?php echo esc_html( $locale->native_name ); ?> 7 8 <?php if ( $locale->native_name != $locale->english_name ) : ?> 9 / <?php echo esc_html( $locale->english_name ); ?> 10 <?php endif; ?> 11 </h1> 12 13 <ul id="locale-details"> 14 <li> 15 <strong><?php _e( 'Locale site:', 'wporg' ); ?></strong> 16 <a href="<?php echo esc_url( $locale_data['rosetta_site_url'] ); ?>"><?php _e( 'View locale site', 'wporg' ); ?></a> 17 </li> 18 19 <li> 20 <strong><?php _e( 'Version:', 'wporg' ); ?></strong> 21 <?php echo esc_html( $locale_data['latest_release'] ); ?> 22 </li> 23 24 <li> 25 <strong><?php _e( 'WordPress Locale:', 'wporg' ); ?></strong> 26 <?php echo esc_html( $locale->wp_locale ); ?> 27 </li> 28 </ul> 29 30 <ul id="locale-download"> 31 <li class="button download-button"> 32 <a href="<?php echo esc_url( $locale_data['localized_core_url'] ); ?>" role="button"> 33 <?php printf( __( 'Download WordPress in %s', 'wporg' ), $locale->native_name ); ?> 34 </a> 35 </li> 36 37 <li class="button download-button"> 38 <a href="<?php echo esc_url( $locale_data['language_pack_url'] ); ?>" role="button"> 39 <?php // translators: %s is the latest version ?> 40 <?php printf( __( 'Download language pack (%s)', 'wporg' ), $locale_data['latest_release'] ); ?> 41 </a> 42 </li> 43 </ul> 44 </div> 45 46 47 <h2>Validators</h2> 48 49 <?php if ( empty( $locale_data['validators'] ) ) : ?> 50 <p><?php printf( __( '% does not have any validators yet.', 'wporg' ), $locale->native_name ); ?></p> 51 <?php else : ?> 52 <ul class="validators"> 53 <?php foreach ( $locale_data['validators'] as $validator ) : ?> 54 <li> 55 <a href="https://profiles.wordpress.org/<?php echo esc_attr( $validator[2] ); ?>"> 56 <img src="https://secure.gravatar.com/avatar/<?php echo esc_attr( $validator[1] ); ?>?size=60" class="gravatar" alt="<?php echo esc_attr( $validator[0] ); ?>" /> 57 </a> 58 59 <a class="web" href="https://profiles.wordpress.org/<?php echo esc_attr( $validator[2] ); ?>"> 60 <?php echo esc_html( $validator[0] ); ?> 61 </a> 62 </li> 63 <?php endforeach; ?> 64 </ul> 65 <?php endif; ?> 66 67 68 <h2>Translators</h2> 69 70 <?php if ( empty( $locale_data['translators'] ) ) : ?> 71 <p><?php printf( __( '% does not have any translators yet.', 'wporg' ), $locale->native_name ); ?></p> 72 <?php else : ?> 73 <ul> 74 <?php foreach ( $locale_data['translators'] as $username => $name ) : ?> 75 <li> 76 <a href="https://profiles.wordpress.org/<?php echo esc_attr( $username ); ?>"> 77 <?php echo esc_html( $name ); ?> 78 </a> 79 </li> 80 <?php endforeach; ?> 81 </ul> 82 <?php endif; ?> 83 84 <p class="become-a-translator" role="alert"> <!-- todo rename to something more generic that can be reused across wporg --> 85 <a href="https://translate.wordpress.org/languages/<?php echo esc_attr( $locale->slug ); ?>"> 86 <?php printf( __( 'Become a translator yourself, check if %s needs some help!', 'wporg' ), $locale->native_name ); ?> 87 </a> 88 </p> 89 90 <?php else : ?> 91 92 <p class="become-a-translator" role="alert"> <!-- todo rename to something more generic that can be reused across wporg --> 93 <?php _e( 'Localization data is not available.', 'wporg' ); ?> 94 </p> 95 96 <?php endif; ?> -
sites/trunk/wordpress.org/public_html/wp-content/plugins/wp-i18n-teams/wp-i18n-teams.php
1 <?php 2 /* 3 Plugin Name: WP I18N Teams 4 Description: Provides shortcodes for displaying details about translation teams. 5 Version: 0.9 6 License: GPLv2 or later 7 Author: Marko Heijnen 8 Author URI: http://www.markoheijnen.com 9 Text Domain: wporg 10 */ 11 12 13 /* 14 * TODO 15 * 16 * inline TODOs 17 * cross browser testing 18 * fix cron bug 19 * final review + double check security 20 * 21 * ask nacin for a sanity check on cache_locale_data() and get_contributors() 22 * deploy new API_WPORG_PATH constant before deploying this 23 */ 24 25 26 class WP_I18n_Teams { 27 const LOCALE_DATA_TRANSIENT_KEY = 'wit_locale_data'; 28 29 /** 30 * Constructor 31 */ 32 public function __construct() { 33 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) ); 34 add_filter( 'cron_schedules', array( $this, 'add_cron_intervals' ) ); 35 add_action( 'wit_refresh_cache', array( $this, 'cache_locale_data' ) ); // todo this runs when visiting wp-cron directly, but not when by visiting pages 36 37 add_shortcode( 'wp-locales', array( $this, 'wp_locales' ) ); 38 39 $this->activate(); // todo shouldn't need this once cron bug is fixed 40 } 41 42 /** 43 * Prepares site to use the plugin during activation 44 */ 45 public function activate() { 46 if ( false === wp_next_scheduled( 'wit_refresh_cache' ) ) { 47 wp_schedule_event( 48 time(), 49 'wit_five_minutes', 50 'wit_refresh_cache' 51 ); 52 } 53 } 54 55 /** 56 * Rolls back activation procedures when de-activating the plugin 57 */ 58 public function deactivate() { 59 wp_clear_scheduled_hook( 'wit_refresh_cache' ); 60 } 61 62 /** 63 * Enqueue JavaScript and CSS 64 */ 65 public function enqueue_assets() { 66 wp_enqueue_style( 'wp-i18n-teams', plugins_url( 'css/front.css', __FILE__ ), array(), 1 ); 67 } 68 69 /** 70 * Adds custom intervals to the cron schedule. 71 * 72 * @param array $schedules 73 * 74 * @return array 75 */ 76 public function add_cron_intervals( $schedules ) { 77 $schedules[ 'wit_five_minutes' ] = array( 78 'interval' => 5 * MINUTE_IN_SECONDS, 79 'display' => 'Every 5 minutes' 80 ); 81 82 return $schedules; 83 } 84 85 /** 86 * Render the [wp-locales] shortcode. 87 * 88 * @param array $attributes 89 * 90 * @return string 91 */ 92 public function wp_locales( $attributes ) { 93 $locale_data = get_transient( self::LOCALE_DATA_TRANSIENT_KEY ); 94 95 ob_start(); 96 97 if ( empty( $_GET['locale'] ) ) { 98 $locales = self::get_locales(); 99 require( __DIR__ . '/views/all-locales.php' ); 100 } else { 101 require_once( WPORGPATH . 'translate/glotpress/locales/locales.php' ); 102 $locale = GP_Locales::by_field( 'wp_locale', $_GET['locale'] ); 103 require( __DIR__ . '/views/locale-details.php' ); 104 } 105 106 return ob_get_clean(); 107 } 108 109 /** 110 * Get GlotPress locales that have a wp_locale, sorted alphabetically. 111 * 112 * @return array 113 */ 114 protected static function get_locales() { 115 require_once( WPORGPATH . 'translate/glotpress/locales/locales.php' ); 116 117 $locales = GP_Locales::locales(); 118 $locales = array_filter( $locales, array( __CLASS__, 'filter_locale_for_wp' ) ); 119 usort( $locales, array( __CLASS__, 'sort_locales' ) ); 120 121 return $locales; 122 } 123 124 /** 125 * Remove locales that are missing a wp_locale. 126 * 127 * This is a callback for array_filter(). 128 * 129 * @param GP_Locale $element 130 * 131 * @return bool 132 */ 133 protected static function filter_locale_for_wp( $element ) { 134 if ( isset( $element->wp_locale ) ) { 135 return true; 136 } else { 137 return false; 138 } 139 } 140 141 /** 142 * Sort GlotPress locales alphabetically by the English name. 143 * 144 * @param GP_Locale $a 145 * @param GP_Locale $b 146 * 147 * @return int 148 */ 149 protected static function sort_locales( $a, $b ) { 150 return strcmp( $a->english_name, $b->english_name ); 151 } 152 153 /** 154 * Gather all the required data and cache it. 155 */ 156 public function cache_locale_data() { 157 global $wpdb; 158 $locales = WP_I18n_Teams::get_locales(); 159 160 $locale_wporg_info = $wpdb->get_results( " 161 SELECT locale, subdomain, latest_release 162 FROM locales 163 ORDER BY locale 164 LIMIT 400" 165 ); 166 167 // Reindex locale wporg info so that locales can be accessed directly 168 foreach ( $locale_wporg_info as $index => $info ) { 169 unset( $locale_wporg_info[ $index ] ); 170 $locale_wporg_info[ $info->locale ] = $info; 171 } 172 173 foreach( $locales as $locale ) { 174 $contributors = self::get_contributors( $locale ); 175 $latest_release = empty( $locale_wporg_info[ $locale->wp_locale ]->latest_release ) ? false : $locale_wporg_info[ $locale->wp_locale ]->latest_release; 176 $rosetta_site_url = empty( $locale_wporg_info[ $locale->wp_locale ]->subdomain ) ? '' : 'https://' . $locale_wporg_info[ $locale->wp_locale ]->subdomain . '.wordpress.org'; 177 $localized_core_url = $rosetta_site_url ? sprintf( '%s/wordpress-%s-%s.zip', $rosetta_site_url, WP_CORE_LATEST_RELEASE, $locale->wp_locale ) : ''; 178 // todo not sure localized url is always in this format? find where it's generated to verify. if have to derive it, try to get them all at once instead of 100+ calls 179 $language_pack_url = sprintf( 'https://downloads.wordpress.org/translation/core/%s/%s.zip', WP_CORE_STABLE_BRANCH, $locale->wp_locale ); 180 $locale_status = self::get_locale_status( $rosetta_site_url, $latest_release ); 181 182 $locale_data[ $locale->wp_locale ] = array( 183 'status' => $locale_status, 184 'rosetta_site_url' => $rosetta_site_url, 185 'localized_core_url' => $localized_core_url, 186 'language_pack_url' => $language_pack_url, 187 'latest_release' => $latest_release, 188 'validators' => $contributors['validators'], 189 'translators' => $contributors['translators'], 190 ); 191 192 $locale_data['status_counts'][ $locale_status ]++; 193 } 194 195 set_transient( self::LOCALE_DATA_TRANSIENT_KEY, $locale_data ); 196 } 197 198 /** 199 * Get the translators and validators for the given locale. 200 * 201 * @param GP_Locale $locale 202 * @return array 203 */ 204 public static function get_contributors( $locale ) { 205 require_once( API_WPORG_PATH . 'core/credits/wp-credits.php' ); 206 207 $credits = WP_Credits::factory( WP_CORE_LATEST_RELEASE, $locale ); 208 $results = $credits->get_results(); 209 210 $contributors = array( 211 'validators' => ! empty( $results['groups']['validators']['data'] ) ? $results['groups']['validators']['data'] : array(), 212 'translators' => ! empty( $results['groups']['translators']['data'] ) ? $results['groups']['translators']['data'] : array(), 213 ); 214 215 return $contributors; 216 } 217 218 /** 219 * Determine the status of the given locale 220 * 221 * @param string $rosetta_site_url 222 * @param string $latest_release 223 * 224 * @return string 225 */ 226 protected static function get_locale_status( $rosetta_site_url, $latest_release ) { 227 if ( $rosetta_site_url ) { 228 if ( $latest_release ) { 229 $one_lower = WP_CORE_LATEST_RELEASE - 0.1; 230 231 if ( $latest_release == WP_CORE_LATEST_RELEASE ) { 232 $status = 'latest'; 233 } else if ( substr( $latest_release, 0, 3 ) == substr( WP_CORE_LATEST_RELEASE, 0, 3 ) ) { 234 $status = 'minor-behind'; 235 } else if ( substr( $latest_release, 0, 3 ) == substr( $one_lower, 0, 3 ) ) { 236 $status = 'major-behind-one'; 237 } else { 238 $status = 'major-behind-many'; 239 } 240 } else { 241 $status = 'no-releases'; 242 } 243 } else { 244 $status = 'no-site'; 245 } 246 247 return $status; 248 } 249 } 250 251 $GLOBALS['wp_i18n_teams'] = new WP_I18n_Teams(); 252 register_activation_hook( __FILE__, array( $GLOBALS['wp_i18n_teams'], 'activate' ) ); 253 register_deactivation_hook( __FILE__, array( $GLOBALS['wp_i18n_teams'], 'deactivate' ) );