Claude-skill-registry i18n-translation
Ensure all user-facing text is translatable via ngx-translate. Use when adding text to UI components, checking for hardcoded strings, or when the user asks about translations.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/i18n-translation" ~/.claude/skills/majiayu000-claude-skill-registry-i18n-translation && rm -rf "$T"
manifest:
skills/data/i18n-translation/SKILL.mdsource content
I18n Translation Skill
Purpose: Ensure all user-facing text uses translation keys, never hardcoded strings.
When to Invoke
- Creating new components with visible text
- Adding labels, buttons, messages to templates
- Reviewing components for i18n compliance
Translation Setup
Library:
@ngx-translate/core + @ngx-translate/http-loader
Files:
- Spanish (primary)apps/web/public_override/assets/i18n/es.json
- Englishapps/web/public_override/assets/i18n/en.json
Key Naming Convention
MODULE.SECTION.KEY_NAME
Examples:
{ "COMMON": { "BUTTONS": { "SAVE": "Guardar", "CANCEL": "Cancelar", "DELETE": "Eliminar", "CONFIRM": "Confirmar", "CLOSE": "Cerrar", "LOADING": "Cargando..." }, "LABELS": { "SEARCH": "Buscar", "FILTER": "Filtrar", "ACTIONS": "Acciones" }, "MESSAGES": { "SUCCESS": "Operación exitosa", "ERROR": "Ha ocurrido un error", "CONFIRM_DELETE": "¿Estás seguro de eliminar?" } }, "COMPONENTS": { "DATA_TABLE": { "NO_DATA": "No hay datos disponibles", "LOADING": "Cargando datos...", "ROWS_PER_PAGE": "Filas por página", "OF": "de" }, "MODAL": { "CLOSE": "Cerrar", "CONFIRM": "Confirmar", "CANCEL": "Cancelar" } } }
Component Pattern
Import TranslateModule
import { TranslateModule } from "@ngx-translate/core"; @Component({ selector: "ui-example", imports: [TranslateModule], template: ` <button>{{ "COMMON.BUTTONS.SAVE" | translate }}</button> `, }) export class ExampleComponent {}
Dynamic Values with Parameters
<!-- Translation with parameter --> <p>{{ 'COMMON.MESSAGES.WELCOME' | translate:{ name: userName() } }}</p> <!-- In JSON: "WELCOME": "Bienvenido, {{name}}" -->
Pluralization
{ "ITEMS": { "COUNT_0": "Sin elementos", "COUNT_1": "1 elemento", "COUNT_OTHER": "{{count}} elementos" } }
Async Pipe Alternative
import { TranslateService } from "@ngx-translate/core"; export class ExampleComponent { private translate = inject(TranslateService); // For complex scenarios message = computed(() => this.translate.instant("COMMON.MESSAGES.SUCCESS")); }
Component Checklist
When creating/reviewing components:
- All visible text uses
pipe| translate - All aria-labels are translatable
- All placeholder text uses translations
- All tooltip content is translatable
- All error messages use translation keys
- Translation keys are added to ALL locale files
Prohibited Patterns
<!-- ❌ DON'T: Hardcoded text --> <button>Save</button> <button>Guardar</button> <!-- ❌ DON'T: Mixed languages --> <p>Click here to {{ 'ACTION' | translate }}</p> <!-- ✅ DO: Full translation --> <button>{{ 'COMMON.BUTTONS.SAVE' | translate }}</button>
Shared Component Translations
All shared components should use
COMPONENTS. prefix:
{ "COMPONENTS": { "BUTTON": { "LOADING": "Cargando..." }, "INPUT": { "REQUIRED": "Este campo es requerido", "INVALID_EMAIL": "Email inválido" }, "EMPTY_STATE": { "DEFAULT_TITLE": "Sin datos", "DEFAULT_MESSAGE": "No hay información disponible" }, "DATA_TABLE": { "NO_RESULTS": "No se encontraron resultados", "LOADING": "Cargando...", "SELECT_ALL": "Seleccionar todo", "ROWS_PER_PAGE": "Filas por página", "PAGE_OF": "Página {{current}} de {{total}}" }, "TOAST": { "CLOSE": "Cerrar" } } }
Validation
After adding translations:
- Check all locale files have the same keys
- Verify no hardcoded text in templates
- Test with different locales
- Verify placeholders render correctly