당신의 스토어 설명이 그 언어로 제대로 쓰여 있는지 마지막으로 확인한 게 언제입니까?
저는 한 번도 없었습니다. 번역이 들어갔고, 글자 수가 맞고, 배포가 성공했으니 됐다고 생각했습니다. 실제로는 프랑스어 설명에서 아포스트로피가 통째로 사라진 채 몇 달이 지나 있었습니다.
왜 본문까지 봤나
키워드 면적이 가짜 한도에 막혀 있던 것을 고치고 나서, 같은 감사를 설명 본문으로 확장했습니다. 이유는 단순합니다 — 검색어를 다 넣어도 본문이 정자가 아니면 그 검색어로 안 잡힙니다.
판정 기준을 하나 정했습니다. 그 로케일 언어에 반드시 나타나야 하는 발음기호가 본문에 하나도 없으면 벗겨진 것으로 본다. 짧은 문구는 정상인데도 걸리므로 400자 넘는 장문만 셌습니다.
40개 슬롯이 걸렸습니다
빠진 것은 발음기호만이 아니었습니다.
프랑스어 본문에서 아포스트로피가 통째로 사라져 있었습니다. qu'elle n'est 가 qu elle n est 가 되고, d'ennemis 가 d ennemis 가 됐습니다. 이건 오타가 아니라 문장이 깨진 상태입니다. 이탈리아어도 l'Heavy 가 l Heavy 로 나가 있었습니다.
터키어가 더 나빴습니다. Slow Time'ı 가 Slow Time u 로, yüzde 70'ini 가 yuzde 70 ini 로 바뀌어 있었습니다. 아포스트로피가 격조사를 붙이는 언어에서 그걸 공백으로 만들면 낱말이 둘로 쪼개집니다. 검색 색인 입장에서는 아예 다른 낱말입니다.
베트남어와 폴란드어는 그 상태로는 읽히지 않습니다. 베트남어는 성조 부호가 의미를 가르고, 폴란드어도 마찬가지입니다. 그 두 로케일의 설명은 몇 달 동안 "읽을 수는 있지만 이상한 글"이 아니라 "읽을 수 없는 글" 이었습니다.
같은 감사에서 나온 두 가지 더
한 앱은 독일어·포르투갈어 슬롯에 영어 원문 2,192자가 그대로 들어 있었습니다. 번역이 안 된 게 아니라, 번역 자리에 원문이 복사돼 있었습니다. 배포는 성공했고, 글자 수도 충분했고, 아무 검사에도 안 걸렸습니다.
그리고 일곱 개 로케일에서 모든 줄 앞에 공백 두 칸이 붙어 있었습니다. 코드 블록에서 붙여넣은 흔적이 그대로 스토어에 나갔습니다.
어떻게 찾았나
탐지는 "이 언어에 반드시 나타나는 문자가 장문에 0개인가"로 합니다.
필수문자 = {
"fr": "àâçéèêëîïôùûü",
"pl": "ąćęłńóśźż",
"vi": "ăâđêôơư",
# ...
}
if len(본문) >= 400 and not any(c in 본문 for c in 필수문자[언어]):
의심.append((앱, 언어))여기에 "벗겨졌을 때만 나타나는 낱말" 을 언어별로 같이 봅니다. horaires decales, attivita, Nachtschwesternkraeften 같은 형태는 정자로 쓰면 나올 수 없습니다. 이쪽이 오탐이 훨씬 적습니다.
고칠 때는 낱말 단위로 치환하고, 치환 대상이 하나라도 없으면 죽게 했습니다.
for 틀린낱말, 맞는낱말 in 치환표:
if 틀린낱말 not in 본문:
raise RuntimeError(f"치환 대상 없음: {틀린낱말}")
본문 = 본문.replace(틀린낱말, 맞는낱말)조용한 미적용을 막기 위해서입니다. 치환이 0건 일어나도 스크립트는 성공으로 끝나니까요.
당신이라면 언제 고치겠습니까
여기서 알아 둘 만한 것이 하나 있습니다. 심사 대기 중인 버전은 설명을 그대로 고칠 수 있습니다. 새 빌드도, 심사 취소도 필요 없습니다. 반대로 이미 판매 중인 버전은 잠겨 있어 409 가 돌아오고, 그건 새 버전을 올려야 고쳐집니다.
그래서 지금 심사 대기인 것부터 고치는 게 순서입니다. 결과는 40슬롯 → 2슬롯. 남은 둘은 판매 중인 앱이라 다음 릴리스에 실었습니다.
자가진단 3줄
- 번역 파이프라인 어딘가에 정규화 단계가 있습니까?
unicodedata.normalize+ ASCII 인코딩,iconv //TRANSLIT, 슬러그 생성기 재사용 — 이 셋이 흔한 범인입니다. - 배포된 본문을 다시 읽어 본 적 있습니까? 쓰기 API가 200을 주는 것과 저장된 값이 보낸 값인 것은 다릅니다.
- 당신의 치환 스크립트는 0건 치환했을 때 성공합니까? 그러면 그 스크립트는 아무것도 보장하지 않습니다.
솔직한 부분
왜 벗겨졌는지는 끝내 못 밝혔습니다. 어느 시점에 ASCII로 정규화하는 단계를 거친 것으로 보이지만, 그 단계를 특정하지 못했습니다. 원인을 못 찾았으니 재발을 막지 못합니다 — 지금 있는 건 재발을 탐지하는 감사기뿐입니다. 이건 고친 게 아니라 알람을 단 것에 가깝습니다.
첫 감사기는 오탐이 절반을 넘었습니다. 짧은 문구는 정상인데도 발음기호가 0이라 걸립니다. 400자 기준을 넣고서야 쓸 만해졌습니다. 이탈리아어는 원래 발음기호를 적게 쓰는 언어라, 정상인 본문도 8개밖에 안 나옵니다. 자동 판정만으로는 못 가르고 낱말을 직접 봐야 했습니다.
같은 감사의 세 번째 층은 부제였습니다 — 부제 36칸이 영어 원문 그대로였고, 그건 또 다른 종류의 구멍이었습니다.
다국어 스토어 리스팅이 있으시다면, 지금 프랑스어 본문 하나만 열어서 아포스트로피가 있는지 보세요. 30초면 됩니다.