Flutter アプリの ARB ファイルで不足キーを見つける

更新 · LocalePilot

英語で追加してドイツ語では忘れたキー、1 つの言語だけで名前が変わったプレースホルダー。こうしたミスはビルドを通り、そのままユーザーの目に触れます。リリース前に検出する方法を紹介します。

お急ぎですか?ブラウザでそのまま 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. 空の値にも注意する

翻訳パイプラインによっては、翻訳されるまでキーを空の値で作成するものがあります。これは「不足」としては表示されないため、テンプレート以外のすべての言語で空文字列を検出するチェックを追加してください。

リリース前のチェックリスト

  • 未翻訳メッセージのファイルが空である。
  • すべての言語がテンプレートと同じキーを持っている。
  • プレースホルダーがキーごとに一致している。
  • テンプレート以外に空の値がない。
  • 長いメッセージを、文が長くなりがちな言語(ドイツ語など)で画面上で確認した。

よくある質問

Flutter は未翻訳を報告してくれますか?

はい、l10n.yaml に untranslated-messages-file を追加すれば、flutter gen-l10n が各言語で不足しているテンプレートのキーをそこに一覧にします。指定しない場合は、まとめの警告が出るだけです。

@key のメタデータはすべての言語にコピーする必要がありますか?

いいえ。メタデータ(説明、プレースホルダー)はテンプレートファイルから読み込まれます。他のファイルには翻訳だけがあれば十分です。

プレースホルダーの名前の誤りを防ぐには?

キーごとに、翻訳の波括弧内の名前とテンプレートで宣言された名前を比較し、異なる場合は CI を失敗させます。