---
name: translate-craft
description: Professional translation and localization for 8 languages (ES, JA, FR, DE, PT, ZH, KO, AR). Covers tone matrix, formality levels, i18n patterns (react-intl, i18next, ICU), RTL layout, cultural adaptation, and locale formatting. Use when user asks to translate text, localize an app, adapt tone, review translations, add i18n, or set up RTL.
license: MIT
compatibility: opencode
triggers:
- translate text from one language to another
- localize an app or website for a new market
- adapt tone/register for a target audience
- review an existing translation for quality
- add i18n support to a codebase
- set up RTL layout for Arabic or Hebrew
- internationalize a React/i18next project
- format dates, currencies, numbers per locale
negatives:
- word-for-word dictionary lookups
- raw machine translation without human review
- translating code comments or variable names
metadata:
version: "4.0.0"
workflow: communication
audience: developers, translators
Translate Craft
Translation that reads as if originally written in the target language. Based on ATA standards, Mozilla l10n best practices, Airbnb style guide, and Microsoft Language Portal.
Core Principle
Translate meaning, not words. If the reader can tell it's a translation, it failed.
Sub-Commands
| Command |
Description |
translate |
Translate text with tone, formality, and cultural adaptation |
localize |
Localize dates, currencies, units, addresses per locale |
i18n |
Set up i18n framework (react-intl / i18next / ICU) |
rtl |
Implement RTL layout with CSS logical properties |
audit |
Review existing translation for quality issues |
teach |
Create a localization guide for a language pair |
Language-Specific Rules (8 languages)
EN → ES (Spanish)
- Formality:
tú (internal), usted (client/external)
- Gender: inclusive language. "El usuario" → "La persona usuaria"
- Length: ~25% longer. Account for UI expansion.
- Passive: Active preferred. "Se decidió" not "Fue decidido"
EN → JA (Japanese)
- Politeness: 3 levels: casual (だ), polite (です), honorific (敬語). Default: polite.
- Subject omission: Drop subjects when clear from context
- Pronouns: Minimize 私/あなた. Overuse sounds foreign.
EN → FR (French)
- Formality:
vous (professional), tu (casual)
- Gender: Everything has gender. Ensure agreement across sentences.
- Punctuation: Non-breaking space before
?, !, :, ;
EN → DE (German)
- Compound nouns: "cloud storage" → "Cloud-Speicher"
- Capitalization: All nouns capitalized
- Formality:
Sie (prof), du (casual)
EN → PT (Portuguese)
- Formality:
você (general), o senhor/a senhora (formal)
- Length: ~20-25% longer
EN → ZH (Mandarin)
- Measure words: 个, 张, 条, 块 — correct classifier per noun
- Tone: 您 (formal) vs 你 (casual)
- Shortened: ~15-20% shorter. More room in UI.
- Script: Simplified for CN. Traditional for TW/HK.
EN → KO (Korean)
- Honorifics: 합쇼체 (formal), 해요체 (polite casual), 해체 (casual). Default: 해요체
- SOV word order: Subject-Object-Verb, opposite of English
EN → AR (Arabic)
- RTL: Everything mirrors. Use CSS logical properties.
- Root system: Words derive from 3-letter roots
- Length: ~25% shorter. Text shrinks in UI.
Workflow
- Identify scope: source, target, audience, medium, tone tier
- Analyze source: flag idioms, cultural references, ambiguity
- Translate: first pass applying language-specific rules
- Adapt tone: adjust register per audience
- Localize: dates, times, currencies, units, phone, addresses
- Restructure: natural target-language word order
- Reverse review: read only target. If you can reconstruct source, too literal.
- UI verify: paste into layout. Check truncation, overflow, RTL, line breaks.
- Final pass: production checklist.
i18n Framework Patterns
ICU Message Syntax
{count, plural, one {# item} other {# items}}
{gender, select, male {He} female {She} other {They}}
RTL Layout (CSS logical properties)
.element {
margin-inline-start: 1rem; /* auto-flips LTR/RTL */
padding-inline: 1rem;
border-inline-end: 1px solid;
}
Locale Formatting Quick Reference
| Format |
EN |
DE |
JA |
AR |
| Date short |
05/12/2026 |
12.05.2026 |
2026/05/12 |
12/05/2026 |
| Time |
3:30 PM |
15:30 |
15:30 |
03:30 م |
| Currency |
$1,234.56 |
1.234,56 € |
¥1,235 |
١٬٢٣٤٫٥٦ ر.س |
| Number |
1,234.56 |
1.234,56 |
1,234.56 |
١٬٢٣٤٫٥٦ |
Production Checklist
Error Handling
| Cause |
Fix |
Placeholder syntax ({name}, %s, {{var}}) broken in translation |
Preserve exact placeholder format. Verify each appears unchanged in output. Test with real data. |
| Text expansion breaking UI layout (German +25%, Spanish +25%) |
Design containers with flex-grow. Test with longest translated string. Account for CJK shortening (-15-20%). |
| False friends between language pairs |
Maintain language-pair-specific false friends list. ES: "embarazada" ≠ "embarrassed". FR: "actuellement" ≠ "actually". DE: "Gift" ≠ "gift". |
| Mixed formality in same document (tú/usted, Sie/du) |
Pick one register at start. Scan entire document for consistency. Language-specific rules table has defaults. |
| Word-for-word translation producing unnatural phrasing |
Restructure to target language word order. KO: SOV. JA: drop subjects. AR: root-based word derivation. |
| RTL layout breaks on dynamically injected content |
Use CSS logical properties exclusively (margin-inline-start, padding-inline, border-inline-end). Never left/right. |
| Back-translation reveals meaning drift |
If reconstructed source differs from original, the translation is too literal or too loose. Adjust: preserve meaning, not word order. |
| Cultural reference doesn't exist in target market |
Adapt or explain. Replace region-specific idioms with natural equivalent. Add brief context for untranslatable concepts. |
Anti-Patterns
| Anti-pattern |
Correct |
| Literal idiom translation |
Find equivalent idiom or drop |
| False friends (embarrassed ≠ embarazada) |
Maintain false friends list per language pair |
| Mixed formality (tú/usted in same paragraph) |
Pick one register. Enforce throughout. |
| Word-for-word structure |
Restructure to target language patterns |
| Ignoring expansion (German +25%) |
Design flexible containers. Test with longest string. |
| RTL as afterthought |
Use CSS logical properties from day 1 |
ICU MessageFormat Advanced Patterns
Plurals (per-language rules)
// EN: 1 item, 2 items
{count, plural, one {# item} other {# items}}
// AR: 0 عناصر, 1 عنصر, 2 عنصران, 3-10 عناصر, 11+ عنصر
{count, plural, zero {# عناصر} one {# عنصر} two {# عنصران} few {# عناصر} many {# عنصر}}
// JA: 日本語は複数形がない(単純)
{count}個
Gender
// ES
{gender, select, male {Estimado} female {Estimada} other {Estimado/a}}
// FR
{gender, select, male {Cher} female {Chère} other {Cher/Chère}}
Select with nested plural
{gender, select,
male {{count, plural, one {Il a # livre} other {Il a # livres}}}
female {{count, plural, one {Elle a # livre} other {Elle a # livres}}}
}
Date/Number Locale Formatting
# Python babel
from babel.dates import format_date, format_datetime
format_date(date, locale='de_DE') # 18.05.2026
format_date(date, locale='en_US') # May 18, 2026
format_date(date, locale='ja_JP') # 2026/05/18
from babel.numbers import format_number, format_currency
format_number(1234567, locale='en_US') # 1,234,567
format_number(1234567, locale='de_DE') # 1.234.567
format_currency(49.99, 'EUR', locale='de_DE') # 49,99 €
// JavaScript Intl
new Intl.DateTimeFormat('ja-JP').format(new Date()) // 2026/5/18
new Intl.DateTimeFormat('ar-SA', { dateStyle: 'full' }).format(new Date())
new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(49.99) // 49,99 €
RTL CSS Patterns
/* Logical properties (direction-aware) */
.element {
margin-inline-start: 16px; /* margin-left in LTR, margin-right in RTL */
padding-inline-end: 8px;
border-inline-start: 2px solid;
text-align: start;
}
/* Avoid: margin-left, padding-right, text-align: left */
Sources
- ATA (American Translators Association)
- Mozilla l10n best practices
- Airbnb translation style guide
- Microsoft Language Portal
- UN Translation guidelines
- W3C Internationalization articles
- FormatJS / ICU Message Syntax
- Google Material Design — RTL guidelines
Checklist
1---2name: translate-craft3description: ---4---5---6name: translate-craft7description: Professional translation and localization for 8 languages (ES, JA, FR, DE, PT, ZH, KO, AR). Covers tone matrix, formality levels, i18n patterns (react-intl, i18next, ICU), RTL layout, cultural adaptation, and locale formatting. Use when user asks to translate text, localize an app, adapt tone, review translations, add i18n, or set up RTL.8license: MIT9compatibility: opencode10triggers:11 - translate text from one language to another12 - localize an app or website for a new market13 - adapt tone/register for a target audience14 - review an existing translation for quality15 - add i18n support to a codebase16 - set up RTL layout for Arabic or Hebrew17 - internationalize a React/i18next project18 - format dates, currencies, numbers per locale19negatives:20 - word-for-word dictionary lookups21 - raw machine translation without human review22 - translating code comments or variable names23metadata:24 version: "4.0.0"25 workflow: communication26 audience: developers, translators27---282930# Translate Craft3132Translation that reads as if originally written in the target language. Based on ATA standards, Mozilla l10n best practices, Airbnb style guide, and Microsoft Language Portal.3334## Core Principle3536Translate **meaning**, not words. If the reader can tell it's a translation, it failed.3738## Sub-Commands3940| Command | Description |41|---------|-------------|42| `translate` | Translate text with tone, formality, and cultural adaptation |43| `localize` | Localize dates, currencies, units, addresses per locale |44| `i18n` | Set up i18n framework (react-intl / i18next / ICU) |45| `rtl` | Implement RTL layout with CSS logical properties |46| `audit` | Review existing translation for quality issues |47| `teach` | Create a localization guide for a language pair |4849## Language-Specific Rules (8 languages)5051### EN → ES (Spanish)52- **Formality**: `tú` (internal), `usted` (client/external)53- **Gender**: inclusive language. "El usuario" → "La persona usuaria"54- **Length**: ~25% longer. Account for UI expansion.55- **Passive**: Active preferred. "Se decidió" not "Fue decidido"5657### EN → JA (Japanese)58- **Politeness**: 3 levels: casual (だ), polite (です), honorific (敬語). Default: polite.59- **Subject omission**: Drop subjects when clear from context60- **Pronouns**: Minimize 私/あなた. Overuse sounds foreign.6162### EN → FR (French)63- **Formality**: `vous` (professional), `tu` (casual)64- **Gender**: Everything has gender. Ensure agreement across sentences.65- **Punctuation**: Non-breaking space before `?`, `!`, `:`, `;`6667### EN → DE (German)68- **Compound nouns**: "cloud storage" → "Cloud-Speicher"69- **Capitalization**: All nouns capitalized70- **Formality**: `Sie` (prof), `du` (casual)7172### EN → PT (Portuguese)73- **Formality**: `você` (general), `o senhor/a senhora` (formal)74- **Length**: ~20-25% longer7576### EN → ZH (Mandarin)77- **Measure words**: 个, 张, 条, 块 — correct classifier per noun78- **Tone**: 您 (formal) vs 你 (casual)79- **Shortened**: ~15-20% shorter. More room in UI.80- **Script**: Simplified for CN. Traditional for TW/HK.8182### EN → KO (Korean)83- **Honorifics**: 합쇼체 (formal), 해요체 (polite casual), 해체 (casual). Default: 해요체84- **SOV word order**: Subject-Object-Verb, opposite of English8586### EN → AR (Arabic)87- **RTL**: Everything mirrors. Use CSS logical properties.88- **Root system**: Words derive from 3-letter roots89- **Length**: ~25% shorter. Text shrinks in UI.9091## Workflow92931. **Identify scope**: source, target, audience, medium, tone tier942. **Analyze source**: flag idioms, cultural references, ambiguity953. **Translate**: first pass applying language-specific rules964. **Adapt tone**: adjust register per audience975. **Localize**: dates, times, currencies, units, phone, addresses986. **Restructure**: natural target-language word order997. **Reverse review**: read only target. If you can reconstruct source, too literal.1008. **UI verify**: paste into layout. Check truncation, overflow, RTL, line breaks.1019. **Final pass**: production checklist.102103## i18n Framework Patterns104105### ICU Message Syntax106```107{count, plural, one {# item} other {# items}}108{gender, select, male {He} female {She} other {They}}109```110111### RTL Layout (CSS logical properties)112```css113.element {114 margin-inline-start: 1rem; /* auto-flips LTR/RTL */115 padding-inline: 1rem;116 border-inline-end: 1px solid;117}118```119120## Locale Formatting Quick Reference121122| Format | EN | DE | JA | AR |123|--------|----|----|----|-----|124| Date short | 05/12/2026 | 12.05.2026 | 2026/05/12 | 12/05/2026 |125| Time | 3:30 PM | 15:30 | 15:30 | 03:30 م |126| Currency | $1,234.56 | 1.234,56 € | ¥1,235 | ١٬٢٣٤٫٥٦ ر.س |127| Number | 1,234.56 | 1.234,56 | 1,234.56 | ١٬٢٣٤٫٥٦ |128129## Production Checklist130131- [ ] Placeholders preserved (`{name}`, `%s`, `{{var}}`)132- [ ] Date/time/currency/units converted per locale133- [ ] Cultural references adapted or explained134- [ ] Idioms replaced with natural equivalent135- [ ] Formality consistent across entire document136- [ ] Gender agreement checked137- [ ] UTF-8 encoding verified138- [ ] UI: expansion/shrinkage accounted for139- [ ] RTL: layout mirrored, numbers left-to-right140- [ ] Read-aloud test passed141- [ ] Back-translation sample checked for meaning drift142143## Error Handling144145| Cause | Fix |146|-------|-----|147| Placeholder syntax (`{name}`, `%s`, `{{var}}`) broken in translation | Preserve exact placeholder format. Verify each appears unchanged in output. Test with real data. |148| Text expansion breaking UI layout (German +25%, Spanish +25%) | Design containers with flex-grow. Test with longest translated string. Account for CJK shortening (-15-20%). |149| False friends between language pairs | Maintain language-pair-specific false friends list. ES: "embarazada" ≠ "embarrassed". FR: "actuellement" ≠ "actually". DE: "Gift" ≠ "gift". |150| Mixed formality in same document (tú/usted, Sie/du) | Pick one register at start. Scan entire document for consistency. Language-specific rules table has defaults. |151| Word-for-word translation producing unnatural phrasing | Restructure to target language word order. KO: SOV. JA: drop subjects. AR: root-based word derivation. |152| RTL layout breaks on dynamically injected content | Use CSS logical properties exclusively (`margin-inline-start`, `padding-inline`, `border-inline-end`). Never `left`/`right`. |153| Back-translation reveals meaning drift | If reconstructed source differs from original, the translation is too literal or too loose. Adjust: preserve meaning, not word order. |154| Cultural reference doesn't exist in target market | Adapt or explain. Replace region-specific idioms with natural equivalent. Add brief context for untranslatable concepts. |155156## Anti-Patterns157158| Anti-pattern | Correct |159|--------------|---------|160| Literal idiom translation | Find equivalent idiom or drop |161| False friends (embarrassed ≠ embarazada) | Maintain false friends list per language pair |162| Mixed formality (tú/usted in same paragraph) | Pick one register. Enforce throughout. |163| Word-for-word structure | Restructure to target language patterns |164| Ignoring expansion (German +25%) | Design flexible containers. Test with longest string. |165| RTL as afterthought | Use CSS logical properties from day 1 |166167## ICU MessageFormat Advanced Patterns168169### Plurals (per-language rules)170```171// EN: 1 item, 2 items172{count, plural, one {# item} other {# items}}173174// AR: 0 عناصر, 1 عنصر, 2 عنصران, 3-10 عناصر, 11+ عنصر175{count, plural, zero {# عناصر} one {# عنصر} two {# عنصران} few {# عناصر} many {# عنصر}}176177// JA: 日本語は複数形がない(単純)178{count}個179```180181### Gender182```183// ES184{gender, select, male {Estimado} female {Estimada} other {Estimado/a}}185186// FR187{gender, select, male {Cher} female {Chère} other {Cher/Chère}}188```189190### Select with nested plural191```192{gender, select,193 male {{count, plural, one {Il a # livre} other {Il a # livres}}}194 female {{count, plural, one {Elle a # livre} other {Elle a # livres}}}195}196```197198### Date/Number Locale Formatting199200```python201# Python babel202from babel.dates import format_date, format_datetime203format_date(date, locale='de_DE') # 18.05.2026204format_date(date, locale='en_US') # May 18, 2026205format_date(date, locale='ja_JP') # 2026/05/18206207from babel.numbers import format_number, format_currency208format_number(1234567, locale='en_US') # 1,234,567209format_number(1234567, locale='de_DE') # 1.234.567210format_currency(49.99, 'EUR', locale='de_DE') # 49,99 €211```212213```javascript214// JavaScript Intl215new Intl.DateTimeFormat('ja-JP').format(new Date()) // 2026/5/18216new Intl.DateTimeFormat('ar-SA', { dateStyle: 'full' }).format(new Date())217new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(49.99) // 49,99 €218```219220### RTL CSS Patterns221222```css223/* Logical properties (direction-aware) */224.element {225 margin-inline-start: 16px; /* margin-left in LTR, margin-right in RTL */226 padding-inline-end: 8px;227 border-inline-start: 2px solid;228 text-align: start;229}230/* Avoid: margin-left, padding-right, text-align: left */231```232233## Sources234235- ATA (American Translators Association)236- Mozilla l10n best practices237- Airbnb translation style guide238- Microsoft Language Portal239- UN Translation guidelines240- W3C Internationalization articles241- FormatJS / ICU Message Syntax242- Google Material Design — RTL guidelines243244## Checklist245246- [ ] Skill loads without errors in the AI agent247- [ ] YAML frontmatter is valid (description, compatibility, audience)248- [ ] Workflow section provides clear step-by-step instructions249- [ ] Error handling section covers common failure modes250- [ ] All referenced files (references/, scripts/, assets/) exist251- [ ] Skill triggers correctly for intended use cases252- [ ] No broken links or missing resources