schema-dsl 2.3.0
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/.eslintignore +10 -0
- package/.eslintrc.json +27 -0
- package/.github/CODE_OF_CONDUCT.md +45 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
- package/.github/ISSUE_TEMPLATE/question.md +31 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +70 -0
- package/.github/SECURITY.md +184 -0
- package/.github/workflows/ci.yml +35 -0
- package/CHANGELOG.md +633 -0
- package/CONTRIBUTING.md +368 -0
- package/LICENSE +21 -0
- package/README.md +1122 -0
- package/STATUS.md +273 -0
- package/docs/FEATURE-INDEX.md +521 -0
- package/docs/INDEX.md +224 -0
- package/docs/api-reference.md +1098 -0
- package/docs/best-practices.md +672 -0
- package/docs/cache-manager.md +336 -0
- package/docs/design-philosophy.md +602 -0
- package/docs/dsl-syntax.md +654 -0
- package/docs/dynamic-locale.md +552 -0
- package/docs/error-handling.md +703 -0
- package/docs/export-guide.md +459 -0
- package/docs/faq.md +576 -0
- package/docs/frontend-i18n-guide.md +290 -0
- package/docs/i18n-user-guide.md +488 -0
- package/docs/label-vs-description.md +262 -0
- package/docs/markdown-exporter.md +398 -0
- package/docs/mongodb-exporter.md +279 -0
- package/docs/multi-type-support.md +319 -0
- package/docs/mysql-exporter.md +257 -0
- package/docs/plugin-system.md +542 -0
- package/docs/postgresql-exporter.md +290 -0
- package/docs/quick-start.md +761 -0
- package/docs/schema-helper.md +340 -0
- package/docs/schema-utils.md +492 -0
- package/docs/string-extensions.md +480 -0
- package/docs/troubleshooting.md +471 -0
- package/docs/type-converter.md +319 -0
- package/docs/type-reference.md +219 -0
- package/docs/validate.md +486 -0
- package/docs/validation-guide.md +484 -0
- package/examples/array-dsl-example.js +227 -0
- package/examples/custom-extension.js +85 -0
- package/examples/dsl-match-example.js +74 -0
- package/examples/dsl-style.js +118 -0
- package/examples/dynamic-locale-configuration.js +348 -0
- package/examples/dynamic-locale-example.js +287 -0
- package/examples/export-demo.js +130 -0
- package/examples/i18n-full-demo.js +310 -0
- package/examples/i18n-memory-safety.examples.js +268 -0
- package/examples/markdown-export.js +71 -0
- package/examples/middleware-usage.js +93 -0
- package/examples/password-reset/README.md +153 -0
- package/examples/password-reset/schema.js +26 -0
- package/examples/password-reset/test.js +101 -0
- package/examples/plugin-system.examples.js +205 -0
- package/examples/simple-example.js +122 -0
- package/examples/string-extensions.js +297 -0
- package/examples/user-registration/README.md +156 -0
- package/examples/user-registration/routes.js +92 -0
- package/examples/user-registration/schema.js +150 -0
- package/examples/user-registration/server.js +74 -0
- package/index.d.ts +1999 -0
- package/index.js +270 -0
- package/index.mjs +30 -0
- package/lib/adapters/DslAdapter.js +653 -0
- package/lib/adapters/index.js +20 -0
- package/lib/config/constants.js +286 -0
- package/lib/config/patterns/creditCard.js +9 -0
- package/lib/config/patterns/idCard.js +9 -0
- package/lib/config/patterns/index.js +8 -0
- package/lib/config/patterns/licensePlate.js +4 -0
- package/lib/config/patterns/passport.js +4 -0
- package/lib/config/patterns/phone.js +9 -0
- package/lib/config/patterns/postalCode.js +5 -0
- package/lib/core/CacheManager.js +376 -0
- package/lib/core/DslBuilder.js +740 -0
- package/lib/core/ErrorCodes.js +233 -0
- package/lib/core/ErrorFormatter.js +342 -0
- package/lib/core/JSONSchemaCore.js +347 -0
- package/lib/core/Locale.js +119 -0
- package/lib/core/MessageTemplate.js +89 -0
- package/lib/core/PluginManager.js +448 -0
- package/lib/core/StringExtensions.js +209 -0
- package/lib/core/Validator.js +316 -0
- package/lib/exporters/MarkdownExporter.js +420 -0
- package/lib/exporters/MongoDBExporter.js +162 -0
- package/lib/exporters/MySQLExporter.js +212 -0
- package/lib/exporters/PostgreSQLExporter.js +289 -0
- package/lib/exporters/index.js +24 -0
- package/lib/locales/en-US.js +65 -0
- package/lib/locales/es-ES.js +66 -0
- package/lib/locales/fr-FR.js +66 -0
- package/lib/locales/index.js +8 -0
- package/lib/locales/ja-JP.js +66 -0
- package/lib/locales/zh-CN.js +93 -0
- package/lib/utils/LRUCache.js +174 -0
- package/lib/utils/SchemaHelper.js +240 -0
- package/lib/utils/SchemaUtils.js +313 -0
- package/lib/utils/TypeConverter.js +245 -0
- package/lib/utils/index.js +13 -0
- package/lib/validators/CustomKeywords.js +203 -0
- package/lib/validators/index.js +11 -0
- package/package.json +70 -0
- package/plugins/custom-format.js +101 -0
- package/plugins/custom-validator.js +200 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# 多语言支持用户指南
|
|
2
|
+
|
|
3
|
+
> **版本**: v2.3.0
|
|
4
|
+
> **更新日期**: 2025-12-29
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📋 目录
|
|
9
|
+
|
|
10
|
+
1. [快速开始](#快速开始)
|
|
11
|
+
2. [配置方式](#配置方式)
|
|
12
|
+
3. [Schema 定义](#schema-定义)
|
|
13
|
+
4. [前端集成](#前端集成)
|
|
14
|
+
5. [最佳实践](#最佳实践)
|
|
15
|
+
6. [常见问题](#常见问题)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 快速开始
|
|
20
|
+
|
|
21
|
+
### 5 分钟上手
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
const { dsl, validate } = require('schema-dsl');
|
|
25
|
+
|
|
26
|
+
// 1. 配置用户语言包
|
|
27
|
+
dsl.config({
|
|
28
|
+
i18n: {
|
|
29
|
+
locales: {
|
|
30
|
+
'zh-CN': {
|
|
31
|
+
'username': '用户名',
|
|
32
|
+
'email': '邮箱地址'
|
|
33
|
+
},
|
|
34
|
+
'en-US': {
|
|
35
|
+
'username': 'Username',
|
|
36
|
+
'email': 'Email Address'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// 2. 定义 Schema(使用 key)
|
|
43
|
+
const schema = dsl({
|
|
44
|
+
username: 'string:3-32!'.label('username'),
|
|
45
|
+
email: 'email!'.label('email')
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// 3. 验证(动态切换语言)
|
|
49
|
+
const result = validate(schema, data, { locale: 'zh-CN' });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 配置方式
|
|
55
|
+
|
|
56
|
+
### 方式 1:直接传入对象(推荐小型项目)
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
dsl.config({
|
|
60
|
+
i18n: {
|
|
61
|
+
locales: {
|
|
62
|
+
'zh-CN': {
|
|
63
|
+
'username': '用户名',
|
|
64
|
+
'email': '邮箱地址',
|
|
65
|
+
'custom.invalidEmail': '邮箱格式不正确'
|
|
66
|
+
},
|
|
67
|
+
'en-US': {
|
|
68
|
+
'username': 'Username',
|
|
69
|
+
'email': 'Email Address',
|
|
70
|
+
'custom.invalidEmail': 'Invalid email format'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**优点**:
|
|
78
|
+
- ✅ 简单直接
|
|
79
|
+
- ✅ 适合小型项目
|
|
80
|
+
- ✅ 无需额外文件
|
|
81
|
+
|
|
82
|
+
**缺点**:
|
|
83
|
+
- ❌ 语言包较大时代码臃肿
|
|
84
|
+
- ❌ 不利于维护
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### 方式 2:从目录加载(推荐大型项目)
|
|
89
|
+
|
|
90
|
+
**目录结构**:
|
|
91
|
+
```
|
|
92
|
+
project/
|
|
93
|
+
├── i18n/
|
|
94
|
+
│ └── labels/
|
|
95
|
+
│ ├── zh-CN.js
|
|
96
|
+
│ ├── en-US.js
|
|
97
|
+
│ └── ja-JP.js
|
|
98
|
+
├── app.js
|
|
99
|
+
└── routes/
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**配置**:
|
|
103
|
+
```javascript
|
|
104
|
+
const path = require('path');
|
|
105
|
+
|
|
106
|
+
dsl.config({
|
|
107
|
+
i18n: {
|
|
108
|
+
localesPath: path.join(__dirname, 'i18n/labels')
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**语言包文件**(`i18n/labels/zh-CN.js`):
|
|
114
|
+
```javascript
|
|
115
|
+
module.exports = {
|
|
116
|
+
// 字段标签
|
|
117
|
+
'username': '用户名',
|
|
118
|
+
'email': '邮箱地址',
|
|
119
|
+
'password': '密码',
|
|
120
|
+
'age': '年龄',
|
|
121
|
+
|
|
122
|
+
// 嵌套字段
|
|
123
|
+
'address.city': '城市',
|
|
124
|
+
'address.street': '街道',
|
|
125
|
+
|
|
126
|
+
// 自定义错误消息
|
|
127
|
+
'custom.invalidEmail': '邮箱格式不正确',
|
|
128
|
+
'custom.emailTaken': '该邮箱已被注册'
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**优点**:
|
|
133
|
+
- ✅ 清晰维护
|
|
134
|
+
- ✅ 支持大型项目
|
|
135
|
+
- ✅ 易于协作
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### 缓存配置(可选)
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
dsl.config({
|
|
143
|
+
cache: {
|
|
144
|
+
maxSize: 10000, // 缓存最大条目数
|
|
145
|
+
ttl: 7200000 // 缓存过期时间(ms)
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**推荐配置**:
|
|
151
|
+
|
|
152
|
+
| 项目规模 | maxSize | 说明 |
|
|
153
|
+
|---------|---------|------|
|
|
154
|
+
| 小型(< 100 Schema) | 1000(默认) | 够用 |
|
|
155
|
+
| 中型(100-1000) | 5000(默认) | 推荐 |
|
|
156
|
+
| 大型(1000-5000) | 10000 | 推荐 |
|
|
157
|
+
| 超大型(> 5000) | 20000 | 推荐 |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Schema 定义
|
|
162
|
+
|
|
163
|
+
### 使用 key 引用语言包
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
const userSchema = dsl({
|
|
167
|
+
// label 使用 key
|
|
168
|
+
username: 'string:3-32!'.label('username'),
|
|
169
|
+
email: 'email!'.label('email'),
|
|
170
|
+
|
|
171
|
+
// messages 使用 key
|
|
172
|
+
password: 'string:8-32!'.label('password').messages({
|
|
173
|
+
'minLength': 'custom.passwordWeak'
|
|
174
|
+
})
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 嵌套字段
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
const addressSchema = dsl({
|
|
182
|
+
address: dsl({
|
|
183
|
+
city: 'string!'.label('address.city'),
|
|
184
|
+
street: 'string!'.label('address.street'),
|
|
185
|
+
zipCode: 'string!'.label('address.zipCode')
|
|
186
|
+
})
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**语言包**:
|
|
191
|
+
```javascript
|
|
192
|
+
{
|
|
193
|
+
'address.city': '城市',
|
|
194
|
+
'address.street': '街道',
|
|
195
|
+
'address.zipCode': '邮编'
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 前端集成
|
|
202
|
+
|
|
203
|
+
### Express 中间件
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
const express = require('express');
|
|
207
|
+
const { validate } = require('schema-dsl');
|
|
208
|
+
|
|
209
|
+
const app = express();
|
|
210
|
+
app.use(express.json());
|
|
211
|
+
|
|
212
|
+
// 中间件:提取语言参数
|
|
213
|
+
app.use((req, res, next) => {
|
|
214
|
+
req.locale = req.headers['accept-language'] ||
|
|
215
|
+
req.query.lang ||
|
|
216
|
+
'zh-CN';
|
|
217
|
+
next();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// API 路由
|
|
221
|
+
app.post('/api/register', (req, res) => {
|
|
222
|
+
// 使用全局 validate,传递 locale
|
|
223
|
+
const result = validate(userSchema, req.body, {
|
|
224
|
+
locale: req.locale
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
if (!result.valid) {
|
|
228
|
+
return res.status(400).json({
|
|
229
|
+
success: false,
|
|
230
|
+
errors: result.errors
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
res.json({ success: true });
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### React 集成
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
import { useState } from 'react';
|
|
244
|
+
|
|
245
|
+
function RegisterForm() {
|
|
246
|
+
const [locale, setLocale] = useState('zh-CN');
|
|
247
|
+
const [errors, setErrors] = useState([]);
|
|
248
|
+
|
|
249
|
+
const handleSubmit = async (formData) => {
|
|
250
|
+
const response = await fetch('/api/register', {
|
|
251
|
+
method: 'POST',
|
|
252
|
+
headers: {
|
|
253
|
+
'Content-Type': 'application/json',
|
|
254
|
+
'Accept-Language': locale // ← 传递语言
|
|
255
|
+
},
|
|
256
|
+
body: JSON.stringify(formData)
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const result = await response.json();
|
|
260
|
+
|
|
261
|
+
if (!result.success) {
|
|
262
|
+
setErrors(result.errors); // 错误消息已经是对应语言
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<div>
|
|
268
|
+
{/* 语言切换 */}
|
|
269
|
+
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
|
|
270
|
+
<option value="zh-CN">中文</option>
|
|
271
|
+
<option value="en-US">English</option>
|
|
272
|
+
<option value="ja-JP">日本語</option>
|
|
273
|
+
</select>
|
|
274
|
+
|
|
275
|
+
<form onSubmit={(e) => {
|
|
276
|
+
e.preventDefault();
|
|
277
|
+
handleSubmit({
|
|
278
|
+
username: e.target.username.value,
|
|
279
|
+
email: e.target.email.value
|
|
280
|
+
});
|
|
281
|
+
}}>
|
|
282
|
+
<input name="username" />
|
|
283
|
+
<input name="email" />
|
|
284
|
+
<button type="submit">提交</button>
|
|
285
|
+
</form>
|
|
286
|
+
|
|
287
|
+
{errors.map(err => (
|
|
288
|
+
<div key={err.path}>{err.message}</div>
|
|
289
|
+
))}
|
|
290
|
+
</div>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### Vue 集成
|
|
298
|
+
|
|
299
|
+
```vue
|
|
300
|
+
<template>
|
|
301
|
+
<div>
|
|
302
|
+
<select v-model="locale">
|
|
303
|
+
<option value="zh-CN">中文</option>
|
|
304
|
+
<option value="en-US">English</option>
|
|
305
|
+
</select>
|
|
306
|
+
|
|
307
|
+
<form @submit.prevent="handleSubmit">
|
|
308
|
+
<input v-model="form.username" />
|
|
309
|
+
<input v-model="form.email" />
|
|
310
|
+
<button type="submit">提交</button>
|
|
311
|
+
</form>
|
|
312
|
+
|
|
313
|
+
<div v-for="error in errors" :key="error.path">
|
|
314
|
+
{{ error.message }}
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
</template>
|
|
318
|
+
|
|
319
|
+
<script setup>
|
|
320
|
+
import { ref, reactive } from 'vue';
|
|
321
|
+
|
|
322
|
+
const locale = ref('zh-CN');
|
|
323
|
+
const form = reactive({ username: '', email: '' });
|
|
324
|
+
const errors = ref([]);
|
|
325
|
+
|
|
326
|
+
const handleSubmit = async () => {
|
|
327
|
+
const response = await fetch('/api/register', {
|
|
328
|
+
method: 'POST',
|
|
329
|
+
headers: {
|
|
330
|
+
'Content-Type': 'application/json',
|
|
331
|
+
'Accept-Language': locale.value
|
|
332
|
+
},
|
|
333
|
+
body: JSON.stringify(form)
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const result = await response.json();
|
|
337
|
+
errors.value = result.errors || [];
|
|
338
|
+
};
|
|
339
|
+
</script>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## 最佳实践
|
|
345
|
+
|
|
346
|
+
### 1. 语言包组织
|
|
347
|
+
|
|
348
|
+
**推荐结构**:
|
|
349
|
+
```
|
|
350
|
+
i18n/
|
|
351
|
+
├── labels/ # 字段标签
|
|
352
|
+
│ ├── zh-CN.js
|
|
353
|
+
│ ├── en-US.js
|
|
354
|
+
│ └── ja-JP.js
|
|
355
|
+
└── messages/ # 自定义消息(可选)
|
|
356
|
+
├── zh-CN.js
|
|
357
|
+
└── en-US.js
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 2. 命名规范
|
|
361
|
+
|
|
362
|
+
**字段标签**:
|
|
363
|
+
```javascript
|
|
364
|
+
{
|
|
365
|
+
'username': '用户名', // 简单字段
|
|
366
|
+
'address.city': '城市', // 嵌套字段
|
|
367
|
+
'order.items[0].name': '商品名称' // 数组字段
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**自定义消息**:
|
|
372
|
+
```javascript
|
|
373
|
+
{
|
|
374
|
+
'custom.emailTaken': '邮箱已被注册',
|
|
375
|
+
'custom.passwordWeak': '密码强度不够',
|
|
376
|
+
'custom.orderExpired': '订单已过期'
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### 3. 语言检测优先级
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
// 推荐优先级
|
|
384
|
+
const locale =
|
|
385
|
+
req.query.lang || // 1. URL 参数(最高优先级)
|
|
386
|
+
req.cookies.lang || // 2. Cookie
|
|
387
|
+
req.headers['accept-language'] || // 3. Accept-Language 头
|
|
388
|
+
'zh-CN'; // 4. 默认语言
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### 4. 语言持久化
|
|
392
|
+
|
|
393
|
+
**前端**:
|
|
394
|
+
```javascript
|
|
395
|
+
// 保存用户语言偏好
|
|
396
|
+
localStorage.setItem('userLanguage', locale);
|
|
397
|
+
|
|
398
|
+
// 恢复语言偏好
|
|
399
|
+
const savedLang = localStorage.getItem('userLanguage') || 'zh-CN';
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## 常见问题
|
|
405
|
+
|
|
406
|
+
### Q1: 如何添加新语言?
|
|
407
|
+
|
|
408
|
+
**A**: 创建新的语言包文件并重启应用
|
|
409
|
+
|
|
410
|
+
```javascript
|
|
411
|
+
// i18n/labels/ko-KR.js(韩语)
|
|
412
|
+
module.exports = {
|
|
413
|
+
'username': '사용자 이름',
|
|
414
|
+
'email': '이메일 주소'
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Q2: 如何处理缺失的翻译?
|
|
419
|
+
|
|
420
|
+
**A**: 系统会自动回退
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
查找顺序:
|
|
424
|
+
1. 用户语言包(i18n/labels/zh-CN.js)
|
|
425
|
+
2. 系统语言包(lib/locales/zh-CN.js)
|
|
426
|
+
3. 使用 key 本身
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Q3: 缓存配置对性能有多大影响?
|
|
430
|
+
|
|
431
|
+
**A**: 大型项目提升 3-10 倍
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
场景:3000 个 Schema
|
|
435
|
+
原配置(1000):33% 命中率
|
|
436
|
+
优化后(5000):100% 命中率
|
|
437
|
+
性能提升:3 倍
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Q4: 是否支持动态加载语言包?
|
|
441
|
+
|
|
442
|
+
**A**: 支持,在应用启动后调用 `dsl.config()`
|
|
443
|
+
|
|
444
|
+
```javascript
|
|
445
|
+
// 动态添加语言
|
|
446
|
+
dsl.config({
|
|
447
|
+
i18n: {
|
|
448
|
+
locales: {
|
|
449
|
+
'fr-FR': require('./i18n/fr-FR.js')
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Q5: 如何与其他 i18n 库协同?
|
|
456
|
+
|
|
457
|
+
**A**: 保持语言同步
|
|
458
|
+
|
|
459
|
+
```javascript
|
|
460
|
+
import i18next from 'i18next';
|
|
461
|
+
import { Locale } from 'schema-dsl';
|
|
462
|
+
|
|
463
|
+
// 同时切换两个库的语言
|
|
464
|
+
function changeLanguage(lang) {
|
|
465
|
+
i18next.changeLanguage(lang);
|
|
466
|
+
Locale.setLocale(lang);
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## 相关文档
|
|
473
|
+
|
|
474
|
+
- [API 参考](./api-reference.md)
|
|
475
|
+
- [完整示例](../examples/i18n-full-demo.js)
|
|
476
|
+
- [实际实现说明](./ACTUAL-MULTILANG-IMPLEMENTATION.md)
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## 更新日志
|
|
481
|
+
|
|
482
|
+
### v2.3.0 (2025-12-29)
|
|
483
|
+
|
|
484
|
+
- ✅ 新增 `dsl.config()` 支持用户语言包配置
|
|
485
|
+
- ✅ 优化缓存配置(1000 → 5000)
|
|
486
|
+
- ✅ 支持动态缓存配置
|
|
487
|
+
- ✅ 完善多语言文档和示例
|
|
488
|
+
|