Install
$ agentstack add skill-kwhorne-elyra-skills-i18n-review ✓ 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
i18n Review
The goal: a translator can ship a new locale without touching code, and the result is correct for native speakers, not "English with words swapped."
When to use
- "Review X for i18n / localization"
- "Audit translation readiness"
- "Make this app translatable"
- "Add support for "
Procedure
- Identify the framework —
i18next,react-intl,vue-i18n,Laravel __(),gettext,Rails I18n, custom? Match existing conventions. - Walk the checklist below
- Group findings by severity
Checklist
String extraction
- [ ] No hardcoded user-facing strings in templates, components, or controllers
- [ ] Strings live in translation files (
en.json,messages.po,lang/en/…) - [ ] Translation keys are stable identifiers, not the English text itself (
auth.login.titlenot"Sign in") - [ ] Keys aren't constructed dynamically (
t('errors.' + code)defeats static extraction — use a switch with explicit keys instead) - [ ] No concatenated sentences:
t('hello') + ' ' + name→ use interpolation:t('hello_name', {name}) - [ ] No HTML embedded in translatable strings — use placeholders or rich-text helpers
- [ ] Plurals use the framework's plural helper, not
if (n === 1)
Plurals
Plural rules vary wildly. English has 2 forms; Polish has 4; Arabic has 6. Don't fake it:
// ❌ Don't
const msg = count === 1 ? '1 item' : `${count} items`;
// ✅ Do
t('item_count', { count })
// en.json: { "item_count_one": "{{count}} item", "item_count_other": "{{count}} items" }
// pl.json: { "item_count_one": "...", "item_count_few": "...", "item_count_many": "...", "item_count_other": "..." }
Dates, numbers, currencies
- [ ] No hardcoded date formats (
YYYY-MM-DD) for display — useIntl.DateTimeFormator framework helper - [ ] Numbers formatted with locale separators (
1,234.56vs1.234,56vs1 234,56) - [ ] Currencies formatted with
Intl.NumberFormat(locale, {style:'currency', currency}), never by string concat ('$' + amount) - [ ] Currency code stored, locale-formatted on display
- [ ] Time zones explicit — store UTC, display in user's TZ
- [ ] Week start day not hardcoded (Sunday vs Monday vs Saturday varies)
Text direction (RTL)
- [ ] Layout uses logical properties:
margin-inline-startnotmargin-left,padding-inline-endnotpadding-right - [ ]
dir="rtl"flips the layout correctly (test with Arabic, Hebrew, or?dir=rtl) - [ ] Icons that imply direction (arrows, back/forward) flip in RTL
- [ ] Numbers and code blocks stay LTR even in RTL contexts
- [ ] No
text-align: leftwhen you mean "start" — usetext-align: start
Sorting & collation
- [ ] Lists sorted with
Intl.Collator(locale), not byte-wise /Array.sort() - [ ] Case-insensitive comparisons use
localeComparewith proper options - [ ] Search/filter is accent-insensitive where appropriate (
sensitivity: 'base')
Input
- [ ] Name fields accept unicode (no
[a-zA-Z]+validation) - [ ] Email validation allows internationalized domains
- [ ] Phone number format not hardcoded to one country (use
libphonenumberor similar) - [ ] Address forms don't assume US-style state/zip
- [ ] Long words / long translations don't break layout (German is famously verbose)
Tooling
- [ ] Linter / extractor rule prevents new hardcoded strings (
eslint-plugin-i18next,i18n-ally,phpcsrules, …) - [ ] CI fails if translations are missing keys (or warns with a baseline)
- [ ] Locale fallback chain is explicit (
fr-CA → fr → en) - [ ] Language switching doesn't require full reload (where the framework supports it)
Quick greps
# Hardcoded English strings in templates (heuristic)
grep -RInE '>[A-Z][a-z]+ [a-z]+' --include='*.{vue,jsx,tsx,blade.php,erb}' . | head
# Concatenated translations
grep -RInE "t\([^)]+\)\s*\+|i18n\.[a-z]+\([^)]+\)\s*\+" --include='*.{js,ts,jsx,tsx,vue}' .
# Hardcoded currency symbols
grep -RInE "['\"\`]\\\$\{|\\\$[0-9]|'\\\$'" --include='*.{js,ts,jsx,tsx,vue,blade.php}' .
# Physical CSS properties that should be logical
grep -RInE 'margin-(left|right)|padding-(left|right)|text-align:\s*(left|right)' \
--include='*.{css,scss,vue,jsx,tsx}' .
# Date format strings that look hardcoded
grep -RInE "format\(['\"](YYYY|DD|MM)" --include='*.{js,ts,jsx,tsx,vue}' .
Output format
## i18n review:
**Framework:**
**Locales in use:**
### 🔴 Blockers
- `path/file.tsx:42` — . **Impact:** . **Fix:** .
### 🟠 Major
- …
### 🟡 Minor
- …
### ✅ What's working
- —
Severity rubric
| Tag | Meaning | |---|---| | 🔴 Blocker | Cannot be translated correctly (hardcoded strings, broken plurals, broken RTL layout) | | 🟠 Major | Renders incorrectly for many locales (date/number format, sorting, address forms) | | 🟡 Minor | Polish (long-text overflow, missing locale fallback) |
Anti-patterns
- ❌
t('You have ' + count + ' messages')— broken in every language with grammatical agreement - ❌ Translating button text but baking in
width: 80px(German "Einstellungen" doesn't fit) - ❌ Storing formatted currency in DB (
"$10.00") - ❌ Sorting names with
Array.sort()instead ofIntl.Collator - ❌ Right-aligned designs that "just work" in LTR
- ❌ Assuming names have a first and a last name with a space between
- ❌ Validating names with
[a-zA-Z\s]+ - ❌ Mirror-flipping all icons in RTL (don't flip clocks, logos, media controls)
Useful references
- Unicode CLDR — locale data the world relies on
- W3C Internationalization Activity — specs and guides
- MDN: Intl — browser-native locale APIs
- Falsehoods Programmers Believe About Names
- Falsehoods Programmers Believe About Time
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: kwhorne
- Source: kwhorne/elyra-skills
- License: MIT
- Homepage: https://elyracode.com
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.