tachybase_todo/docs/zh-CN/development/server/i18n.md
2022-11-06 14:15:05 +08:00

135 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 国际化
NocoBase 国际化基于 [i18next](https://npmjs.com/package/i18next) 实现。
## 如何注册多语言包?
```ts
export class MyPlugin extends Plugin {
load() {
this.app.i18n.addResources('zh-CN', 'test', {
Hello: '你好',
World: '世界',
});
this.app.i18n.addResources('en-US', 'test', {
Hello: 'Hello',
World: 'World',
});
}
}
```
## 两个 i18n 实例
### app.i18n
全局 i18n 实例,一般用于 CLI 中。
```ts
app.i18n.t('World') // “世界”或“World”
```
### ctx.i18n
全局 i18n 的 cloneInstance每个请求的 context 完全独立,通常用于根据客户端语言响应多语言信息。
```ts
app.use(async (ctx, next) => {
ctx.body = `${ctx.i18n.t('Hello')} ${ctx.i18n.t('World')}`;
await next();
});
```
客户端请求参数可以放在 query string 里
```bash
GET /?locale=en-US HTTP/1.1
Host: localhost:13000
```
或放在 request headers 里
```bash
GET / HTTP/1.1
Host: localhost:13000
X-Locale: en-US
```
## 建议配置
以英文文案为 key翻译为 value这样的好处即使多语言缺失也会以英文显示不会造成阅读障碍
```ts
i18n.addResources('zh-CN', 'your-namespace', {
'Show dialog': '显示对话框',
'Hide dialog': '隐藏对话框'
});
```
为了更方便管理多语言文件,推荐在插件中创建一个 `locale` 文件夹,并把对应语言文件都放置在其中:
```bash
|- /my-plugin
|- /src
|- /server
|- locale # 多语言文件夹
|- zh-CN.ts
|- en-US.ts
```
## 示例
### 服务端错误提示
例如用户在店铺对某个商品下单时,如果商品的库存不够,或者未上架,那么下单接口被调用时,应该返回相应的错误。
```ts
const namespace = 'shop';
export default class ShopPlugin extends Plugin {
async load() {
this.app.i18n.addResources('zh-CN', namespace, {
'No such product': '商品不存在',
'Product not on sale': '商品已下架',
'Out of stock': '库存不足',
});
this.app.resource({
name: 'orders',
actions: {
async create(ctx, next) {
const productRepo = ctx.db.getRepository('products');
const product = await productRepo.findOne({
filterByTk: ctx.action.params.values.productId
});
if (!product) {
return ctx.throw(404, ctx.t('No such product'));
}
if (!product.enabled) {
return ctx.throw(400, ctx.t('Product not on sale'));
}
if (!product.inventory) {
return ctx.throw(400, ctx.t('Out of stock'));
}
const orderRepo = ctx.db.getRepository('orders');
ctx.body = await orderRepo.create({
values: {
productId: product.id,
quantity: 1,
totalPrice: product.price,
userId: ctx.state.currentUser.id
}
});
next();
}
}
});
}
}
```