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