diff --git a/examples/attempt-loading/.gitignore b/examples/attempt-loading/.gitignore new file mode 100644 index 0000000..deb3f28 --- /dev/null +++ b/examples/attempt-loading/.gitignore @@ -0,0 +1 @@ +build/out diff --git a/examples/attempt-loading/README.md b/examples/attempt-loading/README.md new file mode 100644 index 0000000..bc57a0b --- /dev/null +++ b/examples/attempt-loading/README.md @@ -0,0 +1,40 @@ +Example of i18n bundles not specified in the master module +========================================================== + +Specifying all available bundles in the master file when a product is released +may not be convenient. If a localization is provided afterwards, the master +module has to be modified, which gets even more difficult when it is compiled +to a single output file. + +This sample does not specify any locales in the master file, which makes the +i18n plugin attempt loading the bundles from the nls directory during the +execution time dynamically. + + nls/strings.js + define({ "root": true }); // "empty" master + nls/root/strings.js + define({ English localization }); + nls/de/strings.js + define({ German localization }); + +Otherwise the usage of bundles in the source code is the same. + +Testing the example +------------------- + +Make sure that you clone the [`requirejs`](https://github.com/jrburke/r.js.git) +and [`r.js`](https://github.com/jrburke/requirejs.git) directories as siblings +of the `i18n` directory where you cloned the i18n plugin. Some files are loaded +by relative parts from them (`require.js and r.js). + +The debug version of this example, which loads every module separately, can +be tested by the following commands: + + open index-debug.html in the web browser + +The release version of this example, which loads all modules compiled to the +single file `zoo.js`, can be compiled and tested by the following commands: + + cd build + node ../../../../r.js/dist/r.js -o build.js + open out/index-release.html in the web browser diff --git a/examples/attempt-loading/build/build.js b/examples/attempt-loading/build/build.js new file mode 100644 index 0000000..95358dd --- /dev/null +++ b/examples/attempt-loading/build/build.js @@ -0,0 +1,15 @@ +{ + appDir: "..", + baseUrl: ".", + mainConfigFile: "../config.js", + dir: "out", + + optimize: "none", + + modules: [ + { + name: "zoo", + include: [ "../../../../../requirejs/require" ] + } + ] +} diff --git a/examples/attempt-loading/config.js b/examples/attempt-loading/config.js new file mode 100644 index 0000000..4615aef --- /dev/null +++ b/examples/attempt-loading/config.js @@ -0,0 +1,5 @@ +require.config({ + paths: { + i18n: "../../i18n" + } +}); diff --git a/examples/attempt-loading/index-debug.html b/examples/attempt-loading/index-debug.html new file mode 100644 index 0000000..3c63324 --- /dev/null +++ b/examples/attempt-loading/index-debug.html @@ -0,0 +1,25 @@ + + + +
+ + + + + +Open the console to watch the life.
+ + + + + diff --git a/examples/attempt-loading/index-release.html b/examples/attempt-loading/index-release.html new file mode 100644 index 0000000..3ecb491 --- /dev/null +++ b/examples/attempt-loading/index-release.html @@ -0,0 +1,24 @@ + + + + + + + + + +Open the console to watch the life.
+ + + + + diff --git a/examples/attempt-loading/main.js b/examples/attempt-loading/main.js new file mode 100644 index 0000000..7275e16 --- /dev/null +++ b/examples/attempt-loading/main.js @@ -0,0 +1,12 @@ +require.config({ + config: { + i18n: { locale: "de-de" } + } +}); + +require(["model/animal"], function (Animal) { + + var cat = new Animal('Cat'); + cat.die(); + +}); diff --git a/examples/attempt-loading/model/animal.js b/examples/attempt-loading/model/animal.js new file mode 100644 index 0000000..b90d370 --- /dev/null +++ b/examples/attempt-loading/model/animal.js @@ -0,0 +1,20 @@ +define(["i18n!nls/strings"], function (strings) { + + function Animal(name) { + this.name = name || "Unknown"; + console.log(strings.AnimalBorn.replace("{0}", this.name)); + } + + Animal.prototype = { + + name: undefined, + + die: function () { + console.log(strings.AnimalDied.replace("{0}", this.name)); + } + + }; + + return Animal; + +}); diff --git a/examples/attempt-loading/nls/cs/strings.js b/examples/attempt-loading/nls/cs/strings.js new file mode 100644 index 0000000..e390078 --- /dev/null +++ b/examples/attempt-loading/nls/cs/strings.js @@ -0,0 +1,4 @@ +define({ + AnimalBorn: "{0} se narodilo.", + AnimalDied: "{0} zemřelo." +}); diff --git a/examples/attempt-loading/nls/de/strings.js b/examples/attempt-loading/nls/de/strings.js new file mode 100644 index 0000000..c2d49fe --- /dev/null +++ b/examples/attempt-loading/nls/de/strings.js @@ -0,0 +1,4 @@ +define({ + AnimalBorn: "Das {0} ist geboren.", + AnimalDied: "Das {0} ist gestorben." +}); diff --git a/examples/attempt-loading/nls/root/strings.js b/examples/attempt-loading/nls/root/strings.js new file mode 100644 index 0000000..482893d --- /dev/null +++ b/examples/attempt-loading/nls/root/strings.js @@ -0,0 +1,4 @@ +define({ + AnimalBorn: "The {0} was born.", + AnimalDied: "The {0} died." +}); diff --git a/examples/attempt-loading/nls/strings.js b/examples/attempt-loading/nls/strings.js new file mode 100644 index 0000000..c272eb3 --- /dev/null +++ b/examples/attempt-loading/nls/strings.js @@ -0,0 +1,3 @@ +define({ + "root": true +}); diff --git a/examples/attempt-loading/zoo.js b/examples/attempt-loading/zoo.js new file mode 100644 index 0000000..a4c84fe --- /dev/null +++ b/examples/attempt-loading/zoo.js @@ -0,0 +1 @@ +define("zoo", ["model/animal"]); diff --git a/i18n.js b/i18n.js index 9fa0c26..e10428d 100644 --- a/i18n.js +++ b/i18n.js @@ -149,7 +149,7 @@ //First, fetch the master bundle, it knows what locales are available. req([masterName], function (master) { //Figure out the best fit - var needed = [], + var needed = [], unknown = [], part; //Always allow for root, then do the rest of the locale parts. @@ -157,24 +157,59 @@ for (i = 0; i < parts.length; i++) { part = parts[i]; current += (current ? "-" : "") + part; - addPart(current, master, needed, toLoad, prefix, suffix); + if (master[current] !== undefined) { + addPart(current, master, needed, toLoad, + prefix, suffix); + } else { + unknown.push(current); + } } //Load all the parts missing. - req(toLoad, function () { - var i, partBundle, part; - for (i = needed.length - 1; i > -1 && needed[i]; i--) { - part = needed[i]; - partBundle = master[part]; - if (partBundle === true || partBundle === 1) { - partBundle = req(prefix + part + '/' + suffix); + function loadKnownParts() { + req(toLoad, function () { + var i, partBundle, part; + for (i = needed.length - 1; i > -1 && needed[i]; i--) { + part = needed[i]; + partBundle = master[part]; + if (partBundle === true || partBundle === 1) { + partBundle = req(prefix + part + '/' + suffix); + } + mixin(value, partBundle); } - mixin(value, partBundle); + + //All done, notify the loader. + onLoad(value); + }); + } + + //Try loading one by one parts not specified in the + //master module and when all were processed, load the + //known rest and build the requested bundle. + function loadUnknownParts() { + current = unknown.shift(); + if (current) { + req([ prefix + current + '/' + suffix ], + function () { + needed.push(current); + master[current] = true; + loadUnknownParts(); + }, function () { + master[current] = false; + loadUnknownParts(); + }); + } else { + loadKnownParts(); } + } - //All done, notify the loader. - onLoad(value); - }); + //If at least one of the fallback locales was specified + // in the master module, do not try the unspecified. + if (needed.length > 1) { + loadKnownParts(); + } else { + loadUnknownParts(); + } }); } }