Flutter 앱의 ARB 파일에서 누락된 키 찾기

업데이트 · LocalePilot

영어에 추가하고 독일어에서는 잊어버린 키, 한 언어에서만 이름이 바뀐 플레이스홀더. 이런 실수는 문제없이 컴파일되고 결국 사용자 눈앞에 나타납니다. 출시 전에 잡아내는 방법을 소개합니다.

브라우저에서 바로 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를 실패시키세요.