@eggjs/i18n 3.0.1 → 4.0.0-beta.17

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.
Files changed (60) hide show
  1. package/README.md +10 -18
  2. package/dist/app/extend/application.d.ts +12 -0
  3. package/dist/app/extend/application.js +48 -0
  4. package/dist/app/extend/context.d.ts +76 -0
  5. package/dist/app/extend/context.js +152 -0
  6. package/dist/{commonjs/app.d.ts → app.d.ts} +10 -8
  7. package/dist/app.js +96 -0
  8. package/{src/types.ts → dist/config/config.default.d.ts} +7 -33
  9. package/dist/config/config.default.js +15 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +4 -0
  12. package/dist/locales.d.ts +7 -0
  13. package/dist/locales.js +53 -0
  14. package/dist/types.d.ts +29 -0
  15. package/dist/types.js +1 -0
  16. package/dist/utils.d.ts +5 -0
  17. package/dist/utils.js +10 -0
  18. package/package.json +54 -73
  19. package/dist/commonjs/app/extend/application.d.ts +0 -8
  20. package/dist/commonjs/app/extend/application.js +0 -80
  21. package/dist/commonjs/app/extend/context.d.ts +0 -72
  22. package/dist/commonjs/app/extend/context.js +0 -177
  23. package/dist/commonjs/app.js +0 -103
  24. package/dist/commonjs/config/config.default.d.ts +0 -5
  25. package/dist/commonjs/config/config.default.js +0 -16
  26. package/dist/commonjs/index.d.ts +0 -1
  27. package/dist/commonjs/index.js +0 -4
  28. package/dist/commonjs/locales.d.ts +0 -3
  29. package/dist/commonjs/locales.js +0 -71
  30. package/dist/commonjs/package.json +0 -3
  31. package/dist/commonjs/types.d.ts +0 -74
  32. package/dist/commonjs/types.js +0 -3
  33. package/dist/commonjs/utils.d.ts +0 -2
  34. package/dist/commonjs/utils.js +0 -12
  35. package/dist/esm/app/extend/application.d.ts +0 -8
  36. package/dist/esm/app/extend/application.js +0 -76
  37. package/dist/esm/app/extend/context.d.ts +0 -72
  38. package/dist/esm/app/extend/context.js +0 -174
  39. package/dist/esm/app.d.ts +0 -56
  40. package/dist/esm/app.js +0 -97
  41. package/dist/esm/config/config.default.d.ts +0 -5
  42. package/dist/esm/config/config.default.js +0 -14
  43. package/dist/esm/index.d.ts +0 -1
  44. package/dist/esm/index.js +0 -2
  45. package/dist/esm/locales.d.ts +0 -3
  46. package/dist/esm/locales.js +0 -65
  47. package/dist/esm/package.json +0 -3
  48. package/dist/esm/types.d.ts +0 -74
  49. package/dist/esm/types.js +0 -2
  50. package/dist/esm/utils.d.ts +0 -2
  51. package/dist/esm/utils.js +0 -8
  52. package/dist/package.json +0 -4
  53. package/src/app/extend/application.ts +0 -91
  54. package/src/app/extend/context.ts +0 -192
  55. package/src/app.ts +0 -107
  56. package/src/config/config.default.ts +0 -15
  57. package/src/index.ts +0 -1
  58. package/src/locales.ts +0 -73
  59. package/src/typings/index.d.ts +0 -4
  60. package/src/utils.ts +0 -8
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # @eggjs/i18n
2
2
 
3
3
  [![NPM version][npm-image]][npm-url]
4
- [![Node.js CI](https://github.com/eggjs/i18n/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/i18n/actions/workflows/nodejs.yml)
5
- [![Test coverage][codecov-image]][codecov-url]
6
4
  [![Known Vulnerabilities][snyk-image]][snyk-url]
7
5
  [![npm download][download-image]][download-url]
8
6
  [![Node.js Version](https://img.shields.io/node/v/@eggjs/i18n.svg?style=flat)](https://nodejs.org/en/download/)
@@ -10,8 +8,6 @@
10
8
 
11
9
  [npm-image]: https://img.shields.io/npm/v/@eggjs/i18n.svg?style=flat-square
12
10
  [npm-url]: https://npmjs.org/package/@eggjs/i18n
13
- [codecov-image]: https://img.shields.io/codecov/c/github/eggjs/i18n.svg?style=flat-square
14
- [codecov-url]: https://codecov.io/github/eggjs/i18n?branch=master
15
11
  [snyk-image]: https://snyk.io/test/npm/@eggjs/i18n/badge.svg?style=flat-square
16
12
  [snyk-url]: https://snyk.io/test/npm/@eggjs/i18n
17
13
  [download-image]: https://img.shields.io/npm/dm/@eggjs/i18n.svg?style=flat-square
@@ -66,16 +62,16 @@ export default {
66
62
  ```ts
67
63
  // config/locale/zh-CN.ts
68
64
  export default {
69
- "Email": "邮箱",
70
- "Welcome back, %s!": "欢迎回来,%s!",
71
- "Hello %s, how are you today?": "你好 %s, 今天过得咋样?",
65
+ Email: '邮箱',
66
+ 'Welcome back, %s!': '欢迎回来,%s!',
67
+ 'Hello %s, how are you today?': '你好 %s, 今天过得咋样?',
72
68
  };
73
69
  ```
74
70
 
75
71
  ```ts
76
72
  // config/locale/en-US.ts
77
73
  export default {
78
- "Email": "Email",
74
+ Email: 'Email',
79
75
  };
80
76
  ```
81
77
 
@@ -94,14 +90,14 @@ export default {
94
90
 
95
91
  I18n 为你提供 `__` (Alias: `gettext`) 函数,让你可以轻松获得 locale 文件夹下面的多语言文本。
96
92
 
97
- > NOTE: __ 是两个下划线哦!
93
+ > NOTE: \_\_ 是两个下划线哦!
98
94
 
99
95
  - `ctx.__ = function (key, value[, value2, ...])`: 类似 util.format 接口
100
96
  - `ctx.__ = function (key, values)`: 支持数组下标占位符方式,如
101
97
 
102
98
  ```ts
103
- ctx.__('{0} {0} {1} {1}'), ['foo', 'bar']);
104
- ctx.gettext('{0} {0} {1} {1}'), ['foo', 'bar']);
99
+ ctx.__('{0} {0} {1} {1}', ['foo', 'bar']);
100
+ ctx.gettext('{0} {0} {1} {1}', ['foo', 'bar']);
105
101
 
106
102
  =>
107
103
  foo foo bar bar
@@ -124,12 +120,8 @@ export default ctx => {
124
120
 
125
121
  ```html
126
122
  <li>{{ __('Email') }}: {{ user.email }}</li>
127
- <li>
128
- {{ __('Hello %s, how are you today?', user.name) }}
129
- </li>
130
- <li>
131
- {{ __('{0} {0} {1} {1}'), ['foo', 'bar']) }}
132
- </li>
123
+ <li>{{ __('Hello %s, how are you today?', user.name) }}</li>
124
+ <li>{{ __('{0} {0} {1} {1}', ['foo', 'bar']) }}</li>
133
125
  ```
134
126
 
135
127
  ### 修改应用的默认语言
@@ -152,6 +144,6 @@ Please open an issue [here](https://github.com/eggjs/egg/issues).
152
144
 
153
145
  ## Contributors
154
146
 
155
- [![Contributors](https://contrib.rocks/image?repo=eggjs/i18n)](https://github.com/eggjs/i18n/graphs/contributors)
147
+ [![Contributors](https://contrib.rocks/image?repo=eggjs/egg)](https://github.com/eggjs/egg/graphs/contributors)
156
148
 
157
149
  Made with [contributors-img](https://contrib.rocks).
@@ -0,0 +1,12 @@
1
+ import { Application } from "egg";
2
+
3
+ //#region src/app/extend/application.d.ts
4
+ declare const I18N_RESOURCES: unique symbol;
5
+ declare class I18nApplication extends Application {
6
+ [I18N_RESOURCES]: Record<string, Record<string, string>>;
7
+ isSupportLocale(locale: string): boolean;
8
+ gettext(locale: string, key: string, value?: any, ...args: any[]): string;
9
+ __(locale: string, key: string, value?: any, ...args: any[]): string;
10
+ }
11
+ //#endregion
12
+ export { I18N_RESOURCES, I18nApplication as default };
@@ -0,0 +1,48 @@
1
+ import { isObject } from "../../utils.js";
2
+ import { debuglog, format } from "node:util";
3
+ import { Application } from "egg";
4
+
5
+ //#region src/app/extend/application.ts
6
+ const debug = debuglog("egg/i18n/app/extend/application");
7
+ const I18N_RESOURCES = Symbol("Application i18n resources");
8
+ var I18nApplication = class extends Application {
9
+ isSupportLocale(locale) {
10
+ return !!this[I18N_RESOURCES][locale];
11
+ }
12
+ gettext(locale, key, value, ...args) {
13
+ if (!locale || !key) return "";
14
+ let text = (this[I18N_RESOURCES][locale] || {})[key];
15
+ if (text === void 0) text = key;
16
+ debug("%s: %j => %j", locale, key, text);
17
+ if (!text) return "";
18
+ if (value === void 0) return text;
19
+ if (args.length === 0) {
20
+ if (isObject(value)) return formatWithObject(text, value);
21
+ if (Array.isArray(value)) return formatWithArray(text, value);
22
+ return format(text, value);
23
+ }
24
+ return format(text, value, ...args);
25
+ }
26
+ __(locale, key, value, ...args) {
27
+ return this.gettext(locale, key, value, ...args);
28
+ }
29
+ };
30
+ const ARRAY_INDEX_RE = /\{(\d+)\}/g;
31
+ function formatWithArray(text, values) {
32
+ return text.replace(ARRAY_INDEX_RE, (original, matched) => {
33
+ const index = parseInt(matched);
34
+ if (index < values.length) return values[index];
35
+ return original;
36
+ });
37
+ }
38
+ const Object_INDEX_RE = /\{(.+?)\}/g;
39
+ function formatWithObject(text, values) {
40
+ return text.replace(Object_INDEX_RE, (original, matched) => {
41
+ const value = values[matched];
42
+ if (value) return value;
43
+ return original;
44
+ });
45
+ }
46
+
47
+ //#endregion
48
+ export { I18N_RESOURCES, I18nApplication as default };
@@ -0,0 +1,76 @@
1
+ import { Context } from "egg";
2
+
3
+ //#region src/app/extend/context.d.ts
4
+ declare class I18nContext extends Context {
5
+ /**
6
+ * get current request locale
7
+ * @member Context#locale
8
+ * @return {String} lower case locale string, e.g.: 'zh-cn', 'en-us'
9
+ */
10
+ get locale(): string;
11
+ set locale(l: string);
12
+ /**
13
+ * `ctx.__` 的别名。
14
+ * @see {@link Context#__}
15
+ * @function Context#gettext
16
+ */
17
+ gettext(key: string, value?: any, ...args: any[]): string;
18
+ /**
19
+ * 如果开启了 I18n 多语言功能,那么会出现此 API,通过它可以获取到当前请求对应的本地化数据。
20
+ *
21
+ * 详细使用说明,请查看 {@link I18n}
22
+ * - `ctx.__ = function (key, value[, value2, ...])`: 类似 `util.format` 接口
23
+ * - `ctx.__ = function (key, values)`: 支持数组下标占位符方式,如
24
+ * - `__` 的别名是 `gettext(key, value)`
25
+ *
26
+ * > NOTE: __ 是两个下划线哦!
27
+ * @function Context#__
28
+ * @example
29
+ * ```js
30
+ * ctx.__('{0} {0} {1} {1}'), ['foo', 'bar'])
31
+ * ctx.gettext('{0} {0} {1} {1}'), ['foo', 'bar'])
32
+ * =>
33
+ * foo foo bar bar
34
+ * ```
35
+ * ##### Controller 下的使用示例
36
+ *
37
+ * ```js
38
+ * module.exports = function* () {
39
+ * this.body = {
40
+ * message: this.__('Welcome back, %s!', this.user.name),
41
+ * // 或者使用 gettext,如果觉得 __ 不好看的话
42
+ * // message: this.gettext('Welcome back, %s!', this.user.name),
43
+ * user: this.user,
44
+ * };
45
+ * };
46
+ * ```
47
+ *
48
+ * ##### View 文件下的使用示例
49
+ *
50
+ * ```html
51
+ * <li>{{ __('Email') }}: {{ user.email }}</li>
52
+ * <li>
53
+ * {{ __('Hello %s, how are you today?', user.name) }}
54
+ * </li>
55
+ * <li>
56
+ * {{ __('{0} {0} {1} {1}'), ['foo', 'bar']) }}
57
+ * </li>
58
+ * ```
59
+ *
60
+ * ##### locale 参数获取途径
61
+ *
62
+ * 优先级从上到下:
63
+ *
64
+ * - query: `/?locale=en-US`
65
+ * - cookie: `locale=zh-TW`
66
+ * - header: `Accept-Language: zh-CN,zh;q=0.5`
67
+ */
68
+ __(key: string, value?: any, ...args: any[]): string;
69
+ __locale: string;
70
+ __getLocale(): string;
71
+ __localeOrigin: string;
72
+ __getLocaleOrigin(): string;
73
+ __setLocale(locale: string): void;
74
+ }
75
+ //#endregion
76
+ export { I18nContext as default };
@@ -0,0 +1,152 @@
1
+ import { formatLocale } from "../../utils.js";
2
+ import { debuglog } from "node:util";
3
+ import { Context } from "egg";
4
+
5
+ //#region src/app/extend/context.ts
6
+ const debug = debuglog("egg/i18n/app/extend/context");
7
+ var I18nContext = class extends Context {
8
+ /**
9
+ * get current request locale
10
+ * @member Context#locale
11
+ * @return {String} lower case locale string, e.g.: 'zh-cn', 'en-us'
12
+ */
13
+ get locale() {
14
+ return this.__getLocale();
15
+ }
16
+ set locale(l) {
17
+ this.__setLocale(l);
18
+ }
19
+ /**
20
+ * `ctx.__` 的别名。
21
+ * @see {@link Context#__}
22
+ * @function Context#gettext
23
+ */
24
+ gettext(key, value, ...args) {
25
+ return this.app.gettext(this.locale, key, value, ...args);
26
+ }
27
+ /**
28
+ * 如果开启了 I18n 多语言功能,那么会出现此 API,通过它可以获取到当前请求对应的本地化数据。
29
+ *
30
+ * 详细使用说明,请查看 {@link I18n}
31
+ * - `ctx.__ = function (key, value[, value2, ...])`: 类似 `util.format` 接口
32
+ * - `ctx.__ = function (key, values)`: 支持数组下标占位符方式,如
33
+ * - `__` 的别名是 `gettext(key, value)`
34
+ *
35
+ * > NOTE: __ 是两个下划线哦!
36
+ * @function Context#__
37
+ * @example
38
+ * ```js
39
+ * ctx.__('{0} {0} {1} {1}'), ['foo', 'bar'])
40
+ * ctx.gettext('{0} {0} {1} {1}'), ['foo', 'bar'])
41
+ * =>
42
+ * foo foo bar bar
43
+ * ```
44
+ * ##### Controller 下的使用示例
45
+ *
46
+ * ```js
47
+ * module.exports = function* () {
48
+ * this.body = {
49
+ * message: this.__('Welcome back, %s!', this.user.name),
50
+ * // 或者使用 gettext,如果觉得 __ 不好看的话
51
+ * // message: this.gettext('Welcome back, %s!', this.user.name),
52
+ * user: this.user,
53
+ * };
54
+ * };
55
+ * ```
56
+ *
57
+ * ##### View 文件下的使用示例
58
+ *
59
+ * ```html
60
+ * <li>{{ __('Email') }}: {{ user.email }}</li>
61
+ * <li>
62
+ * {{ __('Hello %s, how are you today?', user.name) }}
63
+ * </li>
64
+ * <li>
65
+ * {{ __('{0} {0} {1} {1}'), ['foo', 'bar']) }}
66
+ * </li>
67
+ * ```
68
+ *
69
+ * ##### locale 参数获取途径
70
+ *
71
+ * 优先级从上到下:
72
+ *
73
+ * - query: `/?locale=en-US`
74
+ * - cookie: `locale=zh-TW`
75
+ * - header: `Accept-Language: zh-CN,zh;q=0.5`
76
+ */
77
+ __(key, value, ...args) {
78
+ return this.gettext(key, value, ...args);
79
+ }
80
+ __getLocale() {
81
+ if (this.__locale) return this.__locale;
82
+ const { localeAlias, defaultLocale, cookieField, queryField, writeCookie } = this.app.config.i18n;
83
+ const cookieLocale = this.cookies.get(cookieField, { signed: false });
84
+ let locale = this.query[queryField];
85
+ let localeOrigin = "query";
86
+ if (!locale && cookieLocale) {
87
+ locale = cookieLocale;
88
+ localeOrigin = "cookie";
89
+ }
90
+ if (!locale) {
91
+ let languages = this.acceptsLanguages();
92
+ if (languages) if (Array.isArray(languages)) {
93
+ if (languages[0] === "*") languages = languages.slice(1);
94
+ if (languages.length > 0) for (const l of languages) {
95
+ const lang = formatLocale(l);
96
+ if (this.app.isSupportLocale(lang) || localeAlias[lang]) {
97
+ locale = lang;
98
+ localeOrigin = "header";
99
+ break;
100
+ }
101
+ }
102
+ } else {
103
+ locale = languages;
104
+ localeOrigin = "header";
105
+ }
106
+ if (!locale) {
107
+ locale = defaultLocale;
108
+ localeOrigin = "default";
109
+ }
110
+ }
111
+ if (locale in localeAlias) {
112
+ const originalLocale = locale;
113
+ locale = localeAlias[locale];
114
+ debug("Used alias, received %s but using %s", originalLocale, locale);
115
+ }
116
+ locale = formatLocale(locale);
117
+ if (!this.app.isSupportLocale(locale)) {
118
+ debug("Locale %s is not supported. Using default (%s)", locale, defaultLocale);
119
+ locale = defaultLocale;
120
+ }
121
+ if (writeCookie && cookieLocale !== locale && !this.headerSent) updateCookie(this, locale);
122
+ debug("Locale: %s from %s", locale, localeOrigin);
123
+ this.__locale = locale;
124
+ this.__localeOrigin = localeOrigin;
125
+ return locale;
126
+ }
127
+ __getLocaleOrigin() {
128
+ if (this.__localeOrigin) return this.__localeOrigin;
129
+ this.__getLocale();
130
+ return this.__localeOrigin;
131
+ }
132
+ __setLocale(locale) {
133
+ this.__locale = locale;
134
+ this.__localeOrigin = "set";
135
+ if (this.app.config.i18n.writeCookie && !this.headerSent) updateCookie(this, locale);
136
+ }
137
+ };
138
+ function updateCookie(ctx, locale) {
139
+ const { cookieMaxAge, cookieField, cookieDomain } = ctx.app.config.i18n;
140
+ const cookieOptions = {
141
+ httpOnly: false,
142
+ maxAge: cookieMaxAge,
143
+ signed: false,
144
+ domain: cookieDomain,
145
+ overwrite: true
146
+ };
147
+ ctx.cookies.set(cookieField, locale, cookieOptions);
148
+ debug("Saved cookie with locale %s, options: %j", locale, cookieOptions);
149
+ }
150
+
151
+ //#endregion
152
+ export { I18nContext as default };
@@ -1,5 +1,7 @@
1
- import type { ILifecycleBoot } from '@eggjs/core';
2
- import type I18nApplication from './app/extend/application.js';
1
+ import { Application, ILifecycleBoot } from "egg";
2
+
3
+ //#region src/app.d.ts
4
+
3
5
  /**
4
6
  * I18n 国际化
5
7
  *
@@ -47,10 +49,10 @@ import type I18nApplication from './app/extend/application.js';
47
49
  * }
48
50
  * ```
49
51
  */
50
- export default class I18n implements ILifecycleBoot {
51
- private readonly app;
52
- constructor(app: I18nApplication & {
53
- locals: Record<string, any>;
54
- });
55
- didLoad(): Promise<void>;
52
+ declare class I18n implements ILifecycleBoot {
53
+ private readonly app;
54
+ constructor(app: Application);
55
+ didLoad(): Promise<void>;
56
56
  }
57
+ //#endregion
58
+ export { I18n as default };
package/dist/app.js ADDED
@@ -0,0 +1,96 @@
1
+ import { formatLocale } from "./utils.js";
2
+ import { loadLocaleResources } from "./locales.js";
3
+ import path from "node:path";
4
+ import { debuglog } from "node:util";
5
+ import { exists } from "utility";
6
+ import { ms } from "humanize-ms";
7
+
8
+ //#region src/app.ts
9
+ const debug = debuglog("egg/i18n/app");
10
+ /**
11
+ * I18n 国际化
12
+ *
13
+ * 通过设置 Plugin 配置 `i18n: true`,开启多语言支持。
14
+ *
15
+ * #### 语言文件存储路径
16
+ *
17
+ * 统一存放在 `config/locale/*.js` 下( 兼容`config/locales/*.js` ),如包含英文,简体中文,繁体中文的语言文件:
18
+ *
19
+ * ```
20
+ * - config/locale/
21
+ * - en-US.js
22
+ * - zh-CN.js
23
+ * - zh-TW.js
24
+ * ```
25
+ * @class I18n
26
+ * @param {App} app Application object.
27
+ * @example
28
+ *
29
+ * #### I18n 文件内容
30
+ *
31
+ * ```js
32
+ * // config/locale/zh-CN.js
33
+ * module.exports = {
34
+ * "Email": "邮箱",
35
+ * "Welcome back, %s!": "欢迎回来, %s!",
36
+ * "Hello %s, how are you today?": "你好 %s, 今天过得咋样?",
37
+ * };
38
+ * ```
39
+ *
40
+ * ```js
41
+ * // config/locale/en-US.js
42
+ * module.exports = {
43
+ * "Email": "Email",
44
+ * };
45
+ * ```
46
+ * 或者也可以用 JSON 格式的文件:
47
+ *
48
+ * ```js
49
+ * // config/locale/zh-CN.json
50
+ * {
51
+ * "email": "邮箱",
52
+ * "login": "帐号",
53
+ * "createdAt": "注册时间"
54
+ * }
55
+ * ```
56
+ */
57
+ var I18n = class {
58
+ app;
59
+ constructor(app) {
60
+ this.app = app;
61
+ }
62
+ async didLoad() {
63
+ const i18nConfig = this.app.config.i18n;
64
+ i18nConfig.defaultLocale = formatLocale(i18nConfig.defaultLocale);
65
+ i18nConfig.cookieMaxAge = ms(i18nConfig.cookieMaxAge);
66
+ i18nConfig.dirs = Array.isArray(i18nConfig.dirs) ? i18nConfig.dirs : [];
67
+ for (const unit of this.app.loader.getLoadUnits()) {
68
+ let localePath = path.join(unit.path, "config/locale");
69
+ /**
70
+ * 优先选择 `config/locale` 目录下的多语言文件,不存在时再选择 `config/locales` 目录
71
+ * 避免 2 个目录同时存在时可能导致的冲突
72
+ */
73
+ if (!await exists(localePath)) localePath = path.join(unit.path, "config/locales");
74
+ i18nConfig.dirs.push(localePath);
75
+ }
76
+ debug("app.config.i18n.dirs:", i18nConfig.dirs);
77
+ await loadLocaleResources(this.app, i18nConfig);
78
+ const app = this.app;
79
+ function gettextInContext(key, ...args) {
80
+ return app.ctxStorage.getStore().gettext(key, ...args);
81
+ }
82
+ Object.defineProperties(app.locals, {
83
+ __: {
84
+ value: gettextInContext,
85
+ enumerable: true
86
+ },
87
+ gettext: {
88
+ value: gettextInContext,
89
+ enumerable: true
90
+ }
91
+ });
92
+ }
93
+ };
94
+
95
+ //#endregion
96
+ export { I18n as default };
@@ -1,8 +1,5 @@
1
- /**
2
- * I18n options
3
- * @member Config#i18n
4
- */
5
- export interface I18nConfig {
1
+ //#region src/config/config.default.d.ts
2
+ interface I18nConfig {
6
3
  /**
7
4
  * 默认语言是美式英语,毕竟支持多语言,基本都是以英语为母板
8
5
  * 默认值是 `en_US`
@@ -50,31 +47,8 @@ export interface I18nConfig {
50
47
  */
51
48
  writeCookie: boolean;
52
49
  }
53
-
54
- declare module '@eggjs/core' {
55
- // add EggAppConfig overrides types
56
- interface EggAppConfig {
57
- i18n: I18nConfig;
58
- }
59
-
60
- interface Context {
61
- /**
62
- * get and set current request locale
63
- * @member Context#locale
64
- * @return {String} lower case locale string, e.g.: 'zh-cn', 'en-us'
65
- */
66
- locale: string;
67
-
68
- gettext(key: string, value?: any, ...args: any[]): string;
69
- __(key: string, value?: any, ...args: any[]): string;
70
-
71
- __getLocale(): string;
72
- __setLocale(l: string): void;
73
- }
74
-
75
- interface EggCore {
76
- isSupportLocale(locale: string): boolean;
77
- gettext(locale: string, key: string, value?: any, ...args: any[]): string;
78
- __(locale: string, key: string, value?: any, ...args: any[]): string;
79
- }
80
- }
50
+ declare const _default: {
51
+ i18n: I18nConfig;
52
+ };
53
+ //#endregion
54
+ export { I18nConfig, _default as default };
@@ -0,0 +1,15 @@
1
+ //#region src/config/config.default.ts
2
+ var config_default_default = { i18n: {
3
+ defaultLocale: "en_US",
4
+ dirs: [],
5
+ queryField: "locale",
6
+ cookieField: "locale",
7
+ cookieDomain: "",
8
+ cookieMaxAge: "1y",
9
+ localeAlias: {},
10
+ writeCookie: true,
11
+ dir: void 0
12
+ } };
13
+
14
+ //#endregion
15
+ export { config_default_default as default };
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import "./app/extend/application.js";
2
+ import "./app/extend/context.js";
3
+
4
+ export { };
@@ -0,0 +1,7 @@
1
+ import { I18nConfig } from "./config/config.default.js";
2
+ import { Application } from "egg";
3
+
4
+ //#region src/locales.d.ts
5
+ declare function loadLocaleResources(app: Application, options: I18nConfig): Promise<void>;
6
+ //#endregion
7
+ export { loadLocaleResources };
@@ -0,0 +1,53 @@
1
+ import { formatLocale, isObject } from "./utils.js";
2
+ import { I18N_RESOURCES } from "./app/extend/application.js";
3
+ import path from "node:path";
4
+ import { debuglog } from "node:util";
5
+ import { exists, readJSON } from "utility";
6
+ import fs from "node:fs/promises";
7
+ import ini from "ini";
8
+ import yaml from "js-yaml";
9
+ import { importModule } from "@eggjs/utils";
10
+
11
+ //#region src/locales.ts
12
+ const debug = debuglog("egg/i18n/locales");
13
+ async function loadLocaleResources(app, options) {
14
+ const localeDirs = options.dirs;
15
+ const resources = {};
16
+ if (options.dir && !localeDirs.includes(options.dir)) {
17
+ app.deprecate("[@eggjs/i18n] `config.i18n.dir` is deprecated, please use `config.i18n.dirs` instead");
18
+ localeDirs.push(options.dir);
19
+ }
20
+ for (const dir of localeDirs) {
21
+ if (!await exists(dir)) continue;
22
+ const names = await fs.readdir(dir);
23
+ for (const name of names) {
24
+ const filepath = path.join(dir, name);
25
+ const locale = formatLocale(name.split(".")[0]);
26
+ let resource = {};
27
+ if (name.endsWith(".js") || name.endsWith(".ts")) resource = flattening(await importModule(filepath, { importDefaultOnly: true }));
28
+ else if (name.endsWith(".json")) resource = flattening(await readJSON(filepath));
29
+ else if (name.endsWith(".properties")) resource = ini.parse(await fs.readFile(filepath, "utf8"));
30
+ else if (name.endsWith(".yml") || name.endsWith(".yaml")) resource = flattening(yaml.load(await fs.readFile(filepath, "utf8")));
31
+ resources[locale] = resources[locale] || {};
32
+ Object.assign(resources[locale], resource);
33
+ }
34
+ }
35
+ debug("Init locales with %j, got %j resources", options, Object.keys(resources));
36
+ app[I18N_RESOURCES] = resources;
37
+ }
38
+ function flattening(data) {
39
+ const result = {};
40
+ function deepFlat(data$1, prefix) {
41
+ for (const key in data$1) {
42
+ const value = data$1[key];
43
+ const k = prefix ? prefix + "." + key : key;
44
+ if (isObject(value)) deepFlat(value, k);
45
+ else result[k] = String(value);
46
+ }
47
+ }
48
+ deepFlat(data, "");
49
+ return result;
50
+ }
51
+
52
+ //#endregion
53
+ export { loadLocaleResources };
@@ -0,0 +1,29 @@
1
+ import { I18nConfig } from "./config/config.default.js";
2
+
3
+ //#region src/types.d.ts
4
+ declare module 'egg' {
5
+ interface EggAppConfig {
6
+ /**
7
+ * I18n options
8
+ * @member Config#i18n
9
+ */
10
+ i18n: I18nConfig;
11
+ }
12
+ interface Application {
13
+ isSupportLocale(locale: string): boolean;
14
+ gettext(locale: string, key: string, value?: any, ...args: any[]): string;
15
+ __(locale: string, key: string, value?: any, ...args: any[]): string;
16
+ }
17
+ interface Context {
18
+ /**
19
+ * get and set current request locale
20
+ * @member Context#locale
21
+ * @return {String} lower case locale string, e.g.: 'zh-cn', 'en-us'
22
+ */
23
+ locale: string;
24
+ gettext(key: string, value?: any, ...args: any[]): string;
25
+ __(key: string, value?: any, ...args: any[]): string;
26
+ __getLocale(): string;
27
+ __setLocale(l: string): void;
28
+ }
29
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,5 @@
1
+ //#region src/utils.d.ts
2
+ declare function isObject(obj: any): boolean;
3
+ declare function formatLocale(locale: string): string;
4
+ //#endregion
5
+ export { formatLocale, isObject };
package/dist/utils.js ADDED
@@ -0,0 +1,10 @@
1
+ //#region src/utils.ts
2
+ function isObject(obj) {
3
+ return Object.prototype.toString.call(obj) === "[object Object]";
4
+ }
5
+ function formatLocale(locale) {
6
+ return locale.replaceAll("_", "-").toLowerCase();
7
+ }
8
+
9
+ //#endregion
10
+ export { formatLocale, isObject };