ai-translated-localization — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ai-translated-localization (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Scope decisions:
.strings vs .xcstrings).Execution:
stringUnit.state: needs_review in xcstrings — not to be confused with extractionState: stale, which flags a key no longer referenced in code, not a changed source).<TRANSLATE> placeholders shipping).| Locale | Code | Notes |
|---|---|---|
| English | en | Catalog sourceLanguage; translation source for the fan-out |
| Traditional Chinese | zh-Hant | Primary language (author's native locale in the origin project; substitute yours) — author-written alongside en, never AI-translated |
| Japanese | ja | Largest adjacent market outside the Chinese sphere |
| Simplified Chinese | zh-Hans | Converted from zh-Hant + Mainland phrasing review |
| Spanish | es | World's second largest native-speaker base |
| Thai | th | Southeast Asia representative |
| Korean | ko | High-penetration Asian market |
zh-Hant / zh-Hans), not regionforms (zh-TW / zh-CN) — matches the committed catalogs and, if the repo has one (recommended, see Step 5), its L10n completeness gate.
plan.md: "author en + zh-Hant by hand, fan out the other 5 locales from en, write into Localizable.xcstrings" (see Execution playbook Step 1).NS…UsageDescription, incl. NSUserTrackingUsageDescription) in InfoPlist.xcstrings — the privacy manifest itself has no localizable text.strings / .stringsdict (unless an external tool forces it).zh-Hant in the origin project); en is thefan-out source because translator competence is broader from English (see Field notes).
stringUnit.state: new, for later — not extractionState: stale, which marks a key no longer used in code, not a not-yet-translated locale.plan.md.Use when actually performing a translation pass. The flow is source-pair seed → AI fan-out → tricky-case review → completeness check.
zh-Hant in the origin project) is hand-written in parallel — not AI-translated from English. Both are written by the author with intent; the other 5 locales fan out from en.en + zh-Hant populated and extractionState: manual.ja, zh-Hans, es, th, ko) start either absent or with the placeholder string <TRANSLATE> so the fan-out pass can find them with a single grep.For each target locale, translate each key from en (source-of-truth) into the target locale. The AI doing the translation should:
%@, %lld, %1$@, \n, markdown markers (**, _), and any ${...} interpolation tokens are copied verbatim.en, all forms must exist in the target locale (zero / one / two / few / many / other) per CLDR plural categories for that locale — don't blindly copy English's two forms.en's tone. Buttons are imperative, descriptions are neutral, error messages are direct. Don't add politeness markers absent in source (see locale gotchas below).After translation, set that locale's stringUnit.state to translated — translated is a value of stringUnit.state, not of extractionState; leave extractionState at manual or extracted_with_value — so Xcode no longer flags the locale as needing attention.
Lessons captured from real translation passes, to apply as a second-pass review after the bulk AI fan-out — per-locale gotchas for ja, th, ko, es, zh-Hans, and en are in references/locale-gotchas.md.
Beyond per-string correctness, enforce a project-level glossary so the same concept renders identically across locales and screens:
Maintain the glossary as either inline comments in xcstrings, or a sidecar Localization-Glossary.md in docs/ if it grows.
Verification gates before merging a translation pass:
<TRANSLATE> count across xcstrings = 0 (none shipped).stringUnit.state: needs_review count = 0 across all locales (source text changed since last translation, now resolved).stringUnit.state: new count = 0 across all locales (nothing left untranslated).extractionState: stale count = 0 (no orphaned keys left in the catalog that the source code no longer references).localizations dict has every declared locale).InfoPlist.xcstrings: every purpose string (NS…UsageDescription, incl. NSUserTrackingUsageDescription) has every shipped locale — the purpose-string rules themselves are in app-store-review-rejections's privacy-manifest reference.en has N %@ → all locales have N %@ (or locale-specific reordering via %1$@ / %2$@).Scheme → Run → Options → App Language.If the repo has a per-key completeness gate (recommended, see Step 5), it checks per-key locale completeness: every key present in a catalog has all declared locales, no <TRANSLATE>. For the two blind spots it does NOT catch (a required key being absent entirely, and multi-app repos sharing UI modules only) — both have shipped English-fallback bugs in real projects — read references/l10n-gates.md.
When adding keys to a Localizable.xcstrings, text-splice the new entries into the file — do not round-trip the whole catalog through a Python/JSON load → dump. The round-trip reformats Xcode's style ("k" : v space-before- colon + Xcode key order) and produces a multi-thousand-line noise diff that buries the real change. Splicing keeps a clean, reviewable diff (real example: 4400-line noise diff collapsed to 192 lines after switching to splice approach).
For the xcstrings JSON schema (including the "version" field and plural variations) and LLM fan-out / ASC-metadata tooling notes, read references/xcstrings-format.md.
Localizable.xcstrings exists and each key has an entry for every declared locale (2 for the minimum set).PrivacyInfo.xcprivacy has no localizable text; the Info.plist purpose strings in InfoPlist.xcstrings and the App Store privacy policy page do need every shipped locale.apple-platform-targets: xcstrings requires Xcode 15+; aligns with the deployment target's toolchain.collaboration-skills:spec-phase-orchestration: "translation" should be an explicit step in plan.md.asc-api-automation: uploading localized App Store metadata once the strings are final.references/official-docs.md.Real translation passes have surfaced these recurring decisions:
en because translator competence is broader from English than from Chinese for th / ko / es.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.