Install
$ agentstack add skill-ericfitz-skills-coverage ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Validate Localization Coverage
Generate a coverage report for all locales by running the bundled scripts/check-i18n.py analyzer and computing per-locale completeness against the master file.
Bundled tool
scripts/check-i18n.py — the same self-contained Python 3.8+ analyzer used by [[analyze]]. See that skill for the full description.
When you see ${CLAUDE_PLUGIN_ROOT} below, it refers to this plugin's install root — typically ~/.claude/plugins/cache/efitz-skills/loc//. The analyzer lives at the plugin root's scripts/ directory, so the analyzer is at ${CLAUDE_PLUGIN_ROOT}/scripts/check-i18n.py (plugin-root scripts/, NOT a skills//scripts/ subpath). If Claude Code does not pre-substitute the variable when you read this file, resolve it yourself: locate the directory containing this SKILL.md, walk up to the plugin root, and use the absolute path to scripts/check-i18n.py. Do NOT fall back to the legacy $SKILL_DIR form.
Configuration
Reads .claude/i18n.config.json (walked up from pwd). Required fields: locales_dir, master_locale, file_extension.
Optional:
{
"coverage": {
"needs_attention_threshold": 95.0
}
}
Defaults to 95% if absent.
Inputs
None beyond the config file.
Output
{
"master_file": "src/assets/i18n/en-US.json",
"total_keys": 450,
"locales_checked": 15,
"per_locale": {
"ar-SA": {
"file_path": "src/assets/i18n/ar-SA.json",
"missing_keys": ["about.trademarks"],
"missing_count": 1,
"coverage_percent": 99.78,
"extra_keys": []
}
},
"summary": {
"average_coverage": 98.5,
"fully_covered_locales": ["es-ES", "de-DE"],
"needs_attention": [
{"locale": "th-TH", "coverage_percent": 85.2, "missing_count": 67}
],
"total_missing_translations": 245
}
}
Process
1. Run the bundled analyzer
uv run "${CLAUDE_PLUGIN_ROOT}/scripts/check-i18n.py" -y
${CLAUDE_PLUGIN_ROOT}/skills/coverage is the absolute path to this skill's directory (provided by the harness at invocation). The script auto-discovers .claude/i18n.config.json.
2. Parse output
The script emits sections delimited by === Comparing with ===. For each target:
- Lines after
Keys present in but missing in :aremissing_keys(until a blank line or next section). - Lines after
Keys present in but missing in :areextra_keys. No keys missing in .indicates the corresponding list is empty.
Derive locale codes from the target's basename (e.g. ar-SA.json → ar-SA).
3. Count total keys in master
Load /. and recursively count leaf keys (string values, not parent objects). about.title counts as 1.
4. Compute coverage
For each locale:
coverage_percent = round(((total_keys - missing_count) / total_keys) * 100, 2)
5. Summarize
average_coverage: arithmetic mean across locales, rounded to 2 decimals.fully_covered_locales: locales withcoverage_percent === 100.0and no extra keys.needs_attention: locales withcoverage_percent .coverage_percent| number | 0-100, two decimal places. |
| per_locale..extra_keys | string[] | May indicate obsolete or accidentally-added keys. | | summary.average_coverage | number | Mean of coverage_percent. | | summary.needs_attention | object[] | Below threshold, sorted by missing_count desc. |
Notes
- The script sorts locale files in place and moves originals to
$TMPDIR/old-. Pass--dry-runif this is undesirable. - The leaf-counting method here must match the script's: skip
.commentkeys, count only string-valued leaves. - Locale codes are BCP 47. Do not maintain a code-to-name map — let callers derive display names from
Intl.DisplayNamesif needed. - Extra keys can legitimately exist (locale-specific content) but usually indicate stale translations.
- If the script fails, report stderr and exit code; do not produce a partial report unless the user asks for one.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ericfitz
- Source: ericfitz/skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.