Make your application speak like a local product — not like a translated document. Every string becomes a localization decision: what it means here, how the target language says it in software, what your project already says, and how confident that answer is.
npx skills add soumyaRauth/skills-hub --skill practical-localizer
a correct translation ≠ a natural one
Traditional translation asks “what does this sentence translate to?” Practical Localizer asks “what would a real user expect this application to say here?”
English: Chair Literal: a dictionary-valid, formal/literary word Practical: the borrowed word people actually use for the object
Both are “the translation”. Only one of them sounds like a modern app — and which one that is differs by language, product and audience. The same reasoning gives the opposite answer in a neighbouring language where an ordinary native word is in everyday use, which is exactly why no blanket rule survives contact with a real product.
"Hello, {{name}}" → "হ্যালো" the placeholder is gone; nothing fails
t("remove") → "delete forever" the handler was removeMember()
one concept → three target words, one per translation batch
{count, plural,…} → a single fixed form in a locale that needs six
No slash command needed. Installed, it is loaded when a request needs it and stays out of the way otherwise — and when it does shape the work, one ⚡ line says so. How the skills work together →
| Engages | A locale is added; locale files are translated, reviewed or changed; plurals, dates, numbers, currency or right-to-left layout are involved. |
| Stays quiet | English copy changes in an app with no translation catalogs. |
| Depth | Active in its three modes. One line when English copy changes for a key other locales already translate, naming the catalogs now out of date. |
| Works with | ProofBuild, Production Guard, Standards Compass |
| Translation | Localization | |
|---|---|---|
| Unit of work | the string | the decision behind the string |
| Input | a word list | the application |
| “Save” | one target word | one per context, resolved from the call site |
| Technical terms | a rule | a per-term judgement, per language |
| Plurals | source shape copied | the target locale's own categories |
| Dates, money | out of scope | in scope, reported for a formatter fix |
| Direction | out of scope | reported, with the layout work it implies |
| Uncertainty | invisible | an output, with confidence attached |
| Success | every string filled | the product sounds locally written |
source application → localization architecture → language usage profile
→ existing terminology → context extraction → translation strategy
→ natural localization → technical validation → consistency review
Every meaningful term gets exactly one strategy, chosen from evidence:
| Strategy | Use when |
|---|---|
| Translate | The language has a current, ordinary equivalent |
| Transliterate | The borrowed source word is the word users say |
| Preserve | Identifiers, protocols and brands, where translating destroys meaning |
| Adapt | Reword for the same intent, because word-for-word would be unidiomatic |
t("remove") inside removeMember(member)
is not the same word as t("remove") in a file manager —
in many languages, and not in English.
| Mode | You ask | Writes files |
|---|---|---|
| Analyze | “Analyze this app for Bengali localization.” | No |
| Localize | “Localize the checkout flow to Bengali.” | Locale resources only |
| Review | “Review the Bengali localization for naturalness.” | No |
Localize never touches application logic, variable or route names, CSS, or your git history. Hardcoded strings, concatenated sentences and formatter bugs are reported as findings — fixing them is a source change, and that is your call.
Abbreviated, from a review of an existing Bengali locale:
LOCALIZATION REVIEW
────────────────────────────────
Target Bengali (bn-BD) Reviewed 742 strings
High-confidence 18 · Medium 27 · Technical 3
#1 greeting.hello — BLOCKING TECHNICAL ISSUE
Source "Hello, {{name}}" → current "হ্যালো"
The interpolation was dropped; the name never renders.
Confidence: HIGH (mechanical)
#2 team.remove — Context / terminology
Current মুছে ফেলুন ("erase") → recommended সরিয়ে দিন
Rendered in <TeamMemberRow>, handler removeMember(). The member is
taken off the team, not deleted. Bengali distinguishes the two;
English does not.
Confidence: HIGH — the handler and surrounding UI resolve the meaning
#3 sign in — Terminology inconsistency
লগইন (18 occurrences) · প্রবেশ করুন (2 occurrences)
Recommend the established project term everywhere. Adding a third,
better-sounding synonym would be the worst outcome.
Five worked language examples ship with the skill: Bengali, Hindi, Japanese, Arabic, and a European three-language pass. Each one ends by stating what it does not claim.
Language quality is a judgement call. These are not, and they run on everything produced or reviewed.
| Check | Failure is |
|---|---|
Placeholders match the source exactly — {name}, {{name}}, %s, %1$s, :name, <0>…</0> | Blocking |
| Plural categories match what the target locale requires | Blocking |
| Keys, nesting and file syntax unchanged | Blocking |
| HTML, Markdown and rich-text tags intact | Blocking |
| No pluralization faked by string concatenation | High |
| Terminology consistent with the project glossary | High |
Detected by inspection, not assumption: i18next and react-i18next,
react-intl / FormatJS, next-intl, next-i18next, vue-i18n, Laravel
lang/, gettext .po, Rails I18n, Flutter
.arb, Android strings.xml, Apple
.strings and .stringsdict, Java properties
— plus JSON, YAML, XML, PHP and TS/JS catalogs generally.
If your project does localization some other way, the skill reads how it works before touching it.
npx skills add soumyaRauth/skills-hub --skill practical-localizer
npx skills add soumyaRauth/skills-hub --skill practical-localizer --agent claude-code --copy
Practical Localizer is instruction-driven, not a translation engine, and it does not claim perfect or native-quality output.