
Frontend I18n Orchestrator
- 28 installs
- 1 repo stars
- Updated April 25, 2026
- howell5/willhong-skills
Internationalize React, Vue, Next, Nuxt, or Vite projects: auto-detect stack and i18n state, migrate hardcoded strings, localize formatting/routing, and add CI gates.
About
Runs an auto-first i18n workflow that detects the stack and current i18n setup, asks only unresolved business decisions, then migrates strings and enforces quality gates. A developer uses it to internationalize a frontend repo with minimal questions.
- detect_i18n_profile.sh builds an i18n-profile.json before any edits
- Phased migration of strings, formatting, routing/SEO, and CI gates
Frontend I18n Orchestrator by the numbers
- 28 all-time installs (skills.sh)
- Ranked #1,480 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/howell5/willhong-skills --skill frontend-i18n-orchestratorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 28 |
|---|---|
| repo stars | ★ 1 |
| Last updated | April 25, 2026 |
| Repository | howell5/willhong-skills ↗ |
What it does
Internationalize React, Vue, Next, Nuxt, or Vite projects: auto-detect stack and i18n state, migrate hardcoded strings, localize formatting/routing, and add CI gates.
Files
Frontend I18n Orchestrator
Overview
Internationalize frontend projects with an auto-first workflow: 1. Scan repository and infer facts. 2. Ask only business decisions that cannot be inferred reliably. 3. Execute migration in phases with verification gates.
Do not start bulk code edits before finishing detection and decision confirmation.
Platform Compatibility
Use this skill in both Codex and Claude Code.
- In Claude Code, invoke with
$frontend-i18n-orchestrator(or by selecting the skill in UI). - In Codex, invoke the same skill name and follow the same workflow.
- Use the host platform's native shell/file tools for commands and edits.
- Resolve script paths relative to the skill directory first, then to repository root if copied locally.
Workflow
Step 1: Build i18n profile (no questions yet)
Run repository detection first.
Recommended command:
<skill_dir>/scripts/detect_i18n_profile.sh .The script writes i18n-profile.json in repository root.
Detect at minimum:
- framework/runtime: React, Vue, Next, Nuxt, Vite
- package manager and lockfiles
- existing i18n libraries and locale files
- routing setup and locale routing hints
- SEO hints:
lang,hreflang, canonical - hardcoded string hotspots
- date/number/currency localization usage
- CI quality gate hints
Step 2: Ask only unresolved decisions
Read i18n-profile.json, then ask only missing or ambiguous decisions.
Use question set from references/question-flow.md.
Never ask questions that are already confidently detected.
When presenting questions, start with a short auto-detection summary:
- what is certain
- what is ambiguous
- what decisions need user confirmation
Step 3: Plan phased migration
Use framework-specific guidance from references/framework-playbooks.md.
Plan the migration with these phases: 1. Foundation: i18n library setup, locale structure, language switch, fallback behavior. 2. Migration: extract hardcoded UI strings and replace with translation keys. 3. Localization: dates, numbers, currency, pluralization, relative time. 4. Routing and SEO: locale routing, html lang, hreflang, canonical, sitemap. 5. Governance: lint/test/CI gates for missing keys and hardcoded regressions.
Prefer incremental slices (page/module by page/module) over big-bang rewrites.
Step 4: Execute with safe checkpoints
For each phase: 1. apply minimal code changes 2. run project checks/tests 3. report changed files and remaining risk
If a phase introduces conflicts or uncertainty, stop and ask a targeted question.
Step 5: Enforce quality gates
Run baseline validation:
<skill_dir>/scripts/validate_i18n_basics.sh .Then integrate project-native checks (lint/test/build/CI) for:
- missing translation keys
- orphan keys
- hardcoded UI string regressions
Fail CI on configured strict rules after migration baseline is stable.
Step 6: Produce delivery report
Always end with a concise report:
- detection summary and selected strategy
- implemented phases and touched files
- unresolved/needs-human-review items
- commands for ongoing verification
Decision Rules
- Auto-detect first. Ask later.
- Ask only high-impact business choices.
- Never guess target locales.
- Prefer compatibility with existing stack conventions.
- Treat inconsistent existing i18n setups as an ambiguity and ask explicitly.
Common Ambiguities (must ask)
- target locale list
- default locale and fallback policy
- URL strategy (
/en/...vs subdomain vs domain) - translation source strategy (placeholder, MT, human)
- rollout strategy (gradual vs all-at-once)
- strict CI enforcement timing
Resources
- Question flow:
references/question-flow.md - Framework playbooks:
references/framework-playbooks.md - Claude Code usage:
references/claude-code-usage.md - Detection script:
scripts/detect_i18n_profile.sh - Baseline validation script:
scripts/validate_i18n_basics.sh
interface:
display_name: "Frontend i18n"
short_description: "Auto-detect and migrate frontend i18n quickly."
default_prompt: "Use $frontend-i18n-orchestrator to internationalize this frontend project end-to-end with auto-detection and minimal decision prompts."
policy:
allow_implicit_invocation: true
Claude Code Usage
Invocation
Invoke explicitly with:
$frontend-i18n-orchestratorThen request a task, for example:
Use $frontend-i18n-orchestrator to internationalize this repo with auto-detection first and minimal decision questions.Script execution
Do not assume current directory is the skill folder.
Use explicit script path:
<skill_dir>/scripts/detect_i18n_profile.sh <repo_root>
<skill_dir>/scripts/validate_i18n_basics.sh <repo_root>If you copied scripts into the target repo, use repo-relative paths instead.
Tooling behavior
Use Claude Code native shell and file-edit tools for all execution. The workflow remains the same: 1. detect facts 2. ask only unresolved business decisions 3. migrate in phases 4. validate and report
Framework Playbooks
Next.js
Preferred library: next-intl.
Execution notes:
- set locale routing in App Router or Pages Router consistently
- maintain middleware and route segment locale handling
- localize metadata and SEO tags
React (Vite/CRA/custom)
Preferred library: react-i18next (+ i18next).
Execution notes:
- initialize i18n entrypoint once
- use namespaces by feature/page
- enforce no-literal-text linting where practical
Vue 3 (Vite/custom)
Preferred library: vue-i18n.
Execution notes:
- set global i18n plugin in app bootstrap
- use composition API style (
useI18n) in components - split locale files by domain/module
Nuxt
Preferred library/module: @nuxtjs/i18n.
Execution notes:
- configure locale strategy centrally in
nuxt.config - standardize localized routes and fallback behavior
- verify SSR output includes correct
langand alternate links
Common Migration Order
1. Foundation setup 2. Key extraction and replacement 3. Formatter localization 4. Routing/SEO localization 5. CI quality gates
Question Flow (Ask-on-Ambiguity)
Use this template after auto-detection. Ask only unresolved items.
Response Template
1. Detection summary (facts) 2. Ambiguities (why they are ambiguous) 3. Minimal decisions required
Minimal Decision Set
1. Target locales. 2. Default locale and fallback policy. 3. URL strategy for localization. 4. Translation source strategy. 5. Rollout mode (gradual vs all-at-once). 6. CI strictness activation timing.
Example Prompt
I finished auto-detection and confirmed the stack and current i18n state. I only need these decisions before migration:
- Target locales:
- Default locale + fallback:
- URL strategy:
- Translation source:
- Rollout mode:
- CI strictness timing:
Rule
If an item is already clear in project docs/config and confidence is high, do not ask it again.
#!/usr/bin/env bash
set -euo pipefail
ROOT="${1:-.}"
OUT="${2:-$ROOT/i18n-profile.json}"
if ! command -v rg >/dev/null 2>&1; then
echo "[ERROR] rg (ripgrep) is required" >&2
exit 2
fi
cd "$ROOT"
has_file() {
[ -f "$1" ] && echo true || echo false
}
PKG_JSON="{}"
if [ -f package.json ]; then
PKG_JSON="$(cat package.json)"
fi
framework="unknown"
for candidate in next nuxt vue react vite; do
if printf "%s" "$PKG_JSON" | rg -q "\"$candidate\""; then
framework="$candidate"
break
fi
done
pm="unknown"
if [ "$(has_file pnpm-lock.yaml)" = true ]; then pm="pnpm"; fi
if [ "$(has_file yarn.lock)" = true ]; then pm="yarn"; fi
if [ "$(has_file package-lock.json)" = true ]; then pm="npm"; fi
if [ "$(has_file bun.lockb)" = true ] || [ "$(has_file bun.lock)" = true ]; then pm="bun"; fi
i18n_libs_raw="$({ printf "%s" "$PKG_JSON" | rg -o '"(i18next|react-i18next|next-intl|vue-i18n|@nuxtjs/i18n)"' || true; } | tr -d '"' | sort -u | tr '\n' ',' | sed 's/,$//')"
locale_files_count="$({ rg --files -g '*{locale,locales,i18n}*' 2>/dev/null || true; } | wc -l | tr -d ' ')"
hardcoded_candidates="$({ rg -n --glob '!**/*.json' --glob '!**/*.md' --glob '!**/*.yml' --glob '!**/*.yaml' --glob '!**/*.svg' --glob '!**/*.lock' "[\"'][^\"']{3,}[\"']" src app pages components 2>/dev/null || true; } | wc -l | tr -d ' ')"
seo_lang_hints="$({ rg -n '<html[^>]*lang=' . 2>/dev/null || true; } | wc -l | tr -d ' ')"
hreflang_hints="$({ rg -n 'hreflang' . 2>/dev/null || true; } | wc -l | tr -d ' ')"
intl_usage="$({ rg -n 'Intl\.(DateTimeFormat|NumberFormat|RelativeTimeFormat)|toLocale(Date|String)' src app pages components 2>/dev/null || true; } | wc -l | tr -d ' ')"
cat > "$OUT" <<JSON
{
"framework": "$framework",
"packageManager": "$pm",
"hasPackageJson": $(has_file package.json),
"hasExistingI18n": $([ -n "$i18n_libs_raw" ] && echo true || echo false),
"i18nLibraries": [$(printf "%s" "$i18n_libs_raw" | awk -F',' '{for (i=1;i<=NF;i++) if ($i!="") printf "%s\"%s\"", (c++?",":""), $i }')],
"localeFilesCount": $locale_files_count,
"hardcodedStringCandidates": $hardcoded_candidates,
"seoHints": {
"htmlLangOccurrences": $seo_lang_hints,
"hreflangOccurrences": $hreflang_hints
},
"localizationApiHints": {
"intlUsageOccurrences": $intl_usage
},
"confidence": {
"framework": $([ "$framework" = "unknown" ] && echo 0.2 || echo 0.9),
"existingI18n": $([ -n "$i18n_libs_raw" ] && echo 0.9 || echo 0.5)
},
"requiresUserDecisions": [
"targetLocales",
"defaultLocaleAndFallback",
"urlLocalizationStrategy",
"translationSourceStrategy",
"rolloutMode",
"ciStrictnessTiming"
]
}
JSON
echo "[OK] Wrote $OUT"
#!/usr/bin/env bash
set -euo pipefail
ROOT="${1:-.}"
cd "$ROOT"
if ! command -v rg >/dev/null 2>&1; then
echo "[ERROR] rg (ripgrep) is required" >&2
exit 2
fi
echo "[INFO] i18n baseline validation"
locale_files="$({ rg --files -g '*{locale,locales,i18n}*' 2>/dev/null || true; } | wc -l | tr -d ' ')"
hardcoded_left="$({ rg -n --glob '!**/*.json' --glob '!**/*.md' --glob '!**/*.yml' --glob '!**/*.yaml' --glob '!**/*.svg' --glob '!**/*.lock' "[\"'][^\"']{3,}[\"']" src app pages components 2>/dev/null || true; } | wc -l | tr -d ' ')"
missing_key_todo="$({ rg -n 'TODO_I18N|MISSING_TRANSLATION|__MISSING__' src app pages components 2>/dev/null || true; } | wc -l | tr -d ' ')"
printf "locale files: %s\n" "$locale_files"
printf "hardcoded string candidates: %s\n" "$hardcoded_left"
printf "known missing markers: %s\n" "$missing_key_todo"
if [ "$locale_files" -eq 0 ]; then
echo "[WARN] no locale/i18n files detected"
fi
if [ "$hardcoded_left" -gt 0 ]; then
echo "[WARN] hardcoded string candidates still exist"
fi
if [ "$missing_key_todo" -gt 0 ]; then
echo "[WARN] unresolved missing translation markers found"
fi
echo "[OK] baseline validation finished"