1 | /**
|
2 | * @license RequireJS i18n 1.0.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
|
3 | * Available via the MIT or new BSD license.
|
4 | * see: http://github.com/jrburke/requirejs for details
|
5 | */
|
6 | /*jslint regexp: false, nomen: false, plusplus: false, strict: false */
|
7 | /*global require: false, navigator: false, define: false */
|
8 |
|
9 | /**
|
10 | * This plugin handles i18n! prefixed modules. It does the following:
|
11 | *
|
12 | * 1) A regular module can have a dependency on an i18n bundle, but the regular
|
13 | * module does not want to specify what locale to load. So it just specifies
|
14 | * the top-level bundle, like "i18n!nls/colors".
|
15 | *
|
16 | * This plugin will load the i18n bundle at nls/colors, see that it is a root/master
|
17 | * bundle since it does not have a locale in its name. It will then try to find
|
18 | * the best match locale available in that master bundle, then request all the
|
19 | * locale pieces for that best match locale. For instance, if the locale is "en-us",
|
20 | * then the plugin will ask for the "en-us", "en" and "root" bundles to be loaded
|
21 | * (but only if they are specified on the master bundle).
|
22 | *
|
23 | * Once all the bundles for the locale pieces load, then it mixes in all those
|
24 | * locale pieces into each other, then finally sets the context.defined value
|
25 | * for the nls/colors bundle to be that mixed in locale.
|
26 | *
|
27 | * 2) A regular module specifies a specific locale to load. For instance,
|
28 | * i18n!nls/fr-fr/colors. In this case, the plugin needs to load the master bundle
|
29 | * first, at nls/colors, then figure out what the best match locale is for fr-fr,
|
30 | * since maybe only fr or just root is defined for that locale. Once that best
|
31 | * fit is found, all of its locale pieces need to have their bundles loaded.
|
32 | *
|
33 | * Once all the bundles for the locale pieces load, then it mixes in all those
|
34 | * locale pieces into each other, then finally sets the context.defined value
|
35 | * for the nls/fr-fr/colors bundle to be that mixed in locale.
|
36 | */
|
37 | (function () {
|
38 | //regexp for reconstructing the master bundle name from parts of the regexp match
|
39 | //nlsRegExp.exec("foo/bar/baz/nls/en-ca/foo") gives:
|
40 | //["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"]
|
41 | //nlsRegExp.exec("foo/bar/baz/nls/foo") gives:
|
42 | //["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""]
|
43 | //so, if match[5] is blank, it means this is the top bundle definition.
|
44 | var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/,
|
45 | empty = {};
|
46 |
|
47 | //Helper function to avoid repeating code. Lots of arguments in the
|
48 | //desire to stay functional and support RequireJS contexts without having
|
49 | //to know about the RequireJS contexts.
|
50 | function addPart(locale, master, needed, toLoad, prefix, suffix) {
|
51 | if (master[locale]) {
|
52 | needed.push(locale);
|
53 | if (master[locale] === true || master[locale] === 1) {
|
54 | toLoad.push(prefix + locale + '/' + suffix);
|
55 | }
|
56 | }
|
57 | }
|
58 |
|
59 | function addIfExists(req, locale, toLoad, prefix, suffix) {
|
60 | var fullName = prefix + locale + '/' + suffix;
|
61 | if (require._fileExists(req.toUrl(fullName))) {
|
62 | toLoad.push(fullName);
|
63 | }
|
64 | }
|
65 |
|
66 | /**
|
67 | * Simple function to mix in properties from source into target,
|
68 | * but only if target does not already have a property of the same name.
|
69 | * This is not robust in IE for transferring methods that match
|
70 | * Object.prototype names, but the uses of mixin here seem unlikely to
|
71 | * trigger a problem related to that.
|
72 | */
|
73 | function mixin(target, source, force) {
|
74 | for (var prop in source) {
|
75 | if (!(prop in empty) && (!(prop in target) || force)) {
|
76 | target[prop] = source[prop];
|
77 | }
|
78 | }
|
79 | }
|
80 |
|
81 | define({
|
82 | version: '1.0.0',
|
83 | /**
|
84 | * Called when a dependency needs to be loaded.
|
85 | */
|
86 | load: function (name, req, onLoad, config) {
|
87 | config = config || {};
|
88 |
|
89 | var masterName,
|
90 | match = nlsRegExp.exec(name),
|
91 | prefix = match[1],
|
92 | locale = match[4],
|
93 | suffix = match[5],
|
94 | parts = locale.split("-"),
|
95 | toLoad = [],
|
96 | value = {},
|
97 | i, part, current = "";
|
98 |
|
99 | //If match[5] is blank, it means this is the top bundle definition,
|
100 | //so it does not have to be handled. Locale-specific requests
|
101 | //will have a match[4] value but no match[5]
|
102 | if (match[5]) {
|
103 | //locale-specific bundle
|
104 | prefix = match[1];
|
105 | masterName = prefix + suffix;
|
106 | } else {
|
107 | //Top-level bundle.
|
108 | masterName = name;
|
109 | suffix = match[4];
|
110 | locale = config.locale || (config.locale =
|
111 | typeof navigator === "undefined" ? "root" :
|
112 | (navigator.language ||
|
113 | navigator.userLanguage || "root").toLowerCase());
|
114 | parts = locale.split("-");
|
115 | }
|
116 |
|
117 | if (config.isBuild) {
|
118 | //Check for existence of all locale possible files and
|
119 | //require them if exist.
|
120 | toLoad.push(masterName);
|
121 | addIfExists(req, "root", toLoad, prefix, suffix);
|
122 | for (i = 0; (part = parts[i]); i++) {
|
123 | current += (current ? "-" : "") + part;
|
124 | addIfExists(req, current, toLoad, prefix, suffix);
|
125 | }
|
126 |
|
127 | req(toLoad, function () {
|
128 | onLoad();
|
129 | });
|
130 | } else {
|
131 | //First, fetch the master bundle, it knows what locales are available.
|
132 | req([masterName], function (master) {
|
133 | //Figure out the best fit
|
134 | var needed = [];
|
135 |
|
136 | //Always allow for root, then do the rest of the locale parts.
|
137 | addPart("root", master, needed, toLoad, prefix, suffix);
|
138 | for (i = 0; (part = parts[i]); i++) {
|
139 | current += (current ? "-" : "") + part;
|
140 | addPart(current, master, needed, toLoad, prefix, suffix);
|
141 | }
|
142 |
|
143 | //Load all the parts missing.
|
144 | req(toLoad, function () {
|
145 | var i, partBundle;
|
146 | for (i = needed.length - 1; i > -1 && (part = needed[i]); i--) {
|
147 | partBundle = master[part];
|
148 | if (partBundle === true || partBundle === 1) {
|
149 | partBundle = req(prefix + part + '/' + suffix);
|
150 | }
|
151 | mixin(value, partBundle);
|
152 | }
|
153 |
|
154 | //All done, notify the loader.
|
155 | onLoad(value);
|
156 | });
|
157 | });
|
158 | }
|
159 | }
|
160 | });
|
161 | }());
|