jenkins-bot has submitted this change and it was merged.

Change subject: Use jquery.i18n for standalone i18n
......................................................................


Use jquery.i18n for standalone i18n

VisualEditor.php:
* Make jquery.i18n a dependency of ext.visualEditor.standalone

makeStaticLoader.php:
* Remove ve.init.platform.addMessages() call with PHP-generated messages
* Add fake module for jquery.i18n
** Needed because the module might come from MW core
** Also add special treatment for fallbacks.js and language scripts

ve.init.sa.Platform.js:
* Remove basic message system, replace with jquery.i18n
* Add initialize method that loads messages for current language and
  fallbacks

ve.init.sa.Target.js:
* Wait for the platform to initialize before actually doing things
* Add .setup() method to allow callers to short-circuit this process
** This is convenient for callers of ve.init.sa.Target in the test suite

ve.ce.test.js:
* Use existing ve.test.utils function for creating a surface

ve.test.utils.js:
* Call .setup() on the target so we can get a surface synchronously

ve.init.Platform.test.js:
* Make these tests async, wait for the platform to initialize
* Allow for missing messages to be output either as <foo> (MW)
  or foo (jquery.i18n)
* Get rid of message clearing code, namespace test messages instead

Change-Id: Iac7dfd327eadf9b503a61510574d35d748faac92
---
M VisualEditor.php
M demos/ve/index.php
M maintenance/makeStaticLoader.php
M modules/ve/init/sa/ve.init.sa.Platform.js
M modules/ve/init/sa/ve.init.sa.Target.js
M modules/ve/init/ve.init.Platform.js
M modules/ve/test/ce/ve.ce.test.js
M modules/ve/test/index.php
M modules/ve/test/init/ve.init.Platform.test.js
M modules/ve/test/ve.test.utils.js
10 files changed, 203 insertions(+), 118 deletions(-)

Approvals:
  Krinkle: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/VisualEditor.php b/VisualEditor.php
index f5e74df..92c3308 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -266,6 +266,7 @@
                ),
                'dependencies' => array(
                        'ext.visualEditor.base',
+                       'jquery.i18n',
                ),
        ),
 
diff --git a/demos/ve/index.php b/demos/ve/index.php
index 8bf2983..1e3f766 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -101,16 +101,33 @@
                <script 
src="../../modules/ve/init/ve.init.Platform.js"></script>
                <script src="../../modules/ve/init/ve.init.Target.js"></script>
                <script src="../../modules/ve/ve.debug.js"></script>
+               <!-- jquery.i18n -->
+               <script 
src="../../modules/jquery.i18n/src/jquery.i18n.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/jquery.i18n.messagestore.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/jquery.i18n.parser.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/jquery.i18n.emitter.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/jquery.i18n.language.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/jquery.i18n.fallbacks.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/bs.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/dsb.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/fi.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/ga.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/he.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/hsb.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/hu.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/hy.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/la.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/ml.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/os.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/ru.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/sl.js"></script>
+               <script 
src="../../modules/jquery.i18n/src/languages/uk.js"></script>
                <!-- ext.visualEditor.standalone -->
                <script src="../../modules/ve/init/sa/ve.init.sa.js"></script>
                <script 
src="../../modules/ve/init/sa/ve.init.sa.Platform.js"></script>
                <script 
src="../../modules/ve/init/sa/ve.init.sa.Target.js"></script>
                <!-- Standalone init -->
                <script>
-                       <?php
-                               require 
'../../modules/../VisualEditor.i18n.php';
-                               echo 've.init.platform.addMessages( ' . 
json_encode( $messages['en'] ) . " );\n";
-                       ?>
                        ve.init.platform.setModulesUrl( '../../modules' );
                </script>
                <!-- rangy -->
diff --git a/maintenance/makeStaticLoader.php b/maintenance/makeStaticLoader.php
index aeb27d0..98a33ee 100644
--- a/maintenance/makeStaticLoader.php
+++ b/maintenance/makeStaticLoader.php
@@ -158,13 +158,36 @@
        }
 </script>',
                                'bodyAdd' => '<script>
-       <?php
-               require ' . var_export( $i18nScript, true ) . ';
-               echo \'ve.init.platform.addMessages( \' . json_encode( 
$messages[\'en\'] ) . " );\n";
-       ?>
        ve.init.platform.setModulesUrl( \'' . $vePath . '\' );
 </script>'
                        ),
+                       'jquery.i18n' => array(
+                               'scripts' => array(
+                                       'jquery.i18n/src/jquery.i18n.js',
+                                       
'jquery.i18n/src/jquery.i18n.messagestore.js',
+                                       'jquery.i18n/src/jquery.i18n.parser.js',
+                                       
'jquery.i18n/src/jquery.i18n.emitter.js',
+                                       
'jquery.i18n/src/jquery.i18n.language.js',
+                                       // fallbacks.js is not in the real RL 
module, but we need it in the standalone
+                                       
'jquery.i18n/src/jquery.i18n.fallbacks.js',
+                                       // We can't use languageScripts here 
because we don't know what the language
+                                       // will be in advance, so just include 
all of them
+                                       'jquery.i18n/src/languages/bs.js',
+                                       'jquery.i18n/src/languages/dsb.js',
+                                       'jquery.i18n/src/languages/fi.js',
+                                       'jquery.i18n/src/languages/ga.js',
+                                       'jquery.i18n/src/languages/he.js',
+                                       'jquery.i18n/src/languages/hsb.js',
+                                       'jquery.i18n/src/languages/hu.js',
+                                       'jquery.i18n/src/languages/hy.js',
+                                       'jquery.i18n/src/languages/la.js',
+                                       'jquery.i18n/src/languages/ml.js',
+                                       'jquery.i18n/src/languages/os.js',
+                                       'jquery.i18n/src/languages/ru.js',
+                                       'jquery.i18n/src/languages/sl.js',
+                                       'jquery.i18n/src/languages/uk.js',
+                               ),
+                       )
                );
 
                $modules = array(
@@ -175,6 +198,7 @@
                        'unicodejs.wordbreak',
                        // Dependencies for ext.visualEditor.standalone:
                        'ext.visualEditor.base',
+                       'jquery.i18n',
                        'ext.visualEditor.standalone',
                        'Standalone init',
                        // Dependencies for ext.visualEditor.core:
diff --git a/modules/ve/init/sa/ve.init.sa.Platform.js 
b/modules/ve/init/sa/ve.init.sa.Platform.js
index 9e14e38..80f04d1 100644
--- a/modules/ve/init/sa/ve.init.sa.Platform.js
+++ b/modules/ve/init/sa/ve.init.sa.Platform.js
@@ -20,7 +20,6 @@
        // Properties
        this.externalLinkUrlProtocolsRegExp = /^https?\:\/\//;
        this.modulesUrl = 'extensions/VisualEditor/modules';
-       this.messages = {};
        this.parsedMessages = {};
 };
 
@@ -51,23 +50,14 @@
 
 /** @inheritdoc */
 ve.init.sa.Platform.prototype.addMessages = function ( messages ) {
-       for ( var key in messages ) {
-               this.messages[key] = messages[key];
-       }
+       $.i18n().load( messages, $.i18n().locale );
 };
 
-/** @inheritdoc */
-ve.init.sa.Platform.prototype.getMessage = function ( key ) {
-       if ( key in this.messages ) {
-               // Simple message parser, does $N replacement and nothing else.
-               var parameters = Array.prototype.slice.call( arguments, 1 );
-               return this.messages[key].replace( /\$(\d+)/g, function ( str, 
match ) {
-                       var index = parseInt( match, 10 ) - 1;
-                       return parameters[index] !== undefined ? 
parameters[index] : '$' + match;
-               } );
-       }
-       return '<' + key + '>';
-};
+/**
+ * @method
+ * @inheritdoc
+ */
+ve.init.sa.Platform.prototype.getMessage = $.i18n;
 
 /** @inheritdoc */
 ve.init.sa.Platform.prototype.addParsedMessages = function ( messages ) {
@@ -121,6 +111,52 @@
        return langs;
 };
 
+ve.init.sa.Platform.prototype.initialize = function () {
+       var i, len, partialLocale, localeParts, deferred,
+               path = this.getModulesUrl(),
+               locale = $.i18n().locale,
+               languages = [ locale, 'en' ], // Always use 'en' as the final 
fallback
+               languagesCovered = {},
+               promises = [],
+               fallbacks = $.i18n.fallbacks[locale];
+
+       if ( !fallbacks ) {
+               // Try to find something that has fallbacks (which means it's a 
language we know about)
+               // by stripping things from the end. But collect all the 
intermediate ones in case we
+               // go past languages that don't have fallbacks but do exist.
+               localeParts = locale.split( '-' );
+               localeParts.pop();
+               while ( localeParts.length && !fallbacks ) {
+                       partialLocale = localeParts.join( '-' );
+                       languages.push( partialLocale );
+                       fallbacks = $.i18n.fallbacks[partialLocale];
+                       localeParts.pop();
+               }
+       }
+
+       if ( fallbacks ) {
+               languages = languages.concat( fallbacks );
+       }
+
+       for ( i = 0, len = languages.length; i < len; i++ ) {
+               if ( languagesCovered[languages[i]] ) {
+                       continue;
+               }
+               languagesCovered[languages[i]] = true;
+
+               deferred = $.Deferred();
+               $.i18n().load( path + '/ve/i18n/' + languages[i] + '.json', 
languages[i] )
+                       .always( deferred.resolve );
+               promises.push( deferred.promise() );
+
+               deferred = $.Deferred();
+               $.i18n().load( path + '/oojs-ui/i18n/' + languages[i] + 
'.json', languages[i] )
+                       .always( deferred.resolve );
+               promises.push( deferred.promise() );
+       }
+       return $.when.apply( $, promises );
+};
+
 /* Initialization */
 
 ve.init.platform = new ve.init.sa.Platform();
diff --git a/modules/ve/init/sa/ve.init.sa.Target.js 
b/modules/ve/init/sa/ve.init.sa.Target.js
index f68fab6..5b93f48 100644
--- a/modules/ve/init/sa/ve.init.sa.Target.js
+++ b/modules/ve/init/sa/ve.init.sa.Target.js
@@ -24,8 +24,25 @@
        // Parent constructor
        ve.init.Target.call( this, $container );
 
+       this.document = doc;
+
+       ve.init.platform.getInitializedPromise().done( ve.bind( this.setup, 
this ) );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.init.sa.Target, ve.init.Target );
+
+/* Methods */
+
+ve.init.sa.Target.prototype.setup = function () {
+       if ( this.setupDone ) {
+               return;
+       }
+
        // Properties
-       this.surface = new ve.ui.Surface( doc );
+       this.setupDone = true;
+       this.surface = new ve.ui.Surface( this.document );
        this.toolbar = new ve.ui.TargetToolbar( this, this.surface, { 'shadow': 
true } );
 
        // Initialization
@@ -40,7 +57,3 @@
        this.surface.setPasteRules( this.constructor.static.pasteRules );
        this.surface.initialize();
 };
-
-/* Inheritance */
-
-OO.inheritClass( ve.init.sa.Target, ve.init.Target );
diff --git a/modules/ve/init/ve.init.Platform.js 
b/modules/ve/init/ve.init.Platform.js
index cbf4fdf..b594ff8 100644
--- a/modules/ve/init/ve.init.Platform.js
+++ b/modules/ve/init/ve.init.Platform.js
@@ -64,7 +64,7 @@
  * @abstract
  * @param {string} key Message key
  * @param {Mixed...} [args] List of arguments which will be injected at $1, 
$2, etc. in the messaage
- * @returns {string} Localized message
+ * @returns {string} Localized message, or key or '<' + key + '>' if message 
not found
  */
 ve.init.Platform.prototype.getMessage = function () {
        throw new Error( 've.init.Platform.getMessage must be overridden in 
subclass' );
diff --git a/modules/ve/test/ce/ve.ce.test.js b/modules/ve/test/ce/ve.ce.test.js
index 27e85e4..6460f37 100644
--- a/modules/ve/test/ce/ve.ce.test.js
+++ b/modules/ve/test/ce/ve.ce.test.js
@@ -171,7 +171,7 @@
 } );
 
 QUnit.test( 'fakeImes', function ( assert ) {
-       var i, ilen, j, jlen, dom, target, testRunner, testName, testActions, 
seq, testInfo,
+       var i, ilen, j, jlen, surface, testRunner, testName, testActions, seq, 
testInfo,
                action, args, count, foundEndLoop, fakePreventDefault;
 
        // count tests
@@ -211,9 +211,8 @@
                foundEndLoop = false;
                // First element is the testInfo
                testInfo = testActions[0];
-               dom = ve.createDocumentFromHtml( testInfo.startDom || '' );
-               target = new ve.init.sa.Target( $( '<div>' ).appendTo( 
'#qunit-fixture' ), dom );
-               testRunner = new ve.ce.TestRunner( target.surface );
+               surface = ve.test.utils.createSurfaceFromHtml( 
testInfo.startDom || '' );
+               testRunner = new ve.ce.TestRunner( surface );
                // start at 1 to omit the testInfo
                for ( j = 1, jlen = testActions.length; j < jlen; j++ ) {
                        action = testActions[j].action;
@@ -233,6 +232,6 @@
                }
                // Test that there is at least one endLoop
                assert.equal( foundEndLoop, true, testName + ' found at least 
one endLoop' );
-               target.surface.destroy();
+               surface.destroy();
        }
 } );
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 12bebd1..1704373 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -53,16 +53,33 @@
                <script src="../../ve/init/ve.init.Platform.js"></script>
                <script src="../../ve/init/ve.init.Target.js"></script>
                <script src="../../ve/ve.debug.js"></script>
+               <!-- jquery.i18n -->
+               <script src="../../jquery.i18n/src/jquery.i18n.js"></script>
+               <script 
src="../../jquery.i18n/src/jquery.i18n.messagestore.js"></script>
+               <script 
src="../../jquery.i18n/src/jquery.i18n.parser.js"></script>
+               <script 
src="../../jquery.i18n/src/jquery.i18n.emitter.js"></script>
+               <script 
src="../../jquery.i18n/src/jquery.i18n.language.js"></script>
+               <script 
src="../../jquery.i18n/src/jquery.i18n.fallbacks.js"></script>
+               <script src="../../jquery.i18n/src/languages/bs.js"></script>
+               <script src="../../jquery.i18n/src/languages/dsb.js"></script>
+               <script src="../../jquery.i18n/src/languages/fi.js"></script>
+               <script src="../../jquery.i18n/src/languages/ga.js"></script>
+               <script src="../../jquery.i18n/src/languages/he.js"></script>
+               <script src="../../jquery.i18n/src/languages/hsb.js"></script>
+               <script src="../../jquery.i18n/src/languages/hu.js"></script>
+               <script src="../../jquery.i18n/src/languages/hy.js"></script>
+               <script src="../../jquery.i18n/src/languages/la.js"></script>
+               <script src="../../jquery.i18n/src/languages/ml.js"></script>
+               <script src="../../jquery.i18n/src/languages/os.js"></script>
+               <script src="../../jquery.i18n/src/languages/ru.js"></script>
+               <script src="../../jquery.i18n/src/languages/sl.js"></script>
+               <script src="../../jquery.i18n/src/languages/uk.js"></script>
                <!-- ext.visualEditor.standalone -->
                <script src="../../ve/init/sa/ve.init.sa.js"></script>
                <script src="../../ve/init/sa/ve.init.sa.Platform.js"></script>
                <script src="../../ve/init/sa/ve.init.sa.Target.js"></script>
                <!-- Standalone init -->
                <script>
-                       <?php
-                               require '../../../VisualEditor.i18n.php';
-                               echo 've.init.platform.addMessages( ' . 
json_encode( $messages['en'] ) . " );\n";
-                       ?>
                        ve.init.platform.setModulesUrl( '../..' );
                </script>
                <!-- rangy -->
diff --git a/modules/ve/test/init/ve.init.Platform.test.js 
b/modules/ve/test/init/ve.init.Platform.test.js
index 27515f8..15dfba5 100644
--- a/modules/ve/test/init/ve.init.Platform.test.js
+++ b/modules/ve/test/init/ve.init.Platform.test.js
@@ -5,94 +5,71 @@
  * @license The MIT License (MIT); see LICENSE.txt
  */
 
-QUnit.module( 've.init.Platform', {
-       setup: function () {
-               this.platform = ve.init.platform;
+QUnit.module( 've.init.Platform' );
 
-               // Clone and deference instance
-               ve.init.platform = ve.cloneObject( ve.init.platform );
-
-               // Reset internal properties needed to keep tests atomic
-               ve.init.platform.parsedMessages = {};
-
-               // Platform specific properties
-               // TODO: Perhaps this warrants a clearMessages() method?
-               if ( ve.init.sa && ve.init.platform instanceof 
ve.init.sa.Platform ) {
-                       ve.init.platform.messages = {};
-               } else if ( ve.init.mw && ve.init.platform instanceof 
ve.init.mw.Platform ) {
-                       /*global mw */
-                       this.mwMessagesValues = ve.copy( mw.messages.values );
-               }
-       },
-       teardown: function () {
-               ve.init.platform = this.platform;
-               if ( ve.init.mw && ve.init.platform instanceof 
ve.init.mw.Platform ) {
-                       /*global mw */
-                       mw.messages.values = this.mwMessagesValues;
-               }
-       }
-} );
-
-QUnit.test( 'messages', 4, function ( assert ) {
+QUnit.asyncTest( 'messages', 4, function ( assert ) {
        var platform = ve.init.platform;
 
-       assert.strictEqual(
-               platform.getMessage( 'foo' ),
-               '<foo>',
-               'return bracket-wrapped key as fallback'
-       );
+       platform.getInitializedPromise().done( function () {
+               QUnit.start();
+               assert.ok(
+                       /^<?platformtest-foo\>?$/.test( platform.getMessage( 
'platformtest-foo' ) ),
+                       'return plain key as fallback, possibly wrapped in 
brackets'
+               );
 
-       platform.addMessages( {
-               foo: 'Foo & Bar <quux action="followed">by</quux>!',
-               bacon: 'Bacon <&> Ipsum: $1'
+               platform.addMessages( {
+                       'platformtest-foo': 'Foo & Bar <quux 
action="followed">by</quux>!',
+                       'platformtest-bacon': 'Bacon <&> Ipsum: $1'
+               } );
+
+               assert.strictEqual(
+                       platform.getMessage( 'platformtest-foo' ),
+                       'Foo & Bar <quux action="followed">by</quux>!',
+                       'return plain message'
+               );
+
+               assert.strictEqual(
+                       platform.getMessage( 'platformtest-bacon', 10 ),
+                       'Bacon <&> Ipsum: 10',
+                       'return plain message with $# replacements'
+               );
+
+               assert.ok(
+                       /^<?platformtest-quux\>?$/.test( platform.getMessage( 
'platformtest-quux' ) ),
+                       'return plain key as fallback, possibly wrapped in 
brackets (after set up)'
+               );
        } );
-
-       assert.strictEqual(
-               platform.getMessage( 'foo' ),
-               'Foo & Bar <quux action="followed">by</quux>!',
-               'return plain message'
-       );
-
-       assert.strictEqual(
-               platform.getMessage( 'bacon', 10 ),
-               'Bacon <&> Ipsum: 10',
-               'return plain message with $# replacements'
-       );
-
-       assert.strictEqual(
-               platform.getMessage( 'quux' ),
-               '<quux>',
-               'return bracket-wrapped key as fallback (after set up)'
-       );
 } );
 
-QUnit.test( 'parsedMessage', 3, function ( assert ) {
+QUnit.asyncTest( 'parsedMessage', 3, function ( assert ) {
        var platform = ve.init.platform;
 
-       assert.strictEqual(
-               platform.getParsedMessage( 'foo' ),
-               '&lt;foo&gt;',
-               'return html escaped brackets in wrapped-key fallback'
-       );
+       platform.getInitializedPromise().done( function () {
+               QUnit.start();
+               assert.ok(
+                       /^(&lt;)?platformtest-quux(&gt;)?$/.test( 
platform.getMessage( 'platformtest-quux' ) ),
+                       'any brackets in fallbacks are HTML-escaped'
+               );
 
-       platform.addMessages( {
-               foo: 'Foo & Bar <quux action="followed">by</quux>!',
-               bacon: 'Bacon <&> Ipsum: $1'
+               platform.addMessages( {
+                       'platformtest-foo': 'Foo & Bar <quux 
action="followed">by</quux>!',
+                       'platformtest-bacon': 'Bacon <&> Ipsum: $1'
+               } );
+
+               platform.addParsedMessages( {
+                       'platformtest-foo': 'Foo <quux>&lt;html&gt;</quux>'
+               } );
+
+               assert.strictEqual(
+                       platform.getParsedMessage( 'platformtest-foo' ),
+                       'Foo <quux>&lt;html&gt;</quux>',
+                       'prefer value from parsedMessage store'
+               );
+
+               assert.strictEqual(
+                       platform.getParsedMessage( 'platformtest-bacon', 10 ),
+                       'Bacon &lt;&amp;&gt; Ipsum: $1',
+                       'fall back to html-escaped version of plain message, no 
$# replacements'
+               );
        } );
-
-       platform.addParsedMessages( {
-               foo: 'Foo <quux>&lt;html&gt;</quux>'
-       } );
-
-       assert.strictEqual(
-               platform.getParsedMessage( 'foo' ),
-               'Foo <quux>&lt;html&gt;</quux>',
-               'prefer value from parsedMessage store'
-       );
-
-       assert.strictEqual(
-               platform.getParsedMessage( 'bacon', 10 ),
-               'Bacon &lt;&amp;&gt; Ipsum: $1',
-               'fall back to html-escaped version of plain message, no $# 
replacements'
-       );
 } );
diff --git a/modules/ve/test/ve.test.utils.js b/modules/ve/test/ve.test.utils.js
index 8057887..d11e017 100644
--- a/modules/ve/test/ve.test.utils.js
+++ b/modules/ve/test/ve.test.utils.js
@@ -136,5 +136,6 @@
  */
 ve.test.utils.createSurfaceFromDocument = function ( doc ) {
        var target = new ve.init.sa.Target( $( '#qunit-fixture' ), doc );
+       target.setup();
        return target.surface;
 };

-- 
To view, visit https://gerrit.wikimedia.org/r/100503
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Iac7dfd327eadf9b503a61510574d35d748faac92
Gerrit-PatchSet: 12
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to