Plugin Directory

Changeset 2937674


Ignore:
Timestamp:
07/12/2023 01:33:00 PM (3 years ago)
Author:
glotpress
Message:

Update to version 4.0.0-alpha.5 from GitHub

Location:
glotpress
Files:
36 edited
1 copied

Legend:

Unmodified
Added
Removed
  • glotpress/tags/4.0.0-alpha.5/CHANGELOG.md

    r2872254 r2937674  
    11All notable changes to this project will be documented in this file.
    22This project adheres to [Semantic Versioning](http://semver.org/).
     3
     4## [4.0.0-alpha.5] (July 12, 2023)
     5
     6**Features**
     7* Set as old the previous translations with waiting status for this user ([#1536])
     8* Highlight leading and trailing spaces, and double/multiple spaces in the middle ([#1500])
     9* Add I18n to JavaScript ([#1369])
     10* Add plural and plural forms labels to row previews and format the row editor accordingly ([#1506])
     11* Reorder glossary row editor items ([#1622])
     12
     13**Bugfixes**
     14* Fix notice accessing undefined variable ([#1582])
     15* Improve translation strings consistency and comments to translators ([#1600])
     16* Fix PHP error for parameter after optional parameter ([#1465])
     17* Combine the suffixes for shorter regular expression. ([#1651])
     18
     19**Locales**
     20* Update plural expression for Kyrgyz ([#1634])
     21* Shorten the slug for Valencia (Catalan) ([#1635])
    322
    423## [4.0.0-alpha.4] (Feb 28, 2023)
     
    522541
    523542[Unreleased]: https://github.com/GlotPress/GlotPress/compare/3.0.0...HEAD
     543[4.0.0-alpha.5]: https://github.com/GlotPress/GlotPress/compare/4.0.0-alpha.4...4.0.0-alpha.5
    524544[4.0.0-alpha.4]: https://github.com/GlotPress/GlotPress/compare/4.0.0-alpha.3...4.0.0-alpha.4
    525545[4.0.0-alpha.3]: https://github.com/GlotPress/GlotPress/compare/4.0.0-alpha.2...4.0.0-alpha.3
     
    578598[#1364]: https://github.com/GlotPress/GlotPress/pull/1364
    579599[#1360]: https://github.com/GlotPress/GlotPress/pull/1360
    580 [#1360]: https://github.com/GlotPress/GlotPress/pull/1378
     600[#1378]: https://github.com/GlotPress/GlotPress/pull/1378
    581601[#1391]: https://github.com/GlotPress/GlotPress/pull/1391
    582602[#1392]: https://github.com/GlotPress/GlotPress/pull/1392
     
    611631[#1477]: https://github.com/GlotPress/GlotPress/pull/1477
    612632[#1569]: https://github.com/GlotPress/GlotPress/pull/1569
     633[#1536]: https://github.com/GlotPress/GlotPress/pull/1536
     634[#1500]: https://github.com/GlotPress/GlotPress/pull/1500
     635[#1582]: https://github.com/GlotPress/GlotPress/pull/1582
     636[#1600]: https://github.com/GlotPress/GlotPress/pull/1600
     637[#1465]: https://github.com/GlotPress/GlotPress/pull/1465
     638[#1369]: https://github.com/GlotPress/GlotPress/pull/1369
     639[#1506]: https://github.com/GlotPress/GlotPress/pull/1506
     640[#1622]: https://github.com/GlotPress/GlotPress/pull/1622
     641[#1634]: https://github.com/GlotPress/GlotPress/pull/1634
     642[#1635]: https://github.com/GlotPress/GlotPress/pull/1635
     643[#1651]: https://github.com/GlotPress/GlotPress/pull/1651
  • glotpress/tags/4.0.0-alpha.5/assets/css/style.css

    r2872254 r2937674  
    695695}
    696696
     697table.translations td.original ul,
    697698table.translations td.translation ul {
    698699    margin: 0;
     
    701702}
    702703
     704table.translations td.original small,
     705table.translations td.translation small {
     706    font-size: 0.75rem;
     707}
     708
     709table.translations td.original li:not(:last-child),
    703710table.translations td.translation li:not(:last-child) {
    704711    padding-bottom: 0.25em;
     
    732739table.translations td.translation {
    733740    width: 45%;
    734     vertical-align: top;
     741    vertical-align: middle;
    735742}
    736743
     
    957964.editor .translation {
    958965    white-space: pre-wrap;
    959     margin: 1rem 0;
     966    margin: 0 0 1rem 0;
    960967    font-size: 0.875rem;
    961968    font-style: italic;
     
    12771284    padding: 0;
    12781285    margin-left: 2px;
     1286}
     1287
     1288.invisible-spaces {
     1289    background-color: var( --gp-color-secondary-600 );
     1290    opacity: 0.4;
    12791291}
    12801292
  • glotpress/tags/4.0.0-alpha.5/assets/js/common.js

    r2699206 r2937674  
    1 /* global document */
     1/* global document, wp */
    22var $gp = (
    33    function( $ ) {
     
    2929
    3030                    if ( true === dismissable ) {
    31                         dismissButton = ' <button type="button" class="button is-link gp-js-message-dismiss">' + $gp.l10n.dismiss + '</button>';
     31                        dismissButton = ' <button type="button" class="button is-link gp-js-message-dismiss">' + wp.i18n.__( 'Dismiss', 'glotpress' ) + '</button>';
    3232                    }
    3333
  • glotpress/tags/4.0.0-alpha.5/assets/js/editor.js

    r2872254 r2937674  
    250250                editor = $gp.editor.current;
    251251                button.prop( 'disabled', true );
    252                 $gp.notices.notice( 'Saving&hellip;' );
     252                $gp.notices.notice( wp.i18n.__( 'Saving&hellip;', 'glotpress' ) );
    253253
    254254                data = {
     
    273273
    274274                        button.prop( 'disabled', false );
    275                         $gp.notices.success( 'Saved!' );
     275                        $gp.notices.success( wp.i18n.__( 'Saved!', 'glotpress' ) );
    276276
    277277                        for ( original_id in response ) {
     
    285285                    error: function( xhr, msg ) {
    286286                        button.prop( 'disabled', false );
    287                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error saving the translation!';
     287                        /* translators: %s: Error message. */
     288                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error saving the translation!', 'glotpress' );
    288289                        $gp.notices.error( msg );
    289290                    },
     
    299300                editor = $gp.editor.current;
    300301                select.prop( 'disabled', true );
    301                 $gp.notices.notice( 'Setting priority&hellip;' );
     302                $gp.notices.notice( wp.i18n.__( 'Setting priority&hellip;', 'glotpress' ) );
    302303
    303304                data = {
     
    314315
    315316                        select.prop( 'disabled', false );
    316                         $gp.notices.success( 'Priority set!' );
     317                        $gp.notices.success( wp.i18n.__( 'Priority set!', 'glotpress' ) );
    317318                        new_priority_class = 'priority-' + $( 'option:selected', select ).text();
    318319                        $gp.editor.current.addClass( new_priority_class );
     
    321322                    error: function( xhr, msg ) {
    322323                        select.prop( 'disabled', false );
    323                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error setting the priority!';
     324                        /* translators: %s: Error message. */
     325                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error setting the priority!', 'glotpress' );
    324326                        $gp.notices.error( msg );
    325327                    },
     
    327329            },
    328330            set_status: function( button, status ) {
    329                 var editor, data,
     331                var editor, data, status_name,
    330332                    translationChanged = false;
    331333
     
    343345
    344346                if ( translationChanged ) {
    345                     $gp.notices.error( 'Translation has changed! Please add the new translation before changing its status.' );
     347                    $gp.notices.error( wp.i18n.__( 'Translation has changed! Please add the new translation before changing its status.', 'glotpress' ) );
    346348                    return;
    347349                }
    348350
    349351                button.prop( 'disabled', true );
    350                 $gp.notices.notice( 'Setting status to &#8220;' + status + '&#8221;&hellip;' );
     352
     353                switch ( status ) {
     354                    case 'current':
     355                        status_name = wp.i18n._x( 'current', 'Single Status', 'glotpress' );
     356                        break;
     357                    case 'rejected':
     358                        status_name = wp.i18n._x( 'rejected', 'Single Status', 'glotpress' );
     359                        break;
     360                    case 'fuzzy':
     361                        status_name = wp.i18n._x( 'fuzzy', 'Single Status', 'glotpress' );
     362                        break;
     363                    case 'changesrequested':
     364                        status_name = wp.i18n._x( 'changes requested', 'Single Status', 'glotpress' );
     365                        break;
     366                }
     367
     368                /* translators: %s: Status name. */
     369                $gp.notices.notice( wp.i18n.sprintf( wp.i18n.__( 'Setting status to &#8220;%s&#8221;&hellip;', 'glotpress' ), status_name ) );
    351370
    352371                data = {
     
    362381                    success: function( response ) {
    363382                        button.prop( 'disabled', false );
    364                         $gp.notices.success( 'Status set!' );
     383                        $gp.notices.success( wp.i18n.__( 'Status set!', 'glotpress' ) );
    365384                        $gp.editor.replace_current( response );
    366385                        $gp.editor.next();
     
    368387                    error: function( xhr, msg ) {
    369388                        button.prop( 'disabled', false );
    370                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error setting the status!';
     389                        /* translators: %s: Error message. */
     390                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error setting the status!', 'glotpress' );
    371391                        $gp.notices.error( msg );
    372392                    },
     
    379399                }
    380400
    381                 $gp.notices.notice( 'Discarding&hellip;' );
     401                $gp.notices.notice( wp.i18n.__( 'Discarding&hellip;', 'glotpress' ) );
    382402
    383403                data = {
     
    394414                    data: data,
    395415                    success: function( response ) {
    396                         $gp.notices.success( 'Saved!' );
     416                        $gp.notices.success( wp.i18n.__( 'Saved!', 'glotpress' ) );
    397417                        $gp.editor.replace_current( response );
    398418                    },
    399419                    error: function( xhr, msg ) {
    400                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error saving the translation!';
     420                        /* translators: %s: Error message. */
     421                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error saving the translation!', 'glotpress' );
    401422                        $gp.notices.error( msg );
    402423                    },
  • glotpress/tags/4.0.0-alpha.5/assets/js/glossary.js

    r2872254 r2937674  
    1 /* global $gp_glossary_options, $gp, confirm */
     1/* global $gp_glossary_options, $gp, confirm, wp */
    22/* eslint camelcase: "off", no-alert: "off" */
    33$gp.glossary = (
     
    7171
    7272                button.prop( 'disabled', true );
    73                 $gp.notices.notice( 'Saving&hellip;' );
     73                $gp.notices.notice( wp.i18n.__( 'Saving&hellip;', 'glotpress' ) );
    7474
    7575                editor = $gp.glossary.current;
     
    9090                    success: function( response ) {
    9191                        button.prop( 'disabled', false );
    92                         $gp.notices.success( 'Saved!' );
     92                        $gp.notices.success( wp.i18n.__( 'Saved!', 'glotpress' ) );
    9393                        $gp.glossary.replace_current( response );
    9494                    },
    9595                    error: function( xhr, msg ) {
    9696                        button.prop( 'disabled', false );
    97                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error saving the glossary item!';
     97                        /* translators: %s: Error message. */
     98                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error saving the glossary item!', 'glotpress' );
    9899                        $gp.notices.error( msg );
    99100                    },
     
    126127                    data: data,
    127128                    success: function() {
    128                         $gp.notices.success( 'Deleted!' );
     129                        $gp.notices.success( wp.i18n.__( 'Deleted!', 'glotpress' ) );
    129130                        editor.fadeOut( 'fast', function() {
    130131                            this.remove();
     
    136137                    },
    137138                    error: function( xhr, msg ) {
    138                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error deleting the glossary item!';
     139                        /* translators: %s: Error message. */
     140                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error deleting the glossary item!', 'glotpress' );
    139141                        $gp.notices.error( msg );
    140142                    },
  • glotpress/tags/4.0.0-alpha.5/assets/js/mass-create-sets-page.js

    r2699206 r2937674  
    1 /* global $gp_mass_create_sets_options, $gp */
     1/* global $gp_mass_create_sets_options, $gp, wp */
    22/* eslint camelcase: "off" */
    33jQuery( function( $ ) {
     
    1717                var preview = $( '#preview' );
    1818                var preview_html = '';
    19                 preview.html( '<h3>Preview changes:</h3>' );
     19                preview.html( '<h3>' + wp.i18n.__( 'Preview changes:', 'glotpress' ) + '</h3>' );
    2020                preview_html += '<ul>';
    2121                select.prop( 'disabled', false );
     
    2727                    var sets = data[ kind ];
    2828                    var html = '';
    29                     html += '<li><span class="' + kind + '">' + text.replace( '{count}', sets.length ) + '</span>';
     29                    html += '<li><span class="' + kind + '">' + text + '</span>';
    3030                    if ( sets.length ) {
    3131                        html += '<ul>';
     
    3838                    return html;
    3939                }
    40                 preview_html += preview_html_for( 'added', '{count} set(s) will be added' );
    41                 preview_html += preview_html_for( 'removed', '{count} set(s) will be removed' );
     40                /* translators: %s: Number of translation sets. */
     41                preview_html += preview_html_for( 'added', wp.i18n.sprintf( wp.i18n._n( '%s set will be added', '%s sets will be added', data.added.length, 'glotpress' ), data.added.length ) );
     42                /* translators: %s: Number of translation sets. */
     43                preview_html += preview_html_for( 'removed', wp.i18n.sprintf( wp.i18n._n( '%s set will be removed', '%s sets will be removed', data.removed.length, 'glotpress' ), data.removed.length ) );
    4244                preview_html += '</ul>';
    4345                preview.append( preview_html );
     
    4648            error: function( xhr, msg ) {
    4749                select.prop( 'disabled', false );
    48                 msg = xhr.responsehtml ? 'Error: ' + xhr.responsehtml : 'Error saving the translation!';
     50                /* translators: %s: Error message. */
     51                msg = xhr.responsehtml ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responsehtml ) : wp.i18n.__( 'Error saving the translation!', 'glotpress' );
    4952                $gp.notices.error( msg );
    5053            },
  • glotpress/tags/4.0.0-alpha.5/glotpress.php

    r2872254 r2937674  
    44 * Plugin URI: https://wordpress.org/plugins/glotpress/
    55 * Description: GlotPress is a tool to help translators collaborate.
    6  * Version: 4.0.0-alpha.4
     6 * Version: 4.0.0-alpha.5
    77 * Requires at least: 4.6
    88 * Tested up to: 5.9
     
    3030 */
    3131
    32 define( 'GP_VERSION', '4.0.0-alpha.4' );
     32define( 'GP_VERSION', '4.0.0-alpha.5' );
    3333define( 'GP_DB_VERSION', '980' );
    3434define( 'GP_CACHE_VERSION', '3.0' );
  • glotpress/tags/4.0.0-alpha.5/gp-includes/assets-loader.php

    r2872254 r2937674  
    3232    wp_register_script( 'tablesorter', $url . '/vendor/jquery.tablesorter' . $suffix, array( 'jquery' ), '20210429' );
    3333    wp_register_script( 'gp-common', $url . '/common' . $suffix, array( 'jquery', 'wp-i18n' ), '20220319' );
    34     wp_add_inline_script(
    35         'gp-common',
    36         sprintf(
    37             '$gp.l10n = %s',
    38             wp_json_encode(
    39                 array(
    40                     'dismiss' => __( 'Dismiss', 'glotpress' ),
    41                 )
    42             )
    43         )
    44     );
    45 
    4634    wp_register_script( 'gp-editor', $url . '/editor' . $suffix, array( 'gp-common', 'jquery-ui-tooltip', 'wp-wordcount' ), '20220319' );
    4735    wp_register_script( 'gp-glossary', $url . '/glossary' . $suffix, array( 'gp-editor' ), '20220319' );
    4836    wp_register_script( 'gp-translations-page', $url . '/translations-page' . $suffix, array( 'gp-editor' ), '20220327' );
    4937    wp_register_script( 'gp-mass-create-sets-page', $url . '/mass-create-sets-page' . $suffix, array( 'gp-editor' ), '20210429' );
     38
     39    wp_set_script_translations( 'gp-common', 'glotpress' );
     40    wp_set_script_translations( 'gp-editor', 'glotpress' );
     41    wp_set_script_translations( 'gp-glossary', 'glotpress' );
     42    wp_set_script_translations( 'gp-mass-create-sets-page', 'glotpress' );
    5043}
    5144
  • glotpress/tags/4.0.0-alpha.5/gp-includes/meta.php

    r2290426 r2937674  
    8080 * @return bool|int True if meta updated, false if there is an error and the id of the inserted row otherwise.
    8181 */
    82 function gp_update_meta( $object_id = 0, $meta_key, $meta_value, $type, $global = false ) {
     82function gp_update_meta( $object_id, $meta_key, $meta_value, $type, $global = false ) {
    8383    global $wpdb;
    8484
     
    166166 * @return bool
    167167 */
    168 function gp_delete_meta( $object_id = 0, $meta_key, $meta_value, $type, $global = false ) {
     168function gp_delete_meta( $object_id, $meta_key, $meta_value, $type, $global = false ) {
    169169    global $wpdb;
    170170
  • glotpress/tags/4.0.0-alpha.5/gp-includes/router.php

    r2296570 r2937674  
    3232    public function request_uri() {
    3333        global $wp;
    34         return urldecode( '/' . rtrim( $wp->query_vars['gp_route'], '/' ) );
     34        $gp_route = '';
     35        if ( isset( $wp->query_vars['gp_route'] ) ) {
     36            $gp_route = $wp->query_vars['gp_route'];
     37        }
     38        return urldecode( '/' . rtrim( $gp_route, '/' ) );
    3539    }
    3640
  • glotpress/tags/4.0.0-alpha.5/gp-includes/routes/translation.php

    r2872254 r2937674  
    490490                        $message = sprintf(
    491491                        /* translators: %s: Translations count. */
    492                             _n( 'Error requesting changes in %s translation.', 'Error requesting changes in %s translations.', $error, 'glotpress' ),
     492                            _n( 'Error with requesting changes in %s translation.', 'Error with requesting changes in %s translations.', $error, 'glotpress' ),
    493493                            $error
    494494                        );
  • glotpress/tags/4.0.0-alpha.5/gp-includes/things/translation.php

    r2872254 r2937674  
    683683            )
    684684        )
     685        && $this->update(
     686            array( 'status' => 'old' ),
     687            array(
     688                'original_id'        => $this->original_id,
     689                'translation_set_id' => $this->translation_set_id,
     690                'user_id'            => $this->user_id,
     691                'status'             => 'waiting',
     692            )
     693        )
    685694        && $this->save(
    686695            array(
  • glotpress/tags/4.0.0-alpha.5/gp-includes/warnings.php

    r2872254 r2937674  
    844844        if ( $original_start_spaces && ! $translation_start_spaces ) {
    845845            $warnings[] = sprintf(
    846                 /* translators: 1: Number of spaces at the beginning of the original string. */
     846                /* translators: %d: Number of spaces at the beginning of the original string. */
    847847                _n(
    848848                    'The translation appears to be missing %d space at the beginning.',
     
    856856        if ( ( ! $original_start_spaces ) && $translation_start_spaces ) {
    857857            $warnings[] = sprintf(
    858                 /* translators: 1: Number of spaces at the beginning of the translation string. */
     858                /* translators: %d: Number of spaces at the beginning of the translation string. */
    859859                _n(
    860860                    'The translation appears to be adding %d space at the beginning.',
     
    868868        if ( ( $original_end_spaces ) && ( ! $translation_end_spaces ) ) {
    869869            $warnings[] = sprintf(
    870                 /* translators: 1: Number of spaces at the end of the original string. */
     870                /* translators: %d: Number of spaces at the end of the original string. */
    871871                _n(
    872872                    'The translation appears to be missing %d space at the end.',
     
    880880        if ( ! $original_end_spaces && $translation_end_spaces ) {
    881881            $warnings[] = sprintf(
    882                 /* translators: 1: Number of spaces at the end of the translation string. */
     882                /* translators: %d: Number of spaces at the end of the translation string. */
    883883                _n(
    884884                    'The translation appears to be adding %d space at the end.',
     
    892892        if ( $original_start_spaces && $translation_start_spaces && ( $original_start_spaces !== $translation_start_spaces ) ) {
    893893            $warnings[] = sprintf(
    894                 /* translators: 1: Number of spaces at the beginning of the original string. 2: Number of spaces at the beginning of the translation string. */
     894                /* translators: 1: Number of spaces at the beginning of the original string (singular/plural). 2: Number of spaces at the beginning of the translation string. */
    895895                _n(
    896896                    'Expected %1$d space at the beginning, got %2$d.',
     
    905905        if ( $original_end_spaces && $translation_end_spaces && ( $original_end_spaces !== $translation_end_spaces ) ) {
    906906            $warnings[] = sprintf(
    907                 /* translators: 1: Number of spaces at the end of the original string. 2: Number of spaces at the end of the translation string. */
     907                /* translators: 1: Number of spaces at the end of the original string (singular/plural). 2: Number of spaces at the end of the translation string. */
    908908                _n(
    909909                    'Expected %1$d space at the end, got %2$d.',
  • glotpress/tags/4.0.0-alpha.5/gp-templates/glossary-entry-row.php

    r2785382 r2937674  
    4343                ?>
    4444                </select></dd>
     45                <dt><label for="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>"><?php _ex( 'Translation', 'glossary entry', 'glotpress' ); ?></label></dt>
     46                <dd><input type="text" name="glossary_entry[<?php echo esc_attr( $entry->id ); ?>][translation]" id="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>" value="<?php echo esc_attr( $entry->translation ); ?>"></dd>
    4547                <dt><label for="glossary_entry_comments_<?php echo esc_attr( $entry->id ); ?><?php echo esc_attr( $entry->id ); ?>"><?php _ex( 'Comments', 'glossary entry', 'glotpress' ); ?></label></dt>
    4648                <dd><textarea type="text" name="glossary_entry[<?php echo esc_attr( $entry->id ); ?>][comment]" id="glossary_entry_comments_<?php echo esc_attr( $entry->id ); ?>"><?php echo esc_textarea( $entry->comment ); ?></textarea></dd>
    47                 <dt><label for="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>"><?php _ex( 'Translation', 'glossary entry', 'glotpress' ); ?></label></dt>
    48                 <dd><input type="text" name="glossary_entry[<?php echo esc_attr( $entry->id ); ?>][translation]" id="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>" value="<?php echo esc_attr( $entry->translation ); ?>"></dd>
    4949            </dl>
    5050
  • glotpress/tags/4.0.0-alpha.5/gp-templates/helper-functions.php

    r2872254 r2937674  
    4343        $text
    4444    );
     45
     46    // Highlight two or more spaces between words.
     47    $text = preg_replace( '/(?!^)  +(?!$)/', '<span class="invisible-spaces">$0</span>', $text );
     48    // Highlight leading and trailing spaces in single lines.
     49    $text = preg_replace( '/^ +| +$/', '<span class="invisible-spaces">$0</span>', $text );
     50    // Highlight leading spaces in multi lines.
     51    $text = preg_replace( "/\n( +)/", "\n<span class=\"invisible-spaces\">$1</span>", $text );
     52    // Highlight trailing spaces in multi lines.
     53    $text = preg_replace( "/( +)\n/", "<span class=\"invisible-spaces\">$1</span>\n", $text );
    4554
    4655    $text = str_replace( array( "\r", "\n" ), "<span class='invisibles' title='" . esc_attr__( 'New line', 'glotpress' ) . "'>&crarr;</span>\n", $text );
     
    170179        }
    171180
    172         $terms_search = '\b(';
     181        $regex_group = array();
    173182        foreach ( $glossary_entries_suffixes as $term => $suffixes ) {
    174             $terms_search .= preg_quote( $term, '/' );
    175 
    176             if ( ! empty( $suffixes ) ) {
    177                 $terms_search .= '(?:' . implode( '|', $suffixes ) . ')?';
    178             }
    179 
    180             $terms_search .= '|';
     183            $regex_suffix = $suffixes ? '(?:' . implode( '|', $suffixes ) . ')?' : '';
     184
     185            if ( ! isset( $regex_group[ $regex_suffix ] ) ) {
     186                $regex_group[ $regex_suffix ] = array();
     187            }
     188
     189            $regex_group[ $regex_suffix ][] = preg_quote( $term, '/' );
    181190
    182191            $referenced_term = $term;
     
    202211                }
    203212            }
     213        }
     214
     215        // Build the regular expression.
     216        $terms_search = '\b(';
     217        foreach ( $regex_group as $suffix => $terms ) {
     218            $terms_search .= '(?:' . implode( '|', $terms ) . ')' . $suffix . '|';
    204219        }
    205220
  • glotpress/tags/4.0.0-alpha.5/gp-templates/translation-row-editor.php

    r2699206 r2937674  
    1818
    1919$singular = sprintf(
    20     /* translators: %s: Original singular form of the text */
    21     __( 'Singular: %s', 'glotpress' ),
    22     '<span class="original">' . prepare_original( $translation_singular ) . '</span>'
     20    '<small>%s</small><br><span class="original">%s</span>',
     21    __( 'Singular:', 'glotpress' ),
     22    prepare_original( $translation_singular )
    2323);
    24 $plural = sprintf(
    25     /* translators: %s: Original plural form of the text */
    26     __( 'Plural: %s', 'glotpress' ),
    27     '<span class="original">' . ( isset( $translation->plural_glossary_markup ) ? prepare_original( $translation->plural_glossary_markup ) : prepare_original( esc_translation( $translation->plural ) ) ) . '</span>'
     24$plural   = sprintf(
     25    '<small>%s</small><br><span class="original">%s</span>',
     26    __( 'Plural:', 'glotpress' ),
     27    isset( $translation->plural_glossary_markup ) ? prepare_original( $translation->plural_glossary_markup ) : prepare_original( esc_translation( $translation->plural ) )
    2828);
    2929
  • glotpress/tags/4.0.0-alpha.5/gp-templates/translation-row-preview.php

    r2296020 r2937674  
    3030    </td>
    3131    <td class="original">
    32         <span class="original-text"><?php echo prepare_original( $translation_singular ); ?></span>
     32        <?php
     33        if ( ! $translation->plural ) {
     34            ?>
     35            <span class="original-text"><?php echo prepare_original( $translation_singular ); ?></span>
     36            <?php
     37        } else {
     38            $translation_plural = isset( $translation->plural_glossary_markup ) ? $translation->plural_glossary_markup : prepare_original( esc_translation( $translation->plural ) );
     39            ?>
     40            <ul>
     41                <li><small><?php esc_html_e( 'Singular:', 'glotpress' ); ?></small><br><span class="original-text"><?php echo prepare_original( $translation_singular ); ?></span></li>
     42                <li><small><?php esc_html_e( 'Plural:', 'glotpress' ); ?></small><br><span class="original-text"><?php echo prepare_original( $translation_plural ); ?></span></li>
     43            </ul>
     44            <?php
     45        }
     46        ?>
    3347        <?php if ( $translation->context ) : ?>
    3448            <?php /* translators: %s: Context of original */ ?>
     
    4862
    4963        $missing_text = "<span class='missing'>$edit_text</span>";
    50         if ( ! count( array_filter( $translation->translations, 'gp_is_not_null' ) ) ) :
     64        if ( ! count( array_filter( $translation->translations, 'gp_is_not_null' ) ) ) {
    5165            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    5266            echo $missing_text;
    53         elseif ( ! $translation->plural ) :
    54             echo '<span class="translation-text">' . esc_translation( $translation->translations[0] ) . '</span>';
    55         else :
     67        } elseif ( ! $translation->plural || 1 === $locale->nplurals ) {
     68            echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[0] ) ) . '</span>';
     69        } elseif ( $translation->plural && 2 === $locale->nplurals && 'n != 1' === $locale->plural_expression ) {
     70            ?>
     71            <ul>
     72                <li>
     73                    <small><?php esc_html_e( 'Singular:', 'glotpress' ); ?></small><br>
     74                    <?php
     75                    if ( ! isset( $translation->translations[0] ) || gp_is_empty_string( $translation->translations[0] ) ) {
     76                        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     77                        echo $missing_text;
     78                    } else {
     79                        echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[0] ) ) . '</span>';
     80                    }
     81                    ?>
     82                </li>
     83                <li>
     84                    <small><?php esc_html_e( 'Plural:', 'glotpress' ); ?></small><br>
     85                    <?php
     86                    if ( ! isset( $translation->translations[1] ) || gp_is_empty_string( $translation->translations[1] ) ) {
     87                        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     88                        echo $missing_text;
     89                    } else {
     90                        echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[1] ) ) . '</span>';
     91                    }
     92                    ?>
     93                </li>
     94            </ul>
     95            <?php
     96        } else {
     97            ?>
     98            <ul>
     99                <?php
     100                foreach ( range( 0, $locale->nplurals - 1 ) as $plural_index ) {
     101                    $plural_string = implode( ', ', $locale->numbers_for_index( $plural_index ) );
     102                    ?>
     103                    <li>
     104                        <small>
     105                            <?php
     106                            printf(
     107                                /* translators: %s: Plural form. */
     108                                esc_html__( '%s:', 'glotpress' ),
     109                                esc_html( $plural_string )
     110                            );
     111                            ?>
     112                        </small><br>
     113                        <?php
     114                        if ( ! isset( $translation->translations[ $plural_index ] ) || gp_is_empty_string( $translation->translations[ $plural_index ] ) ) {
     115                            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     116                            echo $missing_text;
     117                        } else {
     118                            echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[ $plural_index ] ) ) . '</span>';
     119                        }
     120                        ?>
     121                    </li>
     122                    <?php
     123                }
     124                ?>
     125            </ul>
     126            <?php
     127        }
    56128        ?>
    57             <ul>
    58                 <?php foreach ( $translation->translations as $current_translation ) : ?>
    59                     <li>
    60                     <?php
    61                     // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    62                     echo gp_is_empty_string( $current_translation ) ? $missing_text : '<span class="translation-text">' . esc_translation( $current_translation ) . '</span>';
    63                     ?>
    64                     </li>
    65                 <?php endforeach; ?>
    66             </ul>
    67         <?php endif; ?>
    68129    </td>
    69130    <td class="actions">
  • glotpress/tags/4.0.0-alpha.5/locales/locales.php

    r2872254 r2937674  
    1010    public $lang_code_iso_639_3 = null;
    1111    public $country_code;
    12     public $wp_locale; // This should only be set for locales that are offically supported on translate.wordpress.org.
     12    public $wp_locale; // This should only be set for locales that are officially supported on translate.wordpress.org.
    1313    public $slug;
    1414    public $nplurals = 2;
     
    473473        $ca_valencia->lang_code_iso_639_2 = 'cat';
    474474        $ca_valencia->wp_locale = 'ca_valencia';
    475         $ca_valencia->slug = 'ca-valencia';
     475        $ca_valencia->slug = 'ca-val';
    476476        $ca_valencia->google_code = 'ca';
    477477        $ca_valencia->facebook_locale = 'ca_ES';
     
    16011601        $kir->wp_locale = 'kir';
    16021602        $kir->slug = 'kir';
    1603         $kir->nplurals = 1;
    1604         $kir->plural_expression = '0';
    16051603        $kir->google_code = 'ky';
    16061604        $kir->alphabet = 'cyrillic';
  • glotpress/trunk/CHANGELOG.md

    r2872254 r2937674  
    11All notable changes to this project will be documented in this file.
    22This project adheres to [Semantic Versioning](http://semver.org/).
     3
     4## [4.0.0-alpha.5] (July 12, 2023)
     5
     6**Features**
     7* Set as old the previous translations with waiting status for this user ([#1536])
     8* Highlight leading and trailing spaces, and double/multiple spaces in the middle ([#1500])
     9* Add I18n to JavaScript ([#1369])
     10* Add plural and plural forms labels to row previews and format the row editor accordingly ([#1506])
     11* Reorder glossary row editor items ([#1622])
     12
     13**Bugfixes**
     14* Fix notice accessing undefined variable ([#1582])
     15* Improve translation strings consistency and comments to translators ([#1600])
     16* Fix PHP error for parameter after optional parameter ([#1465])
     17* Combine the suffixes for shorter regular expression. ([#1651])
     18
     19**Locales**
     20* Update plural expression for Kyrgyz ([#1634])
     21* Shorten the slug for Valencia (Catalan) ([#1635])
    322
    423## [4.0.0-alpha.4] (Feb 28, 2023)
     
    522541
    523542[Unreleased]: https://github.com/GlotPress/GlotPress/compare/3.0.0...HEAD
     543[4.0.0-alpha.5]: https://github.com/GlotPress/GlotPress/compare/4.0.0-alpha.4...4.0.0-alpha.5
    524544[4.0.0-alpha.4]: https://github.com/GlotPress/GlotPress/compare/4.0.0-alpha.3...4.0.0-alpha.4
    525545[4.0.0-alpha.3]: https://github.com/GlotPress/GlotPress/compare/4.0.0-alpha.2...4.0.0-alpha.3
     
    578598[#1364]: https://github.com/GlotPress/GlotPress/pull/1364
    579599[#1360]: https://github.com/GlotPress/GlotPress/pull/1360
    580 [#1360]: https://github.com/GlotPress/GlotPress/pull/1378
     600[#1378]: https://github.com/GlotPress/GlotPress/pull/1378
    581601[#1391]: https://github.com/GlotPress/GlotPress/pull/1391
    582602[#1392]: https://github.com/GlotPress/GlotPress/pull/1392
     
    611631[#1477]: https://github.com/GlotPress/GlotPress/pull/1477
    612632[#1569]: https://github.com/GlotPress/GlotPress/pull/1569
     633[#1536]: https://github.com/GlotPress/GlotPress/pull/1536
     634[#1500]: https://github.com/GlotPress/GlotPress/pull/1500
     635[#1582]: https://github.com/GlotPress/GlotPress/pull/1582
     636[#1600]: https://github.com/GlotPress/GlotPress/pull/1600
     637[#1465]: https://github.com/GlotPress/GlotPress/pull/1465
     638[#1369]: https://github.com/GlotPress/GlotPress/pull/1369
     639[#1506]: https://github.com/GlotPress/GlotPress/pull/1506
     640[#1622]: https://github.com/GlotPress/GlotPress/pull/1622
     641[#1634]: https://github.com/GlotPress/GlotPress/pull/1634
     642[#1635]: https://github.com/GlotPress/GlotPress/pull/1635
     643[#1651]: https://github.com/GlotPress/GlotPress/pull/1651
  • glotpress/trunk/assets/css/style.css

    r2872254 r2937674  
    695695}
    696696
     697table.translations td.original ul,
    697698table.translations td.translation ul {
    698699    margin: 0;
     
    701702}
    702703
     704table.translations td.original small,
     705table.translations td.translation small {
     706    font-size: 0.75rem;
     707}
     708
     709table.translations td.original li:not(:last-child),
    703710table.translations td.translation li:not(:last-child) {
    704711    padding-bottom: 0.25em;
     
    732739table.translations td.translation {
    733740    width: 45%;
    734     vertical-align: top;
     741    vertical-align: middle;
    735742}
    736743
     
    957964.editor .translation {
    958965    white-space: pre-wrap;
    959     margin: 1rem 0;
     966    margin: 0 0 1rem 0;
    960967    font-size: 0.875rem;
    961968    font-style: italic;
     
    12771284    padding: 0;
    12781285    margin-left: 2px;
     1286}
     1287
     1288.invisible-spaces {
     1289    background-color: var( --gp-color-secondary-600 );
     1290    opacity: 0.4;
    12791291}
    12801292
  • glotpress/trunk/assets/js/common.js

    r2699206 r2937674  
    1 /* global document */
     1/* global document, wp */
    22var $gp = (
    33    function( $ ) {
     
    2929
    3030                    if ( true === dismissable ) {
    31                         dismissButton = ' <button type="button" class="button is-link gp-js-message-dismiss">' + $gp.l10n.dismiss + '</button>';
     31                        dismissButton = ' <button type="button" class="button is-link gp-js-message-dismiss">' + wp.i18n.__( 'Dismiss', 'glotpress' ) + '</button>';
    3232                    }
    3333
  • glotpress/trunk/assets/js/editor.js

    r2872254 r2937674  
    250250                editor = $gp.editor.current;
    251251                button.prop( 'disabled', true );
    252                 $gp.notices.notice( 'Saving&hellip;' );
     252                $gp.notices.notice( wp.i18n.__( 'Saving&hellip;', 'glotpress' ) );
    253253
    254254                data = {
     
    273273
    274274                        button.prop( 'disabled', false );
    275                         $gp.notices.success( 'Saved!' );
     275                        $gp.notices.success( wp.i18n.__( 'Saved!', 'glotpress' ) );
    276276
    277277                        for ( original_id in response ) {
     
    285285                    error: function( xhr, msg ) {
    286286                        button.prop( 'disabled', false );
    287                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error saving the translation!';
     287                        /* translators: %s: Error message. */
     288                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error saving the translation!', 'glotpress' );
    288289                        $gp.notices.error( msg );
    289290                    },
     
    299300                editor = $gp.editor.current;
    300301                select.prop( 'disabled', true );
    301                 $gp.notices.notice( 'Setting priority&hellip;' );
     302                $gp.notices.notice( wp.i18n.__( 'Setting priority&hellip;', 'glotpress' ) );
    302303
    303304                data = {
     
    314315
    315316                        select.prop( 'disabled', false );
    316                         $gp.notices.success( 'Priority set!' );
     317                        $gp.notices.success( wp.i18n.__( 'Priority set!', 'glotpress' ) );
    317318                        new_priority_class = 'priority-' + $( 'option:selected', select ).text();
    318319                        $gp.editor.current.addClass( new_priority_class );
     
    321322                    error: function( xhr, msg ) {
    322323                        select.prop( 'disabled', false );
    323                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error setting the priority!';
     324                        /* translators: %s: Error message. */
     325                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error setting the priority!', 'glotpress' );
    324326                        $gp.notices.error( msg );
    325327                    },
     
    327329            },
    328330            set_status: function( button, status ) {
    329                 var editor, data,
     331                var editor, data, status_name,
    330332                    translationChanged = false;
    331333
     
    343345
    344346                if ( translationChanged ) {
    345                     $gp.notices.error( 'Translation has changed! Please add the new translation before changing its status.' );
     347                    $gp.notices.error( wp.i18n.__( 'Translation has changed! Please add the new translation before changing its status.', 'glotpress' ) );
    346348                    return;
    347349                }
    348350
    349351                button.prop( 'disabled', true );
    350                 $gp.notices.notice( 'Setting status to &#8220;' + status + '&#8221;&hellip;' );
     352
     353                switch ( status ) {
     354                    case 'current':
     355                        status_name = wp.i18n._x( 'current', 'Single Status', 'glotpress' );
     356                        break;
     357                    case 'rejected':
     358                        status_name = wp.i18n._x( 'rejected', 'Single Status', 'glotpress' );
     359                        break;
     360                    case 'fuzzy':
     361                        status_name = wp.i18n._x( 'fuzzy', 'Single Status', 'glotpress' );
     362                        break;
     363                    case 'changesrequested':
     364                        status_name = wp.i18n._x( 'changes requested', 'Single Status', 'glotpress' );
     365                        break;
     366                }
     367
     368                /* translators: %s: Status name. */
     369                $gp.notices.notice( wp.i18n.sprintf( wp.i18n.__( 'Setting status to &#8220;%s&#8221;&hellip;', 'glotpress' ), status_name ) );
    351370
    352371                data = {
     
    362381                    success: function( response ) {
    363382                        button.prop( 'disabled', false );
    364                         $gp.notices.success( 'Status set!' );
     383                        $gp.notices.success( wp.i18n.__( 'Status set!', 'glotpress' ) );
    365384                        $gp.editor.replace_current( response );
    366385                        $gp.editor.next();
     
    368387                    error: function( xhr, msg ) {
    369388                        button.prop( 'disabled', false );
    370                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error setting the status!';
     389                        /* translators: %s: Error message. */
     390                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error setting the status!', 'glotpress' );
    371391                        $gp.notices.error( msg );
    372392                    },
     
    379399                }
    380400
    381                 $gp.notices.notice( 'Discarding&hellip;' );
     401                $gp.notices.notice( wp.i18n.__( 'Discarding&hellip;', 'glotpress' ) );
    382402
    383403                data = {
     
    394414                    data: data,
    395415                    success: function( response ) {
    396                         $gp.notices.success( 'Saved!' );
     416                        $gp.notices.success( wp.i18n.__( 'Saved!', 'glotpress' ) );
    397417                        $gp.editor.replace_current( response );
    398418                    },
    399419                    error: function( xhr, msg ) {
    400                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error saving the translation!';
     420                        /* translators: %s: Error message. */
     421                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error saving the translation!', 'glotpress' );
    401422                        $gp.notices.error( msg );
    402423                    },
  • glotpress/trunk/assets/js/glossary.js

    r2872254 r2937674  
    1 /* global $gp_glossary_options, $gp, confirm */
     1/* global $gp_glossary_options, $gp, confirm, wp */
    22/* eslint camelcase: "off", no-alert: "off" */
    33$gp.glossary = (
     
    7171
    7272                button.prop( 'disabled', true );
    73                 $gp.notices.notice( 'Saving&hellip;' );
     73                $gp.notices.notice( wp.i18n.__( 'Saving&hellip;', 'glotpress' ) );
    7474
    7575                editor = $gp.glossary.current;
     
    9090                    success: function( response ) {
    9191                        button.prop( 'disabled', false );
    92                         $gp.notices.success( 'Saved!' );
     92                        $gp.notices.success( wp.i18n.__( 'Saved!', 'glotpress' ) );
    9393                        $gp.glossary.replace_current( response );
    9494                    },
    9595                    error: function( xhr, msg ) {
    9696                        button.prop( 'disabled', false );
    97                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error saving the glossary item!';
     97                        /* translators: %s: Error message. */
     98                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error saving the glossary item!', 'glotpress' );
    9899                        $gp.notices.error( msg );
    99100                    },
     
    126127                    data: data,
    127128                    success: function() {
    128                         $gp.notices.success( 'Deleted!' );
     129                        $gp.notices.success( wp.i18n.__( 'Deleted!', 'glotpress' ) );
    129130                        editor.fadeOut( 'fast', function() {
    130131                            this.remove();
     
    136137                    },
    137138                    error: function( xhr, msg ) {
    138                         msg = xhr.responseText ? 'Error: ' + xhr.responseText : 'Error deleting the glossary item!';
     139                        /* translators: %s: Error message. */
     140                        msg = xhr.responseText ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responseText ) : wp.i18n.__( 'Error deleting the glossary item!', 'glotpress' );
    139141                        $gp.notices.error( msg );
    140142                    },
  • glotpress/trunk/assets/js/mass-create-sets-page.js

    r2699206 r2937674  
    1 /* global $gp_mass_create_sets_options, $gp */
     1/* global $gp_mass_create_sets_options, $gp, wp */
    22/* eslint camelcase: "off" */
    33jQuery( function( $ ) {
     
    1717                var preview = $( '#preview' );
    1818                var preview_html = '';
    19                 preview.html( '<h3>Preview changes:</h3>' );
     19                preview.html( '<h3>' + wp.i18n.__( 'Preview changes:', 'glotpress' ) + '</h3>' );
    2020                preview_html += '<ul>';
    2121                select.prop( 'disabled', false );
     
    2727                    var sets = data[ kind ];
    2828                    var html = '';
    29                     html += '<li><span class="' + kind + '">' + text.replace( '{count}', sets.length ) + '</span>';
     29                    html += '<li><span class="' + kind + '">' + text + '</span>';
    3030                    if ( sets.length ) {
    3131                        html += '<ul>';
     
    3838                    return html;
    3939                }
    40                 preview_html += preview_html_for( 'added', '{count} set(s) will be added' );
    41                 preview_html += preview_html_for( 'removed', '{count} set(s) will be removed' );
     40                /* translators: %s: Number of translation sets. */
     41                preview_html += preview_html_for( 'added', wp.i18n.sprintf( wp.i18n._n( '%s set will be added', '%s sets will be added', data.added.length, 'glotpress' ), data.added.length ) );
     42                /* translators: %s: Number of translation sets. */
     43                preview_html += preview_html_for( 'removed', wp.i18n.sprintf( wp.i18n._n( '%s set will be removed', '%s sets will be removed', data.removed.length, 'glotpress' ), data.removed.length ) );
    4244                preview_html += '</ul>';
    4345                preview.append( preview_html );
     
    4648            error: function( xhr, msg ) {
    4749                select.prop( 'disabled', false );
    48                 msg = xhr.responsehtml ? 'Error: ' + xhr.responsehtml : 'Error saving the translation!';
     50                /* translators: %s: Error message. */
     51                msg = xhr.responsehtml ? wp.i18n.sprintf( wp.i18n.__( 'Error: %s', 'glotpress' ), xhr.responsehtml ) : wp.i18n.__( 'Error saving the translation!', 'glotpress' );
    4952                $gp.notices.error( msg );
    5053            },
  • glotpress/trunk/glotpress.php

    r2872254 r2937674  
    44 * Plugin URI: https://wordpress.org/plugins/glotpress/
    55 * Description: GlotPress is a tool to help translators collaborate.
    6  * Version: 4.0.0-alpha.4
     6 * Version: 4.0.0-alpha.5
    77 * Requires at least: 4.6
    88 * Tested up to: 5.9
     
    3030 */
    3131
    32 define( 'GP_VERSION', '4.0.0-alpha.4' );
     32define( 'GP_VERSION', '4.0.0-alpha.5' );
    3333define( 'GP_DB_VERSION', '980' );
    3434define( 'GP_CACHE_VERSION', '3.0' );
  • glotpress/trunk/gp-includes/assets-loader.php

    r2872254 r2937674  
    3232    wp_register_script( 'tablesorter', $url . '/vendor/jquery.tablesorter' . $suffix, array( 'jquery' ), '20210429' );
    3333    wp_register_script( 'gp-common', $url . '/common' . $suffix, array( 'jquery', 'wp-i18n' ), '20220319' );
    34     wp_add_inline_script(
    35         'gp-common',
    36         sprintf(
    37             '$gp.l10n = %s',
    38             wp_json_encode(
    39                 array(
    40                     'dismiss' => __( 'Dismiss', 'glotpress' ),
    41                 )
    42             )
    43         )
    44     );
    45 
    4634    wp_register_script( 'gp-editor', $url . '/editor' . $suffix, array( 'gp-common', 'jquery-ui-tooltip', 'wp-wordcount' ), '20220319' );
    4735    wp_register_script( 'gp-glossary', $url . '/glossary' . $suffix, array( 'gp-editor' ), '20220319' );
    4836    wp_register_script( 'gp-translations-page', $url . '/translations-page' . $suffix, array( 'gp-editor' ), '20220327' );
    4937    wp_register_script( 'gp-mass-create-sets-page', $url . '/mass-create-sets-page' . $suffix, array( 'gp-editor' ), '20210429' );
     38
     39    wp_set_script_translations( 'gp-common', 'glotpress' );
     40    wp_set_script_translations( 'gp-editor', 'glotpress' );
     41    wp_set_script_translations( 'gp-glossary', 'glotpress' );
     42    wp_set_script_translations( 'gp-mass-create-sets-page', 'glotpress' );
    5043}
    5144
  • glotpress/trunk/gp-includes/meta.php

    r2290426 r2937674  
    8080 * @return bool|int True if meta updated, false if there is an error and the id of the inserted row otherwise.
    8181 */
    82 function gp_update_meta( $object_id = 0, $meta_key, $meta_value, $type, $global = false ) {
     82function gp_update_meta( $object_id, $meta_key, $meta_value, $type, $global = false ) {
    8383    global $wpdb;
    8484
     
    166166 * @return bool
    167167 */
    168 function gp_delete_meta( $object_id = 0, $meta_key, $meta_value, $type, $global = false ) {
     168function gp_delete_meta( $object_id, $meta_key, $meta_value, $type, $global = false ) {
    169169    global $wpdb;
    170170
  • glotpress/trunk/gp-includes/router.php

    r2296570 r2937674  
    3232    public function request_uri() {
    3333        global $wp;
    34         return urldecode( '/' . rtrim( $wp->query_vars['gp_route'], '/' ) );
     34        $gp_route = '';
     35        if ( isset( $wp->query_vars['gp_route'] ) ) {
     36            $gp_route = $wp->query_vars['gp_route'];
     37        }
     38        return urldecode( '/' . rtrim( $gp_route, '/' ) );
    3539    }
    3640
  • glotpress/trunk/gp-includes/routes/translation.php

    r2872254 r2937674  
    490490                        $message = sprintf(
    491491                        /* translators: %s: Translations count. */
    492                             _n( 'Error requesting changes in %s translation.', 'Error requesting changes in %s translations.', $error, 'glotpress' ),
     492                            _n( 'Error with requesting changes in %s translation.', 'Error with requesting changes in %s translations.', $error, 'glotpress' ),
    493493                            $error
    494494                        );
  • glotpress/trunk/gp-includes/things/translation.php

    r2872254 r2937674  
    683683            )
    684684        )
     685        && $this->update(
     686            array( 'status' => 'old' ),
     687            array(
     688                'original_id'        => $this->original_id,
     689                'translation_set_id' => $this->translation_set_id,
     690                'user_id'            => $this->user_id,
     691                'status'             => 'waiting',
     692            )
     693        )
    685694        && $this->save(
    686695            array(
  • glotpress/trunk/gp-includes/warnings.php

    r2872254 r2937674  
    844844        if ( $original_start_spaces && ! $translation_start_spaces ) {
    845845            $warnings[] = sprintf(
    846                 /* translators: 1: Number of spaces at the beginning of the original string. */
     846                /* translators: %d: Number of spaces at the beginning of the original string. */
    847847                _n(
    848848                    'The translation appears to be missing %d space at the beginning.',
     
    856856        if ( ( ! $original_start_spaces ) && $translation_start_spaces ) {
    857857            $warnings[] = sprintf(
    858                 /* translators: 1: Number of spaces at the beginning of the translation string. */
     858                /* translators: %d: Number of spaces at the beginning of the translation string. */
    859859                _n(
    860860                    'The translation appears to be adding %d space at the beginning.',
     
    868868        if ( ( $original_end_spaces ) && ( ! $translation_end_spaces ) ) {
    869869            $warnings[] = sprintf(
    870                 /* translators: 1: Number of spaces at the end of the original string. */
     870                /* translators: %d: Number of spaces at the end of the original string. */
    871871                _n(
    872872                    'The translation appears to be missing %d space at the end.',
     
    880880        if ( ! $original_end_spaces && $translation_end_spaces ) {
    881881            $warnings[] = sprintf(
    882                 /* translators: 1: Number of spaces at the end of the translation string. */
     882                /* translators: %d: Number of spaces at the end of the translation string. */
    883883                _n(
    884884                    'The translation appears to be adding %d space at the end.',
     
    892892        if ( $original_start_spaces && $translation_start_spaces && ( $original_start_spaces !== $translation_start_spaces ) ) {
    893893            $warnings[] = sprintf(
    894                 /* translators: 1: Number of spaces at the beginning of the original string. 2: Number of spaces at the beginning of the translation string. */
     894                /* translators: 1: Number of spaces at the beginning of the original string (singular/plural). 2: Number of spaces at the beginning of the translation string. */
    895895                _n(
    896896                    'Expected %1$d space at the beginning, got %2$d.',
     
    905905        if ( $original_end_spaces && $translation_end_spaces && ( $original_end_spaces !== $translation_end_spaces ) ) {
    906906            $warnings[] = sprintf(
    907                 /* translators: 1: Number of spaces at the end of the original string. 2: Number of spaces at the end of the translation string. */
     907                /* translators: 1: Number of spaces at the end of the original string (singular/plural). 2: Number of spaces at the end of the translation string. */
    908908                _n(
    909909                    'Expected %1$d space at the end, got %2$d.',
  • glotpress/trunk/gp-templates/glossary-entry-row.php

    r2785382 r2937674  
    4343                ?>
    4444                </select></dd>
     45                <dt><label for="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>"><?php _ex( 'Translation', 'glossary entry', 'glotpress' ); ?></label></dt>
     46                <dd><input type="text" name="glossary_entry[<?php echo esc_attr( $entry->id ); ?>][translation]" id="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>" value="<?php echo esc_attr( $entry->translation ); ?>"></dd>
    4547                <dt><label for="glossary_entry_comments_<?php echo esc_attr( $entry->id ); ?><?php echo esc_attr( $entry->id ); ?>"><?php _ex( 'Comments', 'glossary entry', 'glotpress' ); ?></label></dt>
    4648                <dd><textarea type="text" name="glossary_entry[<?php echo esc_attr( $entry->id ); ?>][comment]" id="glossary_entry_comments_<?php echo esc_attr( $entry->id ); ?>"><?php echo esc_textarea( $entry->comment ); ?></textarea></dd>
    47                 <dt><label for="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>"><?php _ex( 'Translation', 'glossary entry', 'glotpress' ); ?></label></dt>
    48                 <dd><input type="text" name="glossary_entry[<?php echo esc_attr( $entry->id ); ?>][translation]" id="glossary_entry_translation_<?php echo esc_attr( $entry->id ); ?>" value="<?php echo esc_attr( $entry->translation ); ?>"></dd>
    4949            </dl>
    5050
  • glotpress/trunk/gp-templates/helper-functions.php

    r2872254 r2937674  
    4343        $text
    4444    );
     45
     46    // Highlight two or more spaces between words.
     47    $text = preg_replace( '/(?!^)  +(?!$)/', '<span class="invisible-spaces">$0</span>', $text );
     48    // Highlight leading and trailing spaces in single lines.
     49    $text = preg_replace( '/^ +| +$/', '<span class="invisible-spaces">$0</span>', $text );
     50    // Highlight leading spaces in multi lines.
     51    $text = preg_replace( "/\n( +)/", "\n<span class=\"invisible-spaces\">$1</span>", $text );
     52    // Highlight trailing spaces in multi lines.
     53    $text = preg_replace( "/( +)\n/", "<span class=\"invisible-spaces\">$1</span>\n", $text );
    4554
    4655    $text = str_replace( array( "\r", "\n" ), "<span class='invisibles' title='" . esc_attr__( 'New line', 'glotpress' ) . "'>&crarr;</span>\n", $text );
     
    170179        }
    171180
    172         $terms_search = '\b(';
     181        $regex_group = array();
    173182        foreach ( $glossary_entries_suffixes as $term => $suffixes ) {
    174             $terms_search .= preg_quote( $term, '/' );
    175 
    176             if ( ! empty( $suffixes ) ) {
    177                 $terms_search .= '(?:' . implode( '|', $suffixes ) . ')?';
    178             }
    179 
    180             $terms_search .= '|';
     183            $regex_suffix = $suffixes ? '(?:' . implode( '|', $suffixes ) . ')?' : '';
     184
     185            if ( ! isset( $regex_group[ $regex_suffix ] ) ) {
     186                $regex_group[ $regex_suffix ] = array();
     187            }
     188
     189            $regex_group[ $regex_suffix ][] = preg_quote( $term, '/' );
    181190
    182191            $referenced_term = $term;
     
    202211                }
    203212            }
     213        }
     214
     215        // Build the regular expression.
     216        $terms_search = '\b(';
     217        foreach ( $regex_group as $suffix => $terms ) {
     218            $terms_search .= '(?:' . implode( '|', $terms ) . ')' . $suffix . '|';
    204219        }
    205220
  • glotpress/trunk/gp-templates/translation-row-editor.php

    r2699206 r2937674  
    1818
    1919$singular = sprintf(
    20     /* translators: %s: Original singular form of the text */
    21     __( 'Singular: %s', 'glotpress' ),
    22     '<span class="original">' . prepare_original( $translation_singular ) . '</span>'
     20    '<small>%s</small><br><span class="original">%s</span>',
     21    __( 'Singular:', 'glotpress' ),
     22    prepare_original( $translation_singular )
    2323);
    24 $plural = sprintf(
    25     /* translators: %s: Original plural form of the text */
    26     __( 'Plural: %s', 'glotpress' ),
    27     '<span class="original">' . ( isset( $translation->plural_glossary_markup ) ? prepare_original( $translation->plural_glossary_markup ) : prepare_original( esc_translation( $translation->plural ) ) ) . '</span>'
     24$plural   = sprintf(
     25    '<small>%s</small><br><span class="original">%s</span>',
     26    __( 'Plural:', 'glotpress' ),
     27    isset( $translation->plural_glossary_markup ) ? prepare_original( $translation->plural_glossary_markup ) : prepare_original( esc_translation( $translation->plural ) )
    2828);
    2929
  • glotpress/trunk/gp-templates/translation-row-preview.php

    r2296020 r2937674  
    3030    </td>
    3131    <td class="original">
    32         <span class="original-text"><?php echo prepare_original( $translation_singular ); ?></span>
     32        <?php
     33        if ( ! $translation->plural ) {
     34            ?>
     35            <span class="original-text"><?php echo prepare_original( $translation_singular ); ?></span>
     36            <?php
     37        } else {
     38            $translation_plural = isset( $translation->plural_glossary_markup ) ? $translation->plural_glossary_markup : prepare_original( esc_translation( $translation->plural ) );
     39            ?>
     40            <ul>
     41                <li><small><?php esc_html_e( 'Singular:', 'glotpress' ); ?></small><br><span class="original-text"><?php echo prepare_original( $translation_singular ); ?></span></li>
     42                <li><small><?php esc_html_e( 'Plural:', 'glotpress' ); ?></small><br><span class="original-text"><?php echo prepare_original( $translation_plural ); ?></span></li>
     43            </ul>
     44            <?php
     45        }
     46        ?>
    3347        <?php if ( $translation->context ) : ?>
    3448            <?php /* translators: %s: Context of original */ ?>
     
    4862
    4963        $missing_text = "<span class='missing'>$edit_text</span>";
    50         if ( ! count( array_filter( $translation->translations, 'gp_is_not_null' ) ) ) :
     64        if ( ! count( array_filter( $translation->translations, 'gp_is_not_null' ) ) ) {
    5165            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    5266            echo $missing_text;
    53         elseif ( ! $translation->plural ) :
    54             echo '<span class="translation-text">' . esc_translation( $translation->translations[0] ) . '</span>';
    55         else :
     67        } elseif ( ! $translation->plural || 1 === $locale->nplurals ) {
     68            echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[0] ) ) . '</span>';
     69        } elseif ( $translation->plural && 2 === $locale->nplurals && 'n != 1' === $locale->plural_expression ) {
     70            ?>
     71            <ul>
     72                <li>
     73                    <small><?php esc_html_e( 'Singular:', 'glotpress' ); ?></small><br>
     74                    <?php
     75                    if ( ! isset( $translation->translations[0] ) || gp_is_empty_string( $translation->translations[0] ) ) {
     76                        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     77                        echo $missing_text;
     78                    } else {
     79                        echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[0] ) ) . '</span>';
     80                    }
     81                    ?>
     82                </li>
     83                <li>
     84                    <small><?php esc_html_e( 'Plural:', 'glotpress' ); ?></small><br>
     85                    <?php
     86                    if ( ! isset( $translation->translations[1] ) || gp_is_empty_string( $translation->translations[1] ) ) {
     87                        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     88                        echo $missing_text;
     89                    } else {
     90                        echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[1] ) ) . '</span>';
     91                    }
     92                    ?>
     93                </li>
     94            </ul>
     95            <?php
     96        } else {
     97            ?>
     98            <ul>
     99                <?php
     100                foreach ( range( 0, $locale->nplurals - 1 ) as $plural_index ) {
     101                    $plural_string = implode( ', ', $locale->numbers_for_index( $plural_index ) );
     102                    ?>
     103                    <li>
     104                        <small>
     105                            <?php
     106                            printf(
     107                                /* translators: %s: Plural form. */
     108                                esc_html__( '%s:', 'glotpress' ),
     109                                esc_html( $plural_string )
     110                            );
     111                            ?>
     112                        </small><br>
     113                        <?php
     114                        if ( ! isset( $translation->translations[ $plural_index ] ) || gp_is_empty_string( $translation->translations[ $plural_index ] ) ) {
     115                            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     116                            echo $missing_text;
     117                        } else {
     118                            echo '<span class="translation-text">' . prepare_original( esc_translation( $translation->translations[ $plural_index ] ) ) . '</span>';
     119                        }
     120                        ?>
     121                    </li>
     122                    <?php
     123                }
     124                ?>
     125            </ul>
     126            <?php
     127        }
    56128        ?>
    57             <ul>
    58                 <?php foreach ( $translation->translations as $current_translation ) : ?>
    59                     <li>
    60                     <?php
    61                     // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    62                     echo gp_is_empty_string( $current_translation ) ? $missing_text : '<span class="translation-text">' . esc_translation( $current_translation ) . '</span>';
    63                     ?>
    64                     </li>
    65                 <?php endforeach; ?>
    66             </ul>
    67         <?php endif; ?>
    68129    </td>
    69130    <td class="actions">
  • glotpress/trunk/locales/locales.php

    r2872254 r2937674  
    1010    public $lang_code_iso_639_3 = null;
    1111    public $country_code;
    12     public $wp_locale; // This should only be set for locales that are offically supported on translate.wordpress.org.
     12    public $wp_locale; // This should only be set for locales that are officially supported on translate.wordpress.org.
    1313    public $slug;
    1414    public $nplurals = 2;
     
    473473        $ca_valencia->lang_code_iso_639_2 = 'cat';
    474474        $ca_valencia->wp_locale = 'ca_valencia';
    475         $ca_valencia->slug = 'ca-valencia';
     475        $ca_valencia->slug = 'ca-val';
    476476        $ca_valencia->google_code = 'ca';
    477477        $ca_valencia->facebook_locale = 'ca_ES';
     
    16011601        $kir->wp_locale = 'kir';
    16021602        $kir->slug = 'kir';
    1603         $kir->nplurals = 1;
    1604         $kir->plural_expression = '0';
    16051603        $kir->google_code = 'ky';
    16061604        $kir->alphabet = 'cyrillic';
Note: See TracChangeset for help on using the changeset viewer.