翻訳
Ren'Py には、ビジュアルノベルを翻訳するための包括的なフレームワークがあります。これによって主に4種類のものを翻訳できます:
- 台詞
スクリプトのメインの台詞は、分割、連結、省略、行の並べ替えを伴う翻訳ができます。
- メニューとインターフェイスの文字列
すべてのインターフェイスのテキストが翻訳できます。
- 画像とファイル
ある言語が選択されたときに、通常とは異なる画像やその他のファイルを含められます。
- スタイル
言語に合わせてスタイルをカスタマイズできるため、ある言語が選択された時にゲームで使用されるフォントを自動的に切り替えられます。
Ren'Py の翻訳サポートは現在、正式に認可されている翻訳、つまりゲームの制作者が翻訳者に向けてゲームのスクリプトをリリースしている場合や、制作者自身が翻訳用の雛形を作成している場合に焦点を当てています。正式な認可を得ていない場合の翻訳では、これよりも制限があります。
主言語と副言語
Ren'Py は、それぞれのゲームが1つの主言語によって書かれていると想定します。このときの言語は None 言語と呼ばれますが、その言語が実際に何であっても構いません(例えば、ゲームが英語で書かれている場合は、英語が None 言語となります)。
副言語は、Python の識別子としても振る舞える名前によって関連付けられます(英字またはアンダースコアで始まり、英数字とアンダースコアが続きます)。
None 言語が選択されると、ほとんどの Ren'Py の翻訳関数は例えばアクセス性メニューにあるような Ren'Py 内部組み込みの文字列を除いて無効となります。それらの文字列はあなたのプロジェクトのコードにはありませんが、そのゲームのリリースバージョンにも含まれています。それらは game/tl/None/common.rpym
ファイルにあり、 1) None 言語が英語でないときにそれらの文字列の翻訳を提供すること、 2) それらの文字列を制作者がかれらのゲーム用にカスタマイズできるようにすることだけを目的としています。
そのプロジェクトが作成されたときのランチャーの言語がこのファイルが最初に内部の文字列を翻訳する言語になるでしょう。
翻訳ファイルの生成
プロジェクトのスクリプトが利用できる場合、Ren'Py ランチャーでプロジェクトを開き「Generate Translations(飜訳の生成)」を選んで翻訳ファイルを生成できます。ランチャーは生成する言語の名前の入力を求めた後、翻訳ファイルの作成または更新を行います。
翻訳ファイルはゲームディレクトリーの中の「tl」サブディレクトリーの下に設置されます。例えばチュートリアルプロジェクトの piglatin の翻訳を作成した場合、翻訳ファイルは tutorial/game/tl/piglatin
の下に設置されます。
ゲームのスクリプトファイル1つに対して翻訳ファイルが1つ作成されます。共通のコードで見つかった文字列の翻訳を含めるために、common.rpy ファイルも作成されます。
台詞の翻訳
Ren'Py はビジュアルノベルエンジンなので、ほとんどの翻訳は台詞と対応していると予想しています。Ren'Py には柔軟なフレームワークがあり、台詞の分割、結合、並べ替え、完全な省略を行えます。
翻訳ユニット
翻訳の基本ユニットは、0以上の翻訳可能なステートメントを含むブロックであり、任意で say ステートメントが一つ続きます。翻訳可能なステートメントは voice ステートメントと nvl ステートメントです。例えば、次のゲームを見て下さい:
label start:
e "Thank you for taking a look at the Ren'Py translation framework."
show eileen happy
e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
e "Pretty much everything your game needs!"
これは複数の翻訳ユニットに分割されます。それぞれのユニットには割り当てられた識別子があり、識別子はユニットに先行するラベルと、ユニット内のコードから生成されます(複数のユニットに同一の翻訳番号が割り当てられた場合は、それらを区別するために2つ目以降のユニットに通し番号が振られます)。
上記の例において、生成される1つ目のユニットには start_636ae3f5 という識別子が割り当てられ、次のステートメントを含んでいます:
e "Thank you for taking a look at the Ren'Py translation framework."
2つ目のユニットには start_bd1ad9e1m という識別子が与えられ、次を含みます:
e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
3つ目のユニットには start_9e949aac という識別子が与えられ、次を含みます:
e "Pretty much everything your game needs!"
これらのユニットは、Ren'Py がゲームを読み込んだ時に自動的に生成されます。
Translate ステートメント
ある言語の翻訳を生成するとき、Ren'Py はそれぞれの翻訳ユニットに対応した translate ステートメントを生成します。上記のコードを翻訳するとき、Ren'Py は次のコードを生成します
# game/script.rpy:95
translate piglatin start_636ae3f5:
# e "Thank you for taking a look at the Ren'Py translation framework."
e ""
# game/script.rpy:99
translate piglatin start_bd1ad9e1:
# e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
e ""
# game/script.rpy:101
translate piglatin start_9e949aac:
# e "Pretty much everything your game needs!"
e ""
生成されたコードを編集して翻訳できます。翻訳が完了すると次のようになります
# game/script.rpy:95
translate piglatin start_636ae3f5:
# e "Thank you for taking a look at the Ren'Py translation framework."
e "Ankthay ouyay orfay akingtay away ooklay atway ethay En'Pyray anslationtray ameworkfray."
# game/script.rpy:99
translate piglatin start_bd1ad9e1:
# e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
e "Eway aimway otay ovidepray away omprehensivecay ameworkfray orfay anslatingtray ialogueday, ingsstray, imagesway, andway ylesstay."
# game/script.rpy:101
translate piglatin start_9e949aac:
# e "Pretty much everything your game needs!"
e "Ettypray uchmay everythingway ouryay amegay eedsnay!"
メインスクリプトの中にブロックが見つかると、Ren'Py はそのブロックに対応する translate ステートメントが存在するかどうかを確認します。存在する場合は翻訳前のブロックの代わりに translate ステートメントを実行し、ユーザーに翻訳結果を表示します。
より複雑な翻訳
translate ステートメントでは、原文に対して1対1の翻訳にする必要はありません。例えば、長い行は分割できます:
# game/script.rpy:99
translate piglatin start_bd1ad9e1:
# e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
e "Eway aimway otay ovidepray away omprehensivecay ameworkfray..."
e "...orfay anslatingtray ialogueday, ingsstray, imagesway, andway ylesstay."
または、pass
ステートメントに置き換えて削除できます:
# game/script.rpy:101
translate piglatin start_9e949aac:
# e "Pretty much everything your game needs!"
pass
条件文や Python のコードなどの、台詞以外のステートメントも実行できます。例えば次のコード
e "You scored [points] points!"
これを次のように翻訳できます:
# game/script.rpy:103
translate piglatin start_36562aba:
# e "You scored [points] points!"
$ latin_points = to_roman_numerals(points)
e "Ouyay oredscay [latin_points] ointspay!"
元の言語の台詞のある行を変更しても、その行の再翻訳の要求をしたくないときがあります。例えば英語のタイプミスの修正がロシア語への翻訳プロセスで影響するのは望ましくないです。
これは id
節をsay ステートメントの一部に含め、このステートメントに使用する翻訳 ID を指定して行えます。例
label start:
e "This used to have a typo." id start_61b861a2
ヒント
ラベルの中の複数の場所で同じ台詞が繰り返される場合は、翻訳された台詞の変更には特に注意して下さい。いくつかの例では、次のように翻訳用の識別子をステートメントを使って直接割り当てる必要があるでしょう:
translate None mylabel_03ac197e_1:
"..."
ラベルの追加によっても翻訳の過程で混乱が発生します。これを防ぐには、ラベルに hide
節を与えて翻訳コードから無視されるようにします。:
label ignored_by_translation hide:
"..."
翻訳ブロックが Python のコードを含む場合、コードはブロックの外側に影響を及ぼすべきではありません。何故ならば、言語を変更するときに翻訳ブロックは再度開始されますが、これによって副作用が何度も発生してしまうからです。
メニューと文字列の翻訳
台詞に加えて Ren'Py ではメニューのテキストやその他の文字列を翻訳できます。インターフェイスの翻訳に1対1で対応しています。どこであろうとある文字列が見つかれば、それは別のある文字列に置換されます。
翻訳の生成時に、Ren'Py はスクリプトファイルのメニュー、及び _()
関数で囲まれた文字列をスキャンします。すると、translate strings
ブロック内にスキャンされた文字列が設置されます。例えば、次のコードがあったとします:
define e = Character(_("Eileen"))
# ...
menu:
"Go West":
# ...
"Head East":
# ...
Ren'Py は次のコードを生成します
translate piglatin strings:
old "Eileen"
new ""
old "Go West"
new ""
old "Head East"
new ""
これは次のように翻訳できます:
translate piglatin strings:
old "Eileen"
new "Eileenway"
old "Go West"
new "Ogay Estway"
old "Head East"
new "Eadhay Eastway"
String translation は台詞としては翻訳されない台詞の文字列にも適用されます。
コード中で同一の文字列が複数の場所に存在する場合、文字列は {#...} テキストタグを使って見分けられます。次のようにした場合、それぞれの文字列は同じように表示されますが、Ren'Py は翻訳では異なる文字列として認識します
"New"
"New{#project}"
"New{#game}"
"New{#playlist}"
translate strings
ステートメントは、None 言語の翻訳にも使用できます。これは、英語以外の言語で制作されたゲームに対し、Ren'Py ユーザーインターフェイスを翻訳する場合に利用できます。:
translate None strings:
old "Start Game"
new "Artstay Amegay"
置換テキストの翻訳
文字列を翻訳文字列で置き換えるには、!t
変換フラグを使います。次のコードは台詞とコードの翻訳システムを使って翻訳できます
if mood_points > 5:
$ mood = _("great")
else:
$ mood = _("awful")
"I'm feeling [mood!t]."
翻訳文字列の抽出統合
翻訳文字列はあるプロジェクトから抽出して、他に移せます。これは複数の手順を経ます :
元のプロジェクトを選び、「Generate Translations(飜訳の生成)」を選択します。
抽出する言語を選び、「Extract String Translations(文字列の飜訳を抽出)」をクリックします。
メインメニューに戻り、対象のプロジェクトを選択「Generate Translations(飜訳の生成)」を選択します。
統合する言語を入力し、「Merge String Translations(文字列の飜訳を統合)」を選択します。
統合の管理をするいくつかの設定があります。
- 既にある翻訳を置き換える
チェックすると、 (空でないか、元の文字列の)既存の翻訳は置き換えられます。デフォルトでは統合は既存の翻訳を破棄し、上書きします。
- 言語を反転させる
統合前の文字列に戻します。例えば、英語->ロシア語用の翻訳ファイル作成->英語の翻訳 のような組み合わせでできます。
画像とファイルの翻訳
ゲームを翻訳するとき、ファイルを翻訳版に置き換える必要があるかもしれません。例えば画像にテキストが含まれている場合、意味が分かるようにテキスト部分が別の言語で書かれた画像に置き換えるでしょう。
このような場合に Ren'Py は画像を翻訳ディレクトリーの中から探します。例えば「piglatin」言語において「library.png」を読み込むとき、Ren'Py は「game/tl/piglatin/library.png」を「game/library.png」よりも優先して使います。
そのファイルが game ディレクトリー下のディレクトリーにあるなら、そのディレクトリをその言語直下にも配置するべきです。例えば「 game/gui/main_menu.png 」 は 「 game/tl/piglatin/gui/main_menu.png 」を作成して翻訳できます。
スタイルの翻訳
ゲームの翻訳時に、スタイルの変更 (特にフォント関係のスタイル) が必要になるでしょう。Ren'Py ではこれに対し translate style
ブロックと translate python
ブロックで対応しています。これらのブロックには、言語関係の変数やスタイルを変更するためのコードを含められます。例えば
translate piglatin style default:
font "stonecutter.ttf"
より一般的には台詞に使用されるフォントは gui.text_font
で設定されますが、これは次のようにカスタマイズできます。
translate piglatin python:
gui.text_font = "stonecutter.ttf"
ある言語が実行された時 (ゲームの開始時、もしくは言語が変更された後)、Ren'Py は init フェーズの終了時までスタイルの内容をリセットします。次にすべての translate python
ブロックとスタイルブロック、現在の言語と関連づけられた translate style ブロックを実行します。ファイル内で先に現れるブロックが先に実行されます。最後にスタイルを再構築して変更を反映します。
スタイルの翻訳はどのような .rpy ファイルにも追加できます。
既定の言語
既定の言語は次の方法によって選択します:
翻訳に関連したアクション、関数、変数
言語を切り替える主な方法は、Language アクションの使用です。
-
Language
(language)
ゲームの言語を language に変更します。
- language
翻訳先の言語の文字列、または None のときはゲームスクリプトの既定の言語を使います。
Language アクションを使うと、次のようなコードを使って設定画面に言語設定を追加できます
frame:
style_prefix "pref"
has vbox
label _("Language")
textbutton "English" action Language(None)
textbutton "Igpay Atinlay" action Language("piglatin")
翻訳関連の関数は2つあります:
-
renpy.
change_language
(language, force=False)
現在の言語を language に変更します。この値は文字列、または既定の言語の場合は None にできます。
-
renpy.
known_languages
()
既知の言語のセットを返します。これには既定の言語 None は含まれません。
さらに、文字列の翻訳に関連した 4 つの関数があります:
-
_
(s)
(単一のアンダースコア) s を変更せずに返します。Ren'Py はこの関数で囲まれた文字列をスキャンし、翻訳可能な文字列のリストにそれを追加します。文字列は表示されるまで翻訳されません。
-
__
(s)
(2重アンダースコア) s を現在の言語に直ちに翻訳して返します。この関数で囲まれた文字列は、翻訳可能な文字列のリストに追加されます。翻訳後の文字列が表示される時に、文字列翻訳にマッチすると文字列が2重に翻訳されてしまうことに注意してください。
-
_p
(s)
文字列を再フォーマットしてから、翻訳可能としてフラグをつけます。文字列はテキスト displayable で表示されるときに翻訳されます。これは次の形式で、文字列で使用する複数行を定義することを意図しています。
define config.about = _p("""
These two lines will be combined together
to form a long line.
This line will be separate.
""")
再フォーマットは、各行の最初と最後のホワイトスペースを除去してテキストを1つの行にします。このとき空白行は最後に除去され、空白行があるときは、空白行に分離パラグラフが挿入されます。 {p} タグは行を改行し、空白行は追加しません。
これは文字列の翻訳において、次のように使用できます。
old "These two lines will be combined together to form a long line.\n\nThis line will be separate."
new _p("""
These two lines will be combined together
to form a long line. Bork bork bork.
This line will be separate. Bork bork bork.
""")
-
renpy.
translate_string
(s, language=<renpy.object.Sentinel object at 0x7f79254c9d10>)
s を language に直ちに翻訳して返します。 language が未指定なら、 preferences で設定された言語を使用します。この関数で囲まれた文字列は、 非 翻訳可能文字列のリストに追加されません。翻訳後の文字列が表示される時に文字列翻訳にマッチすると二重翻訳されるので注意してください。
言語関連の変数は2つあります。1つは config.language
で、これはゲームの既定の言語を変更するために使用されます。
-
_preferences.language
現在の言語の名前、または既定の言語が使われている場合は Noneです。これは読み込み専用の変数として扱わなければなりません。言語を変更するには renpy.change_language()
を使用して下さい。
正式な認可を受けていない場合の翻訳
注釈
正式に認可されていない翻訳を作成する前に、ゲーム制作者の許諾を得ることが最善です。
Ren'Py はゲーム制作者からの十分な支援が無い場合の翻訳の作成に、少しだけ対応しています。これはゲームのすべての文字列から自動的に文字列翻訳ファイルを作成する機能です。未翻訳の台詞に対して文字列翻訳を行う方法により、ゲームの翻訳が可能となります。
文字列翻訳ファイルの作成は、次の手順で行います:
RENPY_LANGUAGE 環境変数を翻訳先にしたい言語に設定します。
RENPY_UPDATE_STRINGS 環境変数を空でない値に設定します。
すべてのテキストが表示されるまでゲームを動かします。
これにより「 game/tl/language/strings.rpy 」ファイルが更新され、すべてのテキストが含まれた翻訳の雛形となります。
ゲームに言語切り替え機能が含まれていない場合は、 init python
ブロックで config.language
にその言語を設定するのが適切でしょう。
台詞の文字列翻訳を使った場合、認可を受けていない翻訳者は画像やスタイルの翻訳に対して上記で説明した方法は使えません。