戻る

gt-next@6.8.0

Ernest McCarter avatarErnest McCarter
gt-reactgt-nextgtx-cliv6.8.0statictranslationi18n

概要

コードベースが成熟すればするほど、コンテンツは断片化しやすくなります。 文が関数やユーティリティ、ロジック、サービスなどのあちこちに散らばってしまいます。

function getSubject(gender) { 
  return gender === "male" ? "男の子" : "女の子" 
}
function getObject(toy, gender) { 
  return toy === "ボール" ? "ボール" : getSubject(gender)
}

function Component({ gender, toy }) {
  return (
    <>
      <p>
        かわいい{getSubject(gender)}が{getObject(toy, gender)}で遊んでいます。
      </p>
    </>
  )
}

国際化に取り組まざるを得なくなる頃には、開発者は自分たちで身動きの取れない状態に追い込んでしまっていることに気づきます。 複数ファイルにまたがって、語の一致・活用・語順の変更などを一貫して適用するのは、大規模なリファクタリングなしには現実的ではありません。 従来は、各文のあらゆるバリエーションを手作業で抽出し、それぞれを翻訳辞書に追加する必要がありました。

gt-next 6.8.0 では、「優れた i18n ライブラリはコードベースを変えさせるのではなく、コードベースに適応すべきだ」という考え方を、さらに推し進めています。 gt-next はすでにインラインでコンテンツを翻訳できますが、その種のライブラリにとって本質的な 2 つの機能が不足していました。 (1) 文の分割に対するサポートと、(2) 語の一致・活用・語順の変更を維持したままコンテンツを再利用できることです。

翻訳内で静的関数呼び出しを直接行えるようにするために、<Static> コンポーネントを導入します。

function getSubject(gender) { 
  return gender === "male" ? "男の子" : "女の子" 
}
function getObject(type, gender) { 
  return type === "ボール" ? "ボール" : getSubject(gender)
}

function Component({ gender, toy }) {
  return (
    <T>
      <p>
        美しい<Static>{getSubject(gender)}</Static>が<Static>{getObject(toy, gender)}</Static>で遊んでいます。
      </p>
    </T>
  )
}

重要な考慮事項

とはいえ、<Static> コンポーネントは慎重かつ節度を持って使用することを強く推奨します。 <Static> コンポーネントは強力である一方で、翻訳エントリーの数が大幅に増加する可能性もあります。 誤った使い方をすると、アプリケーションのロード時間に悪影響を及ぼすおそれがあります。

<Static> の使い方

<T> コンポーネントや <Var> コンポーネントと同様に、<Static> コンポーネントは、CLI ツールに対して「どこを翻訳対象として探索するか/しないか」を示すためのフラグです。 これは CLI ツールに対し、<Static> タグ内の関数呼び出しをデリファレンスし、その関数が返すすべての可能なコンテンツを収集・登録するよう指示します。 すべての return 文は、あたかも <T> コンポーネントでラップされているかのように扱われます。

CLI ツールが関数呼び出しからのすべての可能な出力を見つけると、そのそれぞれに対して個別の翻訳エントリを作成します。 たとえば、次のコードは "The boy is beautiful" と "The girl is beautiful" という 2 つの別々の翻訳エントリを作成します。 それぞれの可能な出力に対して個別の翻訳エントリが存在するため、分割された文においても、性・活用・語順を適切にサポートできます: 「El niño es hermoso」および「La niña es hermosa」。

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function Component({ gender }) {
  return (
    <T>
      その<Static>{getSubject(gender)}</Static>は美しいです。
    </T>
  )
}

制限事項と今後の改善

乗算

前述のとおり、<Static> コンポーネントを必要以上に多用すると、多数の翻訳エントリが生成され、読み込み時間に悪影響を与える可能性があります。 たとえば、2 つの <Static> コンポーネントを含むコンポーネントがあり、それぞれが 2 とおりの結果を返す関数呼び出しをラップしているとします。 この場合、4 つの翻訳エントリが作成されます。 <Static> コンポーネントが 1 つ追加されるごとに、各関数呼び出しが取りうる結果の数だけ、翻訳エントリの数が掛け算的に増えていきます。

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function getObject(toy) { 
  return toy === "ball" ? "ball" : "crayon"
}
function Component({ gender, toy }) {
  return (
    <T>
      <Static>{getSubject(gender)}</Static>は<Static>{getObject(toy)}</Static>で遊びます。
    </T>
  )
}

構文

すべての return 文は、あたかも <T> コンポーネントでラップされているかのように扱うことが重要です。 動的な変数や関数呼び出しは、必ず <Var> コンポーネントでラップする必要があります。

現在、<Static> は子要素として関数呼び出しのみをサポートしていますが、将来的にはより複雑な式もサポートできる予定です。 gt-next 6.8.0 時点では、静的関数には次の構文がサポートされています。

function getExamples(key) {
  switch (key) {
    case "string, number, and boolean literals":
      if (condition1) {
        return "男の子"
      } else if (condition2) {
        return 22
      } else {
        return true
      }
    case "jsx expressions":
      return (
        <>
          こんにちは、<Static>{getTitle(title)}</Static>。お元気ですか、<Var>{name}</Var>?
        </>
      );
    case "ternary operators":
      return condition ? "男の子" : "女の子"      
    case "function calls":
      return otherStaticFunction();
  }
}

まとめ

gt-next 6.8.0 では、翻訳の網羅性や文法的な整合性を損なうことなく文の分断を解消するソリューションとして、&lt;Static&gt; コンポーネントが導入されています。