@eggjs/i18n 4.0.0-beta.19 → 4.0.0-beta.21
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/app/extend/application.d.ts +7 -11
- package/dist/app/extend/application.js +69 -41
- package/dist/app/extend/context.d.ts +71 -75
- package/dist/app/extend/context.js +173 -149
- package/dist/app.d.ts +5 -10
- package/dist/app.js +95 -94
- package/dist/config/config.default.d.ts +49 -51
- package/dist/config/config.default.js +14 -15
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -3
- package/dist/locales.d.ts +3 -7
- package/dist/locales.js +62 -49
- package/dist/types.d.ts +26 -28
- package/dist/types.js +2 -1
- package/dist/utils.d.ts +2 -5
- package/dist/utils.js +6 -8
- package/package.json +6 -6
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { Application } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
gettext(locale: string, key: string, value?: any, ...args: any[]): string;
|
|
9
|
-
__(locale: string, key: string, value?: any, ...args: any[]): string;
|
|
1
|
+
import { Application } from 'egg';
|
|
2
|
+
export declare const I18N_RESOURCES: unique symbol;
|
|
3
|
+
export default class I18nApplication extends Application {
|
|
4
|
+
[I18N_RESOURCES]: Record<string, Record<string, string>>;
|
|
5
|
+
isSupportLocale(locale: string): boolean;
|
|
6
|
+
gettext(locale: string, key: string, value?: any, ...args: any[]): string;
|
|
7
|
+
__(locale: string, key: string, value?: any, ...args: any[]): string;
|
|
10
8
|
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { I18N_RESOURCES, I18nApplication as default };
|
|
@@ -1,48 +1,76 @@
|
|
|
1
|
+
import { debuglog, format } from 'node:util';
|
|
2
|
+
import { Application } from 'egg';
|
|
1
3
|
import { isObject } from "../../utils.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
4
|
+
const debug = debuglog('egg/i18n/app/extend/application');
|
|
5
|
+
export const I18N_RESOURCES = Symbol('Application i18n resources');
|
|
6
|
+
export default class I18nApplication extends Application {
|
|
7
|
+
isSupportLocale(locale) {
|
|
8
|
+
return !!this[I18N_RESOURCES][locale];
|
|
9
|
+
}
|
|
10
|
+
gettext(locale, key, value, ...args) {
|
|
11
|
+
if (!locale || !key) {
|
|
12
|
+
// __()
|
|
13
|
+
// __('en')
|
|
14
|
+
return '';
|
|
15
|
+
}
|
|
16
|
+
const resource = this[I18N_RESOURCES][locale] || {};
|
|
17
|
+
let text = resource[key];
|
|
18
|
+
if (text === undefined) {
|
|
19
|
+
text = key;
|
|
20
|
+
}
|
|
21
|
+
debug('%s: %j => %j', locale, key, text);
|
|
22
|
+
if (!text) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
if (value === undefined) {
|
|
26
|
+
// __(locale, key)
|
|
27
|
+
return text;
|
|
28
|
+
}
|
|
29
|
+
if (args.length === 0) {
|
|
30
|
+
if (isObject(value)) {
|
|
31
|
+
// __(locale, key, object)
|
|
32
|
+
// __('zh', '{a} {b} {b} {a}', {a: 'foo', b: 'bar'})
|
|
33
|
+
// =>
|
|
34
|
+
// foo bar bar foo
|
|
35
|
+
return formatWithObject(text, value);
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
// __(locale, key, array)
|
|
39
|
+
// __('zh', '{0} {1} {1} {0}', ['foo', 'bar'])
|
|
40
|
+
// =>
|
|
41
|
+
// foo bar bar foo
|
|
42
|
+
return formatWithArray(text, value);
|
|
43
|
+
}
|
|
44
|
+
// __(locale, key, value)
|
|
45
|
+
return format(text, value);
|
|
46
|
+
}
|
|
47
|
+
// __(locale, key, value1, ...)
|
|
48
|
+
return format(text, value, ...args);
|
|
49
|
+
}
|
|
50
|
+
__(locale, key, value, ...args) {
|
|
51
|
+
return this.gettext(locale, key, value, ...args);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
30
54
|
const ARRAY_INDEX_RE = /\{(\d+)\}/g;
|
|
31
55
|
function formatWithArray(text, values) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
56
|
+
return text.replace(ARRAY_INDEX_RE, (original, matched) => {
|
|
57
|
+
const index = parseInt(matched);
|
|
58
|
+
if (index < values.length) {
|
|
59
|
+
return values[index];
|
|
60
|
+
}
|
|
61
|
+
// not match index, return original text
|
|
62
|
+
return original;
|
|
63
|
+
});
|
|
37
64
|
}
|
|
38
65
|
const Object_INDEX_RE = /\{(.+?)\}/g;
|
|
39
66
|
function formatWithObject(text, values) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
67
|
+
return text.replace(Object_INDEX_RE, (original, matched) => {
|
|
68
|
+
const value = values[matched];
|
|
69
|
+
if (value) {
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
// not match index, return original text
|
|
73
|
+
return original;
|
|
74
|
+
});
|
|
45
75
|
}
|
|
46
|
-
|
|
47
|
-
//#endregion
|
|
48
|
-
export { I18N_RESOURCES, I18nApplication as default };
|
|
76
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBwL2V4dGVuZC9hcHBsaWNhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUU3QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRWxDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUxQyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsaUNBQWlDLENBQUMsQ0FBQztBQUUxRCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLDRCQUE0QixDQUFDLENBQUM7QUFFbkUsTUFBTSxDQUFDLE9BQU8sT0FBTyxlQUFnQixTQUFRLFdBQVc7SUFHdEQsZUFBZSxDQUFDLE1BQWM7UUFDNUIsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFRCxPQUFPLENBQUMsTUFBYyxFQUFFLEdBQVcsRUFBRSxLQUFXLEVBQUUsR0FBRyxJQUFXO1FBQzlELElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNwQixPQUFPO1lBQ1AsV0FBVztZQUNYLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFcEQsSUFBSSxJQUFJLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pCLElBQUksSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3ZCLElBQUksR0FBRyxHQUFHLENBQUM7UUFDYixDQUFDO1FBRUQsS0FBSyxDQUFDLGNBQWMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNWLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztRQUVELElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3hCLGtCQUFrQjtZQUNsQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDdEIsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDcEIsMEJBQTBCO2dCQUMxQixvREFBb0Q7Z0JBQ3BELEtBQUs7Z0JBQ0wsa0JBQWtCO2dCQUNsQixPQUFPLGdCQUFnQixDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN2QyxDQUFDO1lBRUQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3pCLHlCQUF5QjtnQkFDekIsOENBQThDO2dCQUM5QyxLQUFLO2dCQUNMLGtCQUFrQjtnQkFDbEIsT0FBTyxlQUFlLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3RDLENBQUM7WUFFRCx5QkFBeUI7WUFDekIsT0FBTyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFFRCwrQkFBK0I7UUFDL0IsT0FBTyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRCxFQUFFLENBQUMsTUFBYyxFQUFFLEdBQVcsRUFBRSxLQUFXLEVBQUUsR0FBRyxJQUFXO1FBQ3pELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ25ELENBQUM7Q0FDRjtBQUVELE1BQU0sY0FBYyxHQUFHLFlBQVksQ0FBQztBQUNwQyxTQUFTLGVBQWUsQ0FBQyxJQUFZLEVBQUUsTUFBYTtJQUNsRCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUFFO1FBQ3hELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoQyxJQUFJLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDMUIsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdkIsQ0FBQztRQUNELHdDQUF3QztRQUN4QyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLGVBQWUsR0FBRyxZQUFZLENBQUM7QUFDckMsU0FBUyxnQkFBZ0IsQ0FBQyxJQUFZLEVBQUUsTUFBMkI7SUFDakUsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsRUFBRTtRQUN6RCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDOUIsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUNELHdDQUF3QztRQUN4QyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMifQ==
|
|
@@ -1,76 +1,72 @@
|
|
|
1
|
-
import { Context } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
__getLocaleOrigin(): string;
|
|
73
|
-
__setLocale(locale: string): void;
|
|
1
|
+
import { Context } from 'egg';
|
|
2
|
+
export default class I18nContext extends Context {
|
|
3
|
+
/**
|
|
4
|
+
* get current request locale
|
|
5
|
+
* @member Context#locale
|
|
6
|
+
* @return {String} lower case locale string, e.g.: 'zh-cn', 'en-us'
|
|
7
|
+
*/
|
|
8
|
+
get locale(): string;
|
|
9
|
+
set locale(l: string);
|
|
10
|
+
/**
|
|
11
|
+
* `ctx.__` 的别名。
|
|
12
|
+
* @see {@link Context#__}
|
|
13
|
+
* @function Context#gettext
|
|
14
|
+
*/
|
|
15
|
+
gettext(key: string, value?: any, ...args: any[]): string;
|
|
16
|
+
/**
|
|
17
|
+
* 如果开启了 I18n 多语言功能,那么会出现此 API,通过它可以获取到当前请求对应的本地化数据。
|
|
18
|
+
*
|
|
19
|
+
* 详细使用说明,请查看 {@link I18n}
|
|
20
|
+
* - `ctx.__ = function (key, value[, value2, ...])`: 类似 `util.format` 接口
|
|
21
|
+
* - `ctx.__ = function (key, values)`: 支持数组下标占位符方式,如
|
|
22
|
+
* - `__` 的别名是 `gettext(key, value)`
|
|
23
|
+
*
|
|
24
|
+
* > NOTE: __ 是两个下划线哦!
|
|
25
|
+
* @function Context#__
|
|
26
|
+
* @example
|
|
27
|
+
* ```js
|
|
28
|
+
* ctx.__('{0} {0} {1} {1}'), ['foo', 'bar'])
|
|
29
|
+
* ctx.gettext('{0} {0} {1} {1}'), ['foo', 'bar'])
|
|
30
|
+
* =>
|
|
31
|
+
* foo foo bar bar
|
|
32
|
+
* ```
|
|
33
|
+
* ##### Controller 下的使用示例
|
|
34
|
+
*
|
|
35
|
+
* ```js
|
|
36
|
+
* module.exports = function* () {
|
|
37
|
+
* this.body = {
|
|
38
|
+
* message: this.__('Welcome back, %s!', this.user.name),
|
|
39
|
+
* // 或者使用 gettext,如果觉得 __ 不好看的话
|
|
40
|
+
* // message: this.gettext('Welcome back, %s!', this.user.name),
|
|
41
|
+
* user: this.user,
|
|
42
|
+
* };
|
|
43
|
+
* };
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* ##### View 文件下的使用示例
|
|
47
|
+
*
|
|
48
|
+
* ```html
|
|
49
|
+
* <li>{{ __('Email') }}: {{ user.email }}</li>
|
|
50
|
+
* <li>
|
|
51
|
+
* {{ __('Hello %s, how are you today?', user.name) }}
|
|
52
|
+
* </li>
|
|
53
|
+
* <li>
|
|
54
|
+
* {{ __('{0} {0} {1} {1}'), ['foo', 'bar']) }}
|
|
55
|
+
* </li>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* ##### locale 参数获取途径
|
|
59
|
+
*
|
|
60
|
+
* 优先级从上到下:
|
|
61
|
+
*
|
|
62
|
+
* - query: `/?locale=en-US`
|
|
63
|
+
* - cookie: `locale=zh-TW`
|
|
64
|
+
* - header: `Accept-Language: zh-CN,zh;q=0.5`
|
|
65
|
+
*/
|
|
66
|
+
__(key: string, value?: any, ...args: any[]): string;
|
|
67
|
+
__locale: string;
|
|
68
|
+
__getLocale(): string;
|
|
69
|
+
__localeOrigin: string;
|
|
70
|
+
__getLocaleOrigin(): string;
|
|
71
|
+
__setLocale(locale: string): void;
|
|
74
72
|
}
|
|
75
|
-
//#endregion
|
|
76
|
-
export { I18nContext as default };
|
|
@@ -1,152 +1,176 @@
|
|
|
1
|
+
import { debuglog } from 'node:util';
|
|
2
|
+
import { Context } from 'egg';
|
|
1
3
|
import { formatLocale } from "../../utils.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
4
|
+
const debug = debuglog('egg/i18n/app/extend/context');
|
|
5
|
+
export default class I18nContext extends Context {
|
|
6
|
+
/**
|
|
7
|
+
* get current request locale
|
|
8
|
+
* @member Context#locale
|
|
9
|
+
* @return {String} lower case locale string, e.g.: 'zh-cn', 'en-us'
|
|
10
|
+
*/
|
|
11
|
+
get locale() {
|
|
12
|
+
return this.__getLocale();
|
|
13
|
+
}
|
|
14
|
+
set locale(l) {
|
|
15
|
+
this.__setLocale(l);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `ctx.__` 的别名。
|
|
19
|
+
* @see {@link Context#__}
|
|
20
|
+
* @function Context#gettext
|
|
21
|
+
*/
|
|
22
|
+
gettext(key, value, ...args) {
|
|
23
|
+
return this.app.gettext(this.locale, key, value, ...args);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 如果开启了 I18n 多语言功能,那么会出现此 API,通过它可以获取到当前请求对应的本地化数据。
|
|
27
|
+
*
|
|
28
|
+
* 详细使用说明,请查看 {@link I18n}
|
|
29
|
+
* - `ctx.__ = function (key, value[, value2, ...])`: 类似 `util.format` 接口
|
|
30
|
+
* - `ctx.__ = function (key, values)`: 支持数组下标占位符方式,如
|
|
31
|
+
* - `__` 的别名是 `gettext(key, value)`
|
|
32
|
+
*
|
|
33
|
+
* > NOTE: __ 是两个下划线哦!
|
|
34
|
+
* @function Context#__
|
|
35
|
+
* @example
|
|
36
|
+
* ```js
|
|
37
|
+
* ctx.__('{0} {0} {1} {1}'), ['foo', 'bar'])
|
|
38
|
+
* ctx.gettext('{0} {0} {1} {1}'), ['foo', 'bar'])
|
|
39
|
+
* =>
|
|
40
|
+
* foo foo bar bar
|
|
41
|
+
* ```
|
|
42
|
+
* ##### Controller 下的使用示例
|
|
43
|
+
*
|
|
44
|
+
* ```js
|
|
45
|
+
* module.exports = function* () {
|
|
46
|
+
* this.body = {
|
|
47
|
+
* message: this.__('Welcome back, %s!', this.user.name),
|
|
48
|
+
* // 或者使用 gettext,如果觉得 __ 不好看的话
|
|
49
|
+
* // message: this.gettext('Welcome back, %s!', this.user.name),
|
|
50
|
+
* user: this.user,
|
|
51
|
+
* };
|
|
52
|
+
* };
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* ##### View 文件下的使用示例
|
|
56
|
+
*
|
|
57
|
+
* ```html
|
|
58
|
+
* <li>{{ __('Email') }}: {{ user.email }}</li>
|
|
59
|
+
* <li>
|
|
60
|
+
* {{ __('Hello %s, how are you today?', user.name) }}
|
|
61
|
+
* </li>
|
|
62
|
+
* <li>
|
|
63
|
+
* {{ __('{0} {0} {1} {1}'), ['foo', 'bar']) }}
|
|
64
|
+
* </li>
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* ##### locale 参数获取途径
|
|
68
|
+
*
|
|
69
|
+
* 优先级从上到下:
|
|
70
|
+
*
|
|
71
|
+
* - query: `/?locale=en-US`
|
|
72
|
+
* - cookie: `locale=zh-TW`
|
|
73
|
+
* - header: `Accept-Language: zh-CN,zh;q=0.5`
|
|
74
|
+
*/
|
|
75
|
+
__(key, value, ...args) {
|
|
76
|
+
return this.gettext(key, value, ...args);
|
|
77
|
+
}
|
|
78
|
+
// 1. query: /?locale=en-US
|
|
79
|
+
// 2. cookie: locale=zh-TW
|
|
80
|
+
// 3. header: Accept-Language: zh-CN,zh;q=0.5
|
|
81
|
+
__getLocale() {
|
|
82
|
+
if (this.__locale) {
|
|
83
|
+
return this.__locale;
|
|
84
|
+
}
|
|
85
|
+
const { localeAlias, defaultLocale, cookieField, queryField, writeCookie } = this.app.config.i18n;
|
|
86
|
+
const cookieLocale = this.cookies.get(cookieField, { signed: false });
|
|
87
|
+
// 1. Query
|
|
88
|
+
let locale = this.query[queryField];
|
|
89
|
+
let localeOrigin = 'query';
|
|
90
|
+
// 2. Cookie
|
|
91
|
+
if (!locale && cookieLocale) {
|
|
92
|
+
locale = cookieLocale;
|
|
93
|
+
localeOrigin = 'cookie';
|
|
94
|
+
}
|
|
95
|
+
// 3. Header
|
|
96
|
+
if (!locale) {
|
|
97
|
+
// Accept-Language: zh-CN,zh;q=0.5
|
|
98
|
+
// Accept-Language: zh-CN
|
|
99
|
+
let languages = this.acceptsLanguages();
|
|
100
|
+
if (languages) {
|
|
101
|
+
if (Array.isArray(languages)) {
|
|
102
|
+
if (languages[0] === '*') {
|
|
103
|
+
languages = languages.slice(1);
|
|
104
|
+
}
|
|
105
|
+
if (languages.length > 0) {
|
|
106
|
+
for (const l of languages) {
|
|
107
|
+
const lang = formatLocale(l);
|
|
108
|
+
if (this.app.isSupportLocale(lang) || localeAlias[lang]) {
|
|
109
|
+
locale = lang;
|
|
110
|
+
localeOrigin = 'header';
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
locale = languages;
|
|
118
|
+
localeOrigin = 'header';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// all missing, set it to defaultLocale
|
|
122
|
+
if (!locale) {
|
|
123
|
+
locale = defaultLocale;
|
|
124
|
+
localeOrigin = 'default';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// cookie alias
|
|
128
|
+
if (locale in localeAlias) {
|
|
129
|
+
const originalLocale = locale;
|
|
130
|
+
locale = localeAlias[locale];
|
|
131
|
+
debug('Used alias, received %s but using %s', originalLocale, locale);
|
|
132
|
+
}
|
|
133
|
+
locale = formatLocale(locale);
|
|
134
|
+
// validate locale
|
|
135
|
+
if (!this.app.isSupportLocale(locale)) {
|
|
136
|
+
debug('Locale %s is not supported. Using default (%s)', locale, defaultLocale);
|
|
137
|
+
locale = defaultLocale;
|
|
138
|
+
}
|
|
139
|
+
// if header not send, set the locale cookie
|
|
140
|
+
if (writeCookie && cookieLocale !== locale && !this.headerSent) {
|
|
141
|
+
updateCookie(this, locale);
|
|
142
|
+
}
|
|
143
|
+
debug('Locale: %s from %s', locale, localeOrigin);
|
|
144
|
+
this.__locale = locale;
|
|
145
|
+
this.__localeOrigin = localeOrigin;
|
|
146
|
+
return locale;
|
|
147
|
+
}
|
|
148
|
+
__getLocaleOrigin() {
|
|
149
|
+
if (this.__localeOrigin) {
|
|
150
|
+
return this.__localeOrigin;
|
|
151
|
+
}
|
|
152
|
+
this.__getLocale();
|
|
153
|
+
return this.__localeOrigin;
|
|
154
|
+
}
|
|
155
|
+
__setLocale(locale) {
|
|
156
|
+
this.__locale = locale;
|
|
157
|
+
this.__localeOrigin = 'set';
|
|
158
|
+
if (this.app.config.i18n.writeCookie && !this.headerSent) {
|
|
159
|
+
updateCookie(this, locale);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
138
163
|
function updateCookie(ctx, locale) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
164
|
+
const { cookieMaxAge, cookieField, cookieDomain } = ctx.app.config.i18n;
|
|
165
|
+
const cookieOptions = {
|
|
166
|
+
// make sure browser javascript can read the cookie
|
|
167
|
+
httpOnly: false,
|
|
168
|
+
maxAge: cookieMaxAge,
|
|
169
|
+
signed: false,
|
|
170
|
+
domain: cookieDomain,
|
|
171
|
+
overwrite: true,
|
|
172
|
+
};
|
|
173
|
+
ctx.cookies.set(cookieField, locale, cookieOptions);
|
|
174
|
+
debug('Saved cookie with locale %s, options: %j', locale, cookieOptions);
|
|
149
175
|
}
|
|
150
|
-
|
|
151
|
-
//#endregion
|
|
152
|
-
export { I18nContext as default };
|
|
176
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcHAvZXh0ZW5kL2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVyQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRTlCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU5QyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsNkJBQTZCLENBQUMsQ0FBQztBQUV0RCxNQUFNLENBQUMsT0FBTyxPQUFPLFdBQVksU0FBUSxPQUFPO0lBQzlDOzs7O09BSUc7SUFDSCxJQUFJLE1BQU07UUFDUixPQUFPLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQsSUFBSSxNQUFNLENBQUMsQ0FBUztRQUNsQixJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFDLEdBQVcsRUFBRSxLQUFXLEVBQUUsR0FBRyxJQUFXO1FBQzlDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BaURHO0lBQ0gsRUFBRSxDQUFDLEdBQVcsRUFBRSxLQUFXLEVBQUUsR0FBRyxJQUFXO1FBQ3pDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUdELDJCQUEyQjtJQUMzQiwwQkFBMEI7SUFDMUIsNkNBQTZDO0lBQzdDLFdBQVc7UUFDVCxJQUFJ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
|