Project 36: “The Global Translator” — Internationalization
| Attribute | Value |
|---|---|
| File | KIRO_CLI_LEARNING_PROJECTS.md |
| Main Programming Language | JSON (i18n) |
| Coolness Level | Level 2: Practical |
| Difficulty | Level 1: Beginner |
| Knowledge Area | Internationalization |
What you’ll build: An automated translation system that takes your application’s English locale files and generates accurate, context-aware translations for multiple languages while preserving key structure, placeholders, and formatting.
Why it teaches Grunt Work: This project demonstrates how AI agents excel at high-volume, high-precision tasks that are tedious for humans but critical for global applications. You’ll learn to leverage Kiro’s language understanding to maintain translation consistency across hundreds of strings.
Core challenges you’ll face:
- Key structure preservation → Maps to nested object validation and structural equality checking
- Placeholder detection → Maps to regex patterns for interpolation variables (
{name},{{count}},%s) - Context-aware translation → Maps to providing semantic context to avoid literal translations
- Pluralization rules → Maps to ICU MessageFormat and language-specific plural forms
Real World Outcome
You’ll have a CLI tool that transforms a single English locale file into multiple language files with verified structural integrity:
$ ls locales/
en.json
$ cat locales/en.json
{
"common": {
"welcome": "Welcome, {name}!",
"itemCount": "{count, plural, =0 {No items} =1 {One item} other {# items}}",
"errors": {
"notFound": "The resource at {path} was not found",
"unauthorized": "You must be logged in to access this page"
}
},
"dashboard": {
"greeting": "Good {timeOfDay}, {userName}",
"stats": {
"totalUsers": "{count} active users",
"lastLogin": "Last login: {date, date, medium}"
}
}
}
$ kiro translate --source locales/en.json --target es,fr,de,ja,pt
[Kiro CLI Session]
🌍 Global Translator Agent
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 Source: locales/en.json (47 keys)
🎯 Target languages: es, fr, de, ja, pt
Step 1: Analyzing source structure...
✓ Found 47 translation keys
✓ Detected 12 placeholders: {name}, {count}, {path}, {timeOfDay}, {userName}, {date}
✓ Identified 3 plural forms (ICU MessageFormat)
Step 2: Extracting context...
• "welcome" → greeting context, informal tone
• "itemCount" → UI element, requires plural support
• "errors.notFound" → error message, technical context
• "dashboard.greeting" → personalized greeting with time
Step 3: Translating to Spanish (es)...
✓ 47/47 keys translated
✓ All placeholders preserved
✓ Plural rules adapted for Spanish
Step 4: Translating to French (fr)...
✓ 47/47 keys translated
✓ Gender-neutral alternatives used
✓ Plural rules adapted for French
Step 5: Translating to German (de)...
✓ 47/47 keys translated
✓ Formal "Sie" used for general UI
✓ Plural rules adapted for German
Step 6: Translating to Japanese (ja)...
✓ 47/47 keys translated
✓ Polite form (です/ます) used
✓ No plural forms (Japanese uses counters)
Step 7: Translating to Portuguese (pt)...
✓ 47/47 keys translated
✓ Brazilian Portuguese variant selected
✓ Plural rules adapted for Portuguese
Step 8: Validation...
✓ All files have identical key structures
✓ All placeholders match source
✓ No missing or extra keys
✓ ICU MessageFormat syntax valid
✅ Translation complete!
Generated files:
locales/es.json (47 keys)
locales/fr.json (47 keys)
locales/de.json (47 keys)
locales/ja.json (47 keys)
locales/pt.json (47 keys)
$ cat locales/es.json
{
"common": {
"welcome": "¡Bienvenido, {name}!",
"itemCount": "{count, plural, =0 {Sin elementos} =1 {Un elemento} other {# elementos}}",
"errors": {
"notFound": "El recurso en {path} no fue encontrado",
"unauthorized": "Debes iniciar sesión para acceder a esta página"
}
},
"dashboard": {
"greeting": "Buenas {timeOfDay}, {userName}",
"stats": {
"totalUsers": "{count} usuarios activos",
"lastLogin": "Último acceso: {date, date, medium}"
}
}
}
$ npm run validate-locales
> Validating locale files...
✓ All 5 locale files have matching key structure
✓ All placeholders are consistent
✓ ICU MessageFormat syntax is valid
✓ No duplicate keys found
# Your application now supports 5 languages with zero manual translation!
Exactly what happens:
- Kiro reads your English locale file and builds a structural map
- For each target language, it translates strings while preserving:
- Nested object structure (exact key paths)
- Placeholder syntax (
{variableName}) - ICU MessageFormat plural rules
- HTML entities and special characters
- It validates every generated file against the source structure
- It produces a diff report showing what changed beyond just the text
The Core Question You’re Answering
“How do you leverage AI for high-volume, high-precision tasks that require both creativity (natural translation) and rigid constraints (structural validation)?”
This is the essence of “AI as a power tool” — you’re not just prompting for a translation; you’re building a system that:
- Uses AI’s language understanding for quality translations
- Enforces programmatic validation to prevent structural drift
- Scales to hundreds of languages without manual effort
- Maintains consistency across all locales
Concepts You Must Understand First
Stop and research these before coding:
- Internationalization (i18n) vs Localization (l10n)
- What’s the difference between i18n and l10n?
- What are locale codes (en-US, pt-BR, zh-CN)?
- What is the difference between language and region?
- Book Reference: “Internationalization and Localization Using Microsoft .NET” by Nick Symmonds - Ch. 1-2
- ICU MessageFormat
- What are interpolation placeholders?
- How do plural rules work in different languages? (English: one/other, Russian: one/few/many/other)
- What is gender-based inflection?
- Reference: ICU MessageFormat Specification (https://unicode-org.github.io/icu/userguide/format_parse/messages/)
- JSON Structure Validation
- How do you recursively compare nested objects?
- What’s the difference between shallow and deep equality?
- How do you validate that two JSON files have the same keys but different values?
- Book Reference: “JavaScript: The Definitive Guide” by David Flanigan - Ch. 6 (Objects)
- Context-Aware Translation
- Why does “Welcome” translate differently in formal vs informal contexts?
- What are gender-neutral alternatives in gendered languages (French, Spanish)?
- How do you handle culturally-specific idioms?
- Book Reference: “Found in Translation” by Nataly Kelly & Jost Zetzsche
Questions to Guide Your Design
Before implementing, think through these:
- Structural Validation
- How will you detect if a translated file is missing a key?
- How will you validate that placeholders weren’t accidentally translated?
- What happens if the source file changes after translations are generated?
- Should you support nested keys with dot notation (
errors.notFound) or only nested objects?
- Translation Quality
- How do you provide context to Kiro for better translations? (e.g., “button label” vs “error message”)
- Should you allow overrides for specific keys that need manual review?
- How do you handle brand names or technical terms that shouldn’t be translated?
- What about HTML tags inside strings (
<strong>Bold</strong> text)?
- Plural Handling
- How many plural forms does each language have? (English: 2, Arabic: 6)
- Should you use ICU MessageFormat or a simpler plural syntax?
- What happens if the source uses English plural rules but the target language needs different forms?
- Incremental Updates
- If you add 5 new keys to
en.json, should the tool re-translate everything or just the new keys? - How do you track which translations are human-reviewed vs AI-generated?
- Should you version your locale files?
- If you add 5 new keys to
Thinking Exercise
Placeholder Preservation Challenge
You have this English string:
"greeting": "Hello, {name}! You have {count} new {count, plural, =1 {message} other {messages}}."
Kiro translates it to Spanish as:
"greeting": "¡Hola, {nombre}! Tienes {cantidad} {cantidad, plural, =1 {mensaje nuevo} other {mensajes nuevos}}."
Questions to reason through:
- What went wrong? (Hint: look at the placeholder names)
- How would your validation catch this error?
- What instruction would you give Kiro to prevent placeholder name changes?
- How would you handle the fact that Spanish puts the adjective after the noun (“mensajes nuevos” vs “new messages”)?
- Should you allow Kiro to reorder placeholders if the target language has different word order?
The Interview Questions They’ll Ask
Prepare to answer these:
- “How would you handle right-to-left (RTL) languages like Arabic or Hebrew in your translation system?”
- “What’s the difference between i18n and l10n? Give a concrete example.”
- “How do you ensure that date/time formatting respects locale conventions (MM/DD/YYYY vs DD/MM/YYYY)?”
- “Your translation system accidentally translated ‘Apple’ (the company) to ‘Manzana’ (the fruit). How do you prevent this?”
- “What are the security implications of allowing user-provided locale files in your application?”
- “How would you implement translation fallback chains? (e.g., pt-BR → pt → en)”
Hints in Layers
Hint 1: Start with Structure Validation Before you translate anything, write a function that:
- Reads the source JSON
- Extracts all key paths (e.g.,
["common.welcome", "common.itemCount", "common.errors.notFound"]) - Validates that a translated file has exactly the same key paths
- This becomes your “validator” that runs after every translation
Hint 2: Placeholder Detection Extract all placeholders from the source strings using regex:
const placeholderRegex = /\{[^}]+\}/g;
const placeholders = sourceString.match(placeholderRegex);
// ["name}"], ["{count}"]
For each translated string, verify the same placeholders exist (exact match).
Hint 3: Kiro Prompt Structure Give Kiro context for each string:
Translate the following strings to {targetLanguage}.
CRITICAL RULES:
1. Preserve ALL placeholders exactly as written: {name}, {count}, {path}
2. Do NOT translate placeholder names
3. Maintain ICU MessageFormat syntax for plurals
4. Use {formality} tone (formal/informal)
5. Keep HTML tags unchanged
Context: {stringContext} (e.g., "error message", "button label", "greeting")
Source (English):
{
"key": "value with {placeholder}"
}
Return ONLY valid JSON with the same structure.
Hint 4: Validation Loop After translation:
- Parse both source and target JSON
- Extract key paths from both (recursive traversal)
- Assert:
sourceKeys === targetKeys(same order, same depth) - For each key, extract placeholders from source and target
- Assert:
sourcePlaceholders === targetPlaceholders - If validation fails, show diff and ask if Kiro should retry
Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| i18n fundamentals | “Internationalization and Localization Using Microsoft .NET” by Nick Symmonds | Ch. 1-3 |
| JSON manipulation | “JavaScript: The Definitive Guide” by David Flanigan | Ch. 6 |
| ICU MessageFormat | ICU User Guide (online) | Message Formatting |
| Translation best practices | “Found in Translation” by Nataly Kelly | Ch. 4, 7 |
Common Pitfalls and Debugging
Problem 1: “Placeholders are being translated”
- Why: Kiro doesn’t know that
{name}is a variable, not English text - Fix: Explicitly instruct: “Do NOT translate text inside curly braces
{}” - Quick test:
grep -o '{[^}]*}' locales/es.jsonshould matchgrep -o '{[^}]*}' locales/en.json
Problem 2: “Key structure doesn’t match”
- Why: JSON parsing errors or Kiro adding/removing keys
- Fix: Write a structural diff function that shows which keys are missing/extra
- Quick test:
const sourceKeys = Object.keys(flattenObject(source)).sort(); const targetKeys = Object.keys(flattenObject(target)).sort(); console.log("Missing:", sourceKeys.filter(k => !targetKeys.includes(k))); console.log("Extra:", targetKeys.filter(k => !sourceKeys.includes(k)));
Problem 3: “Plural forms are broken in the target language”
- Why: Different languages have different plural categories (English: 2, Russian: 4, Arabic: 6)
- Fix: Use a plural rules library (e.g.,
make-plural) to generate correct ICU syntax - Quick test: Validate with
intl-messageformatparser before writing the file
Problem 4: “HTML tags inside strings are malformed after translation”
- Why: Kiro might rearrange or escape HTML:
<strong>→<strong> - Fix: Instruct Kiro: “Preserve all HTML tags exactly as written, including attributes”
- Quick test: Count
<and>characters before and after translation
Definition of Done
- Source locale file is parsed and all key paths are extracted
- For each target language, a valid JSON file is generated with identical structure
- All placeholders in translated strings match the source (name and count)
- ICU MessageFormat plural syntax is valid and adapted to target language plural rules
- No HTML tags or special characters are malformed
- A validation report shows 100% structural match across all locale files
- Incremental updates work: adding a new key to source updates only that key in translations
- Tool outputs a human-readable diff showing what changed beyond just translations