schema-dsl 1.1.3 → 1.1.4
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 +75 -1275
- package/README.md +221 -2
- package/STATUS.md +34 -2
- package/changelogs/v1.0.0.md +328 -0
- package/changelogs/v1.0.9.md +367 -0
- package/changelogs/v1.1.0.md +389 -0
- package/changelogs/v1.1.1.md +308 -0
- package/changelogs/v1.1.2.md +183 -0
- package/changelogs/v1.1.3.md +161 -0
- package/changelogs/v1.1.4.md +432 -0
- package/docs/dsl-syntax.md +14 -3
- package/docs/optional-marker-guide.md +321 -0
- package/docs/runtime-locale-support.md +443 -0
- package/index.d.ts +126 -10
- package/index.js +6 -3
- package/index.mjs +2 -2
- package/lib/core/DslBuilder.js +11 -2
- package/lib/errors/I18nError.js +21 -6
- package/package.json +1 -1
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# 运行时多语言支持 - schema-dsl
|
|
2
|
+
|
|
3
|
+
**版本**: v1.1.4+
|
|
4
|
+
**更新日期**: 2026-01-13
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📋 概述
|
|
9
|
+
|
|
10
|
+
schema-dsl 的 `dsl.error` 和 `I18nError` 现在支持**运行时指定语言**,无需修改全局语言设置。
|
|
11
|
+
|
|
12
|
+
这对于 **API 开发**特别有用,可以根据每个请求的语言偏好(如 `Accept-Language` 请求头)动态返回对应语言的错误消息。
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🎯 两种使用方式
|
|
17
|
+
|
|
18
|
+
### 方式 1: 全局语言设置(传统方式)
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const { dsl, Locale } = require('schema-dsl');
|
|
22
|
+
|
|
23
|
+
// 设置全局语言
|
|
24
|
+
Locale.setLocale('zh-CN');
|
|
25
|
+
|
|
26
|
+
// 后续所有错误都使用中文
|
|
27
|
+
const error1 = dsl.error.create('account.notFound');
|
|
28
|
+
console.log(error1.message); // "账户不存在"
|
|
29
|
+
|
|
30
|
+
const error2 = dsl.error.create('user.noPermission');
|
|
31
|
+
console.log(error2.message); // "没有管理员权限"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**适用场景**:
|
|
35
|
+
- 单一语言的应用
|
|
36
|
+
- 不需要动态切换语言
|
|
37
|
+
- 简单的错误处理
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### 方式 2: 运行时指定语言(推荐用于 API)⭐
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
const { dsl, Locale } = require('schema-dsl');
|
|
45
|
+
|
|
46
|
+
// 全局保持默认语言
|
|
47
|
+
Locale.setLocale('zh-CN');
|
|
48
|
+
|
|
49
|
+
// 每次调用时指定语言
|
|
50
|
+
const error1 = dsl.error.create('account.notFound', {}, 404, 'zh-CN');
|
|
51
|
+
console.log(error1.message); // "账户不存在"
|
|
52
|
+
|
|
53
|
+
const error2 = dsl.error.create('account.notFound', {}, 404, 'en-US');
|
|
54
|
+
console.log(error2.message); // "Account not found"
|
|
55
|
+
|
|
56
|
+
const error3 = dsl.error.create('account.notFound', {}, 404, 'ja-JP');
|
|
57
|
+
console.log(error3.message); // "account.notFound"(日语未翻译)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**适用场景**:
|
|
61
|
+
- 多语言 API
|
|
62
|
+
- 根据请求头动态返回多语言错误
|
|
63
|
+
- 同一请求中需要多种语言
|
|
64
|
+
- 微服务架构中的错误传递
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🔧 API 参数
|
|
69
|
+
|
|
70
|
+
### dsl.error.create()
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
dsl.error.create(
|
|
74
|
+
code: string, // 错误代码(如 'account.notFound')
|
|
75
|
+
params?: object, // 参数插值(如 { balance: 50 })
|
|
76
|
+
statusCode?: number, // HTTP 状态码(默认 400)
|
|
77
|
+
locale?: string // 🆕 运行时语言(如 'en-US')
|
|
78
|
+
): I18nError
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### dsl.error.throw()
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
dsl.error.throw(
|
|
85
|
+
code: string,
|
|
86
|
+
params?: object,
|
|
87
|
+
statusCode?: number,
|
|
88
|
+
locale?: string // 🆕 运行时语言
|
|
89
|
+
): never
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### dsl.error.assert()
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
dsl.error.assert(
|
|
96
|
+
condition: any,
|
|
97
|
+
code: string,
|
|
98
|
+
params?: object,
|
|
99
|
+
statusCode?: number,
|
|
100
|
+
locale?: string // 🆕 运行时语言
|
|
101
|
+
): void
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 💡 实际应用场景
|
|
107
|
+
|
|
108
|
+
### 场景 1: Express/Koa 中根据请求头返回多语言错误
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const { dsl } = require('schema-dsl');
|
|
112
|
+
|
|
113
|
+
// Express 中间件
|
|
114
|
+
app.get('/api/account/:id', async (req, res, next) => {
|
|
115
|
+
try {
|
|
116
|
+
const account = await getAccount(req.params.id);
|
|
117
|
+
|
|
118
|
+
// 根据请求头获取语言
|
|
119
|
+
const locale = req.headers['accept-language'] || 'zh-CN';
|
|
120
|
+
|
|
121
|
+
// 使用运行时语言抛出错误
|
|
122
|
+
dsl.error.assert(account, 'account.notFound', {}, 404, locale);
|
|
123
|
+
|
|
124
|
+
res.json(account);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof I18nError) {
|
|
127
|
+
return res.status(error.statusCode).json(error.toJSON());
|
|
128
|
+
}
|
|
129
|
+
next(error);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// 请求示例
|
|
134
|
+
// 中文客户端: Accept-Language: zh-CN
|
|
135
|
+
// 响应: { "code": "account.notFound", "message": "账户不存在", ... }
|
|
136
|
+
|
|
137
|
+
// 英文客户端: Accept-Language: en-US
|
|
138
|
+
// 响应: { "code": "account.notFound", "message": "Account not found", ... }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### 场景 2: 微服务架构中的错误传递
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const { dsl } = require('schema-dsl');
|
|
147
|
+
|
|
148
|
+
// 服务 A: 用户服务
|
|
149
|
+
async function getUserService(userId, locale) {
|
|
150
|
+
const user = await db.findUser(userId);
|
|
151
|
+
|
|
152
|
+
// 传递 locale 到错误
|
|
153
|
+
dsl.error.assert(user, 'user.notFound', { userId }, 404, locale);
|
|
154
|
+
|
|
155
|
+
return user;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 服务 B: API 网关
|
|
159
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
160
|
+
try {
|
|
161
|
+
const locale = req.headers['accept-language'] || 'zh-CN';
|
|
162
|
+
|
|
163
|
+
// 调用用户服务,传递 locale
|
|
164
|
+
const user = await getUserService(req.params.id, locale);
|
|
165
|
+
|
|
166
|
+
res.json(user);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
// 错误已经是正确的语言
|
|
169
|
+
res.status(error.statusCode).json(error.toJSON());
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 场景 3: 同一请求中使用多种语言
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
const { dsl } = require('schema-dsl');
|
|
180
|
+
|
|
181
|
+
// 批量验证,为不同用户返回不同语言的错误
|
|
182
|
+
async function batchValidateAccounts(requests) {
|
|
183
|
+
const results = [];
|
|
184
|
+
|
|
185
|
+
for (const req of requests) {
|
|
186
|
+
try {
|
|
187
|
+
const account = await getAccount(req.accountId);
|
|
188
|
+
|
|
189
|
+
// 每个用户使用各自的语言偏好
|
|
190
|
+
dsl.error.assert(
|
|
191
|
+
account.balance >= req.amount,
|
|
192
|
+
'account.insufficientBalance',
|
|
193
|
+
{ balance: account.balance, required: req.amount },
|
|
194
|
+
400,
|
|
195
|
+
req.locale // 每个用户的语言偏好
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
results.push({ success: true, accountId: req.accountId });
|
|
199
|
+
} catch (error) {
|
|
200
|
+
results.push({
|
|
201
|
+
success: false,
|
|
202
|
+
accountId: req.accountId,
|
|
203
|
+
error: error.toJSON() // 错误已经是对应用户的语言
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return results;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 调用示例
|
|
212
|
+
const results = await batchValidateAccounts([
|
|
213
|
+
{ accountId: '001', amount: 100, locale: 'zh-CN' }, // 中文用户
|
|
214
|
+
{ accountId: '002', amount: 200, locale: 'en-US' }, // 英文用户
|
|
215
|
+
{ accountId: '003', amount: 300, locale: 'ja-JP' } // 日文用户
|
|
216
|
+
]);
|
|
217
|
+
|
|
218
|
+
// 结果:每个用户收到对应语言的错误消息
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### 场景 4: GraphQL Resolver 中的多语言错误
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
const { dsl } = require('schema-dsl');
|
|
227
|
+
|
|
228
|
+
const resolvers = {
|
|
229
|
+
Query: {
|
|
230
|
+
account: async (_, { id }, context) => {
|
|
231
|
+
// 从 context 获取用户语言偏好
|
|
232
|
+
const locale = context.user?.locale || 'zh-CN';
|
|
233
|
+
|
|
234
|
+
const account = await getAccount(id);
|
|
235
|
+
|
|
236
|
+
// 使用运行时语言
|
|
237
|
+
dsl.error.assert(account, 'account.notFound', {}, 404, locale);
|
|
238
|
+
|
|
239
|
+
return account;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🔍 运行时语言 vs 全局语言
|
|
248
|
+
|
|
249
|
+
### 对比表
|
|
250
|
+
|
|
251
|
+
| 特性 | 全局语言 | 运行时语言 |
|
|
252
|
+
|------|---------|-----------|
|
|
253
|
+
| 设置方式 | `Locale.setLocale('zh-CN')` | `dsl.error.create(..., locale)` |
|
|
254
|
+
| 影响范围 | 全局所有错误 | 仅当前错误 |
|
|
255
|
+
| 是否改变全局状态 | ✅ 是 | ❌ 否 |
|
|
256
|
+
| 适用场景 | 单一语言应用 | 多语言 API |
|
|
257
|
+
| 并发安全 | ⚠️ 需注意 | ✅ 完全安全 |
|
|
258
|
+
| 推荐用于 | 简单应用 | API/微服务 |
|
|
259
|
+
|
|
260
|
+
### 并发安全性
|
|
261
|
+
|
|
262
|
+
**全局语言**(不推荐用于多语言 API):
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
// ❌ 并发不安全
|
|
266
|
+
app.get('/api/account/:id', async (req, res) => {
|
|
267
|
+
// 修改全局状态
|
|
268
|
+
Locale.setLocale(req.headers['accept-language']);
|
|
269
|
+
|
|
270
|
+
// 如果同时有多个请求,语言会互相干扰
|
|
271
|
+
const error = dsl.error.create('account.notFound');
|
|
272
|
+
// 错误消息可能是错误的语言!
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**运行时语言**(推荐):
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
// ✅ 并发安全
|
|
280
|
+
app.get('/api/account/:id', async (req, res) => {
|
|
281
|
+
const locale = req.headers['accept-language'];
|
|
282
|
+
|
|
283
|
+
// 不修改全局状态,每个请求独立
|
|
284
|
+
const error = dsl.error.create('account.notFound', {}, 404, locale);
|
|
285
|
+
// 错误消息始终是正确的语言
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 📊 测试验证
|
|
292
|
+
|
|
293
|
+
### 运行时语言测试
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
const { dsl, Locale } = require('schema-dsl');
|
|
297
|
+
|
|
298
|
+
// 设置全局为中文
|
|
299
|
+
Locale.setLocale('zh-CN');
|
|
300
|
+
|
|
301
|
+
// 测试1: 运行时指定不同语言
|
|
302
|
+
const error1 = dsl.error.create('account.notFound', {}, 404, 'zh-CN');
|
|
303
|
+
const error2 = dsl.error.create('account.notFound', {}, 404, 'en-US');
|
|
304
|
+
const error3 = dsl.error.create('account.notFound', {}, 404, 'ja-JP');
|
|
305
|
+
|
|
306
|
+
console.log(error1.message); // "账户不存在"
|
|
307
|
+
console.log(error2.message); // "Account not found"
|
|
308
|
+
console.log(error3.message); // "account.notFound"
|
|
309
|
+
|
|
310
|
+
// 测试2: 验证全局语言未被改变
|
|
311
|
+
const currentLocale = Locale.getLocale();
|
|
312
|
+
console.log(currentLocale); // "zh-CN"
|
|
313
|
+
|
|
314
|
+
const error4 = dsl.error.create('user.noPermission'); // 不指定locale
|
|
315
|
+
console.log(error4.message); // "没有管理员权限"(使用全局语言)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 带参数的运行时语言
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
const error1 = dsl.error.create(
|
|
322
|
+
'account.insufficientBalance',
|
|
323
|
+
{ balance: 50, required: 100 },
|
|
324
|
+
400,
|
|
325
|
+
'zh-CN'
|
|
326
|
+
);
|
|
327
|
+
console.log(error1.message); // "余额不足,当前余额50,需要100"
|
|
328
|
+
|
|
329
|
+
const error2 = dsl.error.create(
|
|
330
|
+
'account.insufficientBalance',
|
|
331
|
+
{ balance: 50, required: 100 },
|
|
332
|
+
400,
|
|
333
|
+
'en-US'
|
|
334
|
+
);
|
|
335
|
+
console.log(error2.message); // "Insufficient balance, current: 50, required: 100"
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 🎯 最佳实践
|
|
341
|
+
|
|
342
|
+
### 1. API 开发中始终使用运行时语言
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
// ✅ 推荐
|
|
346
|
+
app.get('/api/account/:id', async (req, res) => {
|
|
347
|
+
const locale = req.headers['accept-language'] || 'zh-CN';
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
const account = await getAccount(req.params.id);
|
|
351
|
+
dsl.error.assert(account, 'account.notFound', {}, 404, locale);
|
|
352
|
+
res.json(account);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
res.status(error.statusCode).json(error.toJSON());
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// ❌ 不推荐
|
|
359
|
+
app.get('/api/account/:id', async (req, res) => {
|
|
360
|
+
Locale.setLocale(req.headers['accept-language']); // 并发不安全
|
|
361
|
+
// ...
|
|
362
|
+
});
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 2. 统一封装语言获取逻辑
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
// 工具函数
|
|
369
|
+
function getUserLocale(req) {
|
|
370
|
+
return req.user?.locale ||
|
|
371
|
+
req.headers['accept-language'] ||
|
|
372
|
+
'zh-CN';
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// 在业务代码中使用
|
|
376
|
+
app.get('/api/account/:id', async (req, res) => {
|
|
377
|
+
const locale = getUserLocale(req);
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
const account = await getAccount(req.params.id);
|
|
381
|
+
dsl.error.assert(account, 'account.notFound', {}, 404, locale);
|
|
382
|
+
res.json(account);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
res.status(error.statusCode).json(error.toJSON());
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### 3. 在微服务间传递 locale
|
|
390
|
+
|
|
391
|
+
```javascript
|
|
392
|
+
// 服务 A: 底层服务
|
|
393
|
+
async function getUser(userId, options = {}) {
|
|
394
|
+
const user = await db.findUser(userId);
|
|
395
|
+
|
|
396
|
+
dsl.error.assert(
|
|
397
|
+
user,
|
|
398
|
+
'user.notFound',
|
|
399
|
+
{ userId },
|
|
400
|
+
404,
|
|
401
|
+
options.locale // 接收 locale 参数
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
return user;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 服务 B: API 网关
|
|
408
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
409
|
+
const locale = getUserLocale(req);
|
|
410
|
+
|
|
411
|
+
try {
|
|
412
|
+
const user = await getUser(req.params.id, { locale });
|
|
413
|
+
res.json(user);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
res.status(error.statusCode).json(error.toJSON());
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 📝 向后兼容
|
|
423
|
+
|
|
424
|
+
✅ **完全向后兼容**
|
|
425
|
+
|
|
426
|
+
- 现有代码无需修改
|
|
427
|
+
- `locale` 参数为可选参数
|
|
428
|
+
- 不传 `locale` 时使用全局语言
|
|
429
|
+
- 所有单元测试通过(949/949)
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## 🔗 相关文档
|
|
434
|
+
|
|
435
|
+
- [多语言配置指南](./i18n.md)
|
|
436
|
+
- [错误处理完整指南](./error-handling.md)
|
|
437
|
+
- [I18nError API 参考](./api-reference.md)
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
**最后更新**: 2026-01-13
|
|
442
|
+
**作者**: schema-dsl Team
|
|
443
|
+
|
package/index.d.ts
CHANGED
|
@@ -285,13 +285,24 @@ export class DslBuilder {
|
|
|
285
285
|
|
|
286
286
|
/**
|
|
287
287
|
* 构造函数
|
|
288
|
-
* @param dslString - DSL字符串(如 'email!', 'string:3-32!', 'types:string|number')
|
|
288
|
+
* @param dslString - DSL字符串(如 'email!', 'string:3-32!', 'string?', 'types:string|number')
|
|
289
289
|
*
|
|
290
290
|
* @example 基础类型
|
|
291
291
|
* ```typescript
|
|
292
|
-
* const builder = new DslBuilder('email!');
|
|
293
|
-
* const builder2 = new DslBuilder('string:3-32');
|
|
294
|
-
* const builder3 = new DslBuilder('
|
|
292
|
+
* const builder = new DslBuilder('email!'); // 必填邮箱
|
|
293
|
+
* const builder2 = new DslBuilder('string:3-32'); // 可选字符串(默认)
|
|
294
|
+
* const builder3 = new DslBuilder('string?'); // 显式可选字符串
|
|
295
|
+
* const builder4 = new DslBuilder('email?'); // 显式可选邮箱
|
|
296
|
+
* const builder5 = new DslBuilder('types:string|number'); // 联合类型
|
|
297
|
+
* ```
|
|
298
|
+
*
|
|
299
|
+
* @example 必填与可选标记
|
|
300
|
+
* ```typescript
|
|
301
|
+
* new DslBuilder('string!') // 必填字符串
|
|
302
|
+
* new DslBuilder('string') // 可选字符串(默认)
|
|
303
|
+
* new DslBuilder('string?') // 显式可选字符串
|
|
304
|
+
* new DslBuilder('email?') // 可选邮箱
|
|
305
|
+
* new DslBuilder('string:3-32?') // 可选字符串,长度3-32
|
|
295
306
|
* ```
|
|
296
307
|
*
|
|
297
308
|
* @example 数字类型比较运算符 (v1.1.2+)
|
|
@@ -317,6 +328,7 @@ export class DslBuilder {
|
|
|
317
328
|
* // 配合必填标记
|
|
318
329
|
* new DslBuilder('number:>=18!') // 必填且 >= 18
|
|
319
330
|
* new DslBuilder('number:>0!') // 必填且 > 0
|
|
331
|
+
* new DslBuilder('number:>0?') // 可选且 > 0(当有值时)
|
|
320
332
|
* ```
|
|
321
333
|
*/
|
|
322
334
|
constructor(dslString: string);
|
|
@@ -1254,12 +1266,26 @@ export namespace dsl {
|
|
|
1254
1266
|
* @param code - 错误代码(多语言 key)
|
|
1255
1267
|
* @param params - 错误参数
|
|
1256
1268
|
* @param statusCode - HTTP 状态码
|
|
1269
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1257
1270
|
* @returns 错误实例
|
|
1271
|
+
*
|
|
1272
|
+
* @example 全局语言
|
|
1273
|
+
* ```typescript
|
|
1274
|
+
* Locale.setLocale('zh-CN');
|
|
1275
|
+
* const error = dsl.error.create('account.notFound');
|
|
1276
|
+
* ```
|
|
1277
|
+
*
|
|
1278
|
+
* @example 运行时指定语言
|
|
1279
|
+
* ```typescript
|
|
1280
|
+
* const error1 = dsl.error.create('account.notFound', {}, 404, 'zh-CN');
|
|
1281
|
+
* const error2 = dsl.error.create('account.notFound', {}, 404, 'en-US');
|
|
1282
|
+
* ```
|
|
1258
1283
|
*/
|
|
1259
1284
|
create(
|
|
1260
1285
|
code: string,
|
|
1261
1286
|
params?: Record<string, any>,
|
|
1262
|
-
statusCode?: number
|
|
1287
|
+
statusCode?: number,
|
|
1288
|
+
locale?: string
|
|
1263
1289
|
): I18nError;
|
|
1264
1290
|
|
|
1265
1291
|
/**
|
|
@@ -1267,12 +1293,25 @@ export namespace dsl {
|
|
|
1267
1293
|
* @param code - 错误代码(多语言 key)
|
|
1268
1294
|
* @param params - 错误参数
|
|
1269
1295
|
* @param statusCode - HTTP 状态码
|
|
1296
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1270
1297
|
* @throws I18nError
|
|
1298
|
+
*
|
|
1299
|
+
* @example 全局语言
|
|
1300
|
+
* ```typescript
|
|
1301
|
+
* Locale.setLocale('zh-CN');
|
|
1302
|
+
* dsl.error.throw('account.notFound');
|
|
1303
|
+
* ```
|
|
1304
|
+
*
|
|
1305
|
+
* @example 运行时指定语言
|
|
1306
|
+
* ```typescript
|
|
1307
|
+
* dsl.error.throw('account.notFound', {}, 404, 'en-US');
|
|
1308
|
+
* ```
|
|
1271
1309
|
*/
|
|
1272
1310
|
throw(
|
|
1273
1311
|
code: string,
|
|
1274
1312
|
params?: Record<string, any>,
|
|
1275
|
-
statusCode?: number
|
|
1313
|
+
statusCode?: number,
|
|
1314
|
+
locale?: string
|
|
1276
1315
|
): never;
|
|
1277
1316
|
|
|
1278
1317
|
/**
|
|
@@ -1281,13 +1320,26 @@ export namespace dsl {
|
|
|
1281
1320
|
* @param code - 错误代码(多语言 key)
|
|
1282
1321
|
* @param params - 错误参数
|
|
1283
1322
|
* @param statusCode - HTTP 状态码
|
|
1323
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1284
1324
|
* @throws I18nError 条件为 false 时抛出
|
|
1325
|
+
*
|
|
1326
|
+
* @example 全局语言
|
|
1327
|
+
* ```typescript
|
|
1328
|
+
* Locale.setLocale('zh-CN');
|
|
1329
|
+
* dsl.error.assert(account, 'account.notFound');
|
|
1330
|
+
* ```
|
|
1331
|
+
*
|
|
1332
|
+
* @example 运行时指定语言
|
|
1333
|
+
* ```typescript
|
|
1334
|
+
* dsl.error.assert(account, 'account.notFound', {}, 404, 'en-US');
|
|
1335
|
+
* ```
|
|
1285
1336
|
*/
|
|
1286
1337
|
assert(
|
|
1287
1338
|
condition: any,
|
|
1288
1339
|
code: string,
|
|
1289
1340
|
params?: Record<string, any>,
|
|
1290
|
-
statusCode?: number
|
|
1341
|
+
statusCode?: number,
|
|
1342
|
+
locale?: string
|
|
1291
1343
|
): asserts condition;
|
|
1292
1344
|
};
|
|
1293
1345
|
}
|
|
@@ -1679,12 +1731,30 @@ export class I18nError extends Error {
|
|
|
1679
1731
|
* @param code - 错误代码
|
|
1680
1732
|
* @param params - 错误参数
|
|
1681
1733
|
* @param statusCode - HTTP 状态码
|
|
1734
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1682
1735
|
* @returns 错误实例
|
|
1736
|
+
*
|
|
1737
|
+
* @example 全局语言
|
|
1738
|
+
* ```typescript
|
|
1739
|
+
* Locale.setLocale('zh-CN');
|
|
1740
|
+
* const error = I18nError.create('account.notFound');
|
|
1741
|
+
* // message: "账户不存在"
|
|
1742
|
+
* ```
|
|
1743
|
+
*
|
|
1744
|
+
* @example 运行时指定语言
|
|
1745
|
+
* ```typescript
|
|
1746
|
+
* const error1 = I18nError.create('account.notFound', {}, 404, 'zh-CN');
|
|
1747
|
+
* // message: "账户不存在"
|
|
1748
|
+
*
|
|
1749
|
+
* const error2 = I18nError.create('account.notFound', {}, 404, 'en-US');
|
|
1750
|
+
* // message: "Account not found"
|
|
1751
|
+
* ```
|
|
1683
1752
|
*/
|
|
1684
1753
|
static create(
|
|
1685
1754
|
code: string,
|
|
1686
1755
|
params?: Record<string, any>,
|
|
1687
|
-
statusCode?: number
|
|
1756
|
+
statusCode?: number,
|
|
1757
|
+
locale?: string
|
|
1688
1758
|
): I18nError;
|
|
1689
1759
|
|
|
1690
1760
|
/**
|
|
@@ -1692,12 +1762,25 @@ export class I18nError extends Error {
|
|
|
1692
1762
|
* @param code - 错误代码
|
|
1693
1763
|
* @param params - 错误参数
|
|
1694
1764
|
* @param statusCode - HTTP 状态码
|
|
1765
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1695
1766
|
* @throws I18nError
|
|
1767
|
+
*
|
|
1768
|
+
* @example 全局语言
|
|
1769
|
+
* ```typescript
|
|
1770
|
+
* Locale.setLocale('zh-CN');
|
|
1771
|
+
* I18nError.throw('account.notFound');
|
|
1772
|
+
* ```
|
|
1773
|
+
*
|
|
1774
|
+
* @example 运行时指定语言
|
|
1775
|
+
* ```typescript
|
|
1776
|
+
* I18nError.throw('account.notFound', {}, 404, 'en-US');
|
|
1777
|
+
* ```
|
|
1696
1778
|
*/
|
|
1697
1779
|
static throw(
|
|
1698
1780
|
code: string,
|
|
1699
1781
|
params?: Record<string, any>,
|
|
1700
|
-
statusCode?: number
|
|
1782
|
+
statusCode?: number,
|
|
1783
|
+
locale?: string
|
|
1701
1784
|
): never;
|
|
1702
1785
|
|
|
1703
1786
|
/**
|
|
@@ -1706,13 +1789,46 @@ export class I18nError extends Error {
|
|
|
1706
1789
|
* @param code - 错误代码
|
|
1707
1790
|
* @param params - 错误参数
|
|
1708
1791
|
* @param statusCode - HTTP 状态码
|
|
1792
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1793
|
+
* @throws I18nError 条件为 false 时抛出
|
|
1794
|
+
*
|
|
1795
|
+
* @example 全局语言
|
|
1796
|
+
* ```typescript
|
|
1797
|
+
* Locale.setLocale('zh-CN');
|
|
1798
|
+
* I18nError.assert(account, 'account.notFound');
|
|
1799
|
+
* ```
|
|
1800
|
+
*
|
|
1801
|
+
* @example 运行时指定语言
|
|
1802
|
+
* ```typescript
|
|
1803
|
+
* I18nError.assert(account, 'account.notFound', {}, 404, 'en-US');
|
|
1804
|
+
* ```
|
|
1805
|
+
*/
|
|
1806
|
+
/**
|
|
1807
|
+
* 断言方法 - 条件不满足时抛错
|
|
1808
|
+
* @param condition - 条件表达式
|
|
1809
|
+
* @param code - 错误代码
|
|
1810
|
+
* @param params - 错误参数
|
|
1811
|
+
* @param statusCode - HTTP 状态码
|
|
1812
|
+
* @param locale - 语言环境(可选,不传则使用全局语言)
|
|
1709
1813
|
* @throws I18nError 条件为 false 时抛出
|
|
1814
|
+
*
|
|
1815
|
+
* @example 全局语言
|
|
1816
|
+
* ```typescript
|
|
1817
|
+
* Locale.setLocale('zh-CN');
|
|
1818
|
+
* I18nError.assert(account, 'account.notFound');
|
|
1819
|
+
* ```
|
|
1820
|
+
*
|
|
1821
|
+
* @example 运行时指定语言
|
|
1822
|
+
* ```typescript
|
|
1823
|
+
* I18nError.assert(account, 'account.notFound', {}, 404, 'en-US');
|
|
1824
|
+
* ```
|
|
1710
1825
|
*/
|
|
1711
1826
|
static assert(
|
|
1712
1827
|
condition: any,
|
|
1713
1828
|
code: string,
|
|
1714
1829
|
params?: Record<string, any>,
|
|
1715
|
-
statusCode?: number
|
|
1830
|
+
statusCode?: number,
|
|
1831
|
+
locale?: string
|
|
1716
1832
|
): asserts condition;
|
|
1717
1833
|
|
|
1718
1834
|
/**
|
package/index.js
CHANGED
|
@@ -59,18 +59,20 @@ dsl.error = {
|
|
|
59
59
|
* @param {string} code - 错误代码(多语言 key)
|
|
60
60
|
* @param {Object} params - 错误参数
|
|
61
61
|
* @param {number} statusCode - HTTP 状态码
|
|
62
|
+
* @param {string} locale - 语言环境(可选,不传则使用全局语言)
|
|
62
63
|
* @returns {I18nError} 错误实例
|
|
63
64
|
*/
|
|
64
|
-
create: (code, params, statusCode) => I18nError.create(code, params, statusCode),
|
|
65
|
+
create: (code, params, statusCode, locale) => I18nError.create(code, params, statusCode, locale),
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
68
|
* 抛出多语言错误
|
|
68
69
|
* @param {string} code - 错误代码(多语言 key)
|
|
69
70
|
* @param {Object} params - 错误参数
|
|
70
71
|
* @param {number} statusCode - HTTP 状态码
|
|
72
|
+
* @param {string} locale - 语言环境(可选,不传则使用全局语言)
|
|
71
73
|
* @throws {I18nError} 直接抛出错误
|
|
72
74
|
*/
|
|
73
|
-
throw: (code, params, statusCode) => I18nError.throw(code, params, statusCode),
|
|
75
|
+
throw: (code, params, statusCode, locale) => I18nError.throw(code, params, statusCode, locale),
|
|
74
76
|
|
|
75
77
|
/**
|
|
76
78
|
* 断言方法 - 条件不满足时抛错
|
|
@@ -78,8 +80,9 @@ dsl.error = {
|
|
|
78
80
|
* @param {string} code - 错误代码(多语言 key)
|
|
79
81
|
* @param {Object} params - 错误参数
|
|
80
82
|
* @param {number} statusCode - HTTP 状态码
|
|
83
|
+
* @param {string} locale - 语言环境(可选,不传则使用全局语言)
|
|
81
84
|
*/
|
|
82
|
-
assert: (condition, code, params, statusCode) => I18nError.assert(condition, code, params, statusCode)
|
|
85
|
+
assert: (condition, code, params, statusCode, locale) => I18nError.assert(condition, code, params, statusCode, locale)
|
|
83
86
|
};
|
|
84
87
|
|
|
85
88
|
/**
|
package/index.mjs
CHANGED