Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Is that skill safe to install?
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
Are you the author of Storelisting?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/snwlee-storelisting)
---
name: storelisting
description: 스토어 등재 현지화 — 로케일 커버리지, 선언과 실제의 어긋남, 필드 길이, 그리고 무엇을 번역하지 않을지의 선언. 트리거 "스토어 등재", "등재 텍스트", "앱 제목", "스토어 설명", "패치 노트", "스크린샷 문구", "ASO".
---
# storelisting
nereus:common 규칙을 따른다. 담당 에이전트: l10n-engineer.
제품이 사용자에게 닿는 표면은 셋인데, 지금까지 검사받은 건 하나뿐이었다:
| 표면 | 누가 보나 |
|---|---|
| 소스 코드 문자열 | `nereus-l10n:l10n` |
| **스토어 등재 텍스트**(제목·설명·패치노트) | **여기** |
| **스토어 이미지 안의 텍스트** | 여기 + `typeface` |
## 0. 이 스킬에는 게이트와 조언자가 따로 있다
| | 게이트 `store-l10n-check.mjs` | 조언자 `aso-advisor.mjs` |
|---|---|---|
| 낸다 | `violations` · `coverage` · `skipped` | `levers` · `unanswerable` |
| 뜻 | 선언과 실제가 어긋났다 | 어디를 먼저 채울까 |
`Ruling: 게이트와 조언자는 파일을 나눈다.` "잘린 채 발행됨"과 "브라질을 먼저 채우면
좋겠음"이 같은 무게로 나오면 진짜가 묻힌다.
## 1. 미달은 위반이 아니다
**요구 집합(Play 86) 대비 진행 상태는 `coverage` 이고, 위반은 선언과 실제가 어긋난 것뿐이다.**
| | 판정 |
|---|---|
| 요구 집합 중 안 채운 로케일 | `coverage.missing` — **위반 아님** |
| **선언한** 로케일인데 필드가 빈 것 | `declared-but-empty` — **위반** |
| 전 로케일 동일 문자열인데 사유 선언 없음 | `untranslated-undeclared` — **위반** |
미달을 위반으로 내면 운영 중인 제품 전부가 즉시 빨개진다. **그러면 사람이 게이트를 끄고,
꺼진 게이트는 아무것도 막지 못한다.** ToonTone 461:0 의 교훈이다.
**미설정은 보호다.** 대상 로케일을 선언하지 않으면 요구 집합이 **스토어 전체**가 된다.
선언 없음을 "영어만 하면 된다"로 읽으면 조용히 최악으로 떨어진다.
**제외는 삭제가 아니라 분류다.** `excluded: [{ locale, why }]` 로 빼면 `skipped` 에
셈과 이유가 남고 요구 집합에서 빠진다. **`why` 가 없으면 제외가 아니다** —
왜 뺐는지 모르면 되돌릴 수도 없다.
## 2. 번역하지 않기로 한 것은 선언한다 — 이 스킬의 핵심
**하네스는 번역할지 말지를 정하지 않는다.** 필드마다 답이 다르고 그건 사업 판단이다:
- **앱 이름은 검색 키워드다.** 번역하면 그 키워드로 오던 유입이 끊긴다.
도너(19 로케일 실운영)는 제목을 전 로케일 동일하게 두는 쪽을 **일부러** 골랐다.
- **설명문·패치노트는 번역하지 않으면 전환이 깎인다.**
하네스가 강제하는 것은 하나뿐 — **판단이 이유와 함께 기록에 남는 것**이다.
```json
"doNotTranslate": [
{ "field": "title", "why": "앱 이름이 검색 키워드다. 번역하면 그 키워드로 오던 유입이 끊긴다" }
]
```
선언이 있으면 전 로케일 동일 문자열이 **정상**이다. 없으면 `untranslated-undeclared` 다 —
지금은 "판단해서 안 한 것"과 "그냥 빠뜨린 것"이 구분되지 않는다.
`Ruling: 경계·분류 선언에 why 를 빼지 않는다 — 이유 없는 경계가 가장 먼저 지워진다.`
로케일이 하나뿐이면 이 판정을 하지 않는다. "전 로케일 동일"이 자명참이라 의미가 없다.
## 3. 검사
```bash
echo '{"store":"play","declaredLocales":["en-US","ko-KR"],"listings":{…},"doNotTranslate":[…]}' \
| node "${CLAUDE_PLUGIN_ROOT}/lib/store-l10n-check.mjs"
```
| 위반 코드 | 왜 조용한가 |
|---|---|
| `declared-but-empty` | Play 가 기본 로케일로 fallback 한다. 발행은 **성공**한다 |
| `untranslated-undeclared` | 아무 일도 일어나지 않는다. 판단과 누락이 구분되지 않을 뿐 |
| `declaration-without-why` | 이유 없는 경계는 다음 사람이 지운다 |
| `field-length-overflow` | 잘린 채 발행되고 에러가 나지 않는다 |
| `locale-code-unknown` | 등재가 거부되는 게 아니라 **그 로케일이 그냥 안 생긴다** |
| `tofu-unverified` · `glyph-missing` · `rtl-split-run` | `typeface` 참조 |
**제한이 선언되지 않은 스토어는 통과로 내지 않는다** — `unmeasured` 에 `field-limits:<store>` 로
남는다. 모르는 것과 통과한 것을 같게 보고하면 검사되지 않은 것이 통과로 읽힌다.
## 4. 어디를 먼저 채울까 — 조언자
```bash
echo '{"coverage":{…},"signals":{"share":{"pt-BR":0.13}}}' \
| node "${CLAUDE_PLUGIN_ROOT}/lib/aso-advisor.mjs"
```
**점유 신호가 없으면 순위를 매기지 않는다.** 지어낸 순위는 그럴듯하게 틀린다.
신호 없는 로케일을 0 으로 보지도 않는다 — 그건 "점유가 없다"는 판정인데 측정한 적이 없는 것이다.
**실측 점유율을 하네스에 적지 않는다.** 계정·시점 종속이라 빨리 낡고, 낡은 수치가
틀린 확신을 만든다. `signals` 로 그때 읽어 넘긴다.
### 답할 수 없는 것
`Ruling: 답할 수 없는 것을 결과에 싣는다 — 검사기가 다 본다고 믿게 만드는 것이 더 나쁘다.`
| 질문 | 등재 텍스트로 왜 못 푸나 |
|---|---|
| 제목을 번역하면 유입이 늘까 줄까 | Play Console 검색 유입 데이터가 필요하다 |
| 번역 품질이 충분한가 | 하네스는 문자열의 존재와 길이만 본다. 의미는 안 본다 |
| 어느 로케일을 먼저 채울까 | 로케일별 점유가 필요하다 |
## 5. 하지 말 것
- **미달을 위반으로 내지 않는다.** 끄게 만드는 게이트는 게이트가 아니다.
- **실측 점유율·매출 수치를 하네스에 복사하지 않는다.**
- **번역 여부를 하네스가 결정하지 않는다.** 선언을 요구할 뿐이다.
- **스토어 API 로 업로드하지 않는다.** 하네스는 판정만 한다.
- **필드 길이·로케일 코드 형식을 코드에 박지 않는다.** `locales.json` 의 `stores` 가 정한다.