JSXの翻訳

JSXコンポーネントの国際化方法

概要

このガイドでは、<T> コンポーネント を使って JSX コンテンツを国際化する方法を説明します。

このガイドを終える頃には、<T> コンポーネントの正しい構文と、避けるべき点が分かるようになります。

以下の内容を扱います:

<T> コンポーネントの使い方

追加オプション

<T> コンポーネントを使うべきタイミング

本番環境での考慮事項

よくある落とし穴

Variable ComponentsBranching Components の使い方をお探しの場合は、それぞれのガイドをご参照ください。


<T> コンポーネントの使い方

翻訳したいHTMLコンテンツがあるとしましょう。

function Greeting() {
  return <p>Hello, world!</p>;
}

そのコンテンツを <T> コンポーネントでラップするだけです。

import { T } from 'gt-next';

function Greeting() {
  return <T><p>Hello, world!</p></T>;
}

ユーザーが選択した現在の言語に応じて、適切な翻訳が表示されます。
ユーザーが言語を切り替える方法については、言語の切り替えをご覧ください。


追加オプション

コンテキスト

場合によっては、翻訳に追加のコンテキストを提供したいことがあります。 これは <T> コンポーネントに context プロップを渡すことで実現できます。

<T context="toast, as in a pop-up notification">
  Click on the toast to dismiss it.
</T>

これは、単語が文脈によって複数の意味を持つ場合に便利です。 例えば、「toast」は食べ物やポップアップ通知のどちらかを指すことがあります。

context プロップは、AIが翻訳の意図を理解するのに役立ちます。

id

<T> コンポーネントに id プロップを渡すこともできます。 これはデバッグの際に便利で、翻訳の編集を容易にします。

<T id="toast">
  Click on the toast to dismiss it.
</T>

<T> コンポーネントを使用するタイミング

<T> コンポーネントは非常に柔軟ですが、常に最適な解決策とは限りません。

静的な HTML や JSX コンテンツ がある場合は、常に <T> コンポーネントの使用を検討してください。

<T> コンポーネントを使用しないタイミング

絶対に <T> コンポーネントを、危険な 動的 コンテンツに対して使用しないでください。

ここでいう動的コンテンツとは、実行時に変更される可能性のあるコンテンツを指します。
ただし、Variable ComponentsBranching Components を使用している場合はこのルールは適用されません。

注意:

Variable components は、コンテンツが動的であってもラップされてサニタイズされているため、<T> コンポーネントで安全に使用できる特別なケースです。

Variable components でラップされたコンテンツは、<T> コンポーネントによって直接翻訳されることはありません。

以下の例は、<T> コンポーネントの無効な使用例です:

<T>
  <p>Your username is {username}</p>
</T>
<T>
  <p>Current date: {new Date().toLocaleDateString()}</p>
</T>
<T>
  <p>Logical Expressions: {username === 'admin' ? 'Yes' : 'No'}</p>
</T>
<T>
  <p>Conditional Rendering: {isAdmin ? 'Yes' : 'No'}</p>
</T>

上記の例では、variable componentsbranching components を使うことで、安全に国際化できます。

const chatMessage = getChatMessageFromServer();
<T>
  <p>{chatMessage}</p>
</T>

この例では、コンテンツが完全に動的なため、クライアントに渡す前にサーバー側で翻訳する必要があります。

コンテンツを API 経由で動的に翻訳する方法については、core ライブラリをご覧ください。


ここでは、<T>コンポーネントの使い方の例をいくつか紹介します。これらはすべて正しい使い方です。

  1. HTMLコンテンツ
<T>
  <p>Hello, world!</p>
</T>
<p>Hello, world!</p>
  1. シンプルなJSXコンテンツ
<T>
  <Button>Click me!</Button>
</T>
<Button>Click me!</Button>
  1. 複雑なJSXコンテンツ
<T>
  <Tooltip>
    <TooltipTrigger>
      <div className="flex items-center gap-2 rounded-full bg-destructive px-3 py-1.5 text-sm text-destructive-foreground">
        <AlertCircle className="h-4 w-4" />
        <span>Free Usage</span>
      </div>
    </TooltipTrigger>
    <TooltipContent>
      <p>
        You are nearing your free monthly limit. Please
        upgrade your plan to avoid any disruptions to your
        service.
      </p>
    </TooltipContent>
  </Tooltip>
</T>
<Tooltip>
  <TooltipTrigger>
    <div className="flex items-center gap-2 rounded-full bg-destructive px-3 py-1.5 text-sm text-destructive-foreground">
      <AlertCircle className="h-4 w-4" />
      <span>Free Usage</span>
    </div>
  </TooltipTrigger>
  <TooltipContent>
    <p>
      You are nearing your free monthly limit. Please
      upgrade your plan to avoid any disruptions to your
      service.
    </p>
  </TooltipContent>
</Tooltip>

<T>コンポーネントは、同じコンポーネント内でどんなネストされたコンテンツにも対応できます。


本番環境での考慮事項

本番環境へのデプロイ

本番環境へデプロイする前に必ず translate コマンドを実行し、すべての翻訳が実行時に利用できるようにしてください。 CD パイプラインやビルドスクリプトの一部として追加することをおすすめします。

package.json
{
  "scripts": {
    "build": "npx gtx-cli translate && <YOUR_BUILD_COMMAND>",
  }
}

アプリケーションのデプロイに関するより詳細なガイドについては、Deployment チュートリアルをご参照ください。 コマンドの詳細については、CLI Tool リファレンスガイドをご覧ください。

挙動: 開発環境と本番環境の違い

開発環境では、<T> コンポーネントがオンデマンドでコンテンツを翻訳します。 つまり、コンポーネントがレンダリングされると、即座に翻訳が実行されます。 このライブラリは、他の言語での開発を容易にするためにこのような挙動になっています。

この挙動を有効にするには、Dev API キーを環境変数に追加するだけです。

本番環境では、<T> コンポーネントが使用するすべての翻訳はビルド時に完了します。 つまり、アプリケーションをデプロイする前に翻訳コマンドを実行する必要があります。

ヒント: 開発環境で本番環境の挙動をシミュレートしたい場合は、開発ビルドで本番用 API キーを使用してください。

プライバシーに関する懸念

一部の例外を除き、<T> コンポーネントでラップされたすべてのコンテンツは General Translation API に送信されて翻訳されます。 これは、ユーザー名やアカウント番号などの機密データをレンダリングする場合には望ましくないかもしれません。

この問題を回避するには、Variable Components を使用して個人情報を扱ってください。 これにより、機密データが General Translation API に送信されることはありません。 変数コンポーネントでラップされたコンテンツのローカライズはローカルで処理されます。


よくある落とし穴

直下の子要素のみ

<T> コンポーネントは、直接子要素として渡されたテキストのみを翻訳します。 つまり、コンポーネント内の内容が <T> に直接渡されていない場合、その内容は翻訳されません。

例を使って説明します:

function UntranslatedContent() {
  return (
    <p>This content is not translated</p>
  );
}

export default function DisplayGreetings() {
  return (
    <T>
      <h1>Hello, this text will be translated</h1>
      <UntranslatedContent />
    </T>
  );
}

この例では、<UntranslatedContent> の中身は翻訳されません。 <T> の直下にある内容、例えば <h1> タグやその子要素のみが翻訳されます。

注意: 良い目安として、ファイル内で2つの <T> タグの間に 直接 書かれている内容は翻訳されます。 翻訳されていない内容には、別の <T> を追加することで翻訳できますが、<T> コンポーネントのネストは推奨されません。

解決方法は?

テキストを直接 <T> コンポーネントで囲んでください。例えば:

function TranslatedContent() {
  return (
    <T>
      <p>This content <b>IS</b> translated</p>
    </T>
  );
}

export default function DisplayGreetings() {
  return (
    <>
      <T>
        <h1>Hello, this text will be translated</h1>
      </T>
      <TranslatedContent />
    </>
  );
}

<T> コンポーネントのネスト

<T> コンポーネントのネストは許可されていません。 React のレンダリングシステムの都合上、予期しない動作やパフォーマンスの問題につながる可能性があります。

やってはいけない例 を示します:

function SomeComponent() {
  return (
    <T>
      Hello, friend!
    </T>
  );
}

export default function NestedTranslation() {
  return (
    <T>
      <T> {/* Don't do this! */} 
        Hello, world! 
      </T>
      <SomeComponent /> {/* This still counts. Don't do this! */}
    </T>
  );
}

この場合の解決策は、一番外側の <T> コンポーネントを削除することです。

動的コンテンツの翻訳

動的なコンテンツを <T> コンポーネントで囲もうとすると、CLI ツールでエラーになります。

例えば、次のような場合はエラーになります:

const username = 'John Doe';
<T>
  <p>Your username is {username}</p>
</T>

この問題を回避するには、Variable ComponentsBranching Components を使って動的な内容をラップしてください。

または、内容が本当に動的でオンデマンドで翻訳する必要がある場合は、<Tx> コンポーネント を使用できます。


概要

  • <T> コンポーネントは、任意のJSXコンテンツを国際化するために使用されます。
  • <T> コンポーネントは、変数コンポーネントや分岐コンポーネントを使用しない限り、動的コンテンツには使用しないでください。
  • 開発環境では、<T> コンポーネントはコンテンツをオンデマンドで翻訳します。
  • 本番環境では、<T> コンポーネントが使用するすべての翻訳はビルド時に完了します。

次のステップ

このガイドはいかがですか?