WordPress.org

Making WordPress.org

Ticket #340: 340.4.diff

File 340.4.diff, 17.7 KB (added by iandunn, 7 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/*
     3Plugin Name: WP I18N Teams
     4Description: Provides shortcodes for displaying details about translation teams.
     5Version:     0.9
     6License:     GPLv2 or later
     7Author:      Marko Heijnen
     8Author URI:  http://www.markoheijnen.com
     9Text 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
     26class 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();
     252register_activation_hook(   __FILE__, array( $GLOBALS['wp_i18n_teams'], 'activate' ) );
     253register_deactivation_hook( __FILE__, array( $GLOBALS['wp_i18n_teams'], 'deactivate' ) );