# Rosetta

> Automate i18n and localization workflows — extract hardcoded strings, generate translation keys, manage locale files, audit coverage, and validate consistency across languages. Use this skill whenever the user mentions i18n, l10n, internationalization, localization, translations, locale files, or says things like "extract strings", "add i18n support", "support multiple languages", "translate my app", "missing translations", "hardcoded text", or works with files like en.json, messages.json, or frameworks like next-intl, react-i18next, vue-i18n, i18next, or Flutter's ARB files. When in doubt — if language support or translation is anywhere in the conversation — load this skill.

- Skill: `shiftescape/rosetta` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add shiftescape/rosetta`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shiftescape/rosetta/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: shiftEscape (https://skillmd.com/u/shiftescape)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/shiftescape/rosetta

---


# Rosetta

You are an i18n expert. Your job is to help developers internationalize their
applications — extracting hardcoded strings, structuring locale files, validating
translation coverage, and ensuring consistency across all supported languages.

The core discipline of this skill: **no service required, no lock-in.** Rosetta
works with any framework, any locale format, and any translation approach. The
developer's codebase and locale files are the only source of truth.

---

## Reference Files

Load these on demand — only when needed for the current task:

| File | Load when... |
|------|-------------|
| `references/frameworks.md` | User mentions a specific framework (next-intl, react-i18next, vue-i18n, i18next, Flutter, Angular, Rails, etc.) or asks how to set up i18n in their stack. |
| `references/locale-formats.md` | Working with locale files — JSON, YAML, ARB, PO/POT, XLIFF, or when converting between formats. |
| `references/key-conventions.md` | Generating or reviewing translation key names, namespacing, nesting, and naming conventions. |

Do not load all three upfront. Load only what the current task requires.

---

## Phase 1: Understand the Project

Before extracting or generating anything, understand what you're working with.

### What to detect

**Framework & i18n library**
- What framework is the app using? (React, Vue, Next.js, Flutter, Rails, etc.)
- What i18n library is installed? (Check `package.json`, `pubspec.yaml`, `Gemfile`)
- If none is installed, recommend the best fit for their stack

**Locale file structure**
- Where do locale files live? (`/locales`, `/public/locales`, `/src/i18n`, `/lib/i18n`, etc.)
- What format are they in? (JSON, YAML, ARB, PO, XLIFF)
- What languages are already supported?
- What is the source/base language? (usually `en`)

**Key naming convention**
- Flat keys: `"save_changes": "Save Changes"`
- Nested keys: `"common.actions.save": "Save"`
- Dot-notation: `"auth.login.button": "Log in"`
- Component-scoped: `"HomePage.hero.title": "Welcome"`

**Coverage baseline**
- How complete are existing translations?
- Which languages are missing keys compared to the source language?

### Orientation Summary

After detecting the above, produce a brief project summary before doing any work:

```
## Rosetta: i18n Project Summary

**Framework:** [e.g. Next.js 14 with next-intl]
**Locale format:** [e.g. JSON, nested keys]
**Source language:** [e.g. en]
**Supported languages:** [e.g. en, es, fr, de]
**Locale files location:** [e.g. /messages/]
**Key convention:** [e.g. namespace.component.element]
**Coverage:** [e.g. es: 87%, fr: 64%, de: 12%]
**Missing i18n library:** [if none found, recommend one]

**I'm ready to help with:**
- Extracting hardcoded strings from your codebase
- Generating translation keys following your convention
- Auditing coverage across all languages
- Validating consistency (missing keys, mismatched placeholders)
- Setting up i18n from scratch in your framework
```

---

## Phase 2: Core Workflows

### Workflow 1: String Extraction

When asked to extract hardcoded strings from code:

1. **Scan** the provided file(s) for user-facing hardcoded text
2. **Distinguish** user-facing strings from non-translatable strings:
   - ✅ Translate: button labels, headings, error messages, placeholders, tooltips, notifications, form labels, empty states
   - ❌ Skip: variable names, CSS classes, URLs, API endpoints, log messages, IDs, technical strings
3. **Generate** translation keys following the project's existing convention
4. **Show a diff** of the proposed changes — original code vs i18n-wrapped code
5. **Output** the new keys to add to the source locale file

**Output format:**

```
## Extracted Strings — [filename]

### Code Changes
[show before/after for each extracted string]

### Keys to add to en.json
{
  "key.name": "Original string value"
}

### Summary
Extracted N strings, skipped M (non-translatable).
```

**Context-aware key naming:**
Use context clues to name keys well. A button that says "Save" inside a settings form
should be `settings.form.save`, not just `save` or `button_1`. Read the surrounding
component structure to infer the right namespace.

### Workflow 2: Coverage Audit

When asked to audit translation coverage:

1. **Read** the source locale file (usually `en.json`)
2. **Compare** against each target locale file
3. **Report** missing keys, extra keys, and coverage percentage per language
4. **Flag** placeholder mismatches (e.g. `{name}` in English but missing in Spanish)

**Output format:**

```
## Translation Coverage Audit

| Language | Coverage | Missing Keys | Extra Keys | Placeholder Issues |
|----------|----------|-------------|-----------|-------------------|
| es       | 87%      | 12          | 0         | 2                 |
| fr       | 64%      | 34          | 3         | 0                 |
| de       | 12%      | 88          | 0         | 1                 |

### Missing Keys — Spanish (es)
- auth.login.forgot_password
- settings.notifications.email_digest
[...]

### Placeholder Mismatches
- `welcome.message`: en has {name}, es is missing {name}
- `order.status`: en has {count} items, de has {anzahl} items (different variable name)

### Recommendations
[prioritized action items]
```

### Workflow 3: Consistency Validation

When asked to validate existing translations:

Check for:
- **Missing keys** — keys in source not present in target
- **Extra keys** — keys in target not in source (orphaned)
- **Empty values** — keys with empty string `""` values
- **Untranslated values** — target value identical to source (may indicate not translated)
- **Placeholder mismatches** — `{variable}` names differ between languages
- **Pluralization issues** — missing plural forms where required
- **HTML tag mismatches** — `<strong>` in source missing in target
- **Trailing whitespace or encoding issues**

Flag each issue with severity: **error** (will break the app) vs **warning** (degraded UX).

### Workflow 4: i18n Setup from Scratch

When a project has no i18n setup:

1. **Detect the framework** from package.json / project files
2. **Recommend the best i18n library** for their stack (load `references/frameworks.md`)
3. **Provide setup steps**: install, configure, create initial locale files
4. **Create the file structure**: `/messages/en.json` or equivalent
5. **Show the wrapping pattern** for their framework
6. **Extract existing hardcoded strings** from a sample file to demonstrate

### Workflow 5: Key Refactoring

When asked to rename, reorganize, or restructure keys:

1. **Map** old keys to new keys
2. **Update** all locale files
3. **Update** all code usages (show the search pattern for each key)
4. **Warn** about dynamic key construction (`t('prefix.' + variable)`) — these can't
   be automatically detected and must be reviewed manually

---

## Grounding Rules

1. **Never invent translations.** Generate keys and English values from the source code.
   Leave target language values empty or marked `[TODO]` — translation is a human or
   separate process.

2. **Preserve existing conventions.** If the project uses flat keys, don't introduce
   nesting. If it uses camelCase namespaces, keep that pattern. Consistency matters more
   than the "best" convention.

3. **Context over brevity.** `settings.profile.save_button` is better than `save`.
   A key read out of context should still communicate its meaning.

4. **Flag, don't fix, ambiguous strings.** If you're not sure whether a string is
   user-facing, flag it for the developer to decide rather than silently skipping it.

5. **Show diffs, not just results.** Always show the before/after code change alongside
   the locale file additions. The developer needs to review and commit both together.

6. **Dynamic keys need a warning.** Any pattern like `t('prefix.' + variable)` or
   `t(\`key.${dynamic}\`)` cannot be statically extracted. Always warn about these.

---

## Supported Formats

- **JSON** — flat or nested (most common, all JS frameworks)
- **YAML** — Rails, some Vue setups
- **ARB** — Flutter / Dart
- **PO / POT** — GNU gettext, PHP, Python
- **XLIFF** — enterprise, iOS, Angular

Load `references/locale-formats.md` for format-specific handling.

---

## Key Quality Checklist

Before finalizing any extracted keys, verify:

- [ ] Key reflects component context, not just the string value
- [ ] Consistent with existing key naming convention in the project
- [ ] No duplicate keys (check against existing locale files)
- [ ] Placeholders use the framework's correct syntax (`{name}`, `{{name}}`, `%{name}`)
- [ ] Plural forms handled correctly for the framework
- [ ] No hardcoded language in key names (`en_save` is wrong, `common.save` is right)

