UNPKG

11.2 kBJavaScriptView Raw
1
2!function(exports, Object, Function) {
3 // jshint newcap:false
4 "use strict";
5 var currentLang, currentMap
6 , isArray = Array.isArray
7 , cache = {}
8 , formatRe = /{(?!;)({[\s\S]*}|\[[\s\S]*]|(?:("|')(?:\\\2|.)*?\2|[^;{}])+?)(?:;((?:(['"\/])(?:\\\4|.)*?\4[gim]*|[^}])*))?}/g
9 , exprRe = /(['"\/])(?:\\\1|.)*?\1[gim]*|\b(?:[$_]|false|in|null|true|typeof|void)\b|\.\w+|\w+\s*:|\s+/g
10 , wordRe = /(\$?)([a-z_][\w$]*)/ig
11 , pattRe = /(\w+)(?::((?:(['"\/])(?:\\\3|.)*?\3[gim]*|[^;])*))?/g
12 , pointerRe = /^([\w ]+)\.([\w ]+)$/
13 , globalTexts = {}
14 , globalVals = i18n.vals = {}
15 // you can use Unicode's fraction slash (U+2044) with superscript and subscript numerals: e.g. ³⁄₄₇
16 // 2^53-1= 9007199254740991 == Number.MAX_SAFE_INTEGER
17 , list = i18n.list = []
18 , ext = i18n.ext = {}
19 , fnScope = {}
20
21 exports.i18n = i18n
22 i18n.add = add
23 i18n.get = get
24 i18n.use = use
25
26 function i18n(str, data) {
27 if (typeof str === "number") return "" + str
28 var out = cache[str] || (
29 cache[str] = makeFn(get(str) || str)
30 )
31 return isString(out) ? out : out(data || {}, i18n, globalVals)
32 }
33
34 function get(str, fallback) {
35 var tmp
36 return isString(str) ? (
37 isString(currentMap[str]) ? currentMap[str] :
38 typeof currentMap[str] === "object" ? currentMap[str][""] :
39 (tmp = pointerRe.exec(str)) && (
40 typeof currentMap[tmp[1]] === "object" &&
41 currentMap[tmp[1]][tmp[2]] ||
42 currentMap[tmp[2]]
43 ) || fallback
44 ) :
45 isArray(str) ?
46 get(str[0], get(str[1], get(str[2], fallback))) :
47 fallback
48 }
49
50
51 function makeFn(str) {
52 var tmp, m, expr, pattern
53 , args = ""
54 , fn = ""
55 , lastIndex = 0
56 for (; m = formatRe.exec(str); ) {
57 for (expr = m[1].replace(exprRe, ""); tmp = wordRe.exec(expr); ) {
58 args += (args ? "," : "var ") + tmp[0] + (
59 tmp[1] ? "=" : "=$['" + tmp[0] + "']!=null?$['" + tmp[0] + "']:"
60 ) + "$g['" + tmp[2] + "']!=null?$g['" + tmp[2] + "']:''"
61 }
62 expr = m[1]
63 if (pattern = get(m[3], m[3])) {
64 if (ext[tmp = pattern.charAt(0)]) {
65 expr = "_." + ext[tmp] + "(" + expr + "," + quote(pattern.slice(tmp == "#" ? 0 : 1)) + ")"
66 } else {
67 for (; tmp = pattRe.exec(pattern); ) {
68 expr = "_." + tmp[1] + ".call($," + expr + (tmp[2] ? "," + tmp[2] : "") + ")"
69 }
70 }
71 }
72 fn += (fn ? "+" : "") + (
73 lastIndex < m.index ?
74 quote(str.slice(lastIndex, m.index)) + "+(" : "("
75 ) + expr + ")"
76 lastIndex = m.index + m[0].length
77 }
78
79 if (fn[0]) try {
80 return Function("$,_,$g", args + ";return(" + fn + (
81 lastIndex < str.length ? ")+" + quote(str.slice(lastIndex)) : ")"
82 ))
83 } catch (e) {
84 /*** debug
85 console.log("makeFn", str, args, fn)
86 console.log(e)
87 /**/
88 }
89 return str.replace(/{;/g, "{")
90 }
91
92 function add(lang, texts) {
93 if (list.indexOf(lang) < 0) {
94 i18n[lang] = Object.create(globalTexts)
95 list.push(lang)
96 if (!currentLang) use(lang)
97 }
98 merge(i18n[lang], texts)
99 }
100
101 function merge(target, map) {
102 for (var k in map) {
103 target[k] = map[k] && map[k].constructor === Object ? merge(Object.create(target), map[k]) : map[k]
104 }
105 return target
106 }
107
108 i18n.def = function(map) {
109 for (var k in map) {
110 add(k, map)
111 }
112 }
113
114 function getLang(lang) {
115 return lang && (
116 i18n[lang = ("" + lang).toLowerCase()] ||
117 i18n[lang = lang.split("-")[0]]
118 ) && lang
119 }
120
121 function use(lang) {
122 lang = getLang(lang)
123 if (lang && currentLang != lang) {
124 cache = {}
125 currentMap = i18n[currentLang = i18n.current = lang] = i18n[currentLang]
126 }
127 return currentLang
128 }
129
130 function isString(str) {
131 return typeof str === "string"
132 }
133 function isObject(obj) {
134 return obj && obj.constructor === Object
135 }
136 function getStr(sub, word, fallback) {
137 return currentMap && (
138 isObject(currentMap[word]) && currentMap[word][sub] ||
139 isObject(currentMap[sub]) && currentMap[sub][word] ||
140 currentMap[word || sub]
141 ) || isString(fallback) && fallback || ""
142 }
143 function quote(str) {
144 return "'" + (str || "").replace(/'/g, "\\'").replace(/\n/g, "\\n") + "'"
145 }
146
147 /*** i18n.date ***/
148 // Software should only ever deal with UTC except when displaying times to the user.
149 // P3Y6M4DT12H30M5S - P is the duration designator (referred to as "period")
150 //
151 var dateRe = /([Md])\1\1\1?|([yMdHhmswSZ])(\2?)|[uUaSeoQ]|'((?:''|[^'])*)'|(["\\\n\r\u2028\u2029])/g
152 , fns = Object.create(null)
153 , tmp1 = new Date()
154 , tmp2 = new Date()
155 , map = {
156 e: "Day()||7",
157 M: "Month()+1",
158 d: "Date()",
159 H: "Hours()",
160 h: "Hours()%12||12",
161 m: "Minutes()",
162 s: "Seconds()",
163 S: "Milliseconds()"
164 }
165
166
167 i18n[ext["@"] = "date"] = date
168 function date(input, _mask, _zone) {
169 var offset, undef
170 , d = typeof input === "number" ? input : isNaN(input) ? Date.parse(input) : +input
171 , locale = currentMap["@"]
172 , mask = locale[_mask] || _mask || locale.iso
173 , zone = _zone != undef ? _zone : Date._tz != undef ? Date._tz : undef
174 , utc = mask.slice(0, 4) == "UTC:"
175 if (zone != undef && !utc) {
176 offset = 60 * zone
177 tmp1.setTime(d + offset * 6e4)
178 utc = mask = "UTC:" + mask
179 } else {
180 tmp1.setTime(d)
181 offset = utc ? 0 : -tmp1.getTimezoneOffset()
182 }
183 return isNaN(d) ? "" + d : (
184 fns[mask] || (fns[mask] = Function("d,a,o,l", "var t;return \"" + dateStr(mask, utc) + "\"")))(
185 tmp1,
186 tmp2,
187 offset,
188 locale
189 )
190 }
191
192 date.dateStr = dateStr
193 function dateStr(mask, utc) {
194 var get = "d.get" + (utc ? "UTC" : "")
195 , setA = "a.setTime(+d+((4-(" + get + map.e + "))*864e5))"
196 return (utc ? mask.slice(4) : mask).replace(dateRe, function(match, MD, single, pad, text, esc) {
197 var str = (
198 esc ? escape(esc).replace(/%u/g, "\\u").replace(/%/g, "\\x") :
199 text !== void 0 ? text.replace(/''/g, "'") :
200 MD ? "l.names[" + get + (MD == "M" ? "Month" : "Day" ) + "()+" + (match == "ddd" ? 24 : MD == "d" ? 31 : match == "MMM" ? 0 : 12) + "]" :
201 match == "u" ? "(d/1000)>>>0" :
202 match == "U" ? "+d" :
203 match == "Q" ? "((" + get + "Month()/3)|0)+1" :
204 match == "a" ? "l[" + get + map.H + ">11?'pm':'am']" :
205 match == "o" ? setA + ",a" + get.slice(1) + "FullYear()" :
206 single == "y" ? get + "FullYear()" + (pad == "y" ? "%100" : "") :
207 single == "Z" ? "(t=o)?(t<0?((t=-t),'-'):'+')+(t<600?'0':'')+(0|(t/60))" + (pad ? "" : "+':'") + "+((t%=60)>9?t:'0'+t):'Z'" :
208 single == "w" ? "Math.ceil(((" + setA + "-a.s" + get.slice(3) + "Month(0,1))/864e5+1)/7)" :
209 get + map[single || match]
210 )
211 return text !== void 0 || esc ? str : "\"+(" + (
212 match == "SS" ? "(t=" + str + ")>9?t>99?t:'0'+t:'00'+t" :
213 pad && single != "Z" ? "(t=" + str + ")>9?t:'0'+t" :
214 str
215 ) + ")+\""
216 })
217 }
218
219 /**/
220
221 /*** i18n.detect ***/
222 i18n.detect = function(fallback) {
223 var navigator = exports.navigator || exports
224
225 // navigator.userLanguage for IE, navigator.language for others
226 return use([navigator.language, navigator.userLanguage].concat(
227 navigator.languages, fallback, list[0]
228 ).filter(getLang)[0])
229 }
230 /**/
231
232 /*** i18n.number ***/
233 var numRe1 = /([^\d#]*)([\d# .,_·']*\/?\d+)(?:(\s*)([a-z%]+)(\d*))?(.*)/
234 , numRe2 = /([.,\/])(\d*)$/
235
236 i18n[ext["#"] = ext["+"] = "number"] = number
237 function number(input, _format) {
238 var format = getStr("#", _format.slice(1), _format)
239 return (cache[format] || (cache[format] = Function(
240 "d,g",
241 "var N=d<0&&(d=-d),n,r,o;return " + numStr(format)
242 )))(input, fnScope)
243 }
244 number.pre = {
245 a: "(o+=d<1e3?'':d<1e6?(d/=1e3,'k'):d<1e9?(d/=1e6,'M'):d<1e12?(d/=1e9,'G'):d<1e15?(d/=1e12,'T'):d<1e18?(d/=1e15,'P'):(d/=1e18,'E')),"
246 }
247 number.post = {
248 }
249
250 function numStr(format) {
251 // format;NaN;negFormat;0;Infinity;-Infinity;roundPoint
252 var conf = format.split(";")
253 , nan_value = conf[1] || "-"
254 , m2 = numRe1.exec(conf[0])
255 , m3 = numRe2.exec(m2[2])
256 , decimals = m3 && m3[2].length || 0
257 , full = m3 ? m2[2].slice(0, m3.index) : m2[2]
258 , num = full.replace(/\D+/g, "")
259 , sLen = num.length
260 , step = decimals ? +(m3[1] === "/" ? 1 / m3[2] : num + "." + m3[2]) : num
261 , decSep = m3 && m3[1]
262 , fn = "d===Infinity?(N?" + quote(conf[5]||nan_value) + ":" + quote(conf[4]||nan_value) + "):d>0||d===0?(o=" + quote(m2[3]) + "," + (number.pre[m2[4]] || "") + "n=" + (
263 // Use exponential notation to fix float rounding
264 // Math.round(1.005*100)/100 = 1 instead of 1.01
265 decimals ?
266 "d>1e-" + (decimals + 1) + "?(n=(d+'e" + decimals + "')/" + (step + "e" + decimals) + "":
267 "d>"+num+"e-1?(n=d/" + num
268 ) + ",Math.floor(n" + (
269 conf[6] == 1 ? "%1?n+1:n" : "+" + (conf[6] || 0.5)
270 ) + ")*" + step + "):0,r=" + (
271 m2[5] ? "(''+(+n.toPrecision(" + (m2[5]) + ")))" :
272 decimals ? "n.toFixed(" + decimals + ")" :
273 "n+''"
274 )
275
276 if (decimals) {
277 if (decSep == "/") {
278 fn += ".replace(/\\.\\d+/,'" + (
279 m3[2] == 5 ?
280 "⅕⅖⅗⅘'.charAt(5" :
281 "⅛¼⅜½⅝¾⅞'.charAt(8"
282 ) + "*(n%1)-1))"
283 } else if (decSep != ".") {
284 fn += ".replace('.','" + decSep + "')"
285 }
286 if (sLen === 0) {
287 fn += ",n<1&&(r=r.slice(1)||'0')"
288 }
289 }
290 if (sLen > 1) {
291 if (decimals) sLen += decimals + 1
292 fn += ",r=(r.length<" + sLen + "?(1e15+r).slice(-" + sLen + "):r)"
293 }
294
295 if (num = full.match(/[^\d#][\d#]+/g)) {
296 fn += ",r=" + numJunk(num, num.length - 1, 0, decimals ? decimals + 1 : 0)
297 }
298
299 if (m2[4] == "o") {
300 number.post.o = "r+(o=g.o," + (
301 fnScope.o = get("ordinal").split(";")
302 ).pop() + ")"
303 }
304
305 fn += (
306 (m2[4] ? ",r=" + (number.post[m2[4]] || "r+o") : "") +
307 // negative format
308 ",N&&n>0?" + quote(conf[2] || "-#").replace("#", "'+r+'") + ":" +
309 (conf[3] ? "n===0?" + quote(conf[3]) + ":" : "") +
310 (m2[1] ? quote(m2[1]) + "+r" : "r") +
311 (m2[6] ? "+" + quote(m2[6]) : "")
312 )
313
314 return fn + "):" + quote(nan_value)
315 }
316
317 function numJunk(arr, i, lastLen, dec) {
318 var len = lastLen + arr[i].length - 1
319
320 return "(n<1e" + len + (
321 lastLen ? "?r.slice(0,-" + (lastLen + dec) + "):" : "?r:"
322 ) + (
323 len < 16 ? numJunk(arr, i?i-1:i, len, dec) : "r.slice(0,-" + (lastLen + dec) + ")"
324 ) + "+" + quote(arr[i].charAt(0)) + "+r.slice(-" + (len + dec) + (
325 lastLen ? ",-" + (lastLen + dec) : ""
326 ) + "))"
327 }
328 /**/
329
330 /*** i18n.pick ***/
331 var pickRe1 = /(\w+)\?/g
332 , pickRe2 = /[;=,]/
333 i18n[ext["?"] = "pick"] = pick
334 function pick(val, word) {
335 for (var arr = getStr("?", word, word).replace(pickRe1, "$1=$1;").split(pickRe2), i = 1|arr.length; i > 0; ) {
336 if ((i-=2) < 0 || arr[i] && (arr[i] == "" + val || +arr[i] <= val)) {
337 return arr[i + 1] || ""
338 }
339 }
340 }
341 /**/
342
343 /*** i18n.plural ***/
344 i18n[ext["*"] = "plural"] = plural
345 function plural(n, word) {
346 var expr = getStr("*", "", "n!=1")
347 return (cache[expr] || (cache[expr] = Function(
348 "a,n",
349 "return (a[+(" + expr + ")]||a[0]).replace('#',n)"
350 )))((getStr("*", word, "# " + word)).split(";"), n)
351 }
352 /**/
353
354 i18n.map = function(input, str, sep, lastSep) {
355 if (!isArray(input)) return input
356 var arr = input.map(function(data) {
357 return i18n(str, data)
358 })
359 , end = lastSep && arr.length > 1 ? lastSep + arr.pop() : ""
360 return arr.join(sep || ", ") + end
361 }
362 i18n.upcase = function(str) {
363 return isString(str) ? str.toUpperCase() : "" + str
364 }
365 i18n.locase = function(str) {
366 return isString(str) ? str.toLowerCase() : "" + str
367 }
368 i18n.json = JSON.stringify
369
370
371}(this, Object, Function) // jshint ignore:line
372
373