브라우저에서 바로 번역의 플레이스홀더를 검사해 보세요. 무료이고 가입이 필요 없으며, 아무것도 업로드되지 않습니다.
%는 어디서 오는가
iOS 앱에서 변수가 있는 현지화 문자열은 형식 문자열이 됩니다. SwiftUI에서는 암묵적으로 그렇게 됩니다.
Text("\(count) items left") // key: "%lld items left"
Text("Welcome back, \(name)!") // key: "Welcome back, %@!"
String(localized: "Total: \(price) €") // price is a Double: "Total: %lf €"
Int는 %lld, String은 %@, Double은 %lf가 됩니다. 예전 API에서는 형식을 직접 씁니다: String(format: NSLocalizedString("items_left", comment: ""), count). 이때 .strings 파일에는 %d나 %ld가 들어갑니다.
어느 쪽이든 번역가가 받는 텍스트에는 중간에 % 기호가 있고, 바로 거기서 문제가 생깁니다.
번역이 깨지는 세 가지 방식
지정자를 빠뜨리기. "Invitez %@ à modifier cette liste" 대신 "Invitez à modifier cette liste". 크래시는 없습니다. 인수가 무시되고 상대의 이름이 화면에서 사라질 뿐입니다. 가장 흔하면서도 눈에 잘 띄지 않는 실수입니다.
타입 바꾸기. %lld를 %@로, 또는 그 반대로 바꾸는 경우입니다. 형식은 인수를 잘못된 타입으로 읽습니다. 잘해야 엉뚱한 숫자, 최악이면 크래시입니다. %@는 객체를 기대하는데 정수가 들어오기 때문입니다.
조용히 순서 바꾸기. 어순이 다른 언어에서 "%@ shared %@"는 두 이름이 뒤바뀐 문장이 됩니다. 구문은 맞지만 의미가 틀립니다. 한국어는 어순이 영어와 크게 다르므로 특히 주의해야 합니다.
위치 지정으로 순서 바꾸기
순서를 바꾸려면 인수에 번호를 붙입니다. %1$@는 첫 번째 인수, %2$@는 두 번째 인수이며, 문장 어디에 있어도 됩니다.
/* source */ "%@ shared %@ with you" = "%1$@ shared %2$@ with you";
/* French */ "%@ shared %@ with you" = "%1$@ vous a partagé %2$@";
/* other order */ "%@ shared %@ with you" = "%2$@ : partagé par %1$@";
기억할 규칙은 하나입니다. 한 문자열 안에서는 모두 번호를 붙이거나 모두 붙이지 않아야 합니다. %1$@와 %@를 섞으면 동작이 정의되지 않습니다.
프랑스어 함정: "20 % de remise"
프랑스어 조판에서는 퍼센트 기호 앞에 공백을 넣습니다: "20 % de remise"(20% 할인). 형식 문자열에서는 이것이 문제가 됩니다. % d(퍼센트, 공백, d)가 유효한 지정자이기 때문입니다. 공백은 printf 플래그("양수 앞에 공백 채우기")이고 d는 정수 변환입니다. 다음 문장은
"Profitez de %lld % de remise"
인수 하나에 %lld와 % d, 두 개의 지정자를 갖게 됩니다. 두 번째 지정자는 존재하지 않는 값을 읽습니다. 올바른 형태는 기호를 두 번 쓰는 것입니다.
"Profitez de %lld %% de remise"
형식을 거치는 문자열, 즉 변수가 하나 이상 있는 문자열에만 해당합니다. 인수가 없는 고정된 "20 % de remise"는 쓴 그대로 표시됩니다. 하지만 번역은 계속 바뀌므로, 누군가 그 문장에 변수를 추가하면 홀로 있는 %는 버그가 됩니다.
복수형
"1 item / 3 items"를 위해 키 두 개와 코드의 if를 쓰지 마세요. String Catalog에서는 %lld items left 키에 복수형 변형(one, other, 언어에 따라 few나 many)을 두고, 각각에 %lld를 넣습니다. 한국어는 other 하나뿐입니다. 한 문장에 따로 변하는 숫자가 두 개 있으면 Xcode는 치환(%#@items@)을 씁니다. 드문 경우이며 Xcode에서 편집합니다.
출시 전 검사
기본 검사는 기계적입니다. 각 번역의 지정자 목록(타입과 위치)이 원문과 일치해야 합니다. LocalePilot의 QA가 .strings와 .xcstrings 파일에서 하는 일이 바로 이것입니다. %@, %1$@, %d, %ld, %lld, %.2f, %u, %i, %s를 인식하고, %%는 텍스트로 취급하며, 빠지거나 남는 지정자를 내보내기 전에 표시합니다. %e나 %x 같은 드문 변환은 바로 "20%en"을 오류로 오인하지 않기 위해 의도적으로 무시합니다. 위의 "% d" 경우는 사람이 검토해야 할 몫입니다. 프랑스어 번역에서 뒤에 공백이 오는 %를 검색해 보세요.