# General Translation Knowledge Base: i18nは自前で構築すべきか、General Translationを使うべきか
URL: https://generaltranslation.com/ja/kb/general-translation-vs-in-house-i18n.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 自前のi18n（言語ごとの辞書と小さな t() ヘルパー）は、対応言語が1〜2つで文言も少ないうちは十分に機能します。しかしアプリが成長するにつれて、複数形規則、フォールバック、ファイルの同期を自分で作り直すことになり、そのうえ翻訳そのものも用意しなければなりません。General Translationのオープンソースライブラリがレンダリングを担い、General Translationがコードから翻訳を生成・更新します。
Category: 国際化
Last updated: 2026-10-16
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-16

国際化 (i18n) は自前でも構築できます。言語ごとのメッセージオブジェクト、キーを引いて変数を埋め込む `t()` ヘルパー、ロケール切り替え、そして数値や日付を扱う組み込みの `Intl` API があれば実現できます。対応言語が1〜2つ、文字列が数十程度なら、たいていはこれで十分です。コーディングエージェントに言語の追加を頼んだときに書かれるのも、多くの場合この形です。アプリの成長とともに膨らんでいくのは、ヘルパーを取り巻くあらゆる部分です。複数形規則、欠落したキーへの対処、すべての言語ファイルをコードと常に同期させること、そして何より、すべての翻訳を用意することです。General Translationのオープンソースライブラリがこのうちランタイム側の作業を担い、General Translationがコードから翻訳を生成・更新します。

## Video

The video is narrated in English, with English captions.

[Should you build your own i18n or use General Translation?](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-general-translation-vs-in-house-i18n.mp4) (43 秒)

Hand-rolled i18n, a dictionary per language and a t() helper, suits one or two languages, but as an app grows you rebuild plurals, fallbacks and file syncing, and still need translations. General Translation's libraries handle rendering, and General Translation generates and updates translations from your code: write copy inside `<T>` with counts in `<Plural>`, run `npx gt translate` before each build, or move your dictionary to JSON files for the CLI.

## 自前の i18n で十分なケース

* **サードパーティへの依存がない。** 辞書もヘルパーも自分で管理するため、コードの隅々まで自分でコントロールできます。
* **フォーマットはプラットフォームに任せられる。** `Intl.NumberFormat`、`Intl.DateTimeFormat`、`Intl.PluralRules`、`Intl.Locale` は[最新のブラウザと Node.js に組み込まれており](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl)、通貨、日付、複数形カテゴリをロケールに応じて書式設定してくれます。
* **文言が少なく、ほとんど変わらない。** プロトタイプや社内ツール、あるいはチームメンバーが追加言語を 1 つだけ書くようなサイトであれば、これ以上の仕組みは必要ありません。
* **複数形の扱いが英語と同じ言語。** 英語もドイツ語も、使う複数形カテゴリは [`one` と `other`](https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html) の 2 つだけです。

## 規模が大きくなると何が破綻するか

ポーランド語の辞書を追加した、典型的な初期バージョンを見てみましょう：

```js title="i18n.mjs"
const messages = {
  en: {
    greeting: 'Hello, {name}!',
    files: { one: '{count} file', other: '{count} files' },
    checkout: 'Checkout',
  },
  pl: {
    greeting: 'Cześć, {name}!',
    files: { one: '{count} plik', other: '{count} pliki' },
    // "checkout" はまだ翻訳されていない
  },
};

export function t(locale, key, vars = {}) {
  let message = messages[locale][key];
  if (typeof message === 'object') {
    message = vars.count === 1 ? message.one : message.other;
  }
  return message.replace(/\{(\w+)\}/g, (_, name) => vars[name]);
}

console.log(t('pl', 'greeting', { name: 'Ania' }));
console.log([1, 2, 5].map((count) => t('pl', 'files', { count })).join(', '));
console.log(t('pl', 'checkout'));
```

Node.js 24 で実行すると：

```text title="Output"
Cześć, Ania!
1 plik, 2 pliki, 5 pliki
TypeError: Cannot read properties of undefined (reading 'replace')
```

2つのバグが同時に発生します。&quot;5 pliki&quot; は誤りで (ポーランド語では &quot;5 plików&quot; が正しい形です) 、さらに未翻訳の `checkout` キーが原因でレンダリングがクラッシュします。プラットフォームには、この両方を解決するための仕組みが揃っています。

```js title="intl.mjs"
// 言語ごとの複数形カテゴリ
for (const locale of ['en', 'ja', 'pl', 'ar']) {
  console.log(locale, new Intl.PluralRules(locale).resolvedOptions().pluralCategories.join(' '));
}
const pl = new Intl.PluralRules('pl');
console.log([1, 2, 5, 22].map((n) => `${n} → ${pl.select(n)}`).join(', '));

// 通貨と日付
const date = new Date(Date.UTC(2026, 9, 16));
for (const locale of ['en-US', 'de-DE', 'ja-JP']) {
  const price = new Intl.NumberFormat(locale, { style: 'currency', currency: 'EUR' }).format(1234.5);
  const day = new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeZone: 'UTC' }).format(date);
  console.log(locale, price, day);
}

// テキストの方向
console.log(new Intl.Locale('ar').getTextInfo().direction);
```

```text title="Output"
en one other
ja other
pl one few many other
ar zero one two few many other
1 → one, 2 → few, 5 → many, 22 → few
en-US €1,234.50 October 16, 2026
de-DE 1.234,50 € 16. Oktober 2026
ja-JP €1,234.50 2026年10月16日
rtl
```

一つひとつの修正は小さくても、積み重なると大きな負担になります。

* **複数形。** `n === 1` はポーランド語 (4つのカテゴリ) やアラビア語 (6つ) では通用しないため、ヘルパーには [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) が必要になり、すべての辞書にもカテゴリごとの文字列が必要になります。 ([Reactで複数形を扱うには？](/kb/how-to-handle-plurals-in-react)を参照) 
* **語順。** `{name}` のようなプレースホルダーを使えば、言語ごとに値の位置を変えられます。文字列連結ではそうはいきません。`t('by') + ' ' + author` では名前が必ず最後に来ますが、日本語では「Ana 著」のように書きます。
* **フォーマット。** `{count}` は数値をそのまま挿入するため、ポーランド語で 12,500 を「12 500」と表示するには、ヘルパーに [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) も組み込む必要があります。
* **キーの欠落。** ヘルパーにはフォールバックチェーン (対象言語 → 翻訳元 → キー) が必要です。これがないと、ユーザーに `undefined` が表示されたり、アプリがクラッシュしたりします。
* **ファイルの同期。** `pl` に `checkout` が欠けていたり、先月の文言のまま残っていたりしても、ユーザーの目に触れるまで誰も気づけません。
* **右から左に書く言語。** アラビア語やヘブライ語では、ページに `lang` と `dir="rtl"` を指定したうえで、レイアウトを左右反転させる必要があります。
* **検索エンジン。** 選択した言語をstateやクッキーに保持する切り替え方式では、すべての言語が1つのURLにまとまってしまいますが、Googleは言語ごとに別のURLを用意することを推奨しています ([多言語サイトの管理](https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites)) 。 ([多言語Next.jsアプリのSEOを設定するには？](/kb/multilingual-nextjs-seo)を参照) 
* **翻訳そのもの。** このコストはどんなヘルパーでも解消できません。「plików」をはじめ、すべての言語のすべての文字列を誰かが書かなければならず、英語が変わるたびにその作業を繰り返すことになります。

ヘルパーで複数形カテゴリ、フォールバック、数値フォーマットまで扱えるようになった時点で、i18nライブラリの中核部分を自作したも同然です。しかも、翻訳は依然として別途必要です。

## General Translation ならこう解決する

General Translation は、自前実装の良い点 (読みやすいコピーとプラットフォーム標準のフォーマット) はそのまま活かしつつ、規模が大きくなるにつれて膨らんでいく部分を肩代わりします。`gt-react` (Next.js の場合は `gt-next`) を使えば、コピーは [`<T>`](/docs/react/reference/components/t) で囲んだままコンポーネント内に記述できるため、辞書やヘルパーを管理する必要はありません：

```tsx title="Inbox.tsx"
import { T, Plural, Num, Var } from 'gt-react';

export function Inbox({ name, count }: { name: string; count: number }) {
  return (
    <T>
      <h1>Welcome back, <Var>{name}</Var></h1>
      <Plural
        n={count}
        singular={<p>You have <Num>{count}</Num> unread message.</p>}
        plural={<p>You have <Num>{count}</Num> unread messages.</p>}
      />
    </T>
  );
}
```

[`<Plural>`](/docs/react/reference/components/plural) は、各ロケールの CLDR 複数形規則 (`Intl.PluralRules` が内部で使っているのと同じ規則) に基づいてブランチを選択するため、`n === 1` のような条件を書き間違える心配がありません。[`<Num>`](/docs/react/reference/components/num) は読み手のロケールに合わせて数値を書式設定し、[`<Var>`](/docs/react/reference/components/var) 内の値が General Translation API に送信されることは一切ありません。以下は、`gt-react` 11.4.12 を使ってサーバー上でレンダリングしたコンポーネントの出力例です。説明のため、[`gt generate`](/docs/cli/reference/commands/generate) で生成したテンプレートにスペイン語の翻訳を手作業で記入しています (React のテキスト区切り文字は除去済み) 。

```html title="Output"
<!-- en, count = 12500 -->
<h1>Welcome back, Ana</h1><p>You have 12,500 unread messages.</p>
<!-- es, count = 12500 -->
<h1>Hola de nuevo, Ana</h1><p>Tienes 12.500 mensajes sin leer.</p>
```

あるロケールにブロックの翻訳が存在しない場合、[`<T>`](/docs/react/reference/components/t) は `undefined` やエラーではなく、ソースコンテンツをレンダリングします。

さらに大きな違いは、翻訳そのものを General Translation が生成する点です。

* **文脈を踏まえて生成。** [`npx gt translate`](/docs/cli/reference/commands/translate) は、各 [`<T>`](/docs/react/reference/components/t) ブロックを、その要素、変数、複数形のブランチ、および [`context`](/docs/react/reference/components/t#context) のメモとあわせて送信し、ロケールごとにファイルを書き出します。用語集で用語を固定し、カスタムプロンプトでトーンを設定すれば、同じコンテキストグループを共有するすべてのプロジェクトに適用されます。 ([翻訳の文脈を定義する](/docs/platform/dashboard/guides/defining-context-for-translations)を参照してください。) 
* **常に同期。** 各実行では新規および変更されたコンテンツのみを翻訳し、それ以外は既存の翻訳を再利用します。CI で実行することも、General Translation の AI エージェントである [Locadex](/docs/platform/locadex/quickstart) に、指定したトリガーでプルリクエストを作成させることもできます。Next.js および React アプリでは、Locadex が既存の文言を [`<T>`](/docs/react/reference/components/t) でラップすることも可能です。
* **人によるレビュー。** チームはダッシュボードで翻訳を編集できます。 ([翻訳のレビューと編集](/docs/platform/dashboard/guides/reviewing-translations)を参照してください。) 
* **書字方向とルーティング。** [`useLocaleDirection`](/docs/react/reference/hooks/use-locale-direction) はアラビア語に対して `'rtl'` を返します。また、`gt-next` は[ミドルウェア](/docs/react/nextjs/app-router-middleware)を使って各ロケールを個別の URL で配信できます。

JavaScript ライブラリは MIT ライセンスで提供されており、翻訳を自前で用意すれば General Translation のアカウントなしで動作します。すべての翻訳をバンドルから読み込むよう設定したアプリは、ランタイムに General Translation へ一切通信しません。翻訳の生成にはホスト型サービスをご利用ください。料金は[従量課金制](https://generaltranslation.com/pricing)です。

大規模な導入例としては、Profound が General Translation を使って自社のプラットフォームとドキュメントを 47 以上のロケールで提供しています。 ([本番環境での導入事例](https://generaltranslation.com/enterprise)を参照してください。)

## 自作・ライブラリ・General Translation の比較一覧

|          | 自作の辞書とヘルパー                      | i18next などのオープンソースライブラリ                                                     | General Translation                                                                                                                                                 |
| -------- | ------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 依存関係     | なし                              | ライブラリ本体と、`react-i18next` などのフレームワーク用バインディング                                 | `gt-react` または `gt-next`、および `gt` CLI                                                                                                                               |
| 複数形      | 選択ロジックを自前で実装し、すべての形をすべてのファイルに記述 | CLDR に基づいて選択。各形は人手または接続した翻訳サービスが用意                                          | [`<Plural>`](/docs/react/reference/components/plural) が CLDR ルールで選択。記述したブランチをもとに、翻訳時に各対象言語の形を生成                                                                       |
| 数値・日付・通貨 | `Intl` API を自分で呼び出す             | `Intl` をベースにした組み込みフォーマッター                                                   | [`<Num>`](/docs/react/reference/components/num)、[`<Currency>`](/docs/react/reference/components/currency)、[`<DateTime>`](/docs/react/reference/components/datetime) |
| 翻訳がない場合  | ヘルパーの実装次第                       | [設定した言語にフォールバックし、それもなければキーを表示](https://www.i18next.com/principles/fallback) | ソースコンテンツをレンダリング                                                                                                                                                     |
| 言語間の同期   | 手作業または自作スクリプト                   | 抽出ツールと、接続した翻訳サービス                                                           | [`npx gt translate`](/docs/cli/reference/commands/translate) を実行するたびに、新規・変更されたコンテンツを翻訳                                                                              |
| 翻訳の担い手   | 人手または組み込んだサービス                  | 人手または接続した翻訳サービス                                                             | JSX でマークした文脈、用語集、カスタムプロンプトを活用する AI。チームはダッシュボードでレビュー                                                                                                                 |
| コスト      | 自分の工数と、組み込んだサービスの費用             | ライブラリは無料。翻訳費用は別途                                                            | JavaScript ライブラリは無料。[翻訳は従量課金](https://generaltranslation.com/pricing)                                                                                               |

## 自前で構築すべき場合

対応言語が 1〜2 言語で、テキスト量が少なく変更もほとんどなく、対象言語の複数形が英語と同じように変化し、翻訳はチームメンバーが書ける場合、あるいはプロトタイプの段階であれば、自前で構築しましょう。複数形規則やフォールバックが必要で、すでに翻訳者や翻訳管理システムがある場合は、i18next などのオープンソースのライブラリを導入しましょう。複数の言語を追加する場合、リリースのたびにテキストが変わる場合、あるいはチームの誰かにポーランド語の複数形を書かせるべきではない場合は、General Translation を使いましょう。General Translation はコードの文脈を踏まえて翻訳を生成し、ビルドのたびにすべての言語を最新の状態に保ちます。 ([General Translation vs. i18next、react-intl、next-intl](/kb/general-translation-vs-i18n-libraries) を参照してください。)

## 辞書はそのままに、翻訳は CLI に任せる

手作業での翻訳をやめるのに、ヘルパーを書き直す必要はありません。各言語のメッセージを JSON ファイル (`locales/en.json`、`locales/es.json`) に移し、`t()` はそのまま使い続けます。あとは `[locale]` プレースホルダーを使って、`gt.config.json` がこれらのファイルを参照するように設定するだけです。

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": [
    "es"
  ],
  "files": {
    "json": {
      "include": [
        "locales/[locale].json"
      ]
    }
  }
}
```

[`npx gt translate --dry-run`](/docs/cli/reference/commands/translate) を実行すると `locales/en.json` が翻訳元として一覧表示され、実際に実行すると `locales/es.json` が書き出されます。この例では、キー構造が一致し、`{name}` のような単純なプレースホルダーを含む英語とスペイン語のメッセージを使用しています。対応ファイルの `locales/en.metadata.json` を用意すると、キーごとに文脈や文字数制限を追加できます。詳しくは [JSON](/docs/cli/reference/formats/json-files) と [キーごとのメタデータ](/docs/cli/reference/keyed-metadata) を参照してください。なお、キーの参照と複数形の選択は引き続き独自のヘルパーが担うため、レンダリングされたスペイン語の出力で両方を確認してください。

ヘルパーから移行するには、コンポーネントを 1 つずつ [`<T>`](/docs/react/reference/components/t) でラップするか、[`useTranslations`](/docs/react/guides/translating-with-dictionaries) を使ってキーベースのまま移行します。コーディングエージェントに作業を任せる場合は、`t()` ヘルパーの作成を依頼するのではなく、General Translation の[エージェント向け手順](/docs/overview/for-coding-agents)を渡してください。まずは [Next.js クイックスタート](/docs/react/nextjs-quickstart) または [React SPA クイックスタート](/docs/react/react-spa-quickstart) から始めましょう。

## 重要なポイント

* 対応言語が 1〜2 つで、テキスト量が少なく、複数形の扱いが英語と同じであれば、辞書、`t()` ヘルパー、組み込みの `Intl` API だけで十分です。
* アプリの規模が大きくなるにつれ、複数形の選択、フォールバック、フォーマット、ファイルの同期、右から左への表記への対応、ロケールごとの URL、さらには翻訳を生成するプロセスまで、自前で保守しなければならなくなります。
* ランタイムの処理は General Translation のライブラリが担い、翻訳はコードを文脈として General Translation が生成します。自作の JSON 辞書を使い続ける場合も、CLI で翻訳できます。

## Related questions

- [General Translation vs. i18next、react-intl、next-intl：どのi18nライブラリを使うべきか？](https://generaltranslation.com/ja/kb/general-translation-vs-i18n-libraries.mdx): i18next、react-intl、next-intlなどのオープンソースライブラリ自体は、翻訳を一切行いません。これらが行うのは、あなた自身や翻訳者、あるいは別のサービスが作成し、言語ごとのカタログファイルに用意した翻訳を表示することだけです。General Translationのライブラリも同じくオープンソースで同じ役割を果たしますが、General Translationはさらに、コードを文脈として活用しながら翻訳そのものも行います。
- [React で複数形を扱うにはどうすればよいですか？](https://generaltranslation.com/ja/kb/how-to-handle-plurals-in-react.mdx): React で複数形を扱うには、各言語の複数形ごとに文を 1 つずつ用意し、その言語の複数形規則に従って選択します。英語の複数形は 2 種類ですが、ロシア語は 4 種類、アラビア語は 6 種類あるためです。gt-react と gt-next に含まれる General Translation の `<Plural>` コンポーネントに翻訳元の形を渡せば、各対象言語に必要な形は General Translation が生成します。
- [多言語対応の Next.js アプリで SEO を設定するには？](https://generaltranslation.com/ja/kb/multilingual-nextjs-seo.mdx): 各言語に /en/about や /es/about のようなプレフィックス付きの URL を割り当て、公開している言語ごとに html lang、自己参照のカノニカル、x-default を含む hreflang の代替リンク、翻訳済みのタイトルと説明文、サイトマップのエントリを出力します。未公開のバージョンには noindex を指定します。General Translation の gt-next は各言語を専用の URL にルーティングし、getGT でタイトルを翻訳します。
- [翻訳ファイルなしでi18nは実現できますか？](https://generaltranslation.com/ja/kb/i18n-without-translation-files.mdx): はい。General Translationの gt-react と gt-next ライブラリを使えば、翻訳キーも、言語ごとに管理するJSONファイルもなしで、ReactとNext.jsのi18nを実現できます。文言は `<T>` コンポーネント内のJSXにインラインで記述したままで、gt translate コマンドがコードから得た文脈をもとに、ビルド時に各言語の翻訳を生成します。さらにLocadexを使えば、プルリクエストを通じて翻訳を常に最新の状態に保てます。
- [Google 翻訳の代替：General Translation と Google 翻訳の比較](https://generaltranslation.com/ja/kb/general-translation-vs-google-translate.mdx): Google 翻訳は、単発のテキストをすばやく翻訳するのに便利ですが、製品を別の言語でリリースするには、各文字列を文脈に沿って翻訳し、用語を統一し、変数や複数形を正しく扱い、レビューを行い、リリースプロセスを整える必要があります。General Translation はコード内の各文字列の文脈を理解し、コードからレビュー、そして毎回のリリースまで、ローカライゼーションのワークフロー全体を自動化します。

## Previous and next questions

- Previous question: [i18next の代替：General Translation と i18next の比較](https://generaltranslation.com/ja/kb/general-translation-vs-i18next.mdx)
- Next question: [Lokalise の代替ツール：General Translation と Lokalise の比較](https://generaltranslation.com/ja/kb/general-translation-vs-lokalise.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/ja/kb/sitemap.md) for every article.
