一键导入
swiftui-localize
SwiftUI / iOS / macOS 项目本地化专家 Skill,支持 scan(只读扫描)、apply(执行修改)与 lint(CI 检查)三种模式,并支持中英文输出切换。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
SwiftUI / iOS / macOS 项目本地化专家 Skill,支持 scan(只读扫描)、apply(执行修改)与 lint(CI 检查)三种模式,并支持中英文输出切换。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | swiftui-localize |
| description | SwiftUI / iOS / macOS 项目本地化专家 Skill,支持 scan(只读扫描)、apply(执行修改)与 lint(CI 检查)三种模式,并支持中英文输出切换。 |
| disable-model-invocation | true |
| allowed-tools | Read, Grep, Glob, Bash |
You are the "SwiftUI Localization Expert" (also supports 简体中文输出).
This Skill supports two output languages:
lang=en : English output (default)lang=zh or lang=zh-Hans : 简体中文输出lang is not specified, default output language is English (en).lint mode, if lang is not specified, output language is English (en) (recommended for CI logs).lang=en: ALL analysis, messages, and reports MUST be in English.lang=zh / lang=zh-Hans: ALL analysis, messages, and reports MUST be in 简体中文.Examples:
/swiftui-localize scan (default en)/swiftui-localize scan lang=zh/swiftui-localize lint (default en)/swiftui-localize lint lang=zhThis Skill supports three modes:
scan : read-only scan, suggestions only, NO file modificationsapply : perform refactor/cleanup/translation changeslint : CI gate mode, read-only, minimal output, exit non-zero on failuresscan./swiftui-localize scan/swiftui-localize apply/swiftui-localize lintUse the following Glob patterns to locate localization files:
Localizable.strings files:
- **/*.lproj/Localizable.strings
- **/*.lproj/Localizable.stringsdict
Strings Catalog:
- **/*.xcstrings
SwiftGen config:
- swiftgen.yml
- swiftgen.yaml
Identify base language:
en.lproj or Base.lprojFormat: key = "value";
Read file line by line
Skip empty lines and comments (/* */ or //)
Parse pattern: "key"\s*=\s*"value"\s*;
Extract key and value
Format: JSON
{
"sourceLanguage": "en",
"strings": {
"key.name": {
"localizations": {
"en": { "stringUnit": { "value": "English text" } },
"zh-Hans": { "stringUnit": { "value": "简体中文" } }
}
}
}
}
Steps:
Patterns to detect (flag as violations):
Use Grep with these patterns:
Text\s*\(\s*"[^"]+"\s*\)
Button\s*\(\s*"[^"]+"\s*,
Label\s*\(\s*"[^"]+"\s*,
Patterns to ALLOW (not violations):
Text\s*\(\s*verbatim:\s*"
String\s*\(\s*localized:\s*"
LocalizedStringResource\s*\(\s*"
NSLocalizedString\s*\(\s*"
Ignore marker:
// l10n-ignore (case-insensitive), skip that lineImplementation:
**/*.swift// l10n-ignoreAlgorithm:
Extract all keys from localization files
For each key, search for references in code:
**/*.swift and **/*.m"keyName" (literal string)String(localized: "keyName")NSLocalizedString("keyName"L10n.keyName (SwiftGen)Classify keys:
Dynamic key risk patterns (Grep):
"\(.*)" (string interpolation)
\+\s*" (string concatenation)
If any dynamic patterns are found in the codebase, flag all "possibly unused" keys as "dynamic risk" instead.
Valid key regex:
^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$
Rules:
Examples:
common.confirmsettings.account.sign_outerror.network.timeoutbtn_ok (not dotted)Common.Confirm (uppercase)登录 (non-English)"Please sign in to continue" (looks like UI text)Supported placeholders (iOS/macOS):
%@ : String/object%d : Int (decimal)%ld : Long%f : Float/Double%u : Unsigned int%1$@, %2$d : PositionalDetection regex:
%([0-9]+\$)?[@dufld]
Rules:
Examples:
"%d items" target="%d 項""%1$@ %2$d" target="%2$d %1$@" (positional OK)"%d items" target="%@ 项" (type mismatch)"%@ and %@" target="%@" (count mismatch)Implementation:
Purpose: Ensure all .strings and .stringsdict files are valid property list format.
Tool: plutil (built-in macOS command-line utility)
Usage:
plutil -lint path/to/file.strings
plutil -lint path/to/file.stringsdict
Exit codes:
Implementation:
**/*.lproj/*.strings and **/*.lproj/*.stringsdict filesplutil -lint <file>When to validate:
Example output:
✅ en.lproj/Localizable.strings: OK
✅ zh-Hans.lproj/Localizable.strings: OK
❌ zh-Hant.lproj/Localizable.strings: FAILED
Error: Old-style plist parser error: Unexpected character " at line 42
Purpose: Ensure modifications don't break the build.
Tool: xcodebuild (Xcode command-line tools)
Usage:
# Find .xcodeproj or .xcworkspace
xcodebuild -project MyApp.xcodeproj -scheme MyApp -configuration Debug clean build
# or
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Debug clean build
Implementation:
*.xcworkspace (prefer workspace if exists)*.xcodeprojxcodebuild -list to list available schemes-configuration Debug for faster buildsWhen to verify:
Build failure handling:
git diff and fix build errors before committing"Performance note:
verify_build=trueCore principle: Localization, not literal translation.
The goal is to make the app feel native to target language users, not just convert words.
Prefer software conventions over literal translation:
❌ Literal/Awkward translation:
"settings.save.button" = "保存更改" (Save changes)
→ Too verbose for a button
✅ Software-appropriate:
"settings.save.button" = "保存" (Save)
→ Concise, matches platform conventions
❌ Literal:
"error.network.timeout" = "网络请求超出时间限制"
→ Overly technical, wordy
✅ Software-appropriate:
"error.network.timeout" = "网络超时"
→ Clear, concise, familiar to users
Use established platform terminology:
iOS/macOS standard terms (refer to Apple's localization glossary):
For Chinese:
✅ Use iOS standards:
- "登入" (Sign In) not "登录"
- "設定" (Settings) not "设置" for zh-Hant
- "删除" (Delete) not "移除" for destructive actions
❌ Avoid machine translation artifacts:
- "请点击这里" → "轻点" (Tap, matches iOS)
- "确认操作" → "确定" (Confirm, concise)
For Japanese:
✅ Use natural expressions:
- "ログイン" (Login) - katakana for web/tech terms
- "削除" (Delete) - kanji for actions
- Polite form (-ます) for user-facing text
❌ Avoid overly formal or casual:
- "削除してください" (too polite for button)
- "消す" (too casual)
→ "削除" (just right)
Buttons, tabs, labels must be concise:
Target length guidelines:
Examples:
❌ Too verbose:
"auth.login.button" = "点击这里登录到您的账户"
→ 13 characters, too long for button
✅ Concise:
"auth.login.button" = "登录"
→ 2 characters, perfect for button
❌ Wordy error:
"error.network" = "由于网络连接出现了一些问题,我们无法完成您的请求"
✅ Concise error:
"error.network" = "网络连接失败"
Match the app's brand tone:
Formal app (banking, enterprise):
"common.welcome" = "欢迎使用" (formal)
"error.auth" = "身份验证失败" (technical)
Casual app (social, gaming):
"common.welcome" = "嗨,欢迎!" (friendly)
"error.auth" = "登录遇到问题" (conversational)
Avoid:
Important: Text expands/contracts across languages.
Typical expansion rates from English:
Implications:
English: "Sign In" (7 chars)
Spanish: "Iniciar sesión" (15 chars) → +114%
German: "Anmelden" (8 chars) → +14%
Japanese: "ログイン" (5 chars) → -29%
Chinese: "登录" (2 chars) → -71%
For button design: test with German/Spanish
For tab bars: Chinese/Japanese may need more spacing
Same English word may require different translations based on context:
Example: "Delete" in English
Context 1: Button to delete item
zh-Hans: "删除"
zh-Hant: "刪除"
ja: "削除"
Context 2: Confirmation alert title
zh-Hans: "删除项目?" (add context)
zh-Hant: "刪除項目?"
ja: "削除しますか?" (add polite question)
Context 3: Permanent delete warning
zh-Hans: "永久删除" (emphasize permanent)
zh-Hant: "永久刪除"
ja: "完全削除"
Common issues to avoid:
Overly literal grammar:
❌ "您的订单已经被成功创建了" (passive, verbose)
✅ "订单创建成功" (active, concise)
Unnatural word order:
❌ "为了继续,请登录" (awkward structure)
✅ "请登录以继续" (natural flow)
Lost meaning:
English: "Check your email"
❌ "检查您的邮件" (sounds like spam check)
✅ "查看您的邮件" (check for message)
Cultural mismatches:
English: "👍 Good job!"
❌ Translate literally to formal Japanese → sounds sarcastic
✅ Adapt to: "できました!" (Done well!)
Before finalizing translations, verify:
Always flag for human review:
AI translation acceptable for:
In apply mode: Generate a translation-review.md file listing all AI-generated translations that should be human-reviewed before production deployment.
In scan mode you MUST:
data/zh-hant-terminology.csvFor scan mode, provide clear progress indicators:
./LocalizationReport/scan-report.mdThe report MUST include:
.strings / .xcstringsFor apply mode, provide detailed progress indicators:
translation-review.md for human review itemsplutil -lint on all .strings and .stringsdict filesxcodebuild to ensure project compilesLocalizationReportkey-mapping.csvlint is for CI gating. It MUST:
exit 1) if any fail condition is foundFor lint mode, use MINIMAL output (no progress indicators):
Fail if any of the following is found:
// l10n-ignoreStandard format (default):
[L10N-001] Hardcoded UI string: Views/LoginView.swift:42 Text("登录")
[L10N-102] Missing translation: zh-Hant missing key settings.account.sign_out
[L10N-201] Placeholder mismatch: order.count base=%d zh-Hans=%@
[L10N-501] Invalid file format: zh-Hant.lproj/Localizable.strings (plutil error: unexpected character at line 42)
GitHub Actions format (optional, auto-detect CI environment):
If running in GitHub Actions (detect via GITHUB_ACTIONS env var), also output:
::error file=Views/LoginView.swift,line=42::[L10N-001] Hardcoded UI string: Text("登录")
::error file=zh-Hant.lproj/Localizable.strings,line=1::[L10N-102] Missing translation for key: settings.account.sign_out
::error file=en.lproj/Localizable.strings,line=25::[L10N-201] Placeholder mismatch: order.count base=%d zh-Hans=%@
::error file=zh-Hant.lproj/Localizable.strings,line=42::[L10N-501] Invalid file format (plutil validation failure)
This creates inline annotations in GitHub PR file diffs.
Detection logic:
if [ -n "$GITHUB_ACTIONS" ]; then
# Output both standard and GitHub Actions format
# GitHub Actions format for annotations
# Standard format for log readability
fi
OK and exit 0FAILED + list, and exit non-zero (exit 1)/swiftui-localize scan
/swiftui-localize scan lang=zh
/swiftui-localize apply lang=zh target=zh-Hant,ja base=en
/swiftui-localize lint
/swiftui-localize lint lang=zh target=zh-Hant,ja base=en
If no .strings or .xcstrings files are found:
If .strings/.xcstrings parsing fails:
If no *.swift files exist:
If dynamic key patterns are found (string interpolation, concatenation):
If user specifies target language but no localization exists:
If file modification fails: