コンテンツにスキップ

ローカライズ

単一ファイル内インライン多言語バリアントと副作用ゼロの即時ホットリロード

本節では、Ktory における単一ファイルでの多言語記述の実現方法について解説します。

@defaultLang: <locale> は注釈のない本文の所属とフォールバックに使うファイル言語です。実行時の主/副言語切替ではありません。省略可能で、@locale バリアントがある場合、現行パーサーは互換性のため zh を既定値とします。多言語宣言がなければ未ローカライズとみなし、実際の言語は null です。多言語スクリプトでは暗黙の既定値を避けるため明示してください。

@locale: は個別のテキストの言語を示します。明示的な @defaultLang 宣言が必須になるわけではありません。本文、選択肢、名前の解決規則は実装仕様に従います。

現在、@[locale] 宣言はセリフと選択肢ラベルをサポートしています。

@defaultLang: ja
アリス:
@zh: 你好,旅行者。
@en: Hello, traveler.
@ja: こんにちは、旅人さん。
.expression(smile)
#choice
* [@zh: "继续"]
[@en: "Continue"]
[@ja: "続ける"]
アリス: 私たち、行こう。

劇本内ではキャラクターの名前が高頻度で登場するため、Ktory はキャラクター名およびその訳名の定義に特化した構文を用意しています。

@speaker 宣言はキャラクター名、訳名、および別名を定義します(大文字・小文字は厳密に区別されます)。ファイル先頭で定義しておくと、Ktory は要求された言語に応じて、定義済みの正しい訳名を自動的に返します。なお、別名は任意項目であり、出力言語としては扱われず、スクリプトからの呼び出し入力としてのみ使用できます。

@speaker en="Chtholly" | ja="クトリ" | cn="珂朵莉"
Chtholly: // ここで Chtholly、クトリ、珂朵莉 のいずれを記述しても、要求言語に応じた正しい訳名が自動的に返されます
@en: You must leave now.
@ja: 今すぐ離れて!
@cn: 快走!

別名を定義したい場合は、@speaker 宣言の直後に別名とコロン(:)を付けるだけです。ただし、@speaker alice: のように空でない表示名が一つも存在しない宣言は、行番号を出力して読み込みを停止します。

@speaker ktr: en="Chtholly" | ja="クトリ" | cn="珂朵莉"
ktr:…… // 別名を使って呼び出すことができます

この構文は、キャラクターが演出時に使用する既定修飾子の定義にも対応しています。

Ktory は要求された言語を優先して返します。要求言語の翻訳が存在しない場合は、defaultLang の言語テキストの取得を試みます。両方に有効な翻訳が存在しない場合、Ktory はそのノードの既存の訳文順に従って最初の有効な翻訳を選択し、ソースコードの位置情報を含んだ Warning を出力します。

TextPayload.ActualLanguage は実際の本文の言語を示し、RequestedLanguage は要求された言語を保持します。例えば、英語(en)が要求され defaultLang が zh の場合、あるテキストで en の翻訳が欠落していると、そのテキストの ActualLanguage は zh となり、RequestedLanguage は依然として en のままになります。この際、Ktory が zh のテキストを英語としてラベル付けすることはありません。

現在、ChoiceOption はローカライズされた Label、RequestedLanguage、および ActualLanguage を提供し、各選択肢ごとに実際の言語を個別に報告します。

TextPayload.SpeakerActualLanguage は宣言された話者名の実際の言語を個別に報告します。これは本文と異なる場合があり、未宣言の話者の場合は空(null)になります。

本文、選択肢、および宣言済みの名前はいずれも上記の第三言語フォールバック規則に従い、欠訳のプレースホルダーを合成することはありません。

player.SetLanguage("en");

SetLanguage(locale, token) はセッション設定です。キャプチャされたセッションが有効である限り、同一セッションで拍が進んだ後や自然終了した後でも言語を変更できます。古いセッションからの要求は無視されます。

切り替えによって現在のテキスト、話者、またはメニューラベルが更新されますが、演出修飾子の再配信やセッション履歴の消去は行われません。その後、宿主側で表示を更新します。PresentationController を使用している場合は、その RefreshLanguage() を呼び出して現在の演出タイミングを処理してください。言語切り替えのために余分な Step() を呼び出さないでください。

同一ファイルでの管理は独立した執筆や翻訳に適しています。ただし、Ktory は言語ごとに複数の Ktory スクリプトファイルを個別に管理することを妨げるものではありません。

RequestedLanguage が主言語、SecondaryLanguage が任意の副言語です。ファイルの defaultLang は注釈のない本文の所属と主言語のフォールバックを定めます。主言語には上記の規則を使い、副言語は一致する訳だけを選び、フォールバックしません。

TextPayload.Text、null を許す TextPayload.SpeakerName、ChoiceOption.Text は、それぞれ Primary と null を許す Secondary を持ちます。各値は Content、RequestedLanguage、ActualLanguage を返します。既存の Content、Speaker、Label は主言語に対応します。

副言語の訳がないフィールドは null です。副言語がそのフィールドの主言語の実際の言語と一致する場合も省略します。異なる言語で同じ文字列の場合は残します。本文と名前は独立して解決するため、副言語の名前だけがある場合もあります。未ローカライズ値や未宣言の名前に言語を捏造しません。注釈のない値は、既知のファイル既定言語と一致する場合にその訳として利用できます。

sequencer.Start(requestedLocale: "zh", secondaryLocale: "en");
sequencer.SetSecondaryLanguage("ja");
presentations.RefreshLanguage(secondaryOnly: true);
sequencer.SetSecondaryLanguage(null); // 副言語を無効化

presentations は MultiTrackPresentationController です。単一 Main の PresentationController では RefreshSecondaryLanguage() を使います。SetLanguage(locale) は副言語設定を保ち、SetLanguageOutput(primary, secondary) は両方を更新します。

副言語の変更は保持中の表示内容と Main の現在の本文・選択肢を更新しますが、進行、選択条件の再評価、消費、タグの再実行を行いません。文字表示と計時も維持します。補助再生ヘッドやセッションが終了した後も保持中の本文は更新でき、非表示になった内容を再表示することはありません。推定読書時間は主言語の実際の内容のみで計算し、主言語の変更には既存の進捗保持規則を使います。二つの値の表示・非表示や配置は renderer が独立して決めます。

各再生ヘッドの現在の文は一つだけです。次の文に入ると表示先にかかわらず前の文を撤去し、空 : も置き換えます。次の at/await で待機している間はまだ次の文に入っておらず、EOF/stop 後も次の文がないため、元の表示寿命まで残して言語を更新できます。LanguageRefresh は token に対応する現在の表示だけを更新し、配置タグの再実行、duration のリセット、撤去済みの文の復活を行いません。現在の表示を隠したら ReleaseOutput(token) を呼びます。読書履歴は現在の表示と別に管理します。

言語ラベルとプレーンテキスト囲み

Section titled “言語ラベルとプレーンテキスト囲み”

@locale: は囲みの外に置き、言語ごとに必要な断片を囲みます。プレーンテキストの断片とブロックを参照してください。囲み内の @en: は文字であり、別の訳文を宣言しません。主言語のフォールバック、副言語の欠落時の省略、副作用を再実行しない言語切り替えの規則は変わりません。

各 Primary/Secondary の結果には、断片ごとの Content と IsLiteral を持つ Segments が付くことがあります。実際に選ばれた言語版とともに渡されるため、拍全体や全言語に共通のプレーンテキストフラグでは扱えません。