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.
Files changed (145) hide show
  1. package/CHANGELOG.md +130 -113
  2. package/LICENSE +21 -21
  3. package/README.md +628 -628
  4. package/dist/{DslBuilder-DkLaOo9Q.d.ts → DslBuilder-BIgQOAXp.d.ts} +2 -0
  5. package/dist/{DslBuilder-DQDN0ZxZ.d.cts → DslBuilder-CjHTucNQ.d.cts} +2 -0
  6. package/dist/{Validator-hFWKGxir.d.ts → Validator-CllRdrY0.d.ts} +1 -1
  7. package/dist/{Validator-C7GsVQOH.d.cts → Validator-D6okG9tr.d.cts} +1 -1
  8. package/dist/index.cjs +75 -29
  9. package/dist/index.d.cts +10 -4
  10. package/dist/index.d.ts +10 -4
  11. package/dist/index.js +75 -29
  12. package/dist/plugins/custom-format.cjs +33 -17
  13. package/dist/plugins/custom-format.d.cts +1 -1
  14. package/dist/plugins/custom-format.d.ts +1 -1
  15. package/dist/plugins/custom-format.js +33 -17
  16. package/dist/plugins/custom-type-example.cjs +33 -17
  17. package/dist/plugins/custom-type-example.d.cts +1 -1
  18. package/dist/plugins/custom-type-example.d.ts +1 -1
  19. package/dist/plugins/custom-type-example.js +33 -17
  20. package/dist/plugins/custom-validator.cjs +0 -2
  21. package/dist/plugins/custom-validator.d.cts +1 -1
  22. package/dist/plugins/custom-validator.d.ts +1 -1
  23. package/dist/plugins/custom-validator.js +0 -2
  24. package/docs/FEATURE-INDEX.md +553 -553
  25. package/docs/add-custom-locale.md +496 -496
  26. package/docs/add-keyword.md +24 -24
  27. package/docs/api-reference.md +1047 -1047
  28. package/docs/api.md +13 -13
  29. package/docs/best-practices-project-structure.md +417 -417
  30. package/docs/best-practices.md +712 -712
  31. package/docs/cache-manager.md +344 -344
  32. package/docs/compile.md +45 -45
  33. package/docs/conditional-api.md +1307 -1307
  34. package/docs/custom-extensions-guide.md +339 -339
  35. package/docs/design-philosophy.md +606 -606
  36. package/docs/doc-index.md +324 -324
  37. package/docs/dsl-syntax.md +714 -714
  38. package/docs/dynamic-locale.md +608 -608
  39. package/docs/enum.md +482 -482
  40. package/docs/error-handling.md +1975 -1975
  41. package/docs/export-guide.md +501 -501
  42. package/docs/export-limitations.md +567 -567
  43. package/docs/faq.md +596 -596
  44. package/docs/frontend-i18n-guide.md +307 -307
  45. package/docs/i18n-user-guide.md +487 -487
  46. package/docs/i18n.md +476 -476
  47. package/docs/index.md +48 -48
  48. package/docs/json-schema-basics.md +40 -40
  49. package/docs/label-vs-description.md +271 -271
  50. package/docs/markdown-exporter.md +406 -406
  51. package/docs/mongodb-exporter.md +302 -302
  52. package/docs/multi-language.md +26 -26
  53. package/docs/multi-type-support.md +322 -322
  54. package/docs/mysql-exporter.md +280 -280
  55. package/docs/number-operators.md +449 -449
  56. package/docs/optional-marker-guide.md +326 -326
  57. package/docs/performance-guide.md +49 -49
  58. package/docs/plugin-system.md +381 -381
  59. package/docs/plugin-type-registration.md +34 -34
  60. package/docs/postgresql-exporter.md +311 -311
  61. package/docs/public/favicon.svg +4 -4
  62. package/docs/quick-start.md +435 -435
  63. package/docs/runtime-locale-support.md +532 -532
  64. package/docs/schema-helper.md +345 -345
  65. package/docs/schema-utils-advanced-issues.md +23 -23
  66. package/docs/schema-utils-best-practices.md +20 -20
  67. package/docs/schema-utils-chaining.md +150 -150
  68. package/docs/schema-utils.md +524 -524
  69. package/docs/security-checklist.md +20 -20
  70. package/docs/string-extensions.md +488 -488
  71. package/docs/troubleshooting.md +486 -486
  72. package/docs/type-converter.md +310 -310
  73. package/docs/type-reference.md +242 -242
  74. package/docs/typescript-guide.md +584 -584
  75. package/docs/union-type-guide.md +157 -157
  76. package/docs/union-types.md +284 -284
  77. package/docs/validate-async.md +491 -491
  78. package/docs/validate-batch.md +49 -49
  79. package/docs/validate-dsl-object-support.md +578 -578
  80. package/docs/validate.md +506 -506
  81. package/docs/validation-guide.md +502 -502
  82. package/docs/validator.md +39 -39
  83. package/package.json +131 -131
  84. package/plugins/custom-format.cjs +8 -8
  85. package/plugins/custom-type-example.cjs +8 -8
  86. package/plugins/custom-validator.cjs +8 -8
  87. package/src/adapters/DslAdapter.ts +111 -111
  88. package/src/adapters/index.ts +1 -1
  89. package/src/config/constants.ts +83 -83
  90. package/src/config/index.ts +2 -2
  91. package/src/config/patterns.ts +77 -77
  92. package/src/core/CacheManager.ts +169 -159
  93. package/src/core/ConditionalBuilder.ts +382 -382
  94. package/src/core/ConditionalRuntime.ts +27 -27
  95. package/src/core/ConditionalValidator.ts +254 -254
  96. package/src/core/DslBuilder.ts +687 -677
  97. package/src/core/ErrorCodes.ts +38 -38
  98. package/src/core/ErrorFormatter.ts +271 -271
  99. package/src/core/JSONSchemaCore.ts +65 -65
  100. package/src/core/Locale.ts +187 -187
  101. package/src/core/MessageTemplate.ts +42 -42
  102. package/src/core/ObjectDslBuilder.ts +64 -64
  103. package/src/core/PluginManager.ts +326 -326
  104. package/src/core/StringExtensions.ts +140 -140
  105. package/src/core/TemplateEngine.ts +44 -44
  106. package/src/core/Validator.ts +448 -448
  107. package/src/errors/I18nError.ts +159 -159
  108. package/src/errors/ValidationError.ts +105 -105
  109. package/src/exporters/BaseExporter.ts +60 -60
  110. package/src/exporters/MarkdownExporter.ts +305 -305
  111. package/src/exporters/MongoDBExporter.ts +126 -126
  112. package/src/exporters/MySQLExporter.ts +156 -155
  113. package/src/exporters/PostgreSQLExporter.ts +222 -222
  114. package/src/exporters/index.ts +18 -18
  115. package/src/index.ts +651 -633
  116. package/src/locales/en-US.ts +160 -160
  117. package/src/locales/es-ES.ts +160 -160
  118. package/src/locales/fr-FR.ts +160 -160
  119. package/src/locales/index.ts +103 -103
  120. package/src/locales/ja-JP.ts +160 -160
  121. package/src/locales/types.ts +156 -156
  122. package/src/locales/zh-CN.ts +160 -160
  123. package/src/parser/ConstraintParser.ts +101 -101
  124. package/src/parser/DslParser.ts +470 -470
  125. package/src/parser/SchemaCompiler.ts +66 -66
  126. package/src/parser/TypeRegistry.ts +250 -250
  127. package/src/parser/index.ts +6 -6
  128. package/src/plugins/custom-format.ts +124 -126
  129. package/src/plugins/custom-type-example.ts +106 -108
  130. package/src/plugins/custom-validator.ts +138 -140
  131. package/src/types/conditional.ts +28 -28
  132. package/src/types/config.ts +59 -59
  133. package/src/types/dsl.ts +131 -131
  134. package/src/types/error.ts +60 -60
  135. package/src/types/index.ts +17 -17
  136. package/src/types/infer.ts +127 -127
  137. package/src/types/plugin.ts +58 -58
  138. package/src/types/safe-regex.d.ts +9 -9
  139. package/src/types/schema.ts +66 -66
  140. package/src/types/validate.ts +71 -71
  141. package/src/utils/SchemaHelper.ts +196 -196
  142. package/src/utils/SchemaUtils.ts +365 -346
  143. package/src/utils/TypeConverter.ts +215 -215
  144. package/src/utils/index.ts +10 -10
  145. 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
+