mm_lang 3.0.0 → 3.0.1
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/README.md +218 -209
- package/index.js +8 -10
- package/lib/lang.js +233 -265
- package/lib/langs_admin.js +2 -2
- package/lib/tools/index.js +16 -0
- package/lib/tools/lang/index.js +59 -0
- package/package.json +6 -5
- package/tool/lang/index.js +7 -0
- package/tool/lang/tool.json +84 -0
package/README.md
CHANGED
|
@@ -1,209 +1,218 @@
|
|
|
1
|
-
# mm_lang
|
|
2
|
-
|
|
3
|
-
超级美眉多语言模块。融合了原 `mm_lang`(i18n 行为)与 `mm_langs`(语言存储)两个模块:`Lang` 负责翻译行为,`Langs` 负责键值存储与 JSON 文件持久化,两者组合实现"动作与数据分离"。
|
|
4
|
-
|
|
5
|
-
> **迁移提示**:`mm_langs` 已合并至本模块,其 `Langs` 类与 `langsAdmin` 从 `mm_lang` 直接导出,API 与报错文案保持不变。原 `require('mm_langs')` 改为 `require('mm_lang')` 即可。
|
|
6
|
-
|
|
7
|
-
## 项目信息
|
|
8
|
-
|
|
9
|
-
- **当前版本**: 2.0.0
|
|
10
|
-
- **更新日期**: 2026-10-30
|
|
11
|
-
- **Gitee地址**: https://gitee.com/qiuwenwu91/mm_lang
|
|
12
|
-
- **依赖**: `
|
|
13
|
-
|
|
14
|
-
## 模块结构
|
|
15
|
-
|
|
16
|
-
| 文件 | 职责 |
|
|
17
|
-
|---|---|
|
|
18
|
-
| `lib/lang.js` | 行为侧:扁平词条表(`语言.层级键`→文本)上的取词、回退链、复数、格式化,只接受扁平入参,**不做文件 IO** |
|
|
19
|
-
| `lib/langs.js` | 数据侧:string→string 键值、JSON 文件 save/load、值类型校验,**不感知语言词条语义** |
|
|
20
|
-
| `lib/langs_admin.js` | 数据侧管理器:Langs 实例按作用域(文件路径)复用,供 Lang 与 langsAdmin 共用 |
|
|
21
|
-
|
|
22
|
-
## 特点
|
|
23
|
-
|
|
24
|
-
- **行为侧**:零文件 IO,`zh_cn`/`en` 内置复数规则,`a.b.c` 层级键,回退链(当前语言 → 基础语言 → 默认语言),占位符替换,日期/数字本地化格式化
|
|
25
|
-
- **数据侧**:键和值都只能是字符串,支持覆盖、删除、判断存在、取副本、清空、JSON 文件持久化
|
|
26
|
-
- **组合使用**:`Lang` 配置 `file` 即获得持久化能力;也可注入自定义 `store` 实例替换存储后端
|
|
27
|
-
|
|
28
|
-
## 安装
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install mm_lang
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## 快速开始
|
|
35
|
-
|
|
36
|
-
```javascript
|
|
37
|
-
const { Lang, Langs, langAdmin } = require('mm_lang');
|
|
38
|
-
|
|
39
|
-
// 纯内存翻译
|
|
40
|
-
const lang = new Lang({
|
|
41
|
-
zh_cn: { common: { hello: '你好,{0}!' }, apple: ['一个苹果', '{count}个苹果'] },
|
|
42
|
-
en: { common: { hello: 'Hello, {0}!' }, apple: ['one apple', '{count} apples'] },
|
|
43
|
-
default: 'zh_cn'
|
|
44
|
-
});
|
|
45
|
-
console.log(lang.get('common.hello', '美眉')); // 你好,美眉!
|
|
46
|
-
lang.setLang('en');
|
|
47
|
-
console.log(lang.t('common.hello', 'MM')); // Hello, MM!
|
|
48
|
-
console.log(lang.tc('apple', 3)); // 3 apples
|
|
49
|
-
|
|
50
|
-
// 带持久化:配置 file 后自动创建 Langs 存储实例
|
|
51
|
-
const persisted = langAdmin('shop', { file: './data/lang.json', default: 'zh_cn' });
|
|
52
|
-
persisted.load(); // 启动时从文件恢复词条
|
|
53
|
-
persisted.set('nav.home', '首页');
|
|
54
|
-
persisted.save(); // 内存词条表即扁平形态,直接落盘(相同 file 复用同一存储实例)
|
|
55
|
-
|
|
56
|
-
// 只用存储(原 mm_langs 用法)
|
|
57
|
-
const langs = new Langs({ file: './data/map.json' });
|
|
58
|
-
langs.set('en', 'english').save();
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## API 说明
|
|
62
|
-
|
|
63
|
-
### 行为侧 `Lang`
|
|
64
|
-
|
|
65
|
-
#### 构造 `new Lang(config)`
|
|
66
|
-
|
|
67
|
-
| 配置项 | 类型 | 默认值 | 说明 |
|
|
68
|
-
| --- | --- | --- | --- |
|
|
69
|
-
| `zh_cn` | `Object` | `{}` | 简体中文词条字典 |
|
|
70
|
-
| `en` | `Object` | `{}` | 英文词条字典 |
|
|
71
|
-
| `default` | `String` | `'zh_cn'` | 默认语言代码,同时作为初始当前语言 |
|
|
72
|
-
| `fallback` | `Boolean` | `true` | 是否启用回退机制 |
|
|
73
|
-
| `locale` | `Object` | `{ zh: 'zh_cn', en: 'en' }` | 完整语言代码到基础语言代码的映射 |
|
|
74
|
-
| `file` | `String` | `''` | 持久化文件路径,配置后自动创建 Langs 存储实例 |
|
|
75
|
-
| `store` | `Langs` | `undefined` | 注入的存储实例(鸭子类型),优先于 `file` |
|
|
76
|
-
| `silent` | `Boolean` | `false` | 是否静默缺失词条/存储异常日志(上层自带日志体系时开启,如 mm_tpl) |
|
|
77
|
-
|
|
78
|
-
实例属性:`config`(词条字典)、`rules`(复数规则)、`now`(当前语言)、`locale`(区域映射)、`file`(持久化路径)、`store`(存储实例或 `null`)。
|
|
79
|
-
|
|
80
|
-
#### 取值与翻译
|
|
81
|
-
|
|
82
|
-
| 方法 | 签名 | 返回值 | 说明 |
|
|
83
|
-
| --- | --- | --- | --- |
|
|
84
|
-
| get | `get(key, ...param)` | `String` | 取翻译文本,支持 `a.b` 层级键;`param` 依次替换 `{0}`、`{1}` 等 |
|
|
85
|
-
| t | `t(key, ...param)` | `String` | `get` 的别名 |
|
|
86
|
-
| tc | `tc(key, count, ...param)` | `String` | 复数形式取词:数组词条按当前语言规则取索引,先替换 `{count}`,再替换 `{1}`、`{2}` 等 |
|
|
87
|
-
|
|
88
|
-
#### 语言管理
|
|
89
|
-
|
|
90
|
-
| 方法 | 签名 | 返回值 | 说明 |
|
|
91
|
-
| --- | --- | --- | --- |
|
|
92
|
-
| setLang | `setLang(lang)` | `String` | 切换语言;找不到时先尝试基础语言映射,仍失败记日志并保持当前语言 |
|
|
93
|
-
| getLangs | `getLangs()` | `Array<String>` | 支持的语言列表(取词条键首段去重,无词条的语言不会出现) |
|
|
94
|
-
| isSupported | `isSupported(lang)` | `Boolean` | 语言是否支持(含基础语言映射,控制键恒为 false) |
|
|
95
|
-
| del | `del(lang)` | `Boolean` | 删除指定语言的全部词条 |
|
|
96
|
-
| hasLang | `hasLang(lang)` | `Boolean` | 某语言是否存在词条 |
|
|
97
|
-
| getDict | `getDict(lang)` | `Object|null` | 导出某语言词条为嵌套字典(形态与语言包文件一致),无词条返回 `null` |
|
|
98
|
-
| set | `set(key, val)` | `any` | 向当前语言写入词条,支持 `a.b` 层级键 |
|
|
99
|
-
| registerPlural | `registerPlural(lang, rule)` | `Boolean` | 注册复数规则,`rule(count)` 返回形式索引 |
|
|
100
|
-
|
|
101
|
-
#### 持久化
|
|
102
|
-
|
|
103
|
-
| 方法 | 签名 | 返回值 | 说明 |
|
|
104
|
-
| --- | --- | --- | --- |
|
|
105
|
-
| save | `save(file?)` | `Boolean` | 词条扁平化后经存储实例落盘;无存储实例返回 `false`(不抛异常) |
|
|
106
|
-
| load | `load(file?)` | `Boolean` | 从存储实例读取扁平键值直接合并进 `config`(结构一致无需转换),文件中的词条优先;失败返回 `false` 且不改动内存词条 |
|
|
107
|
-
|
|
108
|
-
落盘格式为 `语言代码.层级键 → 文本` 的 string→string 键值,例如:
|
|
109
|
-
|
|
110
|
-
```json
|
|
111
|
-
{
|
|
112
|
-
"zh_cn.nav.home": "首页",
|
|
113
|
-
"zh_cn.apple": "\u0001[\"一个苹果\",\"{count}个苹果\"]"
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
> 复数等数组词条以 `\u0001` 前缀 + JSON 文本编码,仍满足存储的 string→string 约束,加载时自动还原为数组。`default`、`fallback`、`locale` 等控制键不参与持久化。
|
|
118
|
-
|
|
119
|
-
#### 格式化
|
|
120
|
-
|
|
121
|
-
| 方法 | 签名 | 返回值 | 说明 |
|
|
122
|
-
| --- | --- | --- | --- |
|
|
123
|
-
| formatDate | `formatDate(dt, format)` | `String` | 默认格式 `YYYY-MM-DD hh:mm:ss`,支持 `YYYY/yyyy`、`MM`、`DD/dd`、`HH/hh`、`mm`、`ss` |
|
|
124
|
-
| formatNumber | `formatNumber(num, options)` | `String` | `options` 支持 `decimals`(默认 2)、`decimal_separator`、`thousands_separator` |
|
|
125
|
-
|
|
126
|
-
### 数据侧 `Langs`
|
|
127
|
-
|
|
128
|
-
| 方法 | 说明 | 参数 | 返回值 |
|
|
129
|
-
|---|---|---|---|
|
|
130
|
-
| set | 设置键值(值必须为字符串) | key, value | Langs |
|
|
131
|
-
| get | 获取值 | key | string\|undefined |
|
|
132
|
-
| del | 删除键 | key | boolean |
|
|
133
|
-
| has | 判断键是否存在 | key | boolean |
|
|
134
|
-
| list | 获取键值表副本 | - | object |
|
|
135
|
-
| clear | 清空所有键 | - | Langs |
|
|
136
|
-
| save | 保存到持久化文件 | - | boolean |
|
|
137
|
-
| load | 从持久化文件加载(逐项校验值类型) | - | boolean |
|
|
138
|
-
|
|
139
|
-
### 管理器
|
|
140
|
-
|
|
141
|
-
| 方法 | 说明 |
|
|
142
|
-
|---|---|
|
|
143
|
-
| langAdmin(scope, config) | 按作用域获取 `Lang` 实例(相同作用域返回同一实例),缺省 `os` |
|
|
144
|
-
| langsAdmin(scope, config) | 按作用域获取 `Langs` 实例,缺省 `os` |
|
|
145
|
-
| admin / langs_admin | 对应的 `Admin` 实例 |
|
|
146
|
-
|
|
147
|
-
## 使用示例
|
|
148
|
-
|
|
149
|
-
### 场景一:回退机制
|
|
150
|
-
|
|
151
|
-
```javascript
|
|
152
|
-
const { Lang } = require('mm_lang');
|
|
153
|
-
|
|
154
|
-
const lang = new Lang({
|
|
155
|
-
zh_cn: { nav: { home: '首页' } },
|
|
156
|
-
en: { nav: { home: 'Home', about: 'About' } },
|
|
157
|
-
default: 'en'
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
lang.setLang('zh_cn');
|
|
161
|
-
console.log(lang.get('nav.about')); // 中文缺失,回退到默认语言 en → "About"
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### 场景二:自定义复数规则
|
|
165
|
-
|
|
166
|
-
```javascript
|
|
167
|
-
const { Lang } = require('mm_lang');
|
|
168
|
-
|
|
169
|
-
const lang = new Lang({ ru: { apple: ['яблоко', 'яблока', 'яблок'] }, default: 'ru' });
|
|
170
|
-
lang.registerPlural('ru', function (count) {
|
|
171
|
-
const n10 = count % 10, n100 = count % 100;
|
|
172
|
-
if (n10 === 1 && n100 !== 11) return 0;
|
|
173
|
-
if (n10 >= 2 && n10 <= 4 && (n100 < 12 || n100 > 14)) return 1;
|
|
174
|
-
return 2;
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
console.log(lang.tc('apple', 1)); // яблоко
|
|
178
|
-
console.log(lang.tc('apple', 3)); // яблока
|
|
179
|
-
console.log(lang.tc('apple', 11)); // яблок
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### 场景三:注入自定义存储
|
|
183
|
-
|
|
184
|
-
```javascript
|
|
185
|
-
const { Lang, Langs } = require('mm_lang');
|
|
186
|
-
|
|
187
|
-
// 任何具备 set/get/list/save/load 的对象都可作为存储
|
|
188
|
-
const store = new Langs({ file: './data/custom.json' });
|
|
189
|
-
const lang = new Lang({ store, zh_cn: { hello: '你好' } });
|
|
190
|
-
lang.save();
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## 目录结构
|
|
194
|
-
|
|
195
|
-
```
|
|
196
|
-
mm_lang/
|
|
197
|
-
├── index.js 入口:导出 Lang / Langs / admin / langs_admin / langAdmin / langsAdmin
|
|
198
|
-
├── lib/
|
|
199
|
-
│ ├── lang.js 行为侧
|
|
200
|
-
│ └── langs.js 数据侧
|
|
201
|
-
├── example/
|
|
202
|
-
│ └── index.js
|
|
203
|
-
├── test.js
|
|
204
|
-
└── package.json
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
## 许可证
|
|
208
|
-
|
|
209
|
-
ISC
|
|
1
|
+
# mm_lang
|
|
2
|
+
|
|
3
|
+
超级美眉多语言模块。融合了原 `mm_lang`(i18n 行为)与 `mm_langs`(语言存储)两个模块:`Lang` 负责翻译行为,`Langs` 负责键值存储与 JSON 文件持久化,两者组合实现"动作与数据分离"。
|
|
4
|
+
|
|
5
|
+
> **迁移提示**:`mm_langs` 已合并至本模块,其 `Langs` 类与 `langsAdmin` 从 `mm_lang` 直接导出,API 与报错文案保持不变。原 `require('mm_langs')` 改为 `require('mm_lang')` 即可。
|
|
6
|
+
|
|
7
|
+
## 项目信息
|
|
8
|
+
|
|
9
|
+
- **当前版本**: 2.0.0
|
|
10
|
+
- **更新日期**: 2026-10-30
|
|
11
|
+
- **Gitee地址**: https://gitee.com/qiuwenwu91/mm_lang
|
|
12
|
+
- **依赖**: `mm_admin`(管理器)、`mm_kv_store`(键值存储基类)
|
|
13
|
+
|
|
14
|
+
## 模块结构
|
|
15
|
+
|
|
16
|
+
| 文件 | 职责 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `lib/lang.js` | 行为侧:扁平词条表(`语言.层级键`→文本)上的取词、回退链、复数、格式化,只接受扁平入参,**不做文件 IO** |
|
|
19
|
+
| `lib/langs.js` | 数据侧:string→string 键值、JSON 文件 save/load、值类型校验,**不感知语言词条语义** |
|
|
20
|
+
| `lib/langs_admin.js` | 数据侧管理器:Langs 实例按作用域(文件路径)复用,供 Lang 与 langsAdmin 共用 |
|
|
21
|
+
|
|
22
|
+
## 特点
|
|
23
|
+
|
|
24
|
+
- **行为侧**:零文件 IO,`zh_cn`/`en` 内置复数规则,`a.b.c` 层级键,回退链(当前语言 → 基础语言 → 默认语言),占位符替换,日期/数字本地化格式化
|
|
25
|
+
- **数据侧**:键和值都只能是字符串,支持覆盖、删除、判断存在、取副本、清空、JSON 文件持久化
|
|
26
|
+
- **组合使用**:`Lang` 配置 `file` 即获得持久化能力;也可注入自定义 `store` 实例替换存储后端
|
|
27
|
+
|
|
28
|
+
## 安装
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install mm_lang
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 快速开始
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
const { Lang, Langs, langAdmin } = require('mm_lang');
|
|
38
|
+
|
|
39
|
+
// 纯内存翻译
|
|
40
|
+
const lang = new Lang({
|
|
41
|
+
zh_cn: { common: { hello: '你好,{0}!' }, apple: ['一个苹果', '{count}个苹果'] },
|
|
42
|
+
en: { common: { hello: 'Hello, {0}!' }, apple: ['one apple', '{count} apples'] },
|
|
43
|
+
default: 'zh_cn'
|
|
44
|
+
});
|
|
45
|
+
console.log(lang.get('common.hello', '美眉')); // 你好,美眉!
|
|
46
|
+
lang.setLang('en');
|
|
47
|
+
console.log(lang.t('common.hello', 'MM')); // Hello, MM!
|
|
48
|
+
console.log(lang.tc('apple', 3)); // 3 apples
|
|
49
|
+
|
|
50
|
+
// 带持久化:配置 file 后自动创建 Langs 存储实例
|
|
51
|
+
const persisted = langAdmin('shop', { file: './data/lang.json', default: 'zh_cn' });
|
|
52
|
+
persisted.load(); // 启动时从文件恢复词条
|
|
53
|
+
persisted.set('nav.home', '首页');
|
|
54
|
+
persisted.save(); // 内存词条表即扁平形态,直接落盘(相同 file 复用同一存储实例)
|
|
55
|
+
|
|
56
|
+
// 只用存储(原 mm_langs 用法)
|
|
57
|
+
const langs = new Langs({ file: './data/map.json' });
|
|
58
|
+
langs.set('en', 'english').save();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API 说明
|
|
62
|
+
|
|
63
|
+
### 行为侧 `Lang`
|
|
64
|
+
|
|
65
|
+
#### 构造 `new Lang(config)`
|
|
66
|
+
|
|
67
|
+
| 配置项 | 类型 | 默认值 | 说明 |
|
|
68
|
+
| --- | --- | --- | --- |
|
|
69
|
+
| `zh_cn` | `Object` | `{}` | 简体中文词条字典 |
|
|
70
|
+
| `en` | `Object` | `{}` | 英文词条字典 |
|
|
71
|
+
| `default` | `String` | `'zh_cn'` | 默认语言代码,同时作为初始当前语言 |
|
|
72
|
+
| `fallback` | `Boolean` | `true` | 是否启用回退机制 |
|
|
73
|
+
| `locale` | `Object` | `{ zh: 'zh_cn', en: 'en' }` | 完整语言代码到基础语言代码的映射 |
|
|
74
|
+
| `file` | `String` | `''` | 持久化文件路径,配置后自动创建 Langs 存储实例 |
|
|
75
|
+
| `store` | `Langs` | `undefined` | 注入的存储实例(鸭子类型),优先于 `file` |
|
|
76
|
+
| `silent` | `Boolean` | `false` | 是否静默缺失词条/存储异常日志(上层自带日志体系时开启,如 mm_tpl) |
|
|
77
|
+
|
|
78
|
+
实例属性:`config`(词条字典)、`rules`(复数规则)、`now`(当前语言)、`locale`(区域映射)、`file`(持久化路径)、`store`(存储实例或 `null`)。
|
|
79
|
+
|
|
80
|
+
#### 取值与翻译
|
|
81
|
+
|
|
82
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
83
|
+
| --- | --- | --- | --- |
|
|
84
|
+
| get | `get(key, ...param)` | `String` | 取翻译文本,支持 `a.b` 层级键;`param` 依次替换 `{0}`、`{1}` 等 |
|
|
85
|
+
| t | `t(key, ...param)` | `String` | `get` 的别名 |
|
|
86
|
+
| tc | `tc(key, count, ...param)` | `String` | 复数形式取词:数组词条按当前语言规则取索引,先替换 `{count}`,再替换 `{1}`、`{2}` 等 |
|
|
87
|
+
|
|
88
|
+
#### 语言管理
|
|
89
|
+
|
|
90
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| setLang | `setLang(lang)` | `String` | 切换语言;找不到时先尝试基础语言映射,仍失败记日志并保持当前语言 |
|
|
93
|
+
| getLangs | `getLangs()` | `Array<String>` | 支持的语言列表(取词条键首段去重,无词条的语言不会出现) |
|
|
94
|
+
| isSupported | `isSupported(lang)` | `Boolean` | 语言是否支持(含基础语言映射,控制键恒为 false) |
|
|
95
|
+
| del | `del(lang)` | `Boolean` | 删除指定语言的全部词条 |
|
|
96
|
+
| hasLang | `hasLang(lang)` | `Boolean` | 某语言是否存在词条 |
|
|
97
|
+
| getDict | `getDict(lang)` | `Object|null` | 导出某语言词条为嵌套字典(形态与语言包文件一致),无词条返回 `null` |
|
|
98
|
+
| set | `set(key, val)` | `any` | 向当前语言写入词条,支持 `a.b` 层级键 |
|
|
99
|
+
| registerPlural | `registerPlural(lang, rule)` | `Boolean` | 注册复数规则,`rule(count)` 返回形式索引 |
|
|
100
|
+
|
|
101
|
+
#### 持久化
|
|
102
|
+
|
|
103
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
104
|
+
| --- | --- | --- | --- |
|
|
105
|
+
| save | `save(file?)` | `Boolean` | 词条扁平化后经存储实例落盘;无存储实例返回 `false`(不抛异常) |
|
|
106
|
+
| load | `load(file?)` | `Boolean` | 从存储实例读取扁平键值直接合并进 `config`(结构一致无需转换),文件中的词条优先;失败返回 `false` 且不改动内存词条 |
|
|
107
|
+
|
|
108
|
+
落盘格式为 `语言代码.层级键 → 文本` 的 string→string 键值,例如:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"zh_cn.nav.home": "首页",
|
|
113
|
+
"zh_cn.apple": "\u0001[\"一个苹果\",\"{count}个苹果\"]"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> 复数等数组词条以 `\u0001` 前缀 + JSON 文本编码,仍满足存储的 string→string 约束,加载时自动还原为数组。`default`、`fallback`、`locale` 等控制键不参与持久化。
|
|
118
|
+
|
|
119
|
+
#### 格式化
|
|
120
|
+
|
|
121
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
122
|
+
| --- | --- | --- | --- |
|
|
123
|
+
| formatDate | `formatDate(dt, format)` | `String` | 默认格式 `YYYY-MM-DD hh:mm:ss`,支持 `YYYY/yyyy`、`MM`、`DD/dd`、`HH/hh`、`mm`、`ss` |
|
|
124
|
+
| formatNumber | `formatNumber(num, options)` | `String` | `options` 支持 `decimals`(默认 2)、`decimal_separator`、`thousands_separator` |
|
|
125
|
+
|
|
126
|
+
### 数据侧 `Langs`
|
|
127
|
+
|
|
128
|
+
| 方法 | 说明 | 参数 | 返回值 |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| set | 设置键值(值必须为字符串) | key, value | Langs |
|
|
131
|
+
| get | 获取值 | key | string\|undefined |
|
|
132
|
+
| del | 删除键 | key | boolean |
|
|
133
|
+
| has | 判断键是否存在 | key | boolean |
|
|
134
|
+
| list | 获取键值表副本 | - | object |
|
|
135
|
+
| clear | 清空所有键 | - | Langs |
|
|
136
|
+
| save | 保存到持久化文件 | - | boolean |
|
|
137
|
+
| load | 从持久化文件加载(逐项校验值类型) | - | boolean |
|
|
138
|
+
|
|
139
|
+
### 管理器
|
|
140
|
+
|
|
141
|
+
| 方法 | 说明 |
|
|
142
|
+
|---|---|
|
|
143
|
+
| langAdmin(scope, config) | 按作用域获取 `Lang` 实例(相同作用域返回同一实例),缺省 `os` |
|
|
144
|
+
| langsAdmin(scope, config) | 按作用域获取 `Langs` 实例,缺省 `os` |
|
|
145
|
+
| admin / langs_admin | 对应的 `Admin` 实例 |
|
|
146
|
+
|
|
147
|
+
## 使用示例
|
|
148
|
+
|
|
149
|
+
### 场景一:回退机制
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
const { Lang } = require('mm_lang');
|
|
153
|
+
|
|
154
|
+
const lang = new Lang({
|
|
155
|
+
zh_cn: { nav: { home: '首页' } },
|
|
156
|
+
en: { nav: { home: 'Home', about: 'About' } },
|
|
157
|
+
default: 'en'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
lang.setLang('zh_cn');
|
|
161
|
+
console.log(lang.get('nav.about')); // 中文缺失,回退到默认语言 en → "About"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 场景二:自定义复数规则
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
const { Lang } = require('mm_lang');
|
|
168
|
+
|
|
169
|
+
const lang = new Lang({ ru: { apple: ['яблоко', 'яблока', 'яблок'] }, default: 'ru' });
|
|
170
|
+
lang.registerPlural('ru', function (count) {
|
|
171
|
+
const n10 = count % 10, n100 = count % 100;
|
|
172
|
+
if (n10 === 1 && n100 !== 11) return 0;
|
|
173
|
+
if (n10 >= 2 && n10 <= 4 && (n100 < 12 || n100 > 14)) return 1;
|
|
174
|
+
return 2;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
console.log(lang.tc('apple', 1)); // яблоко
|
|
178
|
+
console.log(lang.tc('apple', 3)); // яблока
|
|
179
|
+
console.log(lang.tc('apple', 11)); // яблок
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 场景三:注入自定义存储
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
const { Lang, Langs } = require('mm_lang');
|
|
186
|
+
|
|
187
|
+
// 任何具备 set/get/list/save/load 的对象都可作为存储
|
|
188
|
+
const store = new Langs({ file: './data/custom.json' });
|
|
189
|
+
const lang = new Lang({ store, zh_cn: { hello: '你好' } });
|
|
190
|
+
lang.save();
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 目录结构
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
mm_lang/
|
|
197
|
+
├── index.js 入口:导出 Lang / Langs / admin / langs_admin / langAdmin / langsAdmin
|
|
198
|
+
├── lib/
|
|
199
|
+
│ ├── lang.js 行为侧
|
|
200
|
+
│ └── langs.js 数据侧
|
|
201
|
+
├── example/
|
|
202
|
+
│ └── index.js
|
|
203
|
+
├── test.js
|
|
204
|
+
└── package.json
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## 许可证
|
|
208
|
+
|
|
209
|
+
ISC
|
|
210
|
+
|
|
211
|
+
## 工具契约(LLM 可调用)
|
|
212
|
+
|
|
213
|
+
本模块 `tool/` 下登记以下工具契约,实现位于 `lib/tools/<name>/`,`tool/<name>/index.js` 仅为薄适配层。
|
|
214
|
+
其它模块可直接 `require('<pkg>').tools.<name>` 复用实现,无需经过工具注册面。
|
|
215
|
+
|
|
216
|
+
| 工具名 | 标题 | 说明 |
|
|
217
|
+
| --- | --- | --- |
|
|
218
|
+
| `lang` | 多语言词条 | 按语言取词、写词条、语言清单 |
|
package/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const Lang = require('./lib/lang');
|
|
2
2
|
const Langs = require('./lib/langs');
|
|
3
3
|
const langs_admin = require('./lib/langs_admin');
|
|
4
|
-
const
|
|
4
|
+
const { reg } = require('mm_admin');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* 语言实例管理器(行为侧)
|
|
8
8
|
* @type {Admin}
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
const admin = reg('lang');
|
|
11
11
|
admin.setClass(Lang);
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -17,10 +17,7 @@ admin.setClass(Lang);
|
|
|
17
17
|
* @returns {Lang} 语言实例
|
|
18
18
|
*/
|
|
19
19
|
function langAdmin(scope, config) {
|
|
20
|
-
|
|
21
|
-
scope = 'os';
|
|
22
|
-
}
|
|
23
|
-
return admin.get(scope, config);
|
|
20
|
+
return admin.get(scope || 'os', config);
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
/**
|
|
@@ -32,10 +29,7 @@ function langAdmin(scope, config) {
|
|
|
32
29
|
* @returns {Langs} 语言存储实例
|
|
33
30
|
*/
|
|
34
31
|
function langsAdmin(scope, config) {
|
|
35
|
-
|
|
36
|
-
scope = 'os';
|
|
37
|
-
}
|
|
38
|
-
return langs_admin.get(scope, config);
|
|
32
|
+
return langs_admin.get(scope || 'os', config);
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
module.exports = {
|
|
@@ -46,3 +40,7 @@ module.exports = {
|
|
|
46
40
|
langAdmin,
|
|
47
41
|
langsAdmin
|
|
48
42
|
};
|
|
43
|
+
|
|
44
|
+
/* mm-tool-logic-export 工具能力层:其它模块可 require("mm_lang").tools.<name> 直接引用 */
|
|
45
|
+
Object.defineProperty(module.exports, 'tools', { enumerable: true, configurable: true,
|
|
46
|
+
get: function () { return require('./lib/tools'); } });
|