JSXの翻訳

JSXコンポーネントを国際化する方法

概要

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

このガイドを終えると、<T> コンポーネントを使用するための正しい構文と避けるべきことを理解できるようになります。

以下の内容を取り上げます:

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

追加オプション

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

本番環境での考慮事項

よくある落とし穴

変数コンポーネント分岐コンポーネントの使用方法については、それぞれのガイドを参照してください。


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

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

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

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

import { T } from 'gt-react';

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> {/* これはやめましょう! */} 
        Hello, world! 
      </T>
      <SomeComponent /> {/* これも同様です。やめましょう! */}
    </T>
  );
}

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

動的コンテンツの翻訳

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

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

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

この問題を回避するには、動的な内容をラップするために Variable ComponentsBranching Components の利用を検討してください。


概要

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

次のステップ

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