お急ぎですか?ブラウザでそのまま ARB ファイルをチェックできます。無料・登録不要で、何もアップロードされません。
おさらい:ARB ファイルの構成
flutter gen-l10n では、言語ごとに専用のファイル(app_en.arb、app_fr.arb など)があります。l10n.yaml の template-arb-file で指定するテンプレートファイルが基準で、すべてのキーとその @key メタデータ(説明、プレースホルダー)を持っています。
{
"cartCount": "{count, plural, =0{Empty cart} =1{1 item} other{{count} items}}",
"@cartCount": {
"placeholders": { "count": { "type": "int" } }
}
}
1. 未翻訳のメッセージを Flutter に一覧にさせる
l10n.yaml に untranslated-messages-file オプションを追加します。
arb-dir: lib/l10n
template-arb-file: app_en.arb
untranslated-messages-file: untranslated.json
生成のたびに、Flutter は各言語で不足しているテンプレートのキーをこのファイルに書き出します。最も手軽に導入できるチェックです。リリース前に、このファイルが空(または {} だけ)であることを確認してください。
2. 小さな Dart スクリプトでキーを比較する
はっきり失敗する CI チェックなら、スクリプトで十分です。
import 'dart:convert';
import 'dart:io';
void main() {
final dir = Directory('lib/l10n');
final template = _keys(File('lib/l10n/app_en.arb'));
var failed = false;
for (final file in dir.listSync().whereType<File>()) {
if (!file.path.endsWith('.arb')) continue;
final missing = template.difference(_keys(file));
if (missing.isNotEmpty) {
failed = true;
print('${file.path}: ${missing.join(', ')}');
}
}
if (failed) exit(1);
}
Set<String> _keys(File f) => (jsonDecode(f.readAsStringSync()) as Map<String, dynamic>)
.keys
.where((k) => !k.startsWith('@'))
.toSet();
@ で始まるキーはメタデータなので、比較から除外しています。
3. プレースホルダーをチェックする
すべての言語にあるキーでも壊れることがあります。テンプレートが {count} を宣言しているのにフランス語訳が {nombre} を使っていると、gen-l10n はすべてのロケールに nombre を余分なパラメータとして追加し、既存の呼び出し箇所がコンパイルできなくなります。逆に、プレースホルダーを単に落とした翻訳は、何の警告もなく通ります(詳しくは ICU 複数形とプレースホルダーのガイドを参照)。キーごとに、波括弧内の名前を @key.placeholders で宣言された名前と比較してください。ICU メッセージ(plural、select)には注意が必要です。other のようなキーワードはプレースホルダーではありません。
4. 空の値にも注意する
翻訳パイプラインによっては、翻訳されるまでキーを空の値で作成するものがあります。これは「不足」としては表示されないため、テンプレート以外のすべての言語で空文字列を検出するチェックを追加してください。
リリース前のチェックリスト
- 未翻訳メッセージのファイルが空である。
- すべての言語がテンプレートと同じキーを持っている。
- プレースホルダーがキーごとに一致している。
- テンプレート以外に空の値がない。
- 長いメッセージを、文が長くなりがちな言語(ドイツ語など)で画面上で確認した。