翻訳率99.7%でも画面は壊れていた——OSSの日本語化で25か所のプレースホルダ崩れを見つけて本家へPRを出した記録
名古屋でAIシステム開発の会社をやっています。ヘルプデスクOSS LibreDesk(GitHubスター2,861・Go製・AGPL v3)を日本語化しました。この記事は、その過程で見つけた翻訳の落とし穴の話です。
翻訳は「完成」していた
翻訳ファイルは1,536項目。未訳ゼロ。英語のまま残っていたのは13項目だけで、それも google github linkedin のような固有名詞——訳すべきでないものでした。
翻訳率99.7%。 数字の上では完成しています。
それでも画面は壊れていた
本家へPRを出す前に、1項目ずつ英語と突き合わせました。すると、日本語だけに存在するプレースホルダが25か所見つかりました。
| キー | 英語 | 日本語 |
|---|---|---|
globals.messages.add |
Add |
{name} を追加 |
globals.messages.delete |
Delete |
削除 {name} |
ai.apiKeyNotSet |
The AI provider API key is not set… |
{provider} の API キーが… |
一見すると、日本語のほうが親切に見えます。「追加」より「顧客を追加」のほうが分かりやすい。
問題は、呼び出し側が引数を渡していないことでした。
frontend/.../HelpCenterForm.vue: t('globals.messages.add')
internal/ai/ai.go: m.i18n.T("ai.apiKeyNotSet")
どちらも引数なしです。英語では Add がそのまま出るので問題になりませんが、日本語では画面に {name} を追加 と表示されます。
翻訳した人は画面を全部は開いていない。開発者は日本語を読まない。だから誰も気づかないまま残っていました。
翻訳率は品質を保証しない
この経験から、OSSを日本語化するときの確認項目が1つ増えました。
未訳の数ではなく、プレースホルダの一致を見る。
pe = set(re.findall(r'\{[^}]+\}', en[key]))
pj = set(re.findall(r'\{[^}]+\}', ja[key]))
if pe != pj: # ← ここが壊れていると画面に生の {name} が出る
たった数行ですが、翻訳率100%のファイルから25か所の不良を見つけました。日本語化を請ける立場としては、納品前に必ず通すべき検査だと考えています。
なお、意図的に違ってよい場合もあります。今回は2か所残しました。テンプレート構文の使用例を見せている文字列で、例そのものを日本語にしたほうが読み手に伝わるためです。機械的に全部揃えると、かえって分かりにくくなります。
公式イメージでは日本語が使えない
もう1つ、動かして初めて分かったことがあります。
LibreDesk は翻訳ファイルを stuffbin でバイナリに埋め込みます。cmd/init.go の initFS() が外部ファイルでの上書きを許すのは static ディレクトリだけで、i18n は差し替えられません。
つまり、公式イメージに日本語ファイルをマウントしても効きません。自分でビルドする必要があります。
docker compose -f docker-compose.jp.yml up -d --build
実際にビルドして起動し、配信される翻訳をAPIで確認しました。
$ curl -s http://127.0.0.1:18355/api/v1/lang/ja-JP
1,536キー
globals.messages.add = 追加 ← 修正前は「{name} を追加」
globals.terms.read = 既読
画面を見る前にAPIで判別できるので、日本語版が本当に動いているかの確認はこれが確実です。
本家へPRを出しました
修正した翻訳を abhinavxd/libredesk#550 として送りました。翻訳ファイル1つだけの変更です。
PRには、既定言語を日本語に変える変更は入れていません。自社フォークでは正しくても、本家に入れると世界中の利用者の既定が日本語になるためです。日本語化のPRを出すときに混ざりやすいので、分けて考える必要があります。
マージされれば、公式イメージのままで日本語が使えるようになります。 自前ビルドが要らなくなるので、導入の手間が一段下がります。
使いどころ
正直に書くと、LibreDesk は誰にでも勧められるものではありません。
「single binary」を名乗っていますが、PostgreSQL と Redis が別途必要です。共有レンタルサーバーでは動きません。VPSが前提です。
当社は既に FreeScout の日本語導入キットを出していますが、こちらは共有レンタルサーバーで動きます。分かれ方はこうです。
| FreeScout | LibreDesk | |
|---|---|---|
| 動く場所 | 共有レンタルサーバー可 | VPS必須 |
| 必要なもの | PHP + MySQL | Go + PostgreSQL + Redis |
| 日本語 | 公式同梱 | 当社が全訳(本家PR提出済み) |
| ライセンス | AGPL v3 | AGPL v3 |
月数百円で始めたいならFreeScout、VPSを既に持っているならLibreDeskです。
入手経路3つ
経路1: 無料(GitHub・AGPL v3)
日本語版のソースを公開しています。翻訳の中身は買う前に確認できます。
経路2: 導入キット 5,500円
構築して踏んだ落とし穴を手順書にしました。ポート衝突の回避、日本語が出ているかの確認方法、ライブチャットが動かなくなるnginx設定など、動く状態にするまでの時間を買っていただく形です。ソフト本体は含みません(OSSなので無料で入手できます)。
経路3: 構築を任せる 110,000円〜
まとめ
- 翻訳率は品質を保証しない。 未訳ゼロでも、プレースホルダが崩れていれば画面は壊れる
- 検査はプレースホルダの集合比較で足りる。数行で25か所の不良が出た
- 日本語化のPRに、既定言語の変更を混ぜない
- 動いているかは画面ではなくAPIで確かめる