---
title: "i18n 国际化"
description: "NocoBase 插件国际化：locale 目录结构、翻译文件写法、this.t / useT / tExpr 在不同场景的用法。"
keywords: "i18n,国际化,locale,翻译,this.t,useT,tExpr,NocoBase"
---

# i18n 国际化

NocoBase 插件通过 `src/locale/` 目录管理多语言文件。翻译文件写好后，在 Plugin 里用 `this.t()`、在组件里用 `useT()` hook、在 FlowModel 定义里用 `tExpr()` 就能拿到翻译文本。

## 翻译文件

在插件的 `src/locale/` 下按语言创建 JSON 文件，key 是英文原文，value 是对应语言的翻译：

```bash
my-plugin/
└── src/
    └── locale/
        ├── zh-CN.json
        └── en-US.json
```

```json
// src/locale/zh-CN.json
{
  "Hello": "你好",
  "Save": "保存",
  "Your name is {{name}}": "你的名字是 {{name}}",
  "{{count}} February items": "{{count}} 条记录"
}
```

```json
// src/locale/en-US.json
{
  "Hello": "Hello",
  "Save": "Save",
  "Your name is {{name}}": "Your name is {{name}}",
  "{{count}} February items": "{{count}} items"
}
```

几个注意事项：

- **key 用英文原文**，这样即使翻译缺失也能 fallback 到英文
- **变量用双花括号** `{{name}}`，跟 [i18next](https://www.i18next.com/translation-function/interpolation) 的语法一致
- **初次添加语言文件需要重启应用**才能生效，之后修改内容热更新即可
- NocoBase 会自动以插件的**包名**作为翻译的命名空间（namespace），不同插件的翻译不会冲突

## 在 Plugin 中使用：this.t()

在 Plugin 类里，`this.t()` 会**自动注入当前插件的包名作为 namespace**，不需要手动传 `ns`：

```ts
// src/client-v2/plugin.tsx
import { Plugin, Application } from '@nocobase/client-v2';

export class MyPlugin extends Plugin<any, Application> {
  async load() {
    // 自动使用当前插件的包名作为 ns
    console.log(this.t('Hello')); // -> "你好"

    // 注册设置页时用 this.t() 翻译标题
    this.pluginSettingsManager.addMenuItem({
      key: 'my-settings',
      title: this.t('My Settings'),
      icon: 'SettingOutlined',
    });
    this.pluginSettingsManager.addPageTabItem({
      menuKey: 'my-settings',
      key: 'index',
      title: this.t('My Settings'),
      componentLoader: () => import('./pages/MySettingsPage'),
    });
  }
}
```

## 在组件中使用：useT()

在 React 组件里不能直接用 `this.t()`。插件脚手架会自动生成一个 `locale.ts` 文件，里面提供了 `useT()` hook：

```ts
// src/client-v2/locale.ts（脚手架自动生成）
import { tExpr as _tExpr, useFlowEngine } from '@nocobase/flow-engine';
// @ts-ignore
import pkg from './../../package.json';

export function useT() {
  const engine = useFlowEngine();
  return (str: string) => engine.context.t(str, { ns: [pkg.name, 'client'] });
}

export function tExpr(key: string) {
  return _tExpr(key, { ns: [pkg.name, 'client'] });
}
```

在组件里这样用：

```tsx
// src/client-v2/pages/MySettingsPage.tsx
import React from 'react';
import { Button } from 'antd';
import { useT } from '../locale';

export default function MySettingsPage() {
  const t = useT();

  return (
    <div>
      <h2>{t('Hello')}</h2>
      <p>{t('Your name is {{name}}', { name: 'NocoBase' })}</p>
      <Button>{t('Save')}</Button>
    </div>
  );
}
```

`useT()` 返回的 `t` 函数已经绑定了插件的 namespace，直接传 key 就行。

## 在 FlowModel 中使用：tExpr()

`FlowModel.define()` 和 `registerFlow()` 是在模块加载时执行的，此时 i18n 还没初始化，不能直接调用 `t()`。这种场景用 `tExpr()`——它生成一个延迟翻译的表达式字符串，运行时再解析：

```tsx
// src/client-v2/models/MyBlockModel.tsx
import { BlockModel } from '@nocobase/client-v2';
import { tExpr } from '../locale';

export class MyBlockModel extends BlockModel {
  renderComponent() {
    return <div>My custom block</div>;
  }
}

// tExpr 生成类似 '{{t("My block")}}' 的字符串，运行时翻译
MyBlockModel.define({
  label: tExpr('My block'),
});

MyBlockModel.registerFlow({
  key: 'flow1',
  title: tExpr('My Block Settings'),
  on: 'beforeRender',
  steps: {
    editTitle: {
      title: tExpr('Edit Title'),
      uiSchema: {
        title: {
          type: 'string',
          title: tExpr('Title'),
          'x-decorator': 'FormItem',
          'x-component': 'Input',
        },
      },
      handler(ctx, params) {
        ctx.model.props.title = params.title;
      },
    },
  },
});
```

简单来说：`this.t()` 和 `useT()` 用于运行时翻译，`tExpr()` 用于静态定义时的延迟翻译。

:::tip 提示

`tExpr` 有两个来源：插件自动生成的 `locale.ts` 和 `@nocobase/flow-engine`。区别在于 `locale.ts` 里的 `tExpr` 已经绑定了插件的包名作为 namespace，而从 `@nocobase/flow-engine` 直接导入的 `tExpr` 没有 namespace 绑定。**在插件代码里，始终用 `locale.ts` 导出的 `tExpr`**，这样翻译才能正确匹配到插件自己的语言文件。

:::

## 三种用法速查

| 场景 | 用法 | 来源 |
| --- | --- | --- |
| Plugin `load()` 里 | `this.t('key')` | Plugin 基类自带 |
| React 组件里 | `const t = useT(); t('key')` | `locale.ts` |
| FlowModel 静态定义 | `tExpr('key')` | `locale.ts` |

## 相关链接

- [Context → 常用能力 → 国际化](../ctx/common-capabilities#国际化ctxt--ctxi18n) — ctx.t、ctx.i18n 的完整 API 参考
- [语言列表](../../languages) — NocoBase 支持的语言代码完整列表
- [Component 组件开发](./index.md) — 组件中使用 useFlowContext
- [FlowEngine 概述](../flow-engine/index.md) — tExpr 在 FlowModel 中的用法
