---
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 は英語の原文を使用します**。翻訳が欠落していても英語にフォールバックできます
- **変数は二重波括弧** `{{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` には2つのソースがあります：プラグインが自動生成する `locale.ts` と `@nocobase/flow-engine` です。違いは、`locale.ts` の `tExpr` にはプラグインのパッケージ名が namespace としてバインドされていますが、`@nocobase/flow-engine` から直接インポートした `tExpr` には namespace バインドがありません。**プラグインコード内では、常に `locale.ts` からエクスポートされた `tExpr` を使用してください**。これにより翻訳がプラグイン自身の言語ファイルに正しくマッチします。

:::

## 3つの使い方チートシート

| シーン | 使い方 | ソース |
| --- | --- | --- |
| 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) — FlowModel での tExpr の使い方
