@dcloudio/uni-i18n 2.0.0 → 2.0.1-32920211122002
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/uni-i18n.cjs.js +273 -80
- package/dist/uni-i18n.d.ts +61 -21
- package/dist/uni-i18n.es.js +454 -0
- package/package.json +5 -5
- package/dist/uni-i18n.esm.js +0 -274
package/dist/uni-i18n.cjs.js
CHANGED
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
const isArray = Array.isArray;
|
|
5
6
|
const isObject = (val) => val !== null && typeof val === 'object';
|
|
7
|
+
const defaultDelimiters = ['{', '}'];
|
|
6
8
|
class BaseFormatter {
|
|
7
9
|
constructor() {
|
|
8
10
|
this._caches = Object.create(null);
|
|
9
11
|
}
|
|
10
|
-
interpolate(message, values) {
|
|
12
|
+
interpolate(message, values, delimiters = defaultDelimiters) {
|
|
11
13
|
if (!values) {
|
|
12
14
|
return [message];
|
|
13
15
|
}
|
|
14
16
|
let tokens = this._caches[message];
|
|
15
17
|
if (!tokens) {
|
|
16
|
-
tokens = parse(message);
|
|
18
|
+
tokens = parse(message, delimiters);
|
|
17
19
|
this._caches[message] = tokens;
|
|
18
20
|
}
|
|
19
21
|
return compile(tokens, values);
|
|
@@ -21,24 +23,24 @@ class BaseFormatter {
|
|
|
21
23
|
}
|
|
22
24
|
const RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
|
|
23
25
|
const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
|
|
24
|
-
function parse(format) {
|
|
26
|
+
function parse(format, [startDelimiter, endDelimiter]) {
|
|
25
27
|
const tokens = [];
|
|
26
28
|
let position = 0;
|
|
27
29
|
let text = '';
|
|
28
30
|
while (position < format.length) {
|
|
29
31
|
let char = format[position++];
|
|
30
|
-
if (char ===
|
|
32
|
+
if (char === startDelimiter) {
|
|
31
33
|
if (text) {
|
|
32
34
|
tokens.push({ type: 'text', value: text });
|
|
33
35
|
}
|
|
34
36
|
text = '';
|
|
35
37
|
let sub = '';
|
|
36
38
|
char = format[position++];
|
|
37
|
-
while (char !== undefined && char !==
|
|
39
|
+
while (char !== undefined && char !== endDelimiter) {
|
|
38
40
|
sub += char;
|
|
39
41
|
char = format[position++];
|
|
40
42
|
}
|
|
41
|
-
const isClosed = char ===
|
|
43
|
+
const isClosed = char === endDelimiter;
|
|
42
44
|
const type = RE_TOKEN_LIST_VALUE.test(sub)
|
|
43
45
|
? 'list'
|
|
44
46
|
: isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
|
|
@@ -46,12 +48,12 @@ function parse(format) {
|
|
|
46
48
|
: 'unknown';
|
|
47
49
|
tokens.push({ value: sub, type });
|
|
48
50
|
}
|
|
49
|
-
else if (char === '%') {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
51
|
+
// else if (char === '%') {
|
|
52
|
+
// // when found rails i18n syntax, skip text capture
|
|
53
|
+
// if (format[position] !== '{') {
|
|
54
|
+
// text += char
|
|
55
|
+
// }
|
|
56
|
+
// }
|
|
55
57
|
else {
|
|
56
58
|
text += char;
|
|
57
59
|
}
|
|
@@ -62,7 +64,7 @@ function parse(format) {
|
|
|
62
64
|
function compile(tokens, values) {
|
|
63
65
|
const compiled = [];
|
|
64
66
|
let index = 0;
|
|
65
|
-
const mode =
|
|
67
|
+
const mode = isArray(values)
|
|
66
68
|
? 'list'
|
|
67
69
|
: isObject(values)
|
|
68
70
|
? 'named'
|
|
@@ -100,6 +102,11 @@ function compile(tokens, values) {
|
|
|
100
102
|
return compiled;
|
|
101
103
|
}
|
|
102
104
|
|
|
105
|
+
const LOCALE_ZH_HANS = 'zh-Hans';
|
|
106
|
+
const LOCALE_ZH_HANT = 'zh-Hant';
|
|
107
|
+
const LOCALE_EN = 'en';
|
|
108
|
+
const LOCALE_FR = 'fr';
|
|
109
|
+
const LOCALE_ES = 'es';
|
|
103
110
|
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
104
111
|
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
|
|
105
112
|
const defaultFormatter = new BaseFormatter();
|
|
@@ -114,31 +121,31 @@ function normalizeLocale(locale, messages) {
|
|
|
114
121
|
return;
|
|
115
122
|
}
|
|
116
123
|
locale = locale.trim().replace(/_/g, '-');
|
|
117
|
-
if (messages[locale]) {
|
|
124
|
+
if (messages && messages[locale]) {
|
|
118
125
|
return locale;
|
|
119
126
|
}
|
|
120
127
|
locale = locale.toLowerCase();
|
|
121
128
|
if (locale.indexOf('zh') === 0) {
|
|
122
|
-
if (locale.indexOf('-hans')
|
|
123
|
-
return
|
|
129
|
+
if (locale.indexOf('-hans') > -1) {
|
|
130
|
+
return LOCALE_ZH_HANS;
|
|
124
131
|
}
|
|
125
|
-
if (locale.indexOf('-hant')
|
|
126
|
-
return
|
|
132
|
+
if (locale.indexOf('-hant') > -1) {
|
|
133
|
+
return LOCALE_ZH_HANT;
|
|
127
134
|
}
|
|
128
135
|
if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {
|
|
129
|
-
return
|
|
136
|
+
return LOCALE_ZH_HANT;
|
|
130
137
|
}
|
|
131
|
-
return
|
|
138
|
+
return LOCALE_ZH_HANS;
|
|
132
139
|
}
|
|
133
|
-
const lang = startsWith(locale, [
|
|
140
|
+
const lang = startsWith(locale, [LOCALE_EN, LOCALE_FR, LOCALE_ES]);
|
|
134
141
|
if (lang) {
|
|
135
142
|
return lang;
|
|
136
143
|
}
|
|
137
144
|
}
|
|
138
145
|
class I18n {
|
|
139
146
|
constructor({ locale, fallbackLocale, messages, watcher, formater, }) {
|
|
140
|
-
this.locale =
|
|
141
|
-
this.fallbackLocale =
|
|
147
|
+
this.locale = LOCALE_EN;
|
|
148
|
+
this.fallbackLocale = LOCALE_EN;
|
|
142
149
|
this.message = {};
|
|
143
150
|
this.messages = {};
|
|
144
151
|
this.watchers = [];
|
|
@@ -146,8 +153,8 @@ class I18n {
|
|
|
146
153
|
this.fallbackLocale = fallbackLocale;
|
|
147
154
|
}
|
|
148
155
|
this.formater = formater || defaultFormatter;
|
|
149
|
-
this.messages = messages;
|
|
150
|
-
this.setLocale(locale);
|
|
156
|
+
this.messages = messages || {};
|
|
157
|
+
this.setLocale(locale || LOCALE_EN);
|
|
151
158
|
if (watcher) {
|
|
152
159
|
this.watchLocale(watcher);
|
|
153
160
|
}
|
|
@@ -155,10 +162,17 @@ class I18n {
|
|
|
155
162
|
setLocale(locale) {
|
|
156
163
|
const oldLocale = this.locale;
|
|
157
164
|
this.locale = normalizeLocale(locale, this.messages) || this.fallbackLocale;
|
|
165
|
+
if (!this.messages[this.locale]) {
|
|
166
|
+
// 可能初始化时不存在
|
|
167
|
+
this.messages[this.locale] = {};
|
|
168
|
+
}
|
|
158
169
|
this.message = this.messages[this.locale];
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
// 仅发生变化时,通知
|
|
171
|
+
if (oldLocale !== this.locale) {
|
|
172
|
+
this.watchers.forEach((watcher) => {
|
|
173
|
+
watcher(this.locale, oldLocale);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
162
176
|
}
|
|
163
177
|
getLocale() {
|
|
164
178
|
return this.locale;
|
|
@@ -169,6 +183,27 @@ class I18n {
|
|
|
169
183
|
this.watchers.splice(index, 1);
|
|
170
184
|
};
|
|
171
185
|
}
|
|
186
|
+
add(locale, message, override = true) {
|
|
187
|
+
const curMessages = this.messages[locale];
|
|
188
|
+
if (curMessages) {
|
|
189
|
+
if (override) {
|
|
190
|
+
Object.assign(curMessages, message);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
Object.keys(message).forEach((key) => {
|
|
194
|
+
if (!hasOwn(curMessages, key)) {
|
|
195
|
+
curMessages[key] = message[key];
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
this.messages[locale] = message;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
f(message, values, delimiters) {
|
|
205
|
+
return this.formater.interpolate(message, values, delimiters).join('');
|
|
206
|
+
}
|
|
172
207
|
t(key, locale, values) {
|
|
173
208
|
let message = this.message;
|
|
174
209
|
if (typeof locale === 'string') {
|
|
@@ -186,94 +221,252 @@ class I18n {
|
|
|
186
221
|
}
|
|
187
222
|
}
|
|
188
223
|
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
|
|
224
|
+
function watchAppLocale(appVm, i18n) {
|
|
225
|
+
// 需要保证 watch 的触发在组件渲染之前
|
|
226
|
+
if (appVm.$watchLocale) {
|
|
227
|
+
// vue2
|
|
228
|
+
appVm.$watchLocale((newLocale) => {
|
|
192
229
|
i18n.setLocale(newLocale);
|
|
193
|
-
}, {
|
|
194
|
-
immediate: true,
|
|
195
230
|
});
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
appVm.$watch(() => appVm.$locale, (newLocale) => {
|
|
234
|
+
i18n.setLocale(newLocale);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
196
237
|
}
|
|
197
238
|
function getDefaultLocale() {
|
|
198
|
-
if (typeof
|
|
199
|
-
return
|
|
239
|
+
if (typeof uni !== 'undefined' && uni.getLocale) {
|
|
240
|
+
return uni.getLocale();
|
|
200
241
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return
|
|
242
|
+
// 小程序平台,uni 和 uni-i18n 互相引用,导致访问不到 uni,故在 global 上挂了 getLocale
|
|
243
|
+
if (typeof global !== 'undefined' && global.getLocale) {
|
|
244
|
+
return global.getLocale();
|
|
204
245
|
}
|
|
205
|
-
return
|
|
246
|
+
return LOCALE_EN;
|
|
206
247
|
}
|
|
207
|
-
function initVueI18n(
|
|
248
|
+
function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
|
|
249
|
+
// 兼容旧版本入参
|
|
250
|
+
if (typeof locale !== 'string') {
|
|
251
|
+
[locale, messages] = [
|
|
252
|
+
messages,
|
|
253
|
+
locale,
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
if (typeof locale !== 'string') {
|
|
257
|
+
// 因为小程序平台,uni-i18n 和 uni 互相引用,导致此时访问 uni 时,为 undefined
|
|
258
|
+
locale = getDefaultLocale();
|
|
259
|
+
}
|
|
260
|
+
if (typeof fallbackLocale !== 'string') {
|
|
261
|
+
fallbackLocale =
|
|
262
|
+
(typeof __uniConfig !== 'undefined' && __uniConfig.fallbackLocale) ||
|
|
263
|
+
LOCALE_EN;
|
|
264
|
+
}
|
|
208
265
|
const i18n = new I18n({
|
|
209
|
-
locale
|
|
266
|
+
locale,
|
|
210
267
|
fallbackLocale,
|
|
211
268
|
messages,
|
|
269
|
+
watcher,
|
|
212
270
|
});
|
|
213
271
|
let t = (key, values) => {
|
|
214
272
|
if (typeof getApp !== 'function') {
|
|
215
|
-
// app
|
|
273
|
+
// app view
|
|
216
274
|
/* eslint-disable no-func-assign */
|
|
217
275
|
t = function (key, values) {
|
|
218
276
|
return i18n.t(key, values);
|
|
219
277
|
};
|
|
220
278
|
}
|
|
221
279
|
else {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (
|
|
242
|
-
|
|
280
|
+
let isWatchedAppLocale = false;
|
|
281
|
+
t = function (key, values) {
|
|
282
|
+
const appVm = getApp().$vm;
|
|
283
|
+
// 可能$vm还不存在,比如在支付宝小程序中,组件定义较早,在props的default里使用了t()函数(如uni-goods-nav),此时app还未初始化
|
|
284
|
+
// options: {
|
|
285
|
+
// type: Array,
|
|
286
|
+
// default () {
|
|
287
|
+
// return [{
|
|
288
|
+
// icon: 'shop',
|
|
289
|
+
// text: t("uni-goods-nav.options.shop"),
|
|
290
|
+
// }, {
|
|
291
|
+
// icon: 'cart',
|
|
292
|
+
// text: t("uni-goods-nav.options.cart")
|
|
293
|
+
// }]
|
|
294
|
+
// }
|
|
295
|
+
// },
|
|
296
|
+
if (appVm) {
|
|
297
|
+
// 触发响应式
|
|
298
|
+
appVm.$locale;
|
|
299
|
+
if (!isWatchedAppLocale) {
|
|
300
|
+
isWatchedAppLocale = true;
|
|
301
|
+
watchAppLocale(appVm, i18n);
|
|
243
302
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
303
|
+
}
|
|
304
|
+
return i18n.t(key, values);
|
|
305
|
+
};
|
|
247
306
|
}
|
|
248
307
|
return t(key, values);
|
|
249
308
|
};
|
|
250
309
|
return {
|
|
310
|
+
i18n,
|
|
311
|
+
f(message, values, delimiters) {
|
|
312
|
+
return i18n.f(message, values, delimiters);
|
|
313
|
+
},
|
|
251
314
|
t(key, values) {
|
|
252
315
|
return t(key, values);
|
|
253
316
|
},
|
|
317
|
+
add(locale, message, override = true) {
|
|
318
|
+
return i18n.add(locale, message, override);
|
|
319
|
+
},
|
|
320
|
+
watch(fn) {
|
|
321
|
+
return i18n.watchLocale(fn);
|
|
322
|
+
},
|
|
254
323
|
getLocale() {
|
|
255
324
|
return i18n.getLocale();
|
|
256
325
|
},
|
|
257
326
|
setLocale(newLocale) {
|
|
258
327
|
return i18n.setLocale(newLocale);
|
|
259
328
|
},
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const isString = (val) => typeof val === 'string';
|
|
333
|
+
let formater;
|
|
334
|
+
function hasI18nJson(jsonObj, delimiters) {
|
|
335
|
+
if (!formater) {
|
|
336
|
+
formater = new BaseFormatter();
|
|
337
|
+
}
|
|
338
|
+
return walkJsonObj(jsonObj, (jsonObj, key) => {
|
|
339
|
+
const value = jsonObj[key];
|
|
340
|
+
if (isString(value)) {
|
|
341
|
+
if (isI18nStr(value, delimiters)) {
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
return hasI18nJson(value, delimiters);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
function parseI18nJson(jsonObj, values, delimiters) {
|
|
351
|
+
if (!formater) {
|
|
352
|
+
formater = new BaseFormatter();
|
|
353
|
+
}
|
|
354
|
+
walkJsonObj(jsonObj, (jsonObj, key) => {
|
|
355
|
+
const value = jsonObj[key];
|
|
356
|
+
if (isString(value)) {
|
|
357
|
+
if (isI18nStr(value, delimiters)) {
|
|
358
|
+
jsonObj[key] = compileStr(value, values, delimiters);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
parseI18nJson(value, values, delimiters);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return jsonObj;
|
|
366
|
+
}
|
|
367
|
+
function compileI18nJsonStr(jsonStr, { locale, locales, delimiters, }) {
|
|
368
|
+
if (!isI18nStr(jsonStr, delimiters)) {
|
|
369
|
+
return jsonStr;
|
|
370
|
+
}
|
|
371
|
+
if (!formater) {
|
|
372
|
+
formater = new BaseFormatter();
|
|
373
|
+
}
|
|
374
|
+
const localeValues = [];
|
|
375
|
+
Object.keys(locales).forEach((name) => {
|
|
376
|
+
if (name !== locale) {
|
|
377
|
+
localeValues.push({
|
|
378
|
+
locale: name,
|
|
379
|
+
values: locales[name],
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
localeValues.unshift({ locale, values: locales[locale] });
|
|
384
|
+
try {
|
|
385
|
+
return JSON.stringify(compileJsonObj(JSON.parse(jsonStr), localeValues, delimiters), null, 2);
|
|
386
|
+
}
|
|
387
|
+
catch (e) { }
|
|
388
|
+
return jsonStr;
|
|
389
|
+
}
|
|
390
|
+
function isI18nStr(value, delimiters) {
|
|
391
|
+
return value.indexOf(delimiters[0]) > -1;
|
|
392
|
+
}
|
|
393
|
+
function compileStr(value, values, delimiters) {
|
|
394
|
+
return formater.interpolate(value, values, delimiters).join('');
|
|
395
|
+
}
|
|
396
|
+
function compileValue(jsonObj, key, localeValues, delimiters) {
|
|
397
|
+
const value = jsonObj[key];
|
|
398
|
+
if (isString(value)) {
|
|
399
|
+
// 存在国际化
|
|
400
|
+
if (isI18nStr(value, delimiters)) {
|
|
401
|
+
jsonObj[key] = compileStr(value, localeValues[0].values, delimiters);
|
|
402
|
+
if (localeValues.length > 1) {
|
|
403
|
+
// 格式化国际化语言
|
|
404
|
+
const valueLocales = (jsonObj[key + 'Locales'] = {});
|
|
405
|
+
localeValues.forEach((localValue) => {
|
|
406
|
+
valueLocales[localValue.locale] = compileStr(value, localValue.values, delimiters);
|
|
267
407
|
});
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
compileJsonObj(value, localeValues, delimiters);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function compileJsonObj(jsonObj, localeValues, delimiters) {
|
|
416
|
+
walkJsonObj(jsonObj, (jsonObj, key) => {
|
|
417
|
+
compileValue(jsonObj, key, localeValues, delimiters);
|
|
418
|
+
});
|
|
419
|
+
return jsonObj;
|
|
420
|
+
}
|
|
421
|
+
function walkJsonObj(jsonObj, walk) {
|
|
422
|
+
if (isArray(jsonObj)) {
|
|
423
|
+
for (let i = 0; i < jsonObj.length; i++) {
|
|
424
|
+
if (walk(jsonObj, i)) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else if (isObject(jsonObj)) {
|
|
430
|
+
for (const key in jsonObj) {
|
|
431
|
+
if (walk(jsonObj, key)) {
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function resolveLocale(locales) {
|
|
440
|
+
return (locale) => {
|
|
441
|
+
if (!locale) {
|
|
442
|
+
return locale;
|
|
443
|
+
}
|
|
444
|
+
locale = normalizeLocale(locale) || locale;
|
|
445
|
+
return resolveLocaleChain(locale).find((locale) => locales.indexOf(locale) > -1);
|
|
275
446
|
};
|
|
447
|
+
}
|
|
448
|
+
function resolveLocaleChain(locale) {
|
|
449
|
+
const chain = [];
|
|
450
|
+
const tokens = locale.split('-');
|
|
451
|
+
while (tokens.length) {
|
|
452
|
+
chain.push(tokens.join('-'));
|
|
453
|
+
tokens.pop();
|
|
454
|
+
}
|
|
455
|
+
return chain;
|
|
276
456
|
}
|
|
277
457
|
|
|
458
|
+
exports.Formatter = BaseFormatter;
|
|
278
459
|
exports.I18n = I18n;
|
|
460
|
+
exports.LOCALE_EN = LOCALE_EN;
|
|
461
|
+
exports.LOCALE_ES = LOCALE_ES;
|
|
462
|
+
exports.LOCALE_FR = LOCALE_FR;
|
|
463
|
+
exports.LOCALE_ZH_HANS = LOCALE_ZH_HANS;
|
|
464
|
+
exports.LOCALE_ZH_HANT = LOCALE_ZH_HANT;
|
|
465
|
+
exports.compileI18nJsonStr = compileI18nJsonStr;
|
|
466
|
+
exports.hasI18nJson = hasI18nJson;
|
|
279
467
|
exports.initVueI18n = initVueI18n;
|
|
468
|
+
exports.isI18nStr = isI18nStr;
|
|
469
|
+
exports.isString = isString;
|
|
470
|
+
exports.normalizeLocale = normalizeLocale;
|
|
471
|
+
exports.parseI18nJson = parseI18nJson;
|
|
472
|
+
exports.resolveLocale = resolveLocale;
|
package/dist/uni-i18n.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
export declare type BuiltInLocale = typeof LOCALE_ZH_HANS | typeof LOCALE_ZH_HANT | typeof LOCALE_EN | typeof LOCALE_FR | typeof LOCALE_ES;
|
|
1
2
|
|
|
2
|
-
export declare
|
|
3
|
+
export declare function compileI18nJsonStr(jsonStr: string, { locale, locales, delimiters, }: {
|
|
4
|
+
locale: string;
|
|
5
|
+
locales: Record<string, Record<string, string>>;
|
|
6
|
+
delimiters: [string, string];
|
|
7
|
+
}): string;
|
|
3
8
|
|
|
4
|
-
export declare
|
|
5
|
-
|
|
9
|
+
export declare class Formatter {
|
|
10
|
+
_caches: {
|
|
11
|
+
[key: string]: Array<Token>;
|
|
12
|
+
};
|
|
13
|
+
constructor();
|
|
14
|
+
interpolate(message: string, values?: Record<string, unknown> | Array<unknown>, delimiters?: [string, string]): Array<unknown>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare interface Formatter_2 {
|
|
18
|
+
interpolate: (message: string, values?: Record<string, unknown> | Array<unknown>, delimiters?: [string, string]) => Array<unknown>;
|
|
6
19
|
}
|
|
7
20
|
|
|
21
|
+
export declare function hasI18nJson(jsonObj: unknown, delimiters: [string, string]): boolean;
|
|
22
|
+
|
|
8
23
|
export declare class I18n {
|
|
9
24
|
private locale;
|
|
10
25
|
private fallbackLocale;
|
|
@@ -14,36 +29,61 @@ export declare class I18n {
|
|
|
14
29
|
private formater;
|
|
15
30
|
constructor({ locale, fallbackLocale, messages, watcher, formater, }: I18nOptions);
|
|
16
31
|
setLocale(locale: string): void;
|
|
17
|
-
getLocale():
|
|
32
|
+
getLocale(): string;
|
|
18
33
|
watchLocale(fn: LocaleWatcher): () => void;
|
|
34
|
+
add(locale: BuiltInLocale, message: Record<string, string>, override?: boolean): void;
|
|
35
|
+
f(message: string, values?: Record<string, unknown> | Array<unknown>, delimiters?: [string, string]): string;
|
|
19
36
|
t(key: string, values?: Record<string, unknown> | Array<unknown> | BuiltInLocale): string;
|
|
20
37
|
t(key: string, locale?: BuiltInLocale, values?: Record<string, unknown> | Array<unknown>): string;
|
|
21
38
|
}
|
|
22
39
|
|
|
23
40
|
export declare interface I18nOptions {
|
|
24
|
-
locale:
|
|
25
|
-
fallbackLocale?:
|
|
26
|
-
messages
|
|
27
|
-
formater?:
|
|
41
|
+
locale: string;
|
|
42
|
+
fallbackLocale?: string;
|
|
43
|
+
messages?: LocaleMessages;
|
|
44
|
+
formater?: Formatter_2;
|
|
28
45
|
watcher?: LocaleWatcher;
|
|
29
46
|
}
|
|
30
47
|
|
|
31
|
-
export declare function initVueI18n(messages
|
|
48
|
+
export declare function initVueI18n(locale?: string, messages?: LocaleMessages, fallbackLocale?: string, watcher?: (locale: string) => void): {
|
|
49
|
+
i18n: I18n;
|
|
50
|
+
f(message: string, values?: Record<string, unknown> | unknown[] | undefined, delimiters?: [string, string] | undefined): string;
|
|
32
51
|
t(key: string, values?: Record<string, unknown> | unknown[] | undefined): string;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
methods: {
|
|
38
|
-
$$t(key: string, values?: any): string;
|
|
39
|
-
};
|
|
40
|
-
};
|
|
52
|
+
add(locale: BuiltInLocale, message: Record<string, string>, override?: boolean): void;
|
|
53
|
+
watch(fn: LocaleWatcher): () => void;
|
|
54
|
+
getLocale(): string;
|
|
55
|
+
setLocale(newLocale: string): void;
|
|
41
56
|
};
|
|
42
57
|
|
|
43
|
-
export declare
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
export declare function isI18nStr(value: string, delimiters: [string, string]): boolean;
|
|
59
|
+
|
|
60
|
+
export declare const isString: (val: unknown) => val is string;
|
|
61
|
+
|
|
62
|
+
declare type Locale = string;
|
|
63
|
+
|
|
64
|
+
export declare const LOCALE_EN = "en";
|
|
65
|
+
|
|
66
|
+
export declare const LOCALE_ES = "es";
|
|
46
67
|
|
|
47
|
-
export declare
|
|
68
|
+
export declare const LOCALE_FR = "fr";
|
|
69
|
+
|
|
70
|
+
export declare const LOCALE_ZH_HANS = "zh-Hans";
|
|
71
|
+
|
|
72
|
+
export declare const LOCALE_ZH_HANT = "zh-Hant";
|
|
73
|
+
|
|
74
|
+
export declare type LocaleMessages = Record<string, Record<string, string>>;
|
|
75
|
+
|
|
76
|
+
export declare type LocaleWatcher = (newLocale: string, oldLocale: string) => void;
|
|
77
|
+
|
|
78
|
+
export declare function normalizeLocale(locale: string, messages?: LocaleMessages): BuiltInLocale | undefined;
|
|
79
|
+
|
|
80
|
+
export declare function parseI18nJson(jsonObj: unknown, values: Record<string, string>, delimiters: [string, string]): unknown;
|
|
81
|
+
|
|
82
|
+
export declare function resolveLocale(locales: Locale[]): (locale: Locale) => string | undefined;
|
|
83
|
+
|
|
84
|
+
declare type Token = {
|
|
85
|
+
type: 'text' | 'named' | 'list' | 'unknown';
|
|
86
|
+
value: string;
|
|
87
|
+
};
|
|
48
88
|
|
|
49
89
|
export { }
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
const isArray = Array.isArray;
|
|
2
|
+
const isObject = (val) => val !== null && typeof val === 'object';
|
|
3
|
+
const defaultDelimiters = ['{', '}'];
|
|
4
|
+
class BaseFormatter {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._caches = Object.create(null);
|
|
7
|
+
}
|
|
8
|
+
interpolate(message, values, delimiters = defaultDelimiters) {
|
|
9
|
+
if (!values) {
|
|
10
|
+
return [message];
|
|
11
|
+
}
|
|
12
|
+
let tokens = this._caches[message];
|
|
13
|
+
if (!tokens) {
|
|
14
|
+
tokens = parse(message, delimiters);
|
|
15
|
+
this._caches[message] = tokens;
|
|
16
|
+
}
|
|
17
|
+
return compile(tokens, values);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
|
|
21
|
+
const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
|
|
22
|
+
function parse(format, [startDelimiter, endDelimiter]) {
|
|
23
|
+
const tokens = [];
|
|
24
|
+
let position = 0;
|
|
25
|
+
let text = '';
|
|
26
|
+
while (position < format.length) {
|
|
27
|
+
let char = format[position++];
|
|
28
|
+
if (char === startDelimiter) {
|
|
29
|
+
if (text) {
|
|
30
|
+
tokens.push({ type: 'text', value: text });
|
|
31
|
+
}
|
|
32
|
+
text = '';
|
|
33
|
+
let sub = '';
|
|
34
|
+
char = format[position++];
|
|
35
|
+
while (char !== undefined && char !== endDelimiter) {
|
|
36
|
+
sub += char;
|
|
37
|
+
char = format[position++];
|
|
38
|
+
}
|
|
39
|
+
const isClosed = char === endDelimiter;
|
|
40
|
+
const type = RE_TOKEN_LIST_VALUE.test(sub)
|
|
41
|
+
? 'list'
|
|
42
|
+
: isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
|
|
43
|
+
? 'named'
|
|
44
|
+
: 'unknown';
|
|
45
|
+
tokens.push({ value: sub, type });
|
|
46
|
+
}
|
|
47
|
+
// else if (char === '%') {
|
|
48
|
+
// // when found rails i18n syntax, skip text capture
|
|
49
|
+
// if (format[position] !== '{') {
|
|
50
|
+
// text += char
|
|
51
|
+
// }
|
|
52
|
+
// }
|
|
53
|
+
else {
|
|
54
|
+
text += char;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
text && tokens.push({ type: 'text', value: text });
|
|
58
|
+
return tokens;
|
|
59
|
+
}
|
|
60
|
+
function compile(tokens, values) {
|
|
61
|
+
const compiled = [];
|
|
62
|
+
let index = 0;
|
|
63
|
+
const mode = isArray(values)
|
|
64
|
+
? 'list'
|
|
65
|
+
: isObject(values)
|
|
66
|
+
? 'named'
|
|
67
|
+
: 'unknown';
|
|
68
|
+
if (mode === 'unknown') {
|
|
69
|
+
return compiled;
|
|
70
|
+
}
|
|
71
|
+
while (index < tokens.length) {
|
|
72
|
+
const token = tokens[index];
|
|
73
|
+
switch (token.type) {
|
|
74
|
+
case 'text':
|
|
75
|
+
compiled.push(token.value);
|
|
76
|
+
break;
|
|
77
|
+
case 'list':
|
|
78
|
+
compiled.push(values[parseInt(token.value, 10)]);
|
|
79
|
+
break;
|
|
80
|
+
case 'named':
|
|
81
|
+
if (mode === 'named') {
|
|
82
|
+
compiled.push(values[token.value]);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
86
|
+
console.warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
case 'unknown':
|
|
91
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
92
|
+
console.warn(`Detect 'unknown' type of token!`);
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
index++;
|
|
97
|
+
}
|
|
98
|
+
return compiled;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const LOCALE_ZH_HANS = 'zh-Hans';
|
|
102
|
+
const LOCALE_ZH_HANT = 'zh-Hant';
|
|
103
|
+
const LOCALE_EN = 'en';
|
|
104
|
+
const LOCALE_FR = 'fr';
|
|
105
|
+
const LOCALE_ES = 'es';
|
|
106
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
107
|
+
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
|
|
108
|
+
const defaultFormatter = new BaseFormatter();
|
|
109
|
+
function include(str, parts) {
|
|
110
|
+
return !!parts.find((part) => str.indexOf(part) !== -1);
|
|
111
|
+
}
|
|
112
|
+
function startsWith(str, parts) {
|
|
113
|
+
return parts.find((part) => str.indexOf(part) === 0);
|
|
114
|
+
}
|
|
115
|
+
function normalizeLocale(locale, messages) {
|
|
116
|
+
if (!locale) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
locale = locale.trim().replace(/_/g, '-');
|
|
120
|
+
if (messages && messages[locale]) {
|
|
121
|
+
return locale;
|
|
122
|
+
}
|
|
123
|
+
locale = locale.toLowerCase();
|
|
124
|
+
if (locale.indexOf('zh') === 0) {
|
|
125
|
+
if (locale.indexOf('-hans') > -1) {
|
|
126
|
+
return LOCALE_ZH_HANS;
|
|
127
|
+
}
|
|
128
|
+
if (locale.indexOf('-hant') > -1) {
|
|
129
|
+
return LOCALE_ZH_HANT;
|
|
130
|
+
}
|
|
131
|
+
if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {
|
|
132
|
+
return LOCALE_ZH_HANT;
|
|
133
|
+
}
|
|
134
|
+
return LOCALE_ZH_HANS;
|
|
135
|
+
}
|
|
136
|
+
const lang = startsWith(locale, [LOCALE_EN, LOCALE_FR, LOCALE_ES]);
|
|
137
|
+
if (lang) {
|
|
138
|
+
return lang;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
class I18n {
|
|
142
|
+
constructor({ locale, fallbackLocale, messages, watcher, formater, }) {
|
|
143
|
+
this.locale = LOCALE_EN;
|
|
144
|
+
this.fallbackLocale = LOCALE_EN;
|
|
145
|
+
this.message = {};
|
|
146
|
+
this.messages = {};
|
|
147
|
+
this.watchers = [];
|
|
148
|
+
if (fallbackLocale) {
|
|
149
|
+
this.fallbackLocale = fallbackLocale;
|
|
150
|
+
}
|
|
151
|
+
this.formater = formater || defaultFormatter;
|
|
152
|
+
this.messages = messages || {};
|
|
153
|
+
this.setLocale(locale || LOCALE_EN);
|
|
154
|
+
if (watcher) {
|
|
155
|
+
this.watchLocale(watcher);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
setLocale(locale) {
|
|
159
|
+
const oldLocale = this.locale;
|
|
160
|
+
this.locale = normalizeLocale(locale, this.messages) || this.fallbackLocale;
|
|
161
|
+
if (!this.messages[this.locale]) {
|
|
162
|
+
// 可能初始化时不存在
|
|
163
|
+
this.messages[this.locale] = {};
|
|
164
|
+
}
|
|
165
|
+
this.message = this.messages[this.locale];
|
|
166
|
+
// 仅发生变化时,通知
|
|
167
|
+
if (oldLocale !== this.locale) {
|
|
168
|
+
this.watchers.forEach((watcher) => {
|
|
169
|
+
watcher(this.locale, oldLocale);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
getLocale() {
|
|
174
|
+
return this.locale;
|
|
175
|
+
}
|
|
176
|
+
watchLocale(fn) {
|
|
177
|
+
const index = this.watchers.push(fn) - 1;
|
|
178
|
+
return () => {
|
|
179
|
+
this.watchers.splice(index, 1);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
add(locale, message, override = true) {
|
|
183
|
+
const curMessages = this.messages[locale];
|
|
184
|
+
if (curMessages) {
|
|
185
|
+
if (override) {
|
|
186
|
+
Object.assign(curMessages, message);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
Object.keys(message).forEach((key) => {
|
|
190
|
+
if (!hasOwn(curMessages, key)) {
|
|
191
|
+
curMessages[key] = message[key];
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
this.messages[locale] = message;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
f(message, values, delimiters) {
|
|
201
|
+
return this.formater.interpolate(message, values, delimiters).join('');
|
|
202
|
+
}
|
|
203
|
+
t(key, locale, values) {
|
|
204
|
+
let message = this.message;
|
|
205
|
+
if (typeof locale === 'string') {
|
|
206
|
+
locale = normalizeLocale(locale, this.messages);
|
|
207
|
+
locale && (message = this.messages[locale]);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
values = locale;
|
|
211
|
+
}
|
|
212
|
+
if (!hasOwn(message, key)) {
|
|
213
|
+
console.warn(`Cannot translate the value of keypath ${key}. Use the value of keypath as default.`);
|
|
214
|
+
return key;
|
|
215
|
+
}
|
|
216
|
+
return this.formater.interpolate(message[key], values).join('');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function watchAppLocale(appVm, i18n) {
|
|
221
|
+
// 需要保证 watch 的触发在组件渲染之前
|
|
222
|
+
if (appVm.$watchLocale) {
|
|
223
|
+
// vue2
|
|
224
|
+
appVm.$watchLocale((newLocale) => {
|
|
225
|
+
i18n.setLocale(newLocale);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
appVm.$watch(() => appVm.$locale, (newLocale) => {
|
|
230
|
+
i18n.setLocale(newLocale);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function getDefaultLocale() {
|
|
235
|
+
if (typeof uni !== 'undefined' && uni.getLocale) {
|
|
236
|
+
return uni.getLocale();
|
|
237
|
+
}
|
|
238
|
+
// 小程序平台,uni 和 uni-i18n 互相引用,导致访问不到 uni,故在 global 上挂了 getLocale
|
|
239
|
+
if (typeof global !== 'undefined' && global.getLocale) {
|
|
240
|
+
return global.getLocale();
|
|
241
|
+
}
|
|
242
|
+
return LOCALE_EN;
|
|
243
|
+
}
|
|
244
|
+
function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
|
|
245
|
+
// 兼容旧版本入参
|
|
246
|
+
if (typeof locale !== 'string') {
|
|
247
|
+
[locale, messages] = [
|
|
248
|
+
messages,
|
|
249
|
+
locale,
|
|
250
|
+
];
|
|
251
|
+
}
|
|
252
|
+
if (typeof locale !== 'string') {
|
|
253
|
+
// 因为小程序平台,uni-i18n 和 uni 互相引用,导致此时访问 uni 时,为 undefined
|
|
254
|
+
locale = getDefaultLocale();
|
|
255
|
+
}
|
|
256
|
+
if (typeof fallbackLocale !== 'string') {
|
|
257
|
+
fallbackLocale =
|
|
258
|
+
(typeof __uniConfig !== 'undefined' && __uniConfig.fallbackLocale) ||
|
|
259
|
+
LOCALE_EN;
|
|
260
|
+
}
|
|
261
|
+
const i18n = new I18n({
|
|
262
|
+
locale,
|
|
263
|
+
fallbackLocale,
|
|
264
|
+
messages,
|
|
265
|
+
watcher,
|
|
266
|
+
});
|
|
267
|
+
let t = (key, values) => {
|
|
268
|
+
if (typeof getApp !== 'function') {
|
|
269
|
+
// app view
|
|
270
|
+
/* eslint-disable no-func-assign */
|
|
271
|
+
t = function (key, values) {
|
|
272
|
+
return i18n.t(key, values);
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
let isWatchedAppLocale = false;
|
|
277
|
+
t = function (key, values) {
|
|
278
|
+
const appVm = getApp().$vm;
|
|
279
|
+
// 可能$vm还不存在,比如在支付宝小程序中,组件定义较早,在props的default里使用了t()函数(如uni-goods-nav),此时app还未初始化
|
|
280
|
+
// options: {
|
|
281
|
+
// type: Array,
|
|
282
|
+
// default () {
|
|
283
|
+
// return [{
|
|
284
|
+
// icon: 'shop',
|
|
285
|
+
// text: t("uni-goods-nav.options.shop"),
|
|
286
|
+
// }, {
|
|
287
|
+
// icon: 'cart',
|
|
288
|
+
// text: t("uni-goods-nav.options.cart")
|
|
289
|
+
// }]
|
|
290
|
+
// }
|
|
291
|
+
// },
|
|
292
|
+
if (appVm) {
|
|
293
|
+
// 触发响应式
|
|
294
|
+
appVm.$locale;
|
|
295
|
+
if (!isWatchedAppLocale) {
|
|
296
|
+
isWatchedAppLocale = true;
|
|
297
|
+
watchAppLocale(appVm, i18n);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return i18n.t(key, values);
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return t(key, values);
|
|
304
|
+
};
|
|
305
|
+
return {
|
|
306
|
+
i18n,
|
|
307
|
+
f(message, values, delimiters) {
|
|
308
|
+
return i18n.f(message, values, delimiters);
|
|
309
|
+
},
|
|
310
|
+
t(key, values) {
|
|
311
|
+
return t(key, values);
|
|
312
|
+
},
|
|
313
|
+
add(locale, message, override = true) {
|
|
314
|
+
return i18n.add(locale, message, override);
|
|
315
|
+
},
|
|
316
|
+
watch(fn) {
|
|
317
|
+
return i18n.watchLocale(fn);
|
|
318
|
+
},
|
|
319
|
+
getLocale() {
|
|
320
|
+
return i18n.getLocale();
|
|
321
|
+
},
|
|
322
|
+
setLocale(newLocale) {
|
|
323
|
+
return i18n.setLocale(newLocale);
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const isString = (val) => typeof val === 'string';
|
|
329
|
+
let formater;
|
|
330
|
+
function hasI18nJson(jsonObj, delimiters) {
|
|
331
|
+
if (!formater) {
|
|
332
|
+
formater = new BaseFormatter();
|
|
333
|
+
}
|
|
334
|
+
return walkJsonObj(jsonObj, (jsonObj, key) => {
|
|
335
|
+
const value = jsonObj[key];
|
|
336
|
+
if (isString(value)) {
|
|
337
|
+
if (isI18nStr(value, delimiters)) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
return hasI18nJson(value, delimiters);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function parseI18nJson(jsonObj, values, delimiters) {
|
|
347
|
+
if (!formater) {
|
|
348
|
+
formater = new BaseFormatter();
|
|
349
|
+
}
|
|
350
|
+
walkJsonObj(jsonObj, (jsonObj, key) => {
|
|
351
|
+
const value = jsonObj[key];
|
|
352
|
+
if (isString(value)) {
|
|
353
|
+
if (isI18nStr(value, delimiters)) {
|
|
354
|
+
jsonObj[key] = compileStr(value, values, delimiters);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
parseI18nJson(value, values, delimiters);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
return jsonObj;
|
|
362
|
+
}
|
|
363
|
+
function compileI18nJsonStr(jsonStr, { locale, locales, delimiters, }) {
|
|
364
|
+
if (!isI18nStr(jsonStr, delimiters)) {
|
|
365
|
+
return jsonStr;
|
|
366
|
+
}
|
|
367
|
+
if (!formater) {
|
|
368
|
+
formater = new BaseFormatter();
|
|
369
|
+
}
|
|
370
|
+
const localeValues = [];
|
|
371
|
+
Object.keys(locales).forEach((name) => {
|
|
372
|
+
if (name !== locale) {
|
|
373
|
+
localeValues.push({
|
|
374
|
+
locale: name,
|
|
375
|
+
values: locales[name],
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
localeValues.unshift({ locale, values: locales[locale] });
|
|
380
|
+
try {
|
|
381
|
+
return JSON.stringify(compileJsonObj(JSON.parse(jsonStr), localeValues, delimiters), null, 2);
|
|
382
|
+
}
|
|
383
|
+
catch (e) { }
|
|
384
|
+
return jsonStr;
|
|
385
|
+
}
|
|
386
|
+
function isI18nStr(value, delimiters) {
|
|
387
|
+
return value.indexOf(delimiters[0]) > -1;
|
|
388
|
+
}
|
|
389
|
+
function compileStr(value, values, delimiters) {
|
|
390
|
+
return formater.interpolate(value, values, delimiters).join('');
|
|
391
|
+
}
|
|
392
|
+
function compileValue(jsonObj, key, localeValues, delimiters) {
|
|
393
|
+
const value = jsonObj[key];
|
|
394
|
+
if (isString(value)) {
|
|
395
|
+
// 存在国际化
|
|
396
|
+
if (isI18nStr(value, delimiters)) {
|
|
397
|
+
jsonObj[key] = compileStr(value, localeValues[0].values, delimiters);
|
|
398
|
+
if (localeValues.length > 1) {
|
|
399
|
+
// 格式化国际化语言
|
|
400
|
+
const valueLocales = (jsonObj[key + 'Locales'] = {});
|
|
401
|
+
localeValues.forEach((localValue) => {
|
|
402
|
+
valueLocales[localValue.locale] = compileStr(value, localValue.values, delimiters);
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
compileJsonObj(value, localeValues, delimiters);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function compileJsonObj(jsonObj, localeValues, delimiters) {
|
|
412
|
+
walkJsonObj(jsonObj, (jsonObj, key) => {
|
|
413
|
+
compileValue(jsonObj, key, localeValues, delimiters);
|
|
414
|
+
});
|
|
415
|
+
return jsonObj;
|
|
416
|
+
}
|
|
417
|
+
function walkJsonObj(jsonObj, walk) {
|
|
418
|
+
if (isArray(jsonObj)) {
|
|
419
|
+
for (let i = 0; i < jsonObj.length; i++) {
|
|
420
|
+
if (walk(jsonObj, i)) {
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
else if (isObject(jsonObj)) {
|
|
426
|
+
for (const key in jsonObj) {
|
|
427
|
+
if (walk(jsonObj, key)) {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function resolveLocale(locales) {
|
|
436
|
+
return (locale) => {
|
|
437
|
+
if (!locale) {
|
|
438
|
+
return locale;
|
|
439
|
+
}
|
|
440
|
+
locale = normalizeLocale(locale) || locale;
|
|
441
|
+
return resolveLocaleChain(locale).find((locale) => locales.indexOf(locale) > -1);
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function resolveLocaleChain(locale) {
|
|
445
|
+
const chain = [];
|
|
446
|
+
const tokens = locale.split('-');
|
|
447
|
+
while (tokens.length) {
|
|
448
|
+
chain.push(tokens.join('-'));
|
|
449
|
+
tokens.pop();
|
|
450
|
+
}
|
|
451
|
+
return chain;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export { BaseFormatter as Formatter, I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, compileI18nJsonStr, hasI18nJson, initVueI18n, isI18nStr, isString, normalizeLocale, parseI18nJson, resolveLocale };
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcloudio/uni-i18n",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1-32920211122002",
|
|
4
4
|
"description": "@dcloudio/uni-i18n",
|
|
5
|
-
"main": "dist/uni-i18n.cjs.js",
|
|
6
|
-
"module": "dist/uni-i18n.
|
|
7
|
-
"types": "dist/uni-i18n.d.ts",
|
|
5
|
+
"main": "./dist/uni-i18n.cjs.js",
|
|
6
|
+
"module": "./dist/uni-i18n.es.js",
|
|
7
|
+
"types": "./dist/uni-i18n.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
@@ -18,5 +18,5 @@
|
|
|
18
18
|
"bugs": {
|
|
19
19
|
"url": "https://github.com/dcloudio/uni-app/issues"
|
|
20
20
|
},
|
|
21
|
-
"gitHead": "
|
|
21
|
+
"gitHead": "dc33ced4b2fff3063385d9eda8dd1f3539133a67"
|
|
22
22
|
}
|
package/dist/uni-i18n.esm.js
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
const isObject = (val) => val !== null && typeof val === 'object';
|
|
2
|
-
class BaseFormatter {
|
|
3
|
-
constructor() {
|
|
4
|
-
this._caches = Object.create(null);
|
|
5
|
-
}
|
|
6
|
-
interpolate(message, values) {
|
|
7
|
-
if (!values) {
|
|
8
|
-
return [message];
|
|
9
|
-
}
|
|
10
|
-
let tokens = this._caches[message];
|
|
11
|
-
if (!tokens) {
|
|
12
|
-
tokens = parse(message);
|
|
13
|
-
this._caches[message] = tokens;
|
|
14
|
-
}
|
|
15
|
-
return compile(tokens, values);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
const RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
|
|
19
|
-
const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
|
|
20
|
-
function parse(format) {
|
|
21
|
-
const tokens = [];
|
|
22
|
-
let position = 0;
|
|
23
|
-
let text = '';
|
|
24
|
-
while (position < format.length) {
|
|
25
|
-
let char = format[position++];
|
|
26
|
-
if (char === '{') {
|
|
27
|
-
if (text) {
|
|
28
|
-
tokens.push({ type: 'text', value: text });
|
|
29
|
-
}
|
|
30
|
-
text = '';
|
|
31
|
-
let sub = '';
|
|
32
|
-
char = format[position++];
|
|
33
|
-
while (char !== undefined && char !== '}') {
|
|
34
|
-
sub += char;
|
|
35
|
-
char = format[position++];
|
|
36
|
-
}
|
|
37
|
-
const isClosed = char === '}';
|
|
38
|
-
const type = RE_TOKEN_LIST_VALUE.test(sub)
|
|
39
|
-
? 'list'
|
|
40
|
-
: isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
|
|
41
|
-
? 'named'
|
|
42
|
-
: 'unknown';
|
|
43
|
-
tokens.push({ value: sub, type });
|
|
44
|
-
}
|
|
45
|
-
else if (char === '%') {
|
|
46
|
-
// when found rails i18n syntax, skip text capture
|
|
47
|
-
if (format[position] !== '{') {
|
|
48
|
-
text += char;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
text += char;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
text && tokens.push({ type: 'text', value: text });
|
|
56
|
-
return tokens;
|
|
57
|
-
}
|
|
58
|
-
function compile(tokens, values) {
|
|
59
|
-
const compiled = [];
|
|
60
|
-
let index = 0;
|
|
61
|
-
const mode = Array.isArray(values)
|
|
62
|
-
? 'list'
|
|
63
|
-
: isObject(values)
|
|
64
|
-
? 'named'
|
|
65
|
-
: 'unknown';
|
|
66
|
-
if (mode === 'unknown') {
|
|
67
|
-
return compiled;
|
|
68
|
-
}
|
|
69
|
-
while (index < tokens.length) {
|
|
70
|
-
const token = tokens[index];
|
|
71
|
-
switch (token.type) {
|
|
72
|
-
case 'text':
|
|
73
|
-
compiled.push(token.value);
|
|
74
|
-
break;
|
|
75
|
-
case 'list':
|
|
76
|
-
compiled.push(values[parseInt(token.value, 10)]);
|
|
77
|
-
break;
|
|
78
|
-
case 'named':
|
|
79
|
-
if (mode === 'named') {
|
|
80
|
-
compiled.push(values[token.value]);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
84
|
-
console.warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
break;
|
|
88
|
-
case 'unknown':
|
|
89
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
90
|
-
console.warn(`Detect 'unknown' type of token!`);
|
|
91
|
-
}
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
index++;
|
|
95
|
-
}
|
|
96
|
-
return compiled;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
100
|
-
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
|
|
101
|
-
const defaultFormatter = new BaseFormatter();
|
|
102
|
-
function include(str, parts) {
|
|
103
|
-
return !!parts.find((part) => str.indexOf(part) !== -1);
|
|
104
|
-
}
|
|
105
|
-
function startsWith(str, parts) {
|
|
106
|
-
return parts.find((part) => str.indexOf(part) === 0);
|
|
107
|
-
}
|
|
108
|
-
function normalizeLocale(locale, messages) {
|
|
109
|
-
if (!locale) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
locale = locale.trim().replace(/_/g, '-');
|
|
113
|
-
if (messages[locale]) {
|
|
114
|
-
return locale;
|
|
115
|
-
}
|
|
116
|
-
locale = locale.toLowerCase();
|
|
117
|
-
if (locale.indexOf('zh') === 0) {
|
|
118
|
-
if (locale.indexOf('-hans') !== -1) {
|
|
119
|
-
return 'zh-Hans';
|
|
120
|
-
}
|
|
121
|
-
if (locale.indexOf('-hant') !== -1) {
|
|
122
|
-
return 'zh-Hant';
|
|
123
|
-
}
|
|
124
|
-
if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {
|
|
125
|
-
return 'zh-Hant';
|
|
126
|
-
}
|
|
127
|
-
return 'zh-Hans';
|
|
128
|
-
}
|
|
129
|
-
const lang = startsWith(locale, ['en', 'fr', 'es']);
|
|
130
|
-
if (lang) {
|
|
131
|
-
return lang;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
class I18n {
|
|
135
|
-
constructor({ locale, fallbackLocale, messages, watcher, formater, }) {
|
|
136
|
-
this.locale = 'en';
|
|
137
|
-
this.fallbackLocale = 'en';
|
|
138
|
-
this.message = {};
|
|
139
|
-
this.messages = {};
|
|
140
|
-
this.watchers = [];
|
|
141
|
-
if (fallbackLocale) {
|
|
142
|
-
this.fallbackLocale = fallbackLocale;
|
|
143
|
-
}
|
|
144
|
-
this.formater = formater || defaultFormatter;
|
|
145
|
-
this.messages = messages;
|
|
146
|
-
this.setLocale(locale);
|
|
147
|
-
if (watcher) {
|
|
148
|
-
this.watchLocale(watcher);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
setLocale(locale) {
|
|
152
|
-
const oldLocale = this.locale;
|
|
153
|
-
this.locale = normalizeLocale(locale, this.messages) || this.fallbackLocale;
|
|
154
|
-
this.message = this.messages[this.locale];
|
|
155
|
-
this.watchers.forEach((watcher) => {
|
|
156
|
-
watcher(this.locale, oldLocale);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
getLocale() {
|
|
160
|
-
return this.locale;
|
|
161
|
-
}
|
|
162
|
-
watchLocale(fn) {
|
|
163
|
-
const index = this.watchers.push(fn) - 1;
|
|
164
|
-
return () => {
|
|
165
|
-
this.watchers.splice(index, 1);
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
t(key, locale, values) {
|
|
169
|
-
let message = this.message;
|
|
170
|
-
if (typeof locale === 'string') {
|
|
171
|
-
locale = normalizeLocale(locale, this.messages);
|
|
172
|
-
locale && (message = this.messages[locale]);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
values = locale;
|
|
176
|
-
}
|
|
177
|
-
if (!hasOwn(message, key)) {
|
|
178
|
-
console.warn(`Cannot translate the value of keypath ${key}. Use the value of keypath as default.`);
|
|
179
|
-
return key;
|
|
180
|
-
}
|
|
181
|
-
return this.formater.interpolate(message[key], values).join('');
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function initLocaleWatcher(appVm, i18n) {
|
|
186
|
-
appVm.$i18n &&
|
|
187
|
-
appVm.$i18n.vm.$watch('locale', (newLocale) => {
|
|
188
|
-
i18n.setLocale(newLocale);
|
|
189
|
-
}, {
|
|
190
|
-
immediate: true,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
function getDefaultLocale() {
|
|
194
|
-
if (typeof navigator !== 'undefined') {
|
|
195
|
-
return navigator.userLanguage || navigator.language;
|
|
196
|
-
}
|
|
197
|
-
if (typeof plus !== 'undefined') {
|
|
198
|
-
// TODO 待调整为最新的获取语言代码
|
|
199
|
-
return plus.os.language;
|
|
200
|
-
}
|
|
201
|
-
return uni.getSystemInfoSync().language;
|
|
202
|
-
}
|
|
203
|
-
function initVueI18n(messages, fallbackLocale = 'en', locale) {
|
|
204
|
-
const i18n = new I18n({
|
|
205
|
-
locale: locale || fallbackLocale,
|
|
206
|
-
fallbackLocale,
|
|
207
|
-
messages,
|
|
208
|
-
});
|
|
209
|
-
let t = (key, values) => {
|
|
210
|
-
if (typeof getApp !== 'function') {
|
|
211
|
-
// app-plus view
|
|
212
|
-
/* eslint-disable no-func-assign */
|
|
213
|
-
t = function (key, values) {
|
|
214
|
-
return i18n.t(key, values);
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
const appVm = getApp().$vm;
|
|
219
|
-
if (!appVm.$t || !appVm.$i18n) {
|
|
220
|
-
if (!locale) {
|
|
221
|
-
i18n.setLocale(getDefaultLocale());
|
|
222
|
-
}
|
|
223
|
-
/* eslint-disable no-func-assign */
|
|
224
|
-
t = function (key, values) {
|
|
225
|
-
return i18n.t(key, values);
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
initLocaleWatcher(appVm, i18n);
|
|
230
|
-
/* eslint-disable no-func-assign */
|
|
231
|
-
t = function (key, values) {
|
|
232
|
-
const $i18n = appVm.$i18n;
|
|
233
|
-
const silentTranslationWarn = $i18n.silentTranslationWarn;
|
|
234
|
-
$i18n.silentTranslationWarn = true;
|
|
235
|
-
const msg = appVm.$t(key, values);
|
|
236
|
-
$i18n.silentTranslationWarn = silentTranslationWarn;
|
|
237
|
-
if (msg !== key) {
|
|
238
|
-
return msg;
|
|
239
|
-
}
|
|
240
|
-
return i18n.t(key, $i18n.locale, values);
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return t(key, values);
|
|
245
|
-
};
|
|
246
|
-
return {
|
|
247
|
-
t(key, values) {
|
|
248
|
-
return t(key, values);
|
|
249
|
-
},
|
|
250
|
-
getLocale() {
|
|
251
|
-
return i18n.getLocale();
|
|
252
|
-
},
|
|
253
|
-
setLocale(newLocale) {
|
|
254
|
-
return i18n.setLocale(newLocale);
|
|
255
|
-
},
|
|
256
|
-
mixin: {
|
|
257
|
-
beforeCreate() {
|
|
258
|
-
const unwatch = i18n.watchLocale(() => {
|
|
259
|
-
this.$forceUpdate();
|
|
260
|
-
});
|
|
261
|
-
this.$once('hook:beforeDestroy', function () {
|
|
262
|
-
unwatch();
|
|
263
|
-
});
|
|
264
|
-
},
|
|
265
|
-
methods: {
|
|
266
|
-
$$t(key, values) {
|
|
267
|
-
return t(key, values);
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export { I18n, initVueI18n };
|