안드로이드를 만들며 3 — aapt는 줄바꿈을 공백 하나로 접습니다
strings.xml에 두 줄로 적은 문장이 화면에서는 띄어쓰기 하나로 이어 붙었어요. 네 문자열이 그랬고, 번역된 열한 언어가 똑같이 그랬습니다.
지난 두 편에서는 화면에서 조용히 틀어진 것들을 봤어요. 남의 글꼴이 들어온 슬롯, 그리고 그늘로는 세울 수 없던 삼각형이었죠.
이번엔 문장입니다. 그리고 이건 한 언어에서 끝나지 않았어요. 원문이 앓으면 번역이 그 병을 그대로 물려받거든요.
설정 화면에 이런 문장이 떠 있었습니다.
선택 안 해도 계산 가능 나중에 이력에서 변경
한국어인데 뜻이 안 통하죠. “선택 안 해도 계산 가능”과 “나중에 이력에서 변경”, 두 문장이 하나로 붙어 있었어요.
strings.xml에는 이렇게 적혀 있었습니다.
<string name="stock_optional_hint">선택 안 해도 계산 가능
나중에 이력에서 변경</string>
의도는 두 줄이었어요. 화면은 한 줄이었고요.
잇단 공백을 하나로 접는데, 줄바꿈도 공백입니다
안드로이드의 자원 컴파일러(aapt)는 문자열 자원 안의 잇단 공백을 공백 하나로 접습니다. XML에서는 흔한 정리예요. 들여쓰기 때문에 생긴 공백이 화면에 나오면 곤란하니까요.
문제는 줄바꿈도 공백이라는 것이었습니다.
<!-- 적은 것 -->
<string name="a">첫 줄
둘째 줄</string>
<!-- 화면에 나오는 것 -->
첫 줄 둘째 줄
줄을 바꾸고 싶으면 이렇게 적어야 해요.
<string name="a">첫 줄\n둘째 줄</string>
왜 여태 안 보였을까요
두 조각이 각각 마침표로 끝나면 티가 안 납니다.
“A입니다. B입니다.” → “A입니다. B입니다.”
붙어도 읽히죠. 그런데 우리 문장은 명사형 토막이었어요.
“선택 안 해도 계산 가능” + “나중에 이력에서 변경” → “선택 안 해도 계산 가능 나중에 이력에서 변경”
마침표가 없으니 어디서 끊어야 할지 알 수가 없습니다.
같은 병을 앓는 문자열이 넷이었고, 번역된 열한 언어가 전부 똑같이 앓았어요.
여기서 일이 생각보다 커졌습니다.
- 원문이 두 줄이라, 번역도 두 줄로 옮겨졌습니다.
- 접히는 것은 원문에서 일어나는 일이라 번역가가 알아챌 자리가 없어요.
- 빌드도 린트도 아무 말이 없습니다.
- 그 화면을 그 언어로 열어본 사람만 압니다.
열한 언어를 전부 열어보는 사람은 없죠. 그래서 이건 “언젠가 누가 제보하면 아는” 종류의 버그였고, 제보가 안 오면 영영 그대로였을 거예요.
검사를 세웠어요 — 그리고 일부러 틀린 줄을 먼저 넣어봤습니다
번역 완성도를 재는 검사(TranslationCompletenessTest)에 규칙을 하나 더했어요.
날 줄바꿈이 든 문자열을 잡습니다.
세울 때 한 가지를 반드시 했어요. 일부러 틀린 줄을 넣어보고, 검사가 잡는지 먼저 봤습니다.
1. strings.xml 에 두 줄짜리 문자열을 하나 심는다
2. 검사를 돌린다
3. 빨간불이 뜨는 것을 확인한다
4. 심은 것을 걷는다
이 절차를 건너뛰면 검사가 통과할 때 그게 “문제가 없다”인지 “검사가 아무것도 안 본다”인지 알 수 없어요.
안 잡는 검사는 검사가 있다는 사실로 오히려 사람을 안심시킵니다. 그건 없는 것보다 나빠요.
붙어도 뜻이 통하던 줄까지 같이 폈어요
넷 중 둘은 마침표로 끝나서 붙어도 읽혔습니다. 그래도 같이 폈어요.
남겨두면 다음 사람이 그 파일을 열었을 때 “여기서는 줄이 나뉜다”고 믿게 되거든요. 그리고 그 믿음으로 새 문자열을 두 줄로 적습니다.
틀린 예제 하나가 파일 안에 남아 있으면, 그건 예제가 아니라 규칙이 됩니다.
이번 작업에서 정한 기준
- 문자열 자원 안에서는 줄을 바꾸지 않습니다. 줄이 필요하면
\n으로 적어요. - 검사를 세울 때는 일부러 틀린 것을 넣어 잡히는지 먼저 봅니다.
- 붙어도 뜻이 통하던 줄까지 같이 폅니다. 남은 하나가 다음 사람의 본보기가 되니까요.
번역은 원문의 병을 그대로 물려받습니다. 그러니 원문이 건강해야 해요.
결국 바꾼 것
여기까지 세 편은 전부 화면과 문장이 조용히 틀어진 이야기였어요. 전부 “그 자리를 직접 열어본 사람만 아는” 종류였고요.
다음 글은 조금 안쪽으로 들어갑니다. 같은 날 버그 둘이 나왔는데, 나란히 놓고 보니 같은 병이었던 이야기예요.