Agent Skill
2/7/2026

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.

R
reeinharddd
1GitHub Stars
1Views
npx skills add reeinharddd/impulsa-monorepo

SKILL.md

Namei18n-translation
DescriptionEnsure 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.

name: i18n-translation description: "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." version: "1.0.0" author: "@Frontend"

Auto-invocation configuration

auto_invoke: event: "component-creation" condition: "file contains hardcoded user-facing strings"

Required inputs

inputs:

  • component_file: "Path to the component with text"
  • locale: "Target locale (es, en)"

Skill output

output: "Updated component + translation keys"

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:

  • libs/assets/src/i18n/es.json - Source of Truth (Edit here)
  • apps/web/public_override/assets/i18n/es.json - Runtime file (Sync here)

Sync Rule: If you edit libs/assets/..., you MUST copy the file to apps/web/public_override/... for changes to reflect in the running app.

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 | translate pipe
  • 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:

  1. Check all locale files have the same keys
  2. Verify no hardcoded text in templates
  3. Test with different locales
  4. Verify placeholders render correctly

Route Titles (ADR-004)

When reviewing or creating routes, ensure the title property uses a translation key starting with PAGES. or TITLES..

// ✅ VALID
title: "PAGES.SETTINGS.TITLE";

// ❌ INVALID
title: "Settings Page";
Skills Info
Original Name:i18n-translationAuthor:reeinharddd