A internacionalização (i18n) é essencial para construir aplicações Angular globais. Este guia mostra como implementar i18next no Angular com carregamento adequado de recursos, inicialização e padrões de uso.
i18next é uma das estruturas de i18n mais populares, oferecendo recursos poderosos e flexibilidade:
Instale o i18next usando npm ou yarn:
npm install i18nextÉ isso! i18next é uma biblioteca independente sem dependências específicas de framework. Você não precisa de angular-i18next ou qualquer outro wrapper - basta usar i18next diretamente na sua aplicação Angular.
Existem duas abordagens principais para carregar recursos de tradução no Angular com i18next:
Usar imports dinâmicos aproveita a divisão de código do Webpack para carregar traduções sob demanda. Esta abordagem é ideal para aplicações com muitos idiomas ou grandes arquivos de tradução.
Vantagens:
Exemplo: Carregando com Imports Dinâmicos
private async loadLanguageResources(
lang: string,
): Promise<Record<string, Record<string, unknown>>> {
const languageResources: Record<string, Record<string, unknown>> = {};
for (const namespace of NAMESPACES) {
const translationModule = await this.loadJson(lang, namespace);
languageResources[namespace] = translationModule.default;
}
return languageResources;
}
private async loadJson(
language: string,
namespace: string,
): Promise<{ default: Record<string, unknown> }> {
// Webpack automatically code-splits this into separate chunks
return import(`../../i18n/${language}/${namespace}.json`);
}Esta abordagem importa arquivos de tradução como módulos ES, permitindo que o Webpack os divida automaticamente em partes separadas que são carregadas sob demanda.
O plugin HTTP backend carrega traduções via solicitações HTTP de um servidor ou CDN. Isso é útil quando você deseja atualizar traduções sem reconstruir seu aplicativo.
Vantagens:
Desvantagens:
Exemplo: Carregando com HTTP Backend
import HttpBackend from 'i18next-http-backend';
await init({
lng: initialLanguage,
fallbackLng: DEFAULT_LANGUAGE,
backend: {
loadPath: '/assets/i18n/{{lng}}/{{ns}}.json',
},
use: [HttpBackend],
ns: NAMESPACES,
defaultNS: DEFAULT_NAMESPACE,
});Esta abordagem busca arquivos de tradução de um servidor em tempo de execução. Note que isso requer configuração adicional para SSR.
Inicializar o i18next corretamente é crucial para evitar erros em tempo de execução e garantir que as traduções estejam disponíveis quando seu aplicativo renderiza.
A função provideAppInitializer do Angular (introduzida no Angular 18) garante que o i18next esteja totalmente inicializado antes que a aplicação comece a renderizar. A função fornecida é executada durante a inicialização do aplicativo, e a inicialização não é concluída até que a Promise seja resolvida. Isso evita que chaves de tradução apareçam em vez de texto traduzido.
Exemplo: Configuração do Inicializador do App
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
provideAppInitializer(initializeI18n),
// ... more providers
],
};Por que isso é importante:
A função de inicialização lida com o carregamento de recursos e a configuração das definições do i18next.
Exemplo: Inicialização do I18next
public async initializeI18n(): Promise<void> {
const initialLanguage = this.getInitialLanguage();
const resources: Record<string, Record<string, Record<string, unknown>>> = {};
if (isPlatformBrowser(this.platformId)) {
// Browser: Only load the specific language needed
const languageResources = await this.loadLanguageResources(initialLanguage);
resources[initialLanguage] = languageResources;
} else {
// SSR: Load all languages for prerendering
for (const lang of SUPPORTED_LANGUAGES) {
const languageResources = await this.loadLanguageResources(lang);
resources[lang] = languageResources;
}
}
await init({
lng: initialLanguage,
fallbackLng: DEFAULT_LANGUAGE,
resources,
ns: NAMESPACES,
defaultNS: DEFAULT_NAMESPACE,
interpolation: {
escapeValue: false,
},
});
}Pontos-chave:
O pipe de tradução do Angular fornece uma maneira limpa de usar traduções em templates.
Exemplo: Pipe de Tradução
import { Pipe, PipeTransform } from '@angular/core';
import { t } from 'i18next';
@Pipe({
name: 't',
standalone: true,
pure: false, // Need to update when language changes
})
export class TranslatePipe implements PipeTransform {
transform(key: string, options?: Record<string, unknown>): string {
return t(key, options);
}
}O pipe é marcado como puro: false para garantir que ele seja atualizado quando o idioma mudar. Isso é importante porque as mudanças de idioma não modificam a chave de tradução em si.
Em Templates:
<!-- With namespace -->
<p>{{ "common:welcomeMessage" | t }}</p>
<!-- With nested keys -->
<p>{{ "dashboard.title" | t }}</p>
<!-- Simple interpolation -->
<p>{{ "greeting" | t: { name: userName } }}</p>
<!-- Result: "Hello, John!" from greeting: "Hello, {{name}}!" -->
<!-- With Angular pipes -->
<p>{{ "price" | t: { amount: 29.99 | currency } }}</p>
<!-- Result: "Price: $29.99" from: "Price: {{amount}}" -->
<!-- Multiple variables -->
<p>{{ "updated" | t: { date: lastModified | date, user: currentUser } }}</p>
<!-- Result: "Updated on Jan 15, 2024 by Alice" from: "Updated on {{date}} by {{user}}." -->
A interpolação permite que você insira valores dinâmicos em suas traduções. Você pode passar variáveis, usar pipes do Angular para formatação e combinar múltiplos valores em uma única string de tradução.
No Código do Componente:
import { Component } from '@angular/core';
import { t } from 'i18next';
@Component({
selector: 'app-dashboard',
template: `
<h1>{{ title }}</h1>
<p>{{ welcomeMsg }}</p>
`,
})
export class DashboardComponent {
title = t('dashboard.title');
welcomeMsg = t('greeting', { name: 'John' });
}Para uso em templates, a sintaxe do pipe é limpa e legível. Para acesso programático, chame t() diretamente. Isso é útil para mostrar notificações, definir títulos dinâmicos ou lidar com traduções na lógica do componente.
Use notação de ponto que reflita a estrutura do seu app: 'auth:login.title' em vez de 'loginTitle' ou texto cru.
Divida as traduções em namespaces lógicos (por exemplo, common.json, auth.json, dashboard.json) para melhor manutenção.
Use o suporte de pluralização embutido do i18next para lidar corretamente com formas singulares/plurais em todos os idiomas.
Sempre garanta que o i18next esteja inicializado antes de renderizar seu app usando provideAppInitializer() para executar a inicialização durante a inicialização do app.
Use TypeScript para extrair chaves de tradução diretamente dos seus arquivos JSON para segurança de tipo completa. Em vez de manter manualmente definições de tipo, aproveite o typeof do TypeScript e imports dinâmicos para gerar tipos automaticamente a partir dos seus arquivos de tradução reais.
Defina um tipo que extraia todas as chaves possíveis dos seus arquivos de tradução JSON usando um tipo auxiliar NestedKeys recursivo.
import common from './en/common.json'; // defaultNS: DEFAULT_NAMESPACE,
import auth from './en/auth.json'; // namespaces
type NestedKeys<T, Prefix extends string = ''> = T extends object
? {
[K in keyof T & (string | number)]: T[K] extends object
?
| NestedKeys<T[K], `${Prefix}${K & (string | number)}.`>
| `${Prefix}${K & (string | number)}`
: `${Prefix}${K & (string | number)}`;
}[keyof T & (string | number)]
: never;
export type TranslationKey =
| `common:${NestedKeys<typeof common>}`
| `auth:${NestedKeys<typeof auth>}`;Altere o método transform do pipe para aceitar TranslationKey em vez de string. Isso fornece segurança de tipo em templates e garante que apenas chaves de tradução válidas possam ser usadas.
import { Pipe, PipeTransform } from '@angular/core';
import { t } from 'i18next';
import { TranslationKey } from '../../i18n/translation-key';
@Pipe({
name: 't',
standalone: true,
pure: false, // Need to update when language changes
})
export class TranslatePipe implements PipeTransform {
transform(key: TranslationKey, options?: Record<string, unknown>): string {
return t(key, options);
}
}
Agora você obtém autocompletar completo e erros em tempo de compilação para chaves inválidas tanto no código TypeScript quanto nos templates.
t('common:greeting'); // ✅ Autocomplete
t('auth:login.title'); // ✅ Valid
t('invalid.key'); // ❌ IDE shows error
{{ "common:greeting" | t }} // ✅ Valid in templates
{{ "invalid.key" | t }} // ❌ IDE shows errorBenefícios das Chaves de Tradução Seguras em Tipo:
Implemente detecção de idioma inteligente e permita que os usuários troquem de idioma em tempo de execução com carregamento automático de recursos.
Determine o idioma do usuário a ser usado quando seu app iniciar verificando múltiplas fontes em ordem de prioridade.
private getInitialLanguage(): string {
if (isPlatformBrowser(this.platformId)) {
// Try to get language from localStorage (user preference)
const savedLang = localStorage.getItem('language');
if (savedLang) {
return savedLang;
}
// Fall back to browser language
return navigator.language ?? DEFAULT_LANGUAGE;
}
// Default language for SSR
return DEFAULT_LANGUAGE;
}Essa abordagem verifica o localStorage primeiro (preferência do usuário), depois recorre ao idioma do navegador (navigator.language), e finalmente define o idioma padrão do app.
Troque de idiomas em tempo de execução enquanto carrega automaticamente os recursos de tradução sob demanda.
public async switchLanguage(
language: string
): Promise<void> {
// In browser, check if we need to load the translation first
if (isPlatformBrowser(this.platformId)) {
const i18next = await import('i18next');
// Check if any namespace is missing for this language
for (const namespace of NAMESPACES) {
const currentResources = i18next.default.getResourceBundle(lang, namespace);
if (!currentResources) {
// Translation not loaded yet, load it dynamically
const translationModule = await this.loadJson(lang, namespace);
i18next.default.addResourceBundle(
lang,
namespace,
translationModule.default
);
}
}
}
// Switch to the new language
await changeLanguage(lang);
// Save preference to localStorage
if (isPlatformBrowser(this.platformId)) {
localStorage.setItem('language', lang);
}
}Ao usar imports dinâmicos, as traduções são carregadas sob demanda. O método switchLanguage() verifica se os recursos já estão carregados usando getResourceBundle(). Se estiverem faltando, ele importa dinamicamente e os adiciona usando addResourceBundle(). Isso previne requisições de rede redundantes enquanto garante que todas as traduções necessárias estejam disponíveis.
Detalhes Chave da Implementação:
Gerenciar traduções manualmente em vários idiomas é demorado e propenso a erros. É aí que a localização impulsionada por IA entra.
l10n.dev é um serviço de tradução impulsionado por IA especificamente projetado para arquivos JSON do i18next:
Economize horas de trabalho manual de tradução e evite erros comuns como placeholders quebrados ou formas plurais incorretas.
Pronto para agilizar seu fluxo de trabalho de i18n no Angular?
Carregue seus arquivos i18n e deixe a IA cuidar da tradução com consciência de contexto e formatação adequada
Descubra por que a tradução potencializada por IA é melhor para arquivos i18n do que métodos tradicionais
Integre a localização potencializada por IA diretamente em seu pipeline CI/CD
Traga a localização por IA para seu fluxo de trabalho com nossas extensões e plugins
Implementar o i18next no Angular com estratégias adequadas de inicialização e carregamento de recursos garante uma experiência de internacionalização suave.
Combinado com serviços de tradução impulsionados por IA como l10n.dev, você pode construir aplicações verdadeiramente globais mais rápido e com menos erros.
Comece a construir aplicativos Angular multilíngues hoje!