Divinity Original Sin 2(以下、DOS2)は公式で日本語化されているが、その翻訳の品質に不十分な点がある。最近はLLMによる日本語翻訳の品質も上がってきているので、LLMを用いて翻訳をやり直すことが出来ないかと考えた。というわけで、Claude Codeを相棒にして、DOS2の再翻訳プロジェクトをスタートした。
まず最初に、DOS2において、英語テキストがゲームファイルとしてどこに保管されているか明らかにする。
以下、説明の都合上、 <GAME>
をDOS2までのpathとする。(そのまま表記すれば
C:\Program Files (x86)\Steam\steamapps\common\Divinity Original Sin 2
こんな感じになっているはず。)
まず、ゲームにおけるテキストは、
<GAME>\DefEd\Data\Localization\English.pak
で管理されていることが分かった。 .pak
という拡張子は、Larian製ゲームのエンジンが使うアーカイブ形式のファイル拡張子である。
.zip のようなものだと考えればいいだろう。
English.pak
を解凍すると、以下のような構造になっている:
Localization/
└─ English/
├─ english.xml 13,520,502 B ← ★本体。英語原文 92,327件
├─ english_to_F.xml 29 B ← 空(中身は宣言行だけ)
├─ language.lsx 573 B ← 言語定義
├─ Gender/Female/
│ ├─ english.xml 29 B ← 空
│ └─ english_to_F.xml 29 B ← 空
└─ Subtitles/ 245ファイル(すべて .lsx)
├─ CS_Epilogue_hxxx.lsx 203個(エピローグの各場面)
└─ その他 42個
CS_Intro.lsx / CS_Drowning.lsx / CS_BackToRC.lsx など 9個
Ending_1A_Part1A.lsx 〜 Ending_4C_Part2B.lsx 25個
Origin_Intro_{Fane,Ifan,Lohse,Beast,Sebille,RedPrince}.lsx 6個
EndMovie.lsx / Windego_Cutscene_Line_19.lsx
英語原文は english.xml
で管理されていることが分かった。
中身は以下のようになっている:
<contentList>
<content contentuid="h00002e6cg3610g4788g8e0eg7615ac443b6e">We agreed to help Hannag against the Magisters.</content>
<content contentuid="h0001d8b9g13d6g4605g85e9g708fe1e537c8">Custom</content>
...
</contentList>つまり、ゲーム内で取り扱われるテキストには、全て独自のID=
contentuid が割り振られている。
ちなみに、語数で言えば約115万語であり、ハリーポッター全7巻(約108万語)とほぼ同じ量となる!
.pak を解凍する方法コンピュータ上のどんなデータも、それをバイト列として読み取ることが出来る。もちろん、そのバイト列から意味を取り出すことが出来るかは別であるが。
Claudeが解析した結果、 .pak
のバイト列には以下の図のような構造があることが分かった。
目的のファイル(Target File)を .pak
ファイルから取り出す過程は以下のようになる:
headerSize
だけ遡ってheaderを読み込むことが出来る。fileListOffset を読み取る。fileListOffset だけ進んだ位置で、目次(Table
of Contents)の始まりが確定するので、目次が読み込める。.pak に格納されているファイル数
numFiles
の他に、ファイル毎に固定長(280バイト)のブロックが入っている。offset 、末尾を知るための sizeOnDisk
、そしてファイルの圧縮形式を表すフラグ Flags
が含まれている。offset
だけ進んだ位置で目的のファイルが見つかる。これはLZ4圧縮されているので、後は解凍するだけ。まず、人間が扱っているデータをどうやってデジタル化するかという問題意識があった。そこで、人間が扱う標準的な文字に番号を割り当てて、あらゆる文章を数字の列として取り扱う方法が考えられた。有名なのはASCIIコード。
コンピュータが究極的にはスイッチのON/OFFでデータを保持しているから、ビット=2進数1桁が自然な単位となる。しかし1ビットでは2種類の情報しか扱えないので、当然文字は無理だ。というわけで幾つかのビットをまとめて一つの文字に対応させるという規則が考えられる。何個をひとまとまりにするかについて、コンピュータの黎明期には色々案が出たらしいが、結局は8個がスタンダードになった。
数学的に言えば8は2の冪で書けるので、ビットと相性が良い。それに8ビットあれば、256種類の情報が区別出来るので、人間が扱う文字全てを含めてもまだ余裕がある。ということで、これが1バイトという単位になった。
コンピュータ上に存在するあらゆるデータは究極的にはバイトの列である。しかし、実際に読み取る際には1バイト=8ビットが単位となっている。(コンピュータ上で1バイト単位で住所が割り当てられるシステムとなっている。)
8ビットは2進数で8桁となる。人間が読むには桁数が大きすぎる。というわけで、データを人間が読む時にはこれを16進数化するのが一般的である。なぜ16進数かと言えば、それは8ビットがちょうど2桁で表現できるので、区切りが良いからだ。実際、16は8の次の2冪である。
.xml について人間が取り扱う文書について考えてみる。最も簡単に見れば、これは文字の羅列なのであるが、人間同士が理解するためには、そこに構造が付与されるのが普通である。例えば題名とか見出しとか、パラグラフといった構造を文書に付与することによって、人間はその文書を効率的に読み取ることができる。本の場合、そういった構造を付与するためには、文字サイズを大きくしたり、インデントしたりして視覚的な差異を生み出すことになる。これを単に文字の羅列として見るのは、こういった構造化の情報を忘れ去ることと言えるだろう。
HTMLは人間が取り扱う文書について、その構造までを表現するための技術である。ここでは本で行っているような視覚的な差異に頼るのではなく、文書の中に構造を示すための記号(タグ)を埋め込む=マークアップする。
こうして、情報をやり取りする際に、その中身を適切に構造化することで理解しやすくするというのは、人間の自然な習慣である。そこで、文書の構造を超えて、より広範な構造化が行えるように母体として作られたのがXMLというマークアップ言語である。
XMLはExtensible Markup Languageの略である。
例えば天気の情報についてやりとりするなら、気温、湿度、日付といった数字を単に羅列するのではなく、それぞれ特定のタグでくくることで、構造化した方がずっと分かりやすい。ここでXMLの出番となる。XMLは自由にタグを作ることが出来るので、予めその規則さえ共有しておけば、構造化した情報のやり取りをスムーズに行うことが可能となる。