자동화 파이프라인12 분 읽기

lint은 번역 누락이 9건이라고 했습니다. 실제로는 509건이었습니다

MissingTranslation은 로케일 파일에 키가 있는지만 봅니다. 값이 영어 원문 그대로여도 통과합니다. 다섯 개 언어 사용자가 앱의 절반을 영어로 보고 있었고, 지표상으로는 완역이었습니다.

#localization#verification#android#automation#gotchas
개념 도식: 키 존재 · 값 번역 · 카탈로그 등록이라는 세 층과 각 층에서의 검사 결과
글 내용을 요약한 개념 도식.

한 안드로이드 앱의 릴리스 점검에서 lint가 MissingTranslation 9건을 냈습니다. 그것만 채우면 끝나는 줄 알고 시작했습니다.

전수 대조를 돌리니 509건이었습니다.

질문 하나 드리겠습니다. 당신의 번역 검사기는 "키가 있는가"를 봅니까, "그 값이 번역됐는가"를 봅니까? 그 둘은 다른 질문입니다.

1. lint이 보는 것은 키의 존재뿐입니다

MissingTranslation은 로케일 파일에 키가 있는지만 봅니다. 값이 영어 원문 그대로여도 통과합니다.

그 앱의 독일어 · 스페인어 · 프랑스어 · 이탈리아어 · 브라질 포르투갈어는 나중에 추가되면서 영어를 그대로 복사해 둔 상태였습니다.

it 104 · pt-rBR 102 · de 101 · es 101 · fr 101   = 509

포함된 것: 페이월 전체(22키) · 스캔 화면 · 바코드 조회 · 알림 · 레시피 · 계정 화면. 즉 그 다섯 나라 사용자는 앱의 절반을 영어로 보고 있었습니다. 지표상으로는 완역이었습니다.

스토어는 앱이 못 하는 언어를 말하고 있던 이야기자막에 같은 구멍이 있던 이야기가 같은 감사의 다른 층입니다. 그리고 대비 검사는 통과했는데 디자인이 죽어 있던 이야기와 나란히 두면 형태가 같습니다. 검사기가 통과시킨 것이 사용자에게는 깨져 있는 형태입니다.

2. 이건 층이 여러 개인 문제입니다

한 층을 보는 검사는 다른 층에서 언제나 통과합니다. 같은 감사에서 다른 두 층에도 물렸습니다.

층 ① — 소스 문구가 카탈로그에 애초에 없다

번역 검증기가 "전 키 × 전 로케일 번역 있음"을 찍는데 앱은 영어로 나갑니다. 검증기가 카탈로그 만 보기 때문입니다.

소스에 있는 문구가 카탈로그에 없으면 검사 대상이 0건이고, 0건은 언제나 100% 통과입니다.

더 나쁜 형태도 있습니다. 키만 있고 값이 없으면 시스템이 키 문자열 자체를 화면에 그립니다. 사용자가 session.error.outOfMinutes를 읽습니다. 영어보다 나쁩니다.

층 ② — 보간에 붙인 단위, 비라틴 로케일의 라틴 전용 값

로케일 파일이 다 있고 키 수도 같은데 화면에 영어가 나가는 누수 둘입니다.

"${streak}d"처럼 코드가 붙인 단위는 리소스를 우회합니다. 러시아어 통계 화면에 "7d"가 찍혔습니다. 그리고 러시아어 난이도가 Новичок / Casual / Профи / Босс였습니다. Boss는 음차했으면서 Casual만 안 한 것입니다.

3. 그런데 이 판정에는 정상 케이스가 섞입니다

여기가 제일 중요한 부분입니다. 세어서 보고하면 틀립니다.

플릿 전수로 돌리니 15개 앱 247건이 나왔습니다. 표본을 하나씩 확인했더니 대부분 정상이었습니다.

  • 고유명사 · 기관명 · 제품명
  • 여러 언어에서 같은 의학 용어
  • 그 언어의 차용어: 이탈리아어 "Password" · "Account", 프랑스어 "Date", 스페인어 "Legal"
  • 디버그 · 자리표시자 문자열

⚠️ 처음에 "진짜인 것도 있다"며 두 앱의 키를 지목했는데 전부 틀렸습니다. 키마다 근거를 확인하니 하나도 결함이 아니었습니다.

판정 근거는 늘 같은 로케일의 다른 키에 있었습니다.

  • 어떤 앱의 특정 로케일은 짝이 되는 키들은 번역해 두고 두 개만 영어로 뒀습니다. 그 담화에서 쓰는 차용어를 고른 판단이었습니다. 같은 로케일의 다른 파일에서 번역자가 영어 단수/복수를 손본 흔적도 있었습니다.
  • "Digestion" · "Fatigue"는 그게 프랑스어 단어입니다.
  • 어떤 로케일은 본문 전체에서 그 영어 낱말을 차용어로 씁니다. 탭 라벨이 영어로 폴백되는 것이 오히려 일관됩니다.

결론: 그 두 앱에는 코드 변경 0건으로 끝냈습니다. 숫자만 보고 고치면 고유명사를 번역하고 차용어를 뒤집습니다.

자릿수를 신호로 쓸 수 있습니다. 509 vs 나머지 앱당 ≤18. 자릿수가 다르면 성질도 다릅니다. 앞의 것은 파이프라인 사고고 뒤의 것은 어휘 판단입니다.

4. 당신이라면 509건을 어떻게 채우시겠습니까

다섯 언어 × 100여 키입니다.

  • (a) 기계번역 API로 일괄 채운다
  • (b) 손으로 번역한다
  • (c) 다른 곳에서 이미 검증된 번역을 수확한다

저는 (c)였습니다. 용어는 그 앱의 기존 번역에서 가져옵니다.

⚠️ 다른 앱에서 베끼면 앱 안에서 용어가 갈립니다. 중국어 "계정"을 두 앱이 다르게 씁니다. 같은 키가 있는 앱이 없으면 영어 원문이 같은 키를 찾습니다.

그리고 중복 키는 번역하지 말고 없앱니다. "취소"를 뜻하는 키가 두 개였고 덜 쓰이는 쪽만 15로케일 번역이 있었습니다. 호출부를 바꾸고 키를 지웠습니다. 번역 15건 절약.

5. 판정 방법 — 층마다 다릅니다

층 ②(값이 안 번역됨): 로케일 값이 기본 로케일 값과 완전히 같은지 봅니다.

같은 값 + 길이 6자 이상 + 라틴 문자 포함 + 브랜드/고유명사 아님

층 ①(카탈로그에 없음): 소스 → 카탈로그 대조를 검증기에 넣습니다. 화면 문구를 만드는 호출 (Text|Label|Button|Link|Section|navigationTitle|accessibilityLabel 등)의 리터럴과 문자열 조회 키를 뽑고, 보간은 카탈로그가 쓰는 포맷 지정자로 바꾼 뒤(\(n) minutes%lld minutes) 카탈로그 키 집합과 뺍니다. 캡처 전용 화면은 제외합니다. 반대 방향(카탈로그에만 있는 키)은 죽은 키일 뿐이라 막지 않습니다.

보간 누수: 보간 뒤에 글자가 붙은 곳을 찾습니다.

grep -rn '}\w*"' --include='*.kt'

고치는 법은 보통 단위를 떼는 것입니다. 카드 제목이 이미 "연속"이면 단위는 군더더기고, 16개 번역도 복수형 규칙도 필요 없어집니다. 비라틴 로케일의 라틴 전용 값은 ^[A-Za-z0-9 .,!?%-]+$로 걸러내고, 브랜드명과 진짜 관용어는 제외 목록으로 둡니다.

6. 검증은 실기 로케일 조회로

계측 테스트에서 로케일을 바꿔 문자열을 조회하고 값이 영어와 다른지 단정합니다. lint가 못 보는 층을 여기서 봅니다.

음성 대조: 한 키를 영어로 되돌리면 그 키를 지목해 실패해야 합니다. 자리표시자는 치환 전후로 멀티셋 대조를 겁니다.

결과: 498건을 채워 릴리스했습니다.

자가진단 3가지

  1. 당신의 번역 검사기가 검사한 항목 수를 출력합니까? 0건이면 100% 통과입니다. 분모를 안 찍는 검사기는 통과율을 보고할 자격이 없습니다.
  2. 로케일 값이 영어 원문과 글자까지 같은 키가 몇 개입니까? 한 줄 스크립트면 셉니다.
  3. 코드가 문자열에 단위나 접미사를 붙이는 곳이 있습니까? 그 글자는 리소스를 우회합니다.

솔직한 부분

이 감사에서 제가 제일 크게 틀린 것은 509건이 아니라 247건 쪽이었습니다. 숫자를 보고 "플릿 전체가 이렇구나" 했는데, 하나씩 열어 보니 거의 다 번역자가 옳게 내린 판단이었습니다. 제가 만든 검사기가 "Password는 이탈리아어에서도 Password다"를 모를 뿐이었습니다.

검사기를 믿고 고쳤으면 15개 앱의 차용어를 전부 뒤집어 놓았을 겁니다. 검사기가 못 보는 층이 있다는 이 글의 주장은, 제 검사기에도 똑같이 적용됩니다.

지금 딱 하나만 해 보세요. 로케일 파일 하나를 열어 기본 로케일과 값이 같은 줄을 세어 보십시오. 자릿수가 두 자리를 넘으면 그건 어휘 판단이 아니라 파이프라인 사고입니다.

관련 글