Skip to content

Cómo Traducir una App Angular: Guía Completa

Aprende cómo localizar tu app Angular usando @angular/localize o ngx-translate. Esta guía completa cubre traducción de cadenas, pluralización, formato de fechas y mejores prácticas para la t

  • date icon

    19 de noviembre de 2025

  • 06 min de lectura
Cómo Traducir una App Angular: Guía Completa

Traducir tu app Angular es esencial para llegar a una audiencia global. Angular proporciona soporte integrado de internacionalización (i18n) a través de @angular/localize, y también está la popular biblioteca ngx-translate. Esta guía te guiará a través de ambos enfoques para traducir una app Angular.

Entendiendo la Localización de Angular

Angular soporta internacionalización a través de:

  1. @angular/localize - Solución i18n integrada (recomendada para producción)
  2. ngx-translate - Biblioteca de terceros popular (configuración más fácil, traducciones en tiempo de ejecución)

Cubriremos ambos enfoques en esta guía.

Método 1: Usando @angular/localize (i18n Integrado)

El i18n integrado de Angular es la solución oficial y funciona en tiempo de compilación.

Paso 1: Agregar Soporte Angular i18n

ng add @angular/localize

Este comando agrega las dependencias y configuración necesarias.

Paso 2: Marcar Texto para Traducción

Usa el atributo i18n en tus plantillas:

Antes:

<h1>Welcome to our app!</h1>

Después:

<h1 i18n="@@welcome">Welcome to our app!</h1>

O con descripción:

<h1 i18n="Welcome message|@@welcome">Welcome to our app!</h1>

Paso 3: Extraer Mensajes de Traducción

Extrae cadenas traducibles a un archivo de mensajes:

ng extract-i18n --output-path src/locale

Esto crea el archivo messages.xlf con todas las cadenas traducibles.

Paso 4: Crear Archivos de Traducción

Crea archivos de traducción para cada idioma:

src/locale/messages.es.xlf (Español):

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="welcome" datatype="html">
        <source>Welcome to our app!</source>
        <target>¡Bienvenido a nuestra aplicación!</target>
      </trans-unit>
    </body>
  </file>
</xliff>

src/locale/messages.fr.xlf (Francés):

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="welcome" datatype="html">
        <source>Welcome to our app!</source>
        <target>Bienvenue dans notre application!</target>
      </trans-unit>
    </body>
  </file>
</xliff>

Paso 5: Configurar angular.json

Actualiza angular.json para incluir configuraciones de locale:

{
  "projects": {
    "my-app": {
      "i18n": {
        "sourceLocale": "en",
        "locales": {
          "es": {
            "translation": "src/locale/messages.es.xlf"
          },
          "fr": {
            "translation": "src/locale/messages.fr.xlf"
          }
        }
      },
      "architect": {
        "build": {
          "configurations": {
            "es": {
              "localize": ["es"]
            },
            "fr": {
              "localize": ["fr"]
            }
          }
        },
        "serve": {
          "configurations": {
            "es": {
              "browserTarget": "my-app:build:es"
            },
            "fr": {
              "browserTarget": "my-app:build:fr"
            }
          }
        }
      }
    }
  }
}

Paso 6: Compilar para Diferentes Locales

Compila la app para cada locale:

ng build --configuration=es
ng build --configuration=fr

Paso 7: Manejar Variables en Traducciones

Usa interpolación:

<p i18n="User greeting|@@userGreeting">Hello, {{ userName }}!</p>

En el archivo XLF:

<trans-unit id="userGreeting" datatype="html">
  <source>Hello, <x id="INTERPOLATION"/>!</source>
  <target>¡Hola, <x id="INTERPOLATION"/>!</target>
</trans-unit>

Paso 8: Pluralización

Usa formato de mensaje ICU:

<span i18n="Item count|@@itemsCount">
  {count, plural, =0 {No items} one {1 item} other {{{count}} items}}
</span>

Método 2: Usando ngx-translate (Traducciones en Tiempo de Ejecución)

ngx-translate es más fácil de configurar y permite cambio de idioma en tiempo de ejecución.

Paso 1: Instalar ngx-translate

npm install @ngx-translate/core @ngx-translate/http-loader

O con yarn:

yarn add @ngx-translate/core @ngx-translate/http-loader

Paso 2: Crear Archivos de Traducción

Crea archivos JSON para cada idioma:

src/assets/i18n/en.json (Inglés - por defecto):

{
  "app": {
    "welcome": "Welcome to our app!",
    "title": "My Angular App"
  },
  "button": {
    "submit": "Submit",
    "cancel": "Cancel",
    "delete": "Delete"
  },
  "error": {
    "network": "Network error. Please try again.",
    "notFound": "Page not found"
  },
  "items": {
    "count": "{count, plural, =0 {No items} one {# item} other {# items}}"
  },
  "user": {
    "greeting": "Hello, {{name}}! You have {{count}} messages.",
    "greeting_zero": "Hello, {{name}}! You have no messages.",
    "greeting_one": "Hello, {{name}}! You have {{count}} message.",
    "greeting_other": "Hello, {{name}}! You have {{count}} messages."
  }
}

src/assets/i18n/es.json (Español):

{
  "app": {
    "welcome": "¡Bienvenido a nuestra aplicación!",
    "title": "Mi Aplicación Angular"
  },
  "button": {
    "submit": "Enviar",
    "cancel": "Cancelar",
    "delete": "Eliminar"
  },
  "error": {
    "network": "Error de red. Por favor, inténtalo de nuevo.",
    "notFound": "Página no encontrada"
  },
  "items": {
    "count": "{count, plural, =0 {No hay elementos} one {# elemento} other {# elementos}}"
  },
  "user": {
    "greeting": "¡Hola, {{name}}! Tienes {{count}} mensajes.",
    "greeting_zero": "¡Hola, {{name}}! No tienes mensajes.",
    "greeting_one": "¡Hola, {{name}}! Tienes {{count}} mensaje.",
    "greeting_other": "¡Hola, {{name}}! Tienes {{count}} mensajes."
  }
}

src/assets/i18n/fr.json (Francés):

{
  "app": {
    "welcome": "Bienvenue dans notre application!",
    "title": "Mon Application Angular"
  },
  "button": {
    "submit": "Soumettre",
    "cancel": "Annuler",
    "delete": "Supprimer"
  },
  "error": {
    "network": "Erreur réseau. Veuillez réessayer.",
    "notFound": "Page non trouvée"
  },
  "items": {
    "count": "{count, plural, =0 {Aucun élément} one {# élément} other {# éléments}}"
  },
  "user": {
    "greeting": "Bonjour, {{name}}! Vous avez {{count}} messages.",
    "greeting_zero": "Bonjour, {{name}}! Vous n'avez aucun message.",
    "greeting_one": "Bonjour, {{name}}! Vous avez {{count}} message.",
    "greeting_other": "Bonjour, {{name}}! Vous avez {{count}} messages."
  }
}

Paso 3: Configurar App Module

src/app/app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

import { AppComponent } from './app.component';

// Función factory para TranslateHttpLoader
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
      defaultLanguage: 'en'
    })
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Paso 4: Usar Traducciones en Plantillas

Usa el pipe translate:

Antes:

<h1>Welcome to our app!</h1>

Después:

<h1>{{ 'app.welcome' | translate }}</h1>

Paso 5: Usar Traducciones en Componentes

Usa el TranslateService:

src/app/app.component.ts:

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'my-app';

  constructor(private translate: TranslateService) {
    // Establecer idioma por defecto
    translate.setDefaultLang('en');
    
    // Usar idioma del navegador si está disponible
    const browserLang = translate.getBrowserLang();
    translate.use(browserLang?.match(/en|es|fr/) ? browserLang : 'en');
  }
}

Paso 6: Interpolación de Cadenas con Variables

Pasa variables a las traducciones:

Plantilla:

<p>{{ 'user.greeting' | translate: { name: userName, count: messageCount } }}</p>

Componente:

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-user-greeting',
  template: `
    <p>{{ greeting }}</p>
  `
})
export class UserGreetingComponent {
  userName = 'John';
  messageCount = 5;
  greeting = '';

  constructor(private translate: TranslateService) {
    this.translate.get('user.greeting', {
      name: this.userName,
      count: this.messageCount
    }).subscribe((res: string) => {
      this.greeting = res;
    });
  }
}

Paso 7: Pluralización

Usa formato de mensaje ICU:

translation.json:

{
  "items": {
    "count": "{count, plural, =0 {No items} one {# item} other {# items}}"
  }
}

Plantilla:

<p>{{ 'items.count' | translate: { count: itemCount } }}</p>

Componente:

itemCount = 5;

Paso 8: Formatear Fechas

Usa el DatePipe de Angular con locale:

app.module.ts:

import { LOCALE_ID } from '@angular/core';
import { registerLocaleData } from '@angular/common';
import localeEs from '@angular/common/locales/es';
import localeFr from '@angular/common/locales/fr';

registerLocaleData(localeEs);
registerLocaleData(localeFr);

Plantilla:

<p>{{ date | date:'fullDate' }}</p>

Componente:

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-date-display',
  template: `
    <p>{{ date | date:'fullDate' }}</p>
  `
})
export class DateDisplayComponent {
  date = new Date();

  constructor(private translate: TranslateService) {
    // Establecer locale basándose en idioma actual
    this.translate.onLangChange.subscribe((event) => {
      // Actualizar locale para formateo de fechas
      // Esto requiere configuración adicional con LOCALE_ID
    });
  }
}

Paso 9: Formatear Números

Usa el DecimalPipe y CurrencyPipe de Angular:

Plantilla:

<p>Número: {{ number | number }}</p>
<p>Moneda: {{ amount | currency:'USD' }}</p>

Paso 10: Cambiar Idioma Programáticamente

Crea un selector de idioma:

src/app/components/language-switcher/language-switcher.component.ts:

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-language-switcher',
  template: `
    <select (change)="changeLanguage($event)">
      <option value="en" [selected]="currentLang === 'en'">English</option>
      <option value="es" [selected]="currentLang === 'es'">Español</option>
      <option value="fr" [selected]="currentLang === 'fr'">Français</option>
    </select>
  `
})
export class LanguageSwitcherComponent {
  currentLang: string;

  constructor(private translate: TranslateService) {
    this.currentLang = translate.currentLang || translate.defaultLang;
  }

  changeLanguage(event: any) {
    const lang = event.target.value;
    this.translate.use(lang);
    this.currentLang = lang;
    localStorage.setItem('language', lang);
  }
}

Paso 11: Detección de Idioma y Persistencia

Carga el idioma guardado al iniciar la app:

app.component.ts:

import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  constructor(private translate: TranslateService) {
    translate.setDefaultLang('en');
  }

  ngOnInit() {
    // Intentar obtener idioma guardado
    const savedLang = localStorage.getItem('language');
    if (savedLang) {
      this.translate.use(savedLang);
    } else {
      // Usar idioma del navegador
      const browserLang = this.translate.getBrowserLang();
      this.translate.use(browserLang?.match(/en|es|fr/) ? browserLang : 'en');
    }
  }
}

Mejores Prácticas

1. Usar Claves de Traducción Descriptivas

Malo:

{
  "msg1": "Submit"
}

Bueno:

{
  "button": {
    "submit": "Submit"
  }
}

2. Organizar por Característica

{
  "auth": {
    "login": "Login",
    "logout": "Logout"
  },
  "dashboard": {
    "title": "Dashboard"
  }
}

3. Usar Carga Perezosa para Módulos de Características

feature.module.ts:

import { TranslateModule } from '@ngx-translate/core';

@NgModule({
  imports: [
    TranslateModule.forChild() // Usar forChild en módulos de características
  ]
})
export class FeatureModule { }

4. Manejar Traducciones Faltantes

this.translate.get('some.key', { defaultValue: 'Texto por defecto' })
  .subscribe((text: string) => {
    // Usar texto
  });

5. Usar Servicio de Traducción en Servicios

import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Injectable({
  providedIn: 'root'
})
export class NotificationService {
  constructor(private translate: TranslateService) {}

  showError() {
    this.translate.get('error.network').subscribe((message: string) => {
      // Mostrar notificación de error
    });
  }
}

6. Probar Longitudes de Cadenas

Algunos idiomas son más largos que otros. Diseña tu UI para acomodar:

  • Alemán y finlandés: 30-50% más largo que inglés
  • Idiomas asiáticos: Pueden necesitar más espacio vertical

Errores Comunes

1. Olvidar Importar TranslateModule

Siempre importa TranslateModule en módulos que usan traducciones:

imports: [TranslateModule]

2. No Proporcionar HttpClient

Para TranslateHttpLoader, necesitas HttpClientModule:

imports: [HttpClientModule]

3. Codificar Cadenas de Formato Directamente

Malo:

const price = `$${amount.toFixed(2)}`;

Bueno:

{{ amount | currency:'USD' }}

4. No Manejar Traducciones Asíncronas

Las traducciones se cargan de forma asíncrona. Usa observables:

this.translate.get('key').subscribe((text: string) => {
  // Usar texto
});

Avanzado: Cargador de Traducción Personalizado

Crea un cargador personalizado para diferentes fuentes de datos:

import { Observable } from 'rxjs';
import { TranslateLoader } from '@ngx-translate/core';

export class CustomTranslateLoader implements TranslateLoader {
  getTranslation(lang: string): Observable<any> {
    // Cargar traducciones desde fuente personalizada
    return this.http.get(`/api/translations/${lang}`);
  }
}

Avanzado: Caché de Traducciones

Almacena traducciones en caché para reducir solicitudes HTTP:

import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Injectable()
export class TranslationCacheService {
  private cache = new Map<string, any>();

  constructor(private translate: TranslateService) {
    this.translate.onLangChange.subscribe(() => {
      this.cache.clear();
    });
  }

  getTranslation(lang: string): Observable<any> {
    if (this.cache.has(lang)) {
      return of(this.cache.get(lang));
    }
    
    return this.http.get(`/assets/i18n/${lang}.json`).pipe(
      tap(translations => this.cache.set(lang, translations))
    );
  }
}

Avanzado: Soporte RTL

Maneja idiomas de derecha a izquierda:

import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  template: '<div [dir]="textDirection"><router-outlet></router-outlet></div>'
})
export class AppComponent implements OnInit {
  textDirection = 'ltr';

  constructor(private translate: TranslateService) {}

  ngOnInit() {
    this.translate.onLangChange.subscribe((event) => {
      const isRTL = ['ar', 'he', 'fa'].includes(event.lang);
      this.textDirection = isRTL ? 'rtl' : 'ltr';
      document.documentElement.dir = this.textDirection;
      document.documentElement.lang = event.lang;
    });
  }
}

Avanzado: Soporte TypeScript

Crea definiciones de tipo para traducciones:

src/types/translations.d.ts:

export interface Translations {
  app: {
    welcome: string;
    title: string;
  };
  button: {
    submit: string;
    cancel: string;
    delete: string;
  };
  // ... otros tipos de traducción
}

Usar con Angular Universal (SSR)

Para renderizado del lado del servidor:

import { TranslateLoader } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { makeStateKey, TransferState } from '@angular/platform-browser';

export class TranslateBrowserLoader implements TranslateLoader {
  constructor(
    private http: HttpClient,
    private transferState: TransferState
  ) {}

  getTranslation(lang: string): Observable<any> {
    const key = makeStateKey<number>(`transfer-translate-${lang}`);
    const data = this.transferState.get(key, null);

    if (data) {
      return of(data);
    } else {
      return this.http.get(`/assets/i18n/${lang}.json`).pipe(
        tap(data => this.transferState.set(key, data))
      );
    }
  }
}

Conclusión

Localizar tu app Angular se puede hacer a través de dos enfoques principales:

  1. @angular/localize (Integrado) - Listo para producción, traducciones en tiempo de compilación
  2. ngx-translate - Configuración más fácil, traducciones en tiempo de ejecución, más flexible

Elige el método que mejor se ajuste a tus requisitos. Siguiendo estas prácticas, crearás una app que proporciona una experiencia nativa para usuarios en todo el mundo, expandiendo significativamente tu base de usuarios potencial.

Optimiza tu Flujo de Trabajo de Localización Angular

Gestionar traducciones para múltiples idiomas puede volverse complejo a medida que tu app crece. Considera usar una plataforma de gestión de traducciones para:

  • Colaborar con traductores
  • Mantener traducciones sincronizadas con tu código base
  • Automatizar el flujo de trabajo de traducción
  • Mantener consistencia en todos los idiomas
  • Generar archivos de traducción automáticamente

¿Listo para llevar tu app Angular a nivel global? Explora la plataforma de localización de AZbox y optimiza tu flujo de trabajo de traducción:

Ver Planes y Precios de AZbox

Blog

Últimas Publicaciones

Descubre nuestros últimos artículos y actualizaciones.

Servicios de localización de videojuegos: guía 2026 para llevar tu juego al mundo
date icon

21 de febrero de 2026

05 min de lectura

Servicios de localización de videojuegos: guía 2026 para llevar tu juego al mundo

Llevar tu juego a nivel global no es solo traducir texto: es hacer que los jugadores de cada mercado sientan que el jueg

Leer más
Software de localización de apps: guía 2026 para elegir y usar la herramienta adecuada
date icon

20 de febrero de 2026

05 min de lectura

Software de localización de apps: guía 2026 para elegir y usar la herramienta adecuada

Si estás llevando tu app más allá de un solo idioma, el software de localización de apps es la palanca que convierte

Leer más
Traducción para SaaS: Guía Completa para Localizar Tu Producto
date icon

15 de febrero de 2026

04 min de lectura

Traducción para SaaS: Guía Completa para Localizar Tu Producto

La traducción para SaaS ya no es opcional. Si quieres crecer más allá de tu mercado local, necesitas una estrategia

Leer más
Fondo de llamada a la acción

Comienza el Crecimiento Global Hoy

Sube tus archivos de idioma, recibe las traducciones y mantén cada idioma sincronizado mientras tu producto sigue cambiando.

Comenzar - Es Gratis