|
1 | 1 | /*
|
2 | 2 | * l10n.js
|
3 |
| - * 2011-05-12 |
| 3 | + * 2013-04-18 |
4 | 4 | *
|
5 | 5 | * By Eli Grey, http://eligrey.com
|
6 | 6 | * Licensed under the X11/MIT License
|
|
11 | 11 |
|
12 | 12 | /*! @source http://purl.eligrey.com/github/l10n.js/blob/master/l10n.js*/
|
13 | 13 |
|
| 14 | +(function () { |
14 | 15 | "use strict";
|
15 | 16 |
|
16 |
| -(function () { |
| 17 | +var |
| 18 | + undef_type = "undefined" |
| 19 | +, string_type = "string" |
| 20 | +, nav = self.navigator |
| 21 | +, String_ctr = String |
| 22 | +, has_own_prop = Object.prototype.hasOwnProperty |
| 23 | +, load_queues = {} |
| 24 | +, localizations = {} |
| 25 | +, FALSE = !1 |
| 26 | +, TRUE = !0 |
| 27 | +// the official format is application/vnd.oftn.l10n+json, though l10n.js will also |
| 28 | +// accept application/x-l10n+json and application/l10n+json |
| 29 | +, l10n_js_media_type = /^\s*application\/(?:vnd\.oftn\.|x-)?l10n\+json\s*(?:$|;)/i |
| 30 | +, XHR |
| 31 | + |
| 32 | +// property minification aids |
| 33 | +, $locale = "locale" |
| 34 | +, $default_locale = "defaultLocale" |
| 35 | +, $to_locale_string = "toLocaleString" |
| 36 | +, $to_lowercase = "toLowerCase" |
| 37 | + |
| 38 | +, array_index_of = Array.prototype.indexOf || function (item) { |
17 | 39 | var
|
18 |
| - undef_type = "undefined" |
19 |
| - , string_type = "string" |
20 |
| - , String_ctr = String |
21 |
| - , has_own_prop = Object.prototype.hasOwnProperty |
22 |
| - , load_queues = {} |
23 |
| - , localizations = {} |
24 |
| - , FALSE = !1 |
25 |
| - // the official format is application/vnd.oftn.l10n+json, though l10n.js will also |
26 |
| - // accept application/x-l10n+json and application/l10n+json |
27 |
| - , l10n_js_media_type = /^\s*application\/(?:vnd\.oftn\.|x-)?l10n\+json\s*(?:$|;)/i |
28 |
| - , XHR |
29 |
| - , $to_locale_string = "toLocaleString" |
30 |
| - , $to_lowercase = "toLowerCase" |
| 40 | + len = this.length |
| 41 | + , i = 0 |
| 42 | + ; |
31 | 43 |
|
32 |
| - , array_index_of = Array.prototype.indexOf || function (item) { |
33 |
| - var |
34 |
| - len = this.length |
35 |
| - , i = 0 |
36 |
| - ; |
37 |
| - |
38 |
| - for (; i < len; i++) { |
39 |
| - if (i in this && this[i] === item) { |
40 |
| - return i; |
41 |
| - } |
| 44 | + for (; i < len; i++) { |
| 45 | + if (i in this && this[i] === item) { |
| 46 | + return i; |
42 | 47 | }
|
43 |
| - |
44 |
| - return -1; |
45 | 48 | }
|
46 |
| - , request_JSON = function (uri) { |
47 |
| - var req = new XHR(); |
48 |
| - |
49 |
| - // sadly, this has to be blocking to allow for a graceful degrading API |
50 |
| - req.open("GET", uri, FALSE); |
51 |
| - req.send(null); |
| 49 | + |
| 50 | + return -1; |
| 51 | +} |
| 52 | +, request_JSON = function (uri) { |
| 53 | + var req = new XHR(); |
| 54 | + |
| 55 | + // sadly, this has to be blocking to allow for a graceful degrading API |
| 56 | + req.open("GET", uri, FALSE); |
| 57 | + req.send(null); |
| 58 | + |
| 59 | + if (req.status !== 200) { |
| 60 | + // warn about error without stopping execution |
| 61 | + setTimeout(function () { |
| 62 | + // Error messages are not localized as not to cause an infinite loop |
| 63 | + var l10n_err = new Error("Unable to load localization data: " + uri); |
| 64 | + l10n_err.name = "Localization Error"; |
| 65 | + throw l10n_err; |
| 66 | + }, 0); |
52 | 67 |
|
53 |
| - if (req.status !== 200) { |
54 |
| - // warn about error without stopping execution |
55 |
| - setTimeout(function () { |
56 |
| - // Error messages are not localized as not to cause an infinite loop |
57 |
| - var l10n_err = new Error("Unable to load localization data: " + uri); |
58 |
| - l10n_err.name = "Localization Error"; |
59 |
| - throw l10n_err; |
60 |
| - }, 0); |
61 |
| - |
62 |
| - return {}; |
63 |
| - } else { |
64 |
| - return JSON.parse(req.responseText); |
65 |
| - } |
| 68 | + return {}; |
| 69 | + } else { |
| 70 | + return JSON.parse(req.responseText); |
66 | 71 | }
|
67 |
| - , load = String_ctr[$to_locale_string] = function (data) { |
68 |
| - // don't handle function[$to_locale_string](indentationAmount:Number) |
69 |
| - if (arguments.length > 0 && typeof data !== "number") { |
70 |
| - if (typeof data === string_type) { |
71 |
| - load(request_JSON(data)); |
72 |
| - } else if (data === FALSE) { |
73 |
| - // reset all localizations |
74 |
| - localizations = {}; |
75 |
| - } else { |
76 |
| - // Extend current localizations instead of completely overwriting them |
77 |
| - for (var locale in data) { |
78 |
| - if (has_own_prop.call(data, locale)) { |
79 |
| - var localization = data[locale]; |
80 |
| - locale = locale[$to_lowercase](); |
81 |
| - |
82 |
| - if (!(locale in localizations) || localization === FALSE) { |
83 |
| - // reset locale if not existing or reset flag is specified |
84 |
| - localizations[locale] = {}; |
85 |
| - } |
86 |
| - |
87 |
| - if (localization === FALSE) { |
88 |
| - continue; |
89 |
| - } |
90 |
| - |
91 |
| - // URL specified |
92 |
| - if (typeof localization === string_type) { |
93 |
| - if (String_ctr.locale[$to_lowercase]().indexOf(locale) === 0) { |
94 |
| - localization = request_JSON(localization); |
95 |
| - } else { |
96 |
| - // queue loading locale if not needed |
97 |
| - if (!(locale in load_queues)) { |
98 |
| - load_queues[locale] = []; |
99 |
| - } |
100 |
| - load_queues[locale].push(localization); |
101 |
| - continue; |
| 72 | +} |
| 73 | +, load = String_ctr[$to_locale_string] = function (data) { |
| 74 | + // don't handle function[$to_locale_string](indentationAmount:Number) |
| 75 | + if (arguments.length > 0 && typeof data !== "number") { |
| 76 | + if (typeof data === string_type) { |
| 77 | + load(request_JSON(data)); |
| 78 | + } else if (data === FALSE) { |
| 79 | + // reset all localizations |
| 80 | + localizations = {}; |
| 81 | + } else { |
| 82 | + // Extend current localizations instead of completely overwriting them |
| 83 | + var locale, localization, message; |
| 84 | + for (locale in data) { |
| 85 | + if (has_own_prop.call(data, locale)) { |
| 86 | + localization = data[locale]; |
| 87 | + locale = locale[$to_lowercase](); |
| 88 | + |
| 89 | + if (!(locale in localizations) || localization === FALSE) { |
| 90 | + // reset locale if not existing or reset flag is specified |
| 91 | + localizations[locale] = {}; |
| 92 | + } |
| 93 | + |
| 94 | + if (localization === FALSE) { |
| 95 | + continue; |
| 96 | + } |
| 97 | + |
| 98 | + // URL specified |
| 99 | + if (typeof localization === string_type) { |
| 100 | + if (String_ctr[$locale][$to_lowercase]().indexOf(locale) === 0) { |
| 101 | + localization = request_JSON(localization); |
| 102 | + } else { |
| 103 | + // queue loading locale if not needed |
| 104 | + if (!(locale in load_queues)) { |
| 105 | + load_queues[locale] = []; |
102 | 106 | }
|
| 107 | + load_queues[locale].push(localization); |
| 108 | + continue; |
103 | 109 | }
|
104 |
| - |
105 |
| - for (var message in localization) { |
106 |
| - if (has_own_prop.call(localization, message)) { |
107 |
| - localizations[locale][message] = localization[message]; |
108 |
| - } |
| 110 | + } |
| 111 | + |
| 112 | + for (message in localization) { |
| 113 | + if (has_own_prop.call(localization, message)) { |
| 114 | + localizations[locale][message] = localization[message]; |
109 | 115 | }
|
110 | 116 | }
|
111 | 117 | }
|
112 | 118 | }
|
113 | 119 | }
|
114 |
| - // Return what function[$to_locale_string]() normally returns |
115 |
| - return Function.prototype[$to_locale_string].apply(String_ctr, arguments); |
116 | 120 | }
|
117 |
| - , process_load_queue = function (locale) { |
118 |
| - var queue = load_queues[locale], |
119 |
| - i = 0, |
120 |
| - len = queue.length; |
121 |
| - |
122 |
| - for (; i < len; i++) { |
123 |
| - var localization = {}; |
124 |
| - localization[locale] = request_JSON(queue[i]); |
125 |
| - load(localization); |
126 |
| - } |
127 |
| - |
128 |
| - delete load_queues[locale]; |
129 |
| - } |
130 |
| - |
| 121 | + // Return what function[$to_locale_string]() normally returns |
| 122 | + return Function.prototype[$to_locale_string].apply(String_ctr, arguments); |
| 123 | +} |
| 124 | +, process_load_queue = function (locale) { |
| 125 | + var |
| 126 | + queue = load_queues[locale] |
| 127 | + , i = 0 |
| 128 | + , len = queue.length |
| 129 | + , localization |
131 | 130 | ;
|
132 | 131 |
|
133 |
| - if (typeof XMLHttpRequest === undef_type && typeof ActiveXObject !== undef_type) { |
134 |
| - var AXO = ActiveXObject; |
135 |
| - |
136 |
| - XHR = function () { |
137 |
| - try { |
138 |
| - return new AXO("Msxml2.XMLHTTP.6.0"); |
139 |
| - } catch (xhrEx1) {} |
140 |
| - try { |
141 |
| - return new AXO("Msxml2.XMLHTTP.3.0"); |
142 |
| - } catch (xhrEx2) {} |
143 |
| - try { |
144 |
| - return new AXO("Msxml2.XMLHTTP"); |
145 |
| - } catch (xhrEx3) {} |
146 |
| - |
147 |
| - throw new Error("XMLHttpRequest not supported by this browser."); |
148 |
| - }; |
149 |
| - } else { |
150 |
| - XHR = XMLHttpRequest; |
| 132 | + for (; i < len; i++) { |
| 133 | + localization = {}; |
| 134 | + localization[locale] = request_JSON(queue[i]); |
| 135 | + load(localization); |
151 | 136 | }
|
152 | 137 |
|
153 |
| - if (!String_ctr.locale) { |
154 |
| - if (typeof navigator !== undef_type) { |
155 |
| - var nav = navigator; |
156 |
| - String_ctr.locale = nav.language || nav.userLanguage || ""; |
157 |
| - } else { |
158 |
| - String_ctr.locale = ""; |
| 138 | + delete load_queues[locale]; |
| 139 | +} |
| 140 | +, use_default |
| 141 | +, localize = String_ctr.prototype[$to_locale_string] = function () { |
| 142 | + var |
| 143 | + using_default = use_default |
| 144 | + , current_locale = String_ctr[using_default ? $default_locale : $locale] |
| 145 | + , parts = current_locale[$to_lowercase]().split("-") |
| 146 | + , i = parts.length |
| 147 | + , this_val = this.valueOf() |
| 148 | + , locale |
| 149 | + ; |
| 150 | + |
| 151 | + use_default = FALSE; |
| 152 | + |
| 153 | + // Iterate through locales starting at most-specific until a localization is found |
| 154 | + do { |
| 155 | + locale = parts.slice(0, i).join("-"); |
| 156 | + // load locale if not loaded |
| 157 | + if (locale in load_queues) { |
| 158 | + process_load_queue(locale); |
| 159 | + } |
| 160 | + if (locale in localizations && this_val in localizations[locale]) { |
| 161 | + return localizations[locale][this_val]; |
159 | 162 | }
|
160 | 163 | }
|
| 164 | + while (i --> 1); |
161 | 165 |
|
162 |
| - if (typeof document !== undef_type) { |
163 |
| - var |
164 |
| - elts = document.getElementsByTagName("link") |
165 |
| - , i = elts.length |
166 |
| - ; |
167 |
| - |
168 |
| - while (i--) { |
169 |
| - var |
170 |
| - elt = elts[i] |
171 |
| - , rel = (elt.getAttribute("rel") || "")[$to_lowercase]().split(/\s+/) |
172 |
| - ; |
173 |
| - |
174 |
| - if (l10n_js_media_type.test(elt.type)) { |
175 |
| - if (array_index_of.call(rel, "localizations") !== -1) { |
176 |
| - // multiple localizations |
177 |
| - load(elt.getAttribute("href")); |
178 |
| - } else if (array_index_of.call(rel, "localization") !== -1) { |
179 |
| - // single localization |
180 |
| - var localization = {}; |
181 |
| - localization[(elt.getAttribute("hreflang") || "")[$to_lowercase]()] = |
182 |
| - elt.getAttribute("href"); |
183 |
| - load(localization); |
184 |
| - } |
185 |
| - } |
186 |
| - } |
| 166 | + if (!using_default && String_ctr[$default_locale]) { |
| 167 | + use_default = TRUE; |
| 168 | + return localize.call(this_val); |
187 | 169 | }
|
| 170 | + |
| 171 | + return this_val; |
| 172 | +} |
| 173 | +; |
| 174 | + |
| 175 | +if (typeof XMLHttpRequest === undef_type && typeof ActiveXObject !== undef_type) { |
| 176 | + var AXO = ActiveXObject; |
| 177 | + |
| 178 | + XHR = function () { |
| 179 | + try { |
| 180 | + return new AXO("Msxml2.XMLHTTP.6.0"); |
| 181 | + } catch (xhrEx1) {} |
| 182 | + try { |
| 183 | + return new AXO("Msxml2.XMLHTTP.3.0"); |
| 184 | + } catch (xhrEx2) {} |
| 185 | + try { |
| 186 | + return new AXO("Msxml2.XMLHTTP"); |
| 187 | + } catch (xhrEx3) {} |
188 | 188 |
|
189 |
| - String_ctr.prototype[$to_locale_string] = function () { |
| 189 | + throw new Error("XMLHttpRequest not supported by this browser."); |
| 190 | + }; |
| 191 | +} else { |
| 192 | + XHR = XMLHttpRequest; |
| 193 | +} |
| 194 | + |
| 195 | +String_ctr[$default_locale] = String_ctr[$default_locale] || ""; |
| 196 | +String_ctr[$locale] = nav && (nav.language || nav.userLanguage) || ""; |
| 197 | + |
| 198 | +if (typeof document !== undef_type) { |
| 199 | + var |
| 200 | + elts = document.getElementsByTagName("link") |
| 201 | + , i = elts.length |
| 202 | + , localization |
| 203 | + ; |
| 204 | + |
| 205 | + while (i--) { |
190 | 206 | var
|
191 |
| - parts = String_ctr.locale[$to_lowercase]().split("-") |
192 |
| - , i = parts.length |
193 |
| - , this_val = this.valueOf() |
| 207 | + elt = elts[i] |
| 208 | + , rel = (elt.getAttribute("rel") || "")[$to_lowercase]().split(/\s+/) |
194 | 209 | ;
|
195 | 210 |
|
196 |
| - // Iterate through locales starting at most-specific until localization is found |
197 |
| - do { |
198 |
| - var locale = parts.slice(0, i).join("-"); |
199 |
| - // load locale if not loaded |
200 |
| - if (locale in load_queues) { |
201 |
| - process_load_queue(locale); |
202 |
| - } |
203 |
| - if (locale in localizations && this_val in localizations[locale]) { |
204 |
| - return localizations[locale][this_val]; |
| 211 | + if (l10n_js_media_type.test(elt.type)) { |
| 212 | + if (array_index_of.call(rel, "localizations") !== -1) { |
| 213 | + // multiple localizations |
| 214 | + load(elt.getAttribute("href")); |
| 215 | + } else if (array_index_of.call(rel, "localization") !== -1) { |
| 216 | + // single localization |
| 217 | + localization = {}; |
| 218 | + localization[(elt.getAttribute("hreflang") || "")[$to_lowercase]()] = |
| 219 | + elt.getAttribute("href"); |
| 220 | + load(localization); |
205 | 221 | }
|
206 | 222 | }
|
207 |
| - while (i--); |
208 |
| - |
209 |
| - return this_val; |
210 |
| - }; |
| 223 | + } |
| 224 | +} |
| 225 | + |
211 | 226 | }());
|
0 commit comments