schema-dsl 2.0.0 → 2.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/CHANGELOG.md +130 -113
- package/LICENSE +21 -21
- package/README.md +628 -628
- package/dist/{DslBuilder-DkLaOo9Q.d.ts → DslBuilder-BIgQOAXp.d.ts} +2 -0
- package/dist/{DslBuilder-DQDN0ZxZ.d.cts → DslBuilder-CjHTucNQ.d.cts} +2 -0
- package/dist/{Validator-hFWKGxir.d.ts → Validator-CllRdrY0.d.ts} +1 -1
- package/dist/{Validator-C7GsVQOH.d.cts → Validator-D6okG9tr.d.cts} +1 -1
- package/dist/index.cjs +75 -29
- package/dist/index.d.cts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +75 -29
- package/dist/plugins/custom-format.cjs +33 -17
- package/dist/plugins/custom-format.d.cts +1 -1
- package/dist/plugins/custom-format.d.ts +1 -1
- package/dist/plugins/custom-format.js +33 -17
- package/dist/plugins/custom-type-example.cjs +33 -17
- package/dist/plugins/custom-type-example.d.cts +1 -1
- package/dist/plugins/custom-type-example.d.ts +1 -1
- package/dist/plugins/custom-type-example.js +33 -17
- package/dist/plugins/custom-validator.cjs +0 -2
- package/dist/plugins/custom-validator.d.cts +1 -1
- package/dist/plugins/custom-validator.d.ts +1 -1
- package/dist/plugins/custom-validator.js +0 -2
- package/docs/FEATURE-INDEX.md +553 -553
- package/docs/add-custom-locale.md +496 -496
- package/docs/add-keyword.md +24 -24
- package/docs/api-reference.md +1047 -1047
- package/docs/api.md +13 -13
- package/docs/best-practices-project-structure.md +417 -417
- package/docs/best-practices.md +712 -712
- package/docs/cache-manager.md +344 -344
- package/docs/compile.md +45 -45
- package/docs/conditional-api.md +1307 -1307
- package/docs/custom-extensions-guide.md +339 -339
- package/docs/design-philosophy.md +606 -606
- package/docs/doc-index.md +324 -324
- package/docs/dsl-syntax.md +714 -714
- package/docs/dynamic-locale.md +608 -608
- package/docs/enum.md +482 -482
- package/docs/error-handling.md +1975 -1975
- package/docs/export-guide.md +501 -501
- package/docs/export-limitations.md +567 -567
- package/docs/faq.md +596 -596
- package/docs/frontend-i18n-guide.md +307 -307
- package/docs/i18n-user-guide.md +487 -487
- package/docs/i18n.md +476 -476
- package/docs/index.md +48 -48
- package/docs/json-schema-basics.md +40 -40
- package/docs/label-vs-description.md +271 -271
- package/docs/markdown-exporter.md +406 -406
- package/docs/mongodb-exporter.md +302 -302
- package/docs/multi-language.md +26 -26
- package/docs/multi-type-support.md +322 -322
- package/docs/mysql-exporter.md +280 -280
- package/docs/number-operators.md +449 -449
- package/docs/optional-marker-guide.md +326 -326
- package/docs/performance-guide.md +49 -49
- package/docs/plugin-system.md +381 -381
- package/docs/plugin-type-registration.md +34 -34
- package/docs/postgresql-exporter.md +311 -311
- package/docs/public/favicon.svg +4 -4
- package/docs/quick-start.md +435 -435
- package/docs/runtime-locale-support.md +532 -532
- package/docs/schema-helper.md +345 -345
- package/docs/schema-utils-advanced-issues.md +23 -23
- package/docs/schema-utils-best-practices.md +20 -20
- package/docs/schema-utils-chaining.md +150 -150
- package/docs/schema-utils.md +524 -524
- package/docs/security-checklist.md +20 -20
- package/docs/string-extensions.md +488 -488
- package/docs/troubleshooting.md +486 -486
- package/docs/type-converter.md +310 -310
- package/docs/type-reference.md +242 -242
- package/docs/typescript-guide.md +584 -584
- package/docs/union-type-guide.md +157 -157
- package/docs/union-types.md +284 -284
- package/docs/validate-async.md +491 -491
- package/docs/validate-batch.md +49 -49
- package/docs/validate-dsl-object-support.md +578 -578
- package/docs/validate.md +506 -506
- package/docs/validation-guide.md +502 -502
- package/docs/validator.md +39 -39
- package/package.json +131 -131
- package/plugins/custom-format.cjs +8 -8
- package/plugins/custom-type-example.cjs +8 -8
- package/plugins/custom-validator.cjs +8 -8
- package/src/adapters/DslAdapter.ts +111 -111
- package/src/adapters/index.ts +1 -1
- package/src/config/constants.ts +83 -83
- package/src/config/index.ts +2 -2
- package/src/config/patterns.ts +77 -77
- package/src/core/CacheManager.ts +169 -159
- package/src/core/ConditionalBuilder.ts +382 -382
- package/src/core/ConditionalRuntime.ts +27 -27
- package/src/core/ConditionalValidator.ts +254 -254
- package/src/core/DslBuilder.ts +687 -677
- package/src/core/ErrorCodes.ts +38 -38
- package/src/core/ErrorFormatter.ts +271 -271
- package/src/core/JSONSchemaCore.ts +65 -65
- package/src/core/Locale.ts +187 -187
- package/src/core/MessageTemplate.ts +42 -42
- package/src/core/ObjectDslBuilder.ts +64 -64
- package/src/core/PluginManager.ts +326 -326
- package/src/core/StringExtensions.ts +140 -140
- package/src/core/TemplateEngine.ts +44 -44
- package/src/core/Validator.ts +448 -448
- package/src/errors/I18nError.ts +159 -159
- package/src/errors/ValidationError.ts +105 -105
- package/src/exporters/BaseExporter.ts +60 -60
- package/src/exporters/MarkdownExporter.ts +305 -305
- package/src/exporters/MongoDBExporter.ts +126 -126
- package/src/exporters/MySQLExporter.ts +156 -155
- package/src/exporters/PostgreSQLExporter.ts +222 -222
- package/src/exporters/index.ts +18 -18
- package/src/index.ts +651 -633
- package/src/locales/en-US.ts +160 -160
- package/src/locales/es-ES.ts +160 -160
- package/src/locales/fr-FR.ts +160 -160
- package/src/locales/index.ts +103 -103
- package/src/locales/ja-JP.ts +160 -160
- package/src/locales/types.ts +156 -156
- package/src/locales/zh-CN.ts +160 -160
- package/src/parser/ConstraintParser.ts +101 -101
- package/src/parser/DslParser.ts +470 -470
- package/src/parser/SchemaCompiler.ts +66 -66
- package/src/parser/TypeRegistry.ts +250 -250
- package/src/parser/index.ts +6 -6
- package/src/plugins/custom-format.ts +124 -126
- package/src/plugins/custom-type-example.ts +106 -108
- package/src/plugins/custom-validator.ts +138 -140
- package/src/types/conditional.ts +28 -28
- package/src/types/config.ts +59 -59
- package/src/types/dsl.ts +131 -131
- package/src/types/error.ts +60 -60
- package/src/types/index.ts +17 -17
- package/src/types/infer.ts +127 -127
- package/src/types/plugin.ts +58 -58
- package/src/types/safe-regex.d.ts +9 -9
- package/src/types/schema.ts +66 -66
- package/src/types/validate.ts +71 -71
- package/src/utils/SchemaHelper.ts +196 -196
- package/src/utils/SchemaUtils.ts +365 -346
- package/src/utils/TypeConverter.ts +215 -215
- package/src/utils/index.ts +10 -10
- package/src/validators/CustomKeywords.ts +477 -477
package/docs/i18n.md
CHANGED
|
@@ -1,476 +1,476 @@
|
|
|
1
|
-
# 多语言配置指南
|
|
2
|
-
|
|
3
|
-
**版本**: v2.0.0-beta.1
|
|
4
|
-
**最后更新**: 2026-04-30
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 📚 多语言文档导航
|
|
9
|
-
|
|
10
|
-
根据你的需求选择合适的文档:
|
|
11
|
-
|
|
12
|
-
- 🚀 **新手快速上手**: [i18n.md](./i18n.md)(当前文档)- 5分钟学会基础用法
|
|
13
|
-
- 📖 **完整使用指南**: [i18n-user-guide.md](./i18n-user-guide.md) - 详细的用户指南和最佳实践
|
|
14
|
-
- 🎯 **添加新语言**: [add-custom-locale.md](./add-custom-locale.md) - 添加自定义语言包教程
|
|
15
|
-
- 🔄 **动态切换语言**: [dynamic-locale.md](./dynamic-locale.md) - API开发中的动态语言切换
|
|
16
|
-
- 🌐 **前端集成**: [frontend-i18n-guide.md](./frontend-i18n-guide.md) - 前后端分离项目集成指南
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## 📖 概述
|
|
21
|
-
|
|
22
|
-
schema-dsl 支持完整的多语言功能,允许你自定义字段标签和错误消息的翻译。
|
|
23
|
-
|
|
24
|
-
> **Node.js 要求**:`>=18.0.0`
|
|
25
|
-
|
|
26
|
-
**目录加载(Node >=18)默认支持的语言文件格式**:
|
|
27
|
-
- `.js`(CommonJS 语言包)
|
|
28
|
-
- `.cjs`
|
|
29
|
-
- `.json`
|
|
30
|
-
- `.jsonc`
|
|
31
|
-
- `.json5`
|
|
32
|
-
|
|
33
|
-
> **推荐**:如果你的应用是 `type: module` / ESM 项目,优先使用 `.cjs`、`.json`、`.jsonc`、`.json5`;`.js` 更适合 CommonJS 语言包文件。
|
|
34
|
-
|
|
35
|
-
**v2 当前能力**:
|
|
36
|
-
- ✅ 支持参数化语言切换(无需修改全局状态)
|
|
37
|
-
- ✅ 支持自定义错误消息(三种格式)
|
|
38
|
-
- ✅ TypeScript 类型定义完整
|
|
39
|
-
- ✅ 目录递归加载 `.js/.cjs/.json/.jsonc/.json5`
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 🚀 快速开始
|
|
44
|
-
|
|
45
|
-
### 方式1:验证时动态指定语言(推荐)⭐
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
const { dsl, validate } = require('schema-dsl');
|
|
49
|
-
|
|
50
|
-
const schema = dsl({ username: 'string:3-32!' });
|
|
51
|
-
|
|
52
|
-
// 使用中文错误消息
|
|
53
|
-
const result = validate(schema, { username: 'ab' }, { locale: 'zh-CN' });
|
|
54
|
-
// message: "username长度不能少于3个字符"
|
|
55
|
-
|
|
56
|
-
// 使用英文错误消息
|
|
57
|
-
const result2 = validate(schema, { username: 'ab' }, { locale: 'en-US' });
|
|
58
|
-
// message: "username length must be at least 3"
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 方式2:使用全局配置(向后兼容)
|
|
62
|
-
|
|
63
|
-
```javascript
|
|
64
|
-
const { Locale } = require('schema-dsl');
|
|
65
|
-
|
|
66
|
-
// 设置默认语言
|
|
67
|
-
Locale.setLocale('zh-CN');
|
|
68
|
-
|
|
69
|
-
// 后续验证会使用中文错误消息
|
|
70
|
-
const result = validate(schema, data);
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## 📝 内置语言支持
|
|
76
|
-
|
|
77
|
-
schema-dsl 内置了以下语言包:
|
|
78
|
-
|
|
79
|
-
| 语言代码 | 语言名称 | 支持状态 |
|
|
80
|
-
|---------|---------|---------|
|
|
81
|
-
| `zh-CN` | 简体中文 | ✅ 完整支持 |
|
|
82
|
-
| `en-US` | 英语(美国)| ✅ 完整支持 |
|
|
83
|
-
| `ja-JP` | 日语 | ✅ 完整支持 |
|
|
84
|
-
| `es-ES` | 西班牙语 | ✅ 完整支持 |
|
|
85
|
-
| `fr-FR` | 法语 | ✅ 完整支持 |
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## 🎯 高级用法
|
|
90
|
-
|
|
91
|
-
### 基础配置
|
|
92
|
-
|
|
93
|
-
```javascript
|
|
94
|
-
const { dsl, validate } = require('schema-dsl');
|
|
95
|
-
const path = require('path');
|
|
96
|
-
|
|
97
|
-
// ✅ 方式 1: 从目录加载(推荐)
|
|
98
|
-
dsl.config({
|
|
99
|
-
i18n: path.join(__dirname, 'i18n/dsl') // Node >=18:支持 .js/.cjs/.json/.jsonc/.json5
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// ✅ 方式 2: 直接传入对象
|
|
103
|
-
dsl.config({
|
|
104
|
-
i18n: {
|
|
105
|
-
'zh-CN': require('./i18n/dsl/zh-CN'),
|
|
106
|
-
'en-US': require('./i18n/dsl/en-US')
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### 目录结构
|
|
112
|
-
|
|
113
|
-
```text
|
|
114
|
-
project/
|
|
115
|
-
├── i18n/
|
|
116
|
-
│ └── dsl/ # schema-dsl 语言包目录
|
|
117
|
-
│ ├── zh-CN.cjs # CommonJS / ESM 项目都稳定
|
|
118
|
-
│ ├── en-US.jsonc # 带注释/末尾逗号
|
|
119
|
-
│ └── ja-JP.json5 # JSON5 风格(可选)
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## 📝 语言包格式
|
|
125
|
-
|
|
126
|
-
### 完整示例 (`i18n/dsl/zh-CN.cjs`)
|
|
127
|
-
|
|
128
|
-
```javascript
|
|
129
|
-
module.exports = {
|
|
130
|
-
// ========== 字段标签 ==========
|
|
131
|
-
'field.username': '用户名',
|
|
132
|
-
'field.email': '邮箱地址',
|
|
133
|
-
'field.password': '密码',
|
|
134
|
-
'field.age': '年龄',
|
|
135
|
-
|
|
136
|
-
// ========== 覆盖默认错误消息 ==========
|
|
137
|
-
'required': '{{#label}}是必填项',
|
|
138
|
-
'string.minLength': '{{#label}}长度不能少于{{#limit}}个字符',
|
|
139
|
-
'string.maxLength': '{{#label}}长度不能超过{{#limit}}个字符',
|
|
140
|
-
'string.enum': '{{#label}}必须是以下值之一: {{#valids}}',
|
|
141
|
-
'number.base': '{{#label}}必须是数字类型',
|
|
142
|
-
'number.min': '{{#label}}不能小于{{#limit}}',
|
|
143
|
-
'number.max': '{{#label}}不能大于{{#limit}}',
|
|
144
|
-
'boolean.base': '{{#label}}必须是布尔类型',
|
|
145
|
-
'enum': '{{#label}}必须是以下值之一: {{#allowed}}',
|
|
146
|
-
|
|
147
|
-
// ========== 自定义错误消息 ==========
|
|
148
|
-
'custom.invalidEmail': '邮箱格式不正确,请重新输入',
|
|
149
|
-
'custom.emailTaken': '该邮箱已被注册',
|
|
150
|
-
'custom.passwordWeak': '密码强度不够'
|
|
151
|
-
};
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## 🎯 使用方法
|
|
157
|
-
|
|
158
|
-
### 1. 字段标签翻译
|
|
159
|
-
|
|
160
|
-
```javascript
|
|
161
|
-
const schema = dsl({
|
|
162
|
-
username: dsl('string:3-32!').label('field.username'),
|
|
163
|
-
email: dsl('email!').label('field.email')
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const result = validate(schema, { username: 'ab' });
|
|
167
|
-
// 错误消息: "用户名长度不能少于3个字符"
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### 2. 覆盖默认错误消息
|
|
171
|
-
|
|
172
|
-
```javascript
|
|
173
|
-
// 语言包
|
|
174
|
-
module.exports = {
|
|
175
|
-
'required': '{{#label}}必须填写'
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
// Schema
|
|
179
|
-
const schema = dsl({ username: 'string!' });
|
|
180
|
-
|
|
181
|
-
validate(schema, {});
|
|
182
|
-
// 错误消息: "username必须填写"
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### 3. 自定义错误消息
|
|
186
|
-
|
|
187
|
-
```javascript
|
|
188
|
-
const schema = dsl({
|
|
189
|
-
status: dsl('active|inactive').messages({
|
|
190
|
-
'enum': '状态必须是 active 或 inactive'
|
|
191
|
-
})
|
|
192
|
-
});
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### 4. 动态语言切换
|
|
196
|
-
|
|
197
|
-
```javascript
|
|
198
|
-
dsl.config({
|
|
199
|
-
i18n: {
|
|
200
|
-
'zh-CN': { 'required': '{{#label}}是必填项' },
|
|
201
|
-
'en-US': { 'required': '{{#label}} is required' }
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// 默认语言(en-US)
|
|
206
|
-
validate(schema, data);
|
|
207
|
-
|
|
208
|
-
// 切换到英文
|
|
209
|
-
validate(schema, data, { locale: 'en-US' });
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## 📋 内置错误消息键
|
|
215
|
-
|
|
216
|
-
### 通用错误
|
|
217
|
-
|
|
218
|
-
| 错误键 | 说明 | 中文消息示例 |
|
|
219
|
-
|--------|------|--------------|
|
|
220
|
-
| `required` | 必填字段缺失 | {{#label}}是必填项 |
|
|
221
|
-
| `enum` | 枚举值不在范围 | {{#label}}必须是以下值之一: {{#allowed}} |
|
|
222
|
-
| `pattern` | 格式不正确 | {{#label}}格式不正确 |
|
|
223
|
-
|
|
224
|
-
### String 错误
|
|
225
|
-
|
|
226
|
-
| 错误键 | 说明 |
|
|
227
|
-
|--------|------|
|
|
228
|
-
| `string.minLength` | 最小长度 |
|
|
229
|
-
| `string.maxLength` | 最大长度 |
|
|
230
|
-
| `string.pattern` | 正则不匹配 |
|
|
231
|
-
| `string.enum` | 字符串枚举 |
|
|
232
|
-
|
|
233
|
-
### Number 错误
|
|
234
|
-
|
|
235
|
-
| 错误键 | 说明 |
|
|
236
|
-
|--------|------|
|
|
237
|
-
| `number.base` | 类型不是数字 |
|
|
238
|
-
| `number.min` | 小于最小值 |
|
|
239
|
-
| `number.max` | 大于最大值 |
|
|
240
|
-
| `number.integer` | 不是整数 |
|
|
241
|
-
|
|
242
|
-
### Boolean 错误
|
|
243
|
-
|
|
244
|
-
| 错误键 | 说明 |
|
|
245
|
-
|--------|------|
|
|
246
|
-
| `boolean.base` | 类型不是布尔值 |
|
|
247
|
-
|
|
248
|
-
### Array 错误
|
|
249
|
-
|
|
250
|
-
| 错误键 | 说明 |
|
|
251
|
-
|--------|------|
|
|
252
|
-
| `array.base` | 类型不是数组 |
|
|
253
|
-
| `array.min` | 元素数量不足 |
|
|
254
|
-
| `array.max` | 元素数量过多 |
|
|
255
|
-
| `array.unique` | 包含重复元素 |
|
|
256
|
-
|
|
257
|
-
### Format 错误
|
|
258
|
-
|
|
259
|
-
| 错误键 | 说明 |
|
|
260
|
-
|--------|------|
|
|
261
|
-
| `format.email` | 邮箱格式错误 |
|
|
262
|
-
| `format.url` | URL格式错误 |
|
|
263
|
-
| `format.uuid` | UUID格式错误 |
|
|
264
|
-
| `format.date` | 日期格式错误 |
|
|
265
|
-
| `format.binary` | Base64编码错误 |
|
|
266
|
-
|
|
267
|
-
### Pattern 错误
|
|
268
|
-
|
|
269
|
-
| 错误键 | 说明 |
|
|
270
|
-
|--------|------|
|
|
271
|
-
| `pattern.phone` | 手机号格式错误 |
|
|
272
|
-
| `pattern.idCard` | 身份证格式错误 |
|
|
273
|
-
| `pattern.objectId` | ObjectId格式错误 |
|
|
274
|
-
|
|
275
|
-
完整列表请参考: `src/locales/zh-CN.ts`
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## 🔧 高级用法
|
|
280
|
-
|
|
281
|
-
### 嵌套字段标签
|
|
282
|
-
|
|
283
|
-
```javascript
|
|
284
|
-
// 语言包
|
|
285
|
-
module.exports = {
|
|
286
|
-
'field.address.city': '城市',
|
|
287
|
-
'field.address.street': '街道'
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// Schema
|
|
291
|
-
const schema = dsl({
|
|
292
|
-
address: {
|
|
293
|
-
city: dsl('string!').label('field.address.city'),
|
|
294
|
-
street: dsl('string!').label('field.address.street')
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### 错误消息优先级
|
|
300
|
-
|
|
301
|
-
1. **字段级自定义消息** - `.messages()` 方法
|
|
302
|
-
2. **Schema级标签** - `.label()` 方法
|
|
303
|
-
3. **语言包自定义消息** - `i18n` 配置
|
|
304
|
-
4. **默认错误消息** - 内置语言包
|
|
305
|
-
|
|
306
|
-
```javascript
|
|
307
|
-
// 优先级示例
|
|
308
|
-
dsl.config({
|
|
309
|
-
i18n: {
|
|
310
|
-
'zh-CN': {
|
|
311
|
-
'required': '全局必填消息' // 优先级 3
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
const schema = dsl({
|
|
317
|
-
username: dsl('string!')
|
|
318
|
-
.label('用户名') // 优先级 2
|
|
319
|
-
.messages({ 'required': '必须填' }) // 优先级 1(最高)
|
|
320
|
-
});
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### 多语言最佳实践
|
|
324
|
-
|
|
325
|
-
#### 1. 目录结构
|
|
326
|
-
|
|
327
|
-
```text
|
|
328
|
-
project/
|
|
329
|
-
├── i18n/
|
|
330
|
-
│ └── dsl/
|
|
331
|
-
│ ├── zh-CN.cjs # 中文
|
|
332
|
-
│ ├── en-US.jsonc # 英文
|
|
333
|
-
│ ├── ja-JP.json5 # 日语
|
|
334
|
-
│ └── index.cjs # 导出工具
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
#### 2. 导出工具 (`i18n/dsl/index.cjs`)
|
|
338
|
-
|
|
339
|
-
```javascript
|
|
340
|
-
const path = require('path');
|
|
341
|
-
|
|
342
|
-
module.exports = {
|
|
343
|
-
'zh-CN': require('./zh-CN.cjs'),
|
|
344
|
-
'en-US': require('./en-US.jsonc'),
|
|
345
|
-
'ja-JP': require('./ja-JP.json5')
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
// 使用
|
|
349
|
-
dsl.config({
|
|
350
|
-
i18n: require('./i18n/dsl')
|
|
351
|
-
});
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
#### 3. 消息复用
|
|
355
|
-
|
|
356
|
-
```javascript
|
|
357
|
-
// i18n/dsl/common.cjs
|
|
358
|
-
module.exports = {
|
|
359
|
-
required: '{{#label}}是必填项',
|
|
360
|
-
minLength: '{{#label}}长度不能少于{{#limit}}个字符'
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
// i18n/dsl/zh-CN.cjs
|
|
364
|
-
const common = require('./common.cjs');
|
|
365
|
-
|
|
366
|
-
module.exports = {
|
|
367
|
-
...common,
|
|
368
|
-
'field.username': '用户名',
|
|
369
|
-
'field.email': '邮箱'
|
|
370
|
-
};
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
## 📊 完整示例
|
|
376
|
-
|
|
377
|
-
### 用户管理系统
|
|
378
|
-
|
|
379
|
-
```javascript
|
|
380
|
-
const { dsl, validate } = require('schema-dsl');
|
|
381
|
-
const path = require('path');
|
|
382
|
-
|
|
383
|
-
// 配置多语言
|
|
384
|
-
dsl.config({
|
|
385
|
-
i18n: path.join(__dirname, 'i18n/dsl')
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
// 定义 Schema
|
|
389
|
-
const userSchema = dsl({
|
|
390
|
-
username: dsl('string:3-32!').label('field.username'),
|
|
391
|
-
email: dsl('email!').label('field.email'),
|
|
392
|
-
password: dsl('string:8-32!').label('field.password'),
|
|
393
|
-
age: dsl('number:18-120').label('field.age'),
|
|
394
|
-
role: dsl('admin|user|guest!').label('field.role')
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
// 验证(中文)
|
|
398
|
-
let result = validate(userSchema, {
|
|
399
|
-
username: 'ab',
|
|
400
|
-
email: 'invalid',
|
|
401
|
-
role: 'admin'
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
console.log(result.errors);
|
|
405
|
-
// [
|
|
406
|
-
// { path: 'username', message: '用户名长度不能少于3个字符' },
|
|
407
|
-
// { path: 'email', message: '邮箱地址必须是有效的邮箱地址' },
|
|
408
|
-
// { path: 'password', message: '密码是必填项' }
|
|
409
|
-
// ]
|
|
410
|
-
|
|
411
|
-
// 验证(英文)
|
|
412
|
-
result = validate(userSchema, {
|
|
413
|
-
username: 'ab'
|
|
414
|
-
}, { locale: 'en-US' });
|
|
415
|
-
|
|
416
|
-
console.log(result.errors[0].message);
|
|
417
|
-
// "username must be at least 3 characters"
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
---
|
|
421
|
-
|
|
422
|
-
## 🐛 常见问题
|
|
423
|
-
|
|
424
|
-
### 1. 语言包不生效?
|
|
425
|
-
|
|
426
|
-
**检查清单**:
|
|
427
|
-
- ✅ 配置键是否正确(`i18n` 而非 `locales`)
|
|
428
|
-
- ✅ 目录路径是否正确
|
|
429
|
-
- ✅ 文件名是否为语言代码(如 `zh-CN.cjs` / `zh-CN.jsonc`)
|
|
430
|
-
- ✅ `.js` 文件是否为 CommonJS(`module.exports`),若是 ESM 项目优先使用 `.cjs` / `.json*`
|
|
431
|
-
|
|
432
|
-
### 2. 错误消息仍然是英文?
|
|
433
|
-
|
|
434
|
-
**原因**: 当前请求没有显式传入 `locale`,或全局默认语言尚未切到你期望的语言
|
|
435
|
-
|
|
436
|
-
```javascript
|
|
437
|
-
// 方法 1: 全局设置
|
|
438
|
-
const { Locale } = require('schema-dsl');
|
|
439
|
-
Locale.setLocale('zh-CN');
|
|
440
|
-
|
|
441
|
-
// 方法 2: 验证时指定
|
|
442
|
-
validate(schema, data, { locale: 'zh-CN' });
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### 3. 自定义消息不显示?
|
|
446
|
-
|
|
447
|
-
**检查优先级**:
|
|
448
|
-
- `.messages()` > `.label()` > 语言包 > 默认
|
|
449
|
-
|
|
450
|
-
```javascript
|
|
451
|
-
// 错误:label 会被 messages 覆盖
|
|
452
|
-
dsl('string!')
|
|
453
|
-
.label('用户名')
|
|
454
|
-
.messages({ 'required': '必填' }) // 这个生效
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
---
|
|
458
|
-
|
|
459
|
-
## 📚 相关文档
|
|
460
|
-
|
|
461
|
-
- [快速开始](https://github.com/vextjs/schema-dsl/blob/main/README.md)
|
|
462
|
-
- [API 参考](./api.md)
|
|
463
|
-
- [完整示例](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/i18n.ts)
|
|
464
|
-
|
|
465
|
-
---
|
|
466
|
-
|
|
467
|
-
## 对应示例文件
|
|
468
|
-
|
|
469
|
-
**示例入口**: [i18n.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/i18n.ts)
|
|
470
|
-
**说明**: 覆盖内置 locale 切换、字段级消息优先级,以及自定义 locale 的最小工作路径。
|
|
471
|
-
|
|
472
|
-
---
|
|
473
|
-
|
|
474
|
-
**文档生成时间**: 2026-05-08
|
|
475
|
-
**版本**: v1.0.1
|
|
476
|
-
|
|
1
|
+
# 多语言配置指南
|
|
2
|
+
|
|
3
|
+
**版本**: v2.0.0-beta.1
|
|
4
|
+
**最后更新**: 2026-04-30
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📚 多语言文档导航
|
|
9
|
+
|
|
10
|
+
根据你的需求选择合适的文档:
|
|
11
|
+
|
|
12
|
+
- 🚀 **新手快速上手**: [i18n.md](./i18n.md)(当前文档)- 5分钟学会基础用法
|
|
13
|
+
- 📖 **完整使用指南**: [i18n-user-guide.md](./i18n-user-guide.md) - 详细的用户指南和最佳实践
|
|
14
|
+
- 🎯 **添加新语言**: [add-custom-locale.md](./add-custom-locale.md) - 添加自定义语言包教程
|
|
15
|
+
- 🔄 **动态切换语言**: [dynamic-locale.md](./dynamic-locale.md) - API开发中的动态语言切换
|
|
16
|
+
- 🌐 **前端集成**: [frontend-i18n-guide.md](./frontend-i18n-guide.md) - 前后端分离项目集成指南
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📖 概述
|
|
21
|
+
|
|
22
|
+
schema-dsl 支持完整的多语言功能,允许你自定义字段标签和错误消息的翻译。
|
|
23
|
+
|
|
24
|
+
> **Node.js 要求**:`>=18.0.0`
|
|
25
|
+
|
|
26
|
+
**目录加载(Node >=18)默认支持的语言文件格式**:
|
|
27
|
+
- `.js`(CommonJS 语言包)
|
|
28
|
+
- `.cjs`
|
|
29
|
+
- `.json`
|
|
30
|
+
- `.jsonc`
|
|
31
|
+
- `.json5`
|
|
32
|
+
|
|
33
|
+
> **推荐**:如果你的应用是 `type: module` / ESM 项目,优先使用 `.cjs`、`.json`、`.jsonc`、`.json5`;`.js` 更适合 CommonJS 语言包文件。
|
|
34
|
+
|
|
35
|
+
**v2 当前能力**:
|
|
36
|
+
- ✅ 支持参数化语言切换(无需修改全局状态)
|
|
37
|
+
- ✅ 支持自定义错误消息(三种格式)
|
|
38
|
+
- ✅ TypeScript 类型定义完整
|
|
39
|
+
- ✅ 目录递归加载 `.js/.cjs/.json/.jsonc/.json5`
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🚀 快速开始
|
|
44
|
+
|
|
45
|
+
### 方式1:验证时动态指定语言(推荐)⭐
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const { dsl, validate } = require('schema-dsl');
|
|
49
|
+
|
|
50
|
+
const schema = dsl({ username: 'string:3-32!' });
|
|
51
|
+
|
|
52
|
+
// 使用中文错误消息
|
|
53
|
+
const result = validate(schema, { username: 'ab' }, { locale: 'zh-CN' });
|
|
54
|
+
// message: "username长度不能少于3个字符"
|
|
55
|
+
|
|
56
|
+
// 使用英文错误消息
|
|
57
|
+
const result2 = validate(schema, { username: 'ab' }, { locale: 'en-US' });
|
|
58
|
+
// message: "username length must be at least 3"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 方式2:使用全局配置(向后兼容)
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const { Locale } = require('schema-dsl');
|
|
65
|
+
|
|
66
|
+
// 设置默认语言
|
|
67
|
+
Locale.setLocale('zh-CN');
|
|
68
|
+
|
|
69
|
+
// 后续验证会使用中文错误消息
|
|
70
|
+
const result = validate(schema, data);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 📝 内置语言支持
|
|
76
|
+
|
|
77
|
+
schema-dsl 内置了以下语言包:
|
|
78
|
+
|
|
79
|
+
| 语言代码 | 语言名称 | 支持状态 |
|
|
80
|
+
|---------|---------|---------|
|
|
81
|
+
| `zh-CN` | 简体中文 | ✅ 完整支持 |
|
|
82
|
+
| `en-US` | 英语(美国)| ✅ 完整支持 |
|
|
83
|
+
| `ja-JP` | 日语 | ✅ 完整支持 |
|
|
84
|
+
| `es-ES` | 西班牙语 | ✅ 完整支持 |
|
|
85
|
+
| `fr-FR` | 法语 | ✅ 完整支持 |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 🎯 高级用法
|
|
90
|
+
|
|
91
|
+
### 基础配置
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
const { dsl, validate } = require('schema-dsl');
|
|
95
|
+
const path = require('path');
|
|
96
|
+
|
|
97
|
+
// ✅ 方式 1: 从目录加载(推荐)
|
|
98
|
+
dsl.config({
|
|
99
|
+
i18n: path.join(__dirname, 'i18n/dsl') // Node >=18:支持 .js/.cjs/.json/.jsonc/.json5
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ✅ 方式 2: 直接传入对象
|
|
103
|
+
dsl.config({
|
|
104
|
+
i18n: {
|
|
105
|
+
'zh-CN': require('./i18n/dsl/zh-CN'),
|
|
106
|
+
'en-US': require('./i18n/dsl/en-US')
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 目录结构
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
project/
|
|
115
|
+
├── i18n/
|
|
116
|
+
│ └── dsl/ # schema-dsl 语言包目录
|
|
117
|
+
│ ├── zh-CN.cjs # CommonJS / ESM 项目都稳定
|
|
118
|
+
│ ├── en-US.jsonc # 带注释/末尾逗号
|
|
119
|
+
│ └── ja-JP.json5 # JSON5 风格(可选)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 📝 语言包格式
|
|
125
|
+
|
|
126
|
+
### 完整示例 (`i18n/dsl/zh-CN.cjs`)
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
module.exports = {
|
|
130
|
+
// ========== 字段标签 ==========
|
|
131
|
+
'field.username': '用户名',
|
|
132
|
+
'field.email': '邮箱地址',
|
|
133
|
+
'field.password': '密码',
|
|
134
|
+
'field.age': '年龄',
|
|
135
|
+
|
|
136
|
+
// ========== 覆盖默认错误消息 ==========
|
|
137
|
+
'required': '{{#label}}是必填项',
|
|
138
|
+
'string.minLength': '{{#label}}长度不能少于{{#limit}}个字符',
|
|
139
|
+
'string.maxLength': '{{#label}}长度不能超过{{#limit}}个字符',
|
|
140
|
+
'string.enum': '{{#label}}必须是以下值之一: {{#valids}}',
|
|
141
|
+
'number.base': '{{#label}}必须是数字类型',
|
|
142
|
+
'number.min': '{{#label}}不能小于{{#limit}}',
|
|
143
|
+
'number.max': '{{#label}}不能大于{{#limit}}',
|
|
144
|
+
'boolean.base': '{{#label}}必须是布尔类型',
|
|
145
|
+
'enum': '{{#label}}必须是以下值之一: {{#allowed}}',
|
|
146
|
+
|
|
147
|
+
// ========== 自定义错误消息 ==========
|
|
148
|
+
'custom.invalidEmail': '邮箱格式不正确,请重新输入',
|
|
149
|
+
'custom.emailTaken': '该邮箱已被注册',
|
|
150
|
+
'custom.passwordWeak': '密码强度不够'
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 🎯 使用方法
|
|
157
|
+
|
|
158
|
+
### 1. 字段标签翻译
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
const schema = dsl({
|
|
162
|
+
username: dsl('string:3-32!').label('field.username'),
|
|
163
|
+
email: dsl('email!').label('field.email')
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const result = validate(schema, { username: 'ab' });
|
|
167
|
+
// 错误消息: "用户名长度不能少于3个字符"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 2. 覆盖默认错误消息
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
// 语言包
|
|
174
|
+
module.exports = {
|
|
175
|
+
'required': '{{#label}}必须填写'
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Schema
|
|
179
|
+
const schema = dsl({ username: 'string!' });
|
|
180
|
+
|
|
181
|
+
validate(schema, {});
|
|
182
|
+
// 错误消息: "username必须填写"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 3. 自定义错误消息
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
const schema = dsl({
|
|
189
|
+
status: dsl('active|inactive').messages({
|
|
190
|
+
'enum': '状态必须是 active 或 inactive'
|
|
191
|
+
})
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 4. 动态语言切换
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
dsl.config({
|
|
199
|
+
i18n: {
|
|
200
|
+
'zh-CN': { 'required': '{{#label}}是必填项' },
|
|
201
|
+
'en-US': { 'required': '{{#label}} is required' }
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// 默认语言(en-US)
|
|
206
|
+
validate(schema, data);
|
|
207
|
+
|
|
208
|
+
// 切换到英文
|
|
209
|
+
validate(schema, data, { locale: 'en-US' });
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 📋 内置错误消息键
|
|
215
|
+
|
|
216
|
+
### 通用错误
|
|
217
|
+
|
|
218
|
+
| 错误键 | 说明 | 中文消息示例 |
|
|
219
|
+
|--------|------|--------------|
|
|
220
|
+
| `required` | 必填字段缺失 | {{#label}}是必填项 |
|
|
221
|
+
| `enum` | 枚举值不在范围 | {{#label}}必须是以下值之一: {{#allowed}} |
|
|
222
|
+
| `pattern` | 格式不正确 | {{#label}}格式不正确 |
|
|
223
|
+
|
|
224
|
+
### String 错误
|
|
225
|
+
|
|
226
|
+
| 错误键 | 说明 |
|
|
227
|
+
|--------|------|
|
|
228
|
+
| `string.minLength` | 最小长度 |
|
|
229
|
+
| `string.maxLength` | 最大长度 |
|
|
230
|
+
| `string.pattern` | 正则不匹配 |
|
|
231
|
+
| `string.enum` | 字符串枚举 |
|
|
232
|
+
|
|
233
|
+
### Number 错误
|
|
234
|
+
|
|
235
|
+
| 错误键 | 说明 |
|
|
236
|
+
|--------|------|
|
|
237
|
+
| `number.base` | 类型不是数字 |
|
|
238
|
+
| `number.min` | 小于最小值 |
|
|
239
|
+
| `number.max` | 大于最大值 |
|
|
240
|
+
| `number.integer` | 不是整数 |
|
|
241
|
+
|
|
242
|
+
### Boolean 错误
|
|
243
|
+
|
|
244
|
+
| 错误键 | 说明 |
|
|
245
|
+
|--------|------|
|
|
246
|
+
| `boolean.base` | 类型不是布尔值 |
|
|
247
|
+
|
|
248
|
+
### Array 错误
|
|
249
|
+
|
|
250
|
+
| 错误键 | 说明 |
|
|
251
|
+
|--------|------|
|
|
252
|
+
| `array.base` | 类型不是数组 |
|
|
253
|
+
| `array.min` | 元素数量不足 |
|
|
254
|
+
| `array.max` | 元素数量过多 |
|
|
255
|
+
| `array.unique` | 包含重复元素 |
|
|
256
|
+
|
|
257
|
+
### Format 错误
|
|
258
|
+
|
|
259
|
+
| 错误键 | 说明 |
|
|
260
|
+
|--------|------|
|
|
261
|
+
| `format.email` | 邮箱格式错误 |
|
|
262
|
+
| `format.url` | URL格式错误 |
|
|
263
|
+
| `format.uuid` | UUID格式错误 |
|
|
264
|
+
| `format.date` | 日期格式错误 |
|
|
265
|
+
| `format.binary` | Base64编码错误 |
|
|
266
|
+
|
|
267
|
+
### Pattern 错误
|
|
268
|
+
|
|
269
|
+
| 错误键 | 说明 |
|
|
270
|
+
|--------|------|
|
|
271
|
+
| `pattern.phone` | 手机号格式错误 |
|
|
272
|
+
| `pattern.idCard` | 身份证格式错误 |
|
|
273
|
+
| `pattern.objectId` | ObjectId格式错误 |
|
|
274
|
+
|
|
275
|
+
完整列表请参考: `src/locales/zh-CN.ts`
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## 🔧 高级用法
|
|
280
|
+
|
|
281
|
+
### 嵌套字段标签
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
// 语言包
|
|
285
|
+
module.exports = {
|
|
286
|
+
'field.address.city': '城市',
|
|
287
|
+
'field.address.street': '街道'
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// Schema
|
|
291
|
+
const schema = dsl({
|
|
292
|
+
address: {
|
|
293
|
+
city: dsl('string!').label('field.address.city'),
|
|
294
|
+
street: dsl('string!').label('field.address.street')
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### 错误消息优先级
|
|
300
|
+
|
|
301
|
+
1. **字段级自定义消息** - `.messages()` 方法
|
|
302
|
+
2. **Schema级标签** - `.label()` 方法
|
|
303
|
+
3. **语言包自定义消息** - `i18n` 配置
|
|
304
|
+
4. **默认错误消息** - 内置语言包
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
// 优先级示例
|
|
308
|
+
dsl.config({
|
|
309
|
+
i18n: {
|
|
310
|
+
'zh-CN': {
|
|
311
|
+
'required': '全局必填消息' // 优先级 3
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const schema = dsl({
|
|
317
|
+
username: dsl('string!')
|
|
318
|
+
.label('用户名') // 优先级 2
|
|
319
|
+
.messages({ 'required': '必须填' }) // 优先级 1(最高)
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 多语言最佳实践
|
|
324
|
+
|
|
325
|
+
#### 1. 目录结构
|
|
326
|
+
|
|
327
|
+
```text
|
|
328
|
+
project/
|
|
329
|
+
├── i18n/
|
|
330
|
+
│ └── dsl/
|
|
331
|
+
│ ├── zh-CN.cjs # 中文
|
|
332
|
+
│ ├── en-US.jsonc # 英文
|
|
333
|
+
│ ├── ja-JP.json5 # 日语
|
|
334
|
+
│ └── index.cjs # 导出工具
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### 2. 导出工具 (`i18n/dsl/index.cjs`)
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
const path = require('path');
|
|
341
|
+
|
|
342
|
+
module.exports = {
|
|
343
|
+
'zh-CN': require('./zh-CN.cjs'),
|
|
344
|
+
'en-US': require('./en-US.jsonc'),
|
|
345
|
+
'ja-JP': require('./ja-JP.json5')
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// 使用
|
|
349
|
+
dsl.config({
|
|
350
|
+
i18n: require('./i18n/dsl')
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### 3. 消息复用
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
// i18n/dsl/common.cjs
|
|
358
|
+
module.exports = {
|
|
359
|
+
required: '{{#label}}是必填项',
|
|
360
|
+
minLength: '{{#label}}长度不能少于{{#limit}}个字符'
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// i18n/dsl/zh-CN.cjs
|
|
364
|
+
const common = require('./common.cjs');
|
|
365
|
+
|
|
366
|
+
module.exports = {
|
|
367
|
+
...common,
|
|
368
|
+
'field.username': '用户名',
|
|
369
|
+
'field.email': '邮箱'
|
|
370
|
+
};
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## 📊 完整示例
|
|
376
|
+
|
|
377
|
+
### 用户管理系统
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
const { dsl, validate } = require('schema-dsl');
|
|
381
|
+
const path = require('path');
|
|
382
|
+
|
|
383
|
+
// 配置多语言
|
|
384
|
+
dsl.config({
|
|
385
|
+
i18n: path.join(__dirname, 'i18n/dsl')
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
// 定义 Schema
|
|
389
|
+
const userSchema = dsl({
|
|
390
|
+
username: dsl('string:3-32!').label('field.username'),
|
|
391
|
+
email: dsl('email!').label('field.email'),
|
|
392
|
+
password: dsl('string:8-32!').label('field.password'),
|
|
393
|
+
age: dsl('number:18-120').label('field.age'),
|
|
394
|
+
role: dsl('admin|user|guest!').label('field.role')
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// 验证(中文)
|
|
398
|
+
let result = validate(userSchema, {
|
|
399
|
+
username: 'ab',
|
|
400
|
+
email: 'invalid',
|
|
401
|
+
role: 'admin'
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
console.log(result.errors);
|
|
405
|
+
// [
|
|
406
|
+
// { path: 'username', message: '用户名长度不能少于3个字符' },
|
|
407
|
+
// { path: 'email', message: '邮箱地址必须是有效的邮箱地址' },
|
|
408
|
+
// { path: 'password', message: '密码是必填项' }
|
|
409
|
+
// ]
|
|
410
|
+
|
|
411
|
+
// 验证(英文)
|
|
412
|
+
result = validate(userSchema, {
|
|
413
|
+
username: 'ab'
|
|
414
|
+
}, { locale: 'en-US' });
|
|
415
|
+
|
|
416
|
+
console.log(result.errors[0].message);
|
|
417
|
+
// "username must be at least 3 characters"
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 🐛 常见问题
|
|
423
|
+
|
|
424
|
+
### 1. 语言包不生效?
|
|
425
|
+
|
|
426
|
+
**检查清单**:
|
|
427
|
+
- ✅ 配置键是否正确(`i18n` 而非 `locales`)
|
|
428
|
+
- ✅ 目录路径是否正确
|
|
429
|
+
- ✅ 文件名是否为语言代码(如 `zh-CN.cjs` / `zh-CN.jsonc`)
|
|
430
|
+
- ✅ `.js` 文件是否为 CommonJS(`module.exports`),若是 ESM 项目优先使用 `.cjs` / `.json*`
|
|
431
|
+
|
|
432
|
+
### 2. 错误消息仍然是英文?
|
|
433
|
+
|
|
434
|
+
**原因**: 当前请求没有显式传入 `locale`,或全局默认语言尚未切到你期望的语言
|
|
435
|
+
|
|
436
|
+
```javascript
|
|
437
|
+
// 方法 1: 全局设置
|
|
438
|
+
const { Locale } = require('schema-dsl');
|
|
439
|
+
Locale.setLocale('zh-CN');
|
|
440
|
+
|
|
441
|
+
// 方法 2: 验证时指定
|
|
442
|
+
validate(schema, data, { locale: 'zh-CN' });
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### 3. 自定义消息不显示?
|
|
446
|
+
|
|
447
|
+
**检查优先级**:
|
|
448
|
+
- `.messages()` > `.label()` > 语言包 > 默认
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
// 错误:label 会被 messages 覆盖
|
|
452
|
+
dsl('string!')
|
|
453
|
+
.label('用户名')
|
|
454
|
+
.messages({ 'required': '必填' }) // 这个生效
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## 📚 相关文档
|
|
460
|
+
|
|
461
|
+
- [快速开始](https://github.com/vextjs/schema-dsl/blob/main/README.md)
|
|
462
|
+
- [API 参考](./api.md)
|
|
463
|
+
- [完整示例](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/i18n.ts)
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## 对应示例文件
|
|
468
|
+
|
|
469
|
+
**示例入口**: [i18n.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/i18n.ts)
|
|
470
|
+
**说明**: 覆盖内置 locale 切换、字段级消息优先级,以及自定义 locale 的最小工作路径。
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
**文档生成时间**: 2026-05-08
|
|
475
|
+
**版本**: v1.0.1
|
|
476
|
+
|