gt-react@10.18.0
概要
このリリースでは、gt-react で導出可能なコンテキスト値をサポートしました。コンテンツを翻訳する際、原文と訳文が常に 1 対 1 で対応するとは限りません。1 つの英語フレーズに対して、別の言語では複数の訳文が必要になる場合があります。コンテキストの導出により、1 つのソース文字列から複数の翻訳エントリを生成して、この問題に対応できます。
背景: GT の翻訳の仕組み
GT の翻訳システムでは、翻訳対象の文字列を gt() で囲みます。
import { useGT } from 'gt-react';
function Greeting() {
const gt = useGT();
return <p>{gt("Hello, world!")}</p>;
}gt() を呼び出すたびに、翻訳されるテキストである ソースエントリ が作成されます。通常、1 つの ソースエントリ から、各言語につき 1 つの翻訳が生成されます。
derive とは?
derive() 関数は、異なる runtime の値に応じて、1 つの gt() 呼び出しから複数の翻訳エントリを登録するよう GT CLI に指示します。バリアントごとに個別の gt() 呼び出しを書く代わりに、derive() を使ってすべてのバリアントを 1 か所にまとめて表現でき、CLI がビルド時に適切な ソースエントリ を生成します。
たとえば、英語では "The boy/girl is playing," のように性別を区別しませんが、スペイン語では区別します ("El niño está jugando" と "La niña está jugando") 。derive() を使えば、これを 1 つの gt() 呼び出しで処理できます。
const subject = isBoy ? "boy" : "girl";
gt(`The ${derive(subject)} is playing.`);CLI は derive() 呼び出しを認識し、2 つのソースエントリ (1 つは "The boy is playing."、もう 1 つは "The girl is playing.") を登録します。各エントリにはそれぞれ個別の翻訳が付き、スペイン語でも正しい語形一致になります。
問題: one-to-many の対応関係
ソースエントリ が 翻訳エントリ にどのように対応するかについて、3 つのケースを考えてみましょう:
ケース1: 一対一の対応
各ソースエントリは、それぞれ1つの翻訳エントリにマッピングされます。これはわかりやすいケースです。
| ソースエントリ | 翻訳エントリ |
|---|---|
| The boy is beautiful. | El niño es hermoso. |
| The girl is beautiful. | La niña es hermosa. |
ケース2: 多対一マッピング
複数のソースエントリが、1つの翻訳エントリに対応します。たとえば、英語には複数形がありますが、中国語 (標準語) にはありません。
| ソースエントリ | 翻訳エントリ |
|---|---|
I have {n} cat. | 我有{n}只猫。 |
I have {n} cats. |
ケース 3: 1対多のマッピング
1 つのソースエントリに対して、複数の 訳文が必要になる場合があります。たとえば、スペイン語では英語と異なり、形容詞が性に一致します。
| ソースエントリ | 翻訳エントリ |
|---|---|
| I am tired | Estoy cansado |
| Estoy cansada |
このケースは、このリリース以前はサポートされていませんでした。GT はこれまで、ソースエントリと訳文は 1 対 1 に対応すると想定していました。
解決策: $context を使った derive
GT の $context オプションを使うと、同じソーステキストに対応する翻訳エントリを区別できます。derive() と組み合わせれば、呼び出し側でそれを表現できます。
import { useGT, derive } from 'gt-react';
function StatusMessage({ isMasculine }) {
const gt = useGT();
return (
<p>
{gt("I am tired", {
$context: derive(
isMasculine ? "inflect as masculine" : "inflect as feminine"
)
})}
</p>
);
}ビルド時に、CLI は derive() の呼び出しを検出し、2 つの独立したソースエントリを登録します。それぞれについて個別の翻訳が生成されます。
"I am tired" ($context: "inflect as masculine") → "Estoy cansado"
"I am tired" ($context: "inflect as feminine") → "Estoy cansada"
runtime では、isMasculine の値に応じて適切な翻訳が選択されます。
derive() を使わない場合、これを 2 つの別個の呼び出しとして記述する必要があります:
// derive なし — より冗長で、ソーステキストが重複する
const message = isMasculine
? gt("I am tired", { $context: "inflect as masculine" })
: gt("I am tired", { $context: "inflect as feminine" });derive() を使えば、重複を減らしながら同じ結果を得られ、意図もより明確になります。
なぜ単純に条件分岐を使わないのですか?
コンテンツ文字列と同様に、$context の値も 静的 である必要があります。CLI がビルド時にそれらを解決する必要があるためです。取りうる値を CLI が把握できないので、runtime 式をそのまま $context として渡すことはできません。derive() は、呼び出しスタックをたどって渡されうるすべての静的文字列を解決し、それぞれについて CLI が source entry を登録できるようにすることで、この問題を解決します。
まとめ
コンテキスト導出は、翻訳モデルの根本的な課題、つまりソースエントリと翻訳エントリの間の 1 対多の対応を表現できないという問題を解決します。derive() と $context を組み合わせることで、1 回の gt() 呼び出しから複数の訳文を生成し、それらを runtime に適切に区別できるようになります。