A internacionalização (i18n) é essencial para criar aplicações Angular globais. Este guia mostra como implementar o i18next no Angular com carregamento de recursos, inicialização e padrões de uso adequados.
O i18next é um dos frameworks de i18n mais populares, oferecendo recursos poderosos e flexibilidade:
Instale o i18next usando npm ou yarn:
npm install i18nextÉ isso! O i18next é uma biblioteca independente sem dependências específicas de framework. Você não precisa do angular-i18next ou de qualquer outro wrapper - basta usar o i18next diretamente na sua aplicação Angular.
Existem duas abordagens principais para carregar recursos de tradução no Angular com i18next:
O uso de importações dinâmicas 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 arquivos de tradução grandes.
Vantagens:
Exemplo: Carregando com Importações Dinâmicas
private async loadLanguageResources(
lang: string,
): Promise<Record<string, Record<string, unknown>>> {
const languageResources: Record<string, Record<string, unknown>> = {};
// Load all namespaces for the given language in parallel
await Promise.all(
NAMESPACES.map(async (namespace) => {
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 blocos separados que são carregados sob demanda.
O plugin HTTP backend carrega traduções via requisições HTTP de um servidor ou CDN. Isso é útil quando você deseja atualizar traduções sem reconstruir sua aplicação.
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. Observe 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 sua aplicação renderizar.
A função provideAppInitializer do Angular (introduzida no Angular 18) garante que o i18next seja totalmente inicializado antes que a aplicação comece a renderizar. A função fornecida é executada durante o bootstrap da aplicação, 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 do texto traduzido.
Exemplo: Configuração do App Initializer
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 pure: false para garantir que ele seja atualizado quando o idioma mudar. Isso é importante porque 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 vários 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 exibir 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 da sua aplicação: 'auth:login.title' em vez de 'loginTitle' ou texto bruto.
Divida as traduções em namespaces lógicos (por exemplo, common.json, auth.json, dashboard.json) para melhor manutenibilidade.
Use o suporte nativo do i18next para pluralização para lidar corretamente com formas singulares/plurais em todos os idiomas.
Sempre garanta que o i18next seja inicializado antes de renderizar sua aplicação usando provideAppInitializer() para executar a inicialização durante o bootstrap da aplicação.
Use TypeScript para extrair chaves de tradução diretamente dos seus arquivos JSON para segurança total de tipos. Em vez de manter manualmente as definições de tipo, aproveite o typeof do TypeScript e importações dinâmicas 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 tipos nos 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 preenchimento automático completo via IntelliSense 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 com Segurança de Tipos:
Implemente detecção inteligente de idioma e permita que os usuários alternem idiomas em tempo de execução com carregamento automático de recursos.
Determine o idioma do usuário a ser usado quando sua aplicação iniciar, verificando várias 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;
}Esta abordagem verifica o localStorage primeiro (preferência do usuário), depois recorre ao idioma do navegador (navigator.language) e, finalmente, assume o idioma padrão da aplicação.
Alterne idiomas em tempo de execução enquanto carrega automaticamente 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');
await Promise.all(
NAMESPACES.map(async (namespace) => {
const currentResources = i18next.default.getResourceBundle(
lang,
namespace,
);
// Check if any namespace is missing for this language
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 importações dinâmicas, as traduções são carregadas sob demanda. O método switchLanguage() verifica se os recursos já estão carregados usando getResourceBundle(). Se estiverem ausentes, ele os importa dinamicamente e os adiciona usando addResourceBundle(). Isso evita requisições de rede redundantes enquanto garante que todas as traduções necessárias estejam disponíveis.
Detalhes da Implementação:
Gerenciar traduções manualmente em vários idiomas é demorado e propenso a erros. É aí que entra a localização via IA.
l10n.dev é um serviço de tradução via IA projetado especificamente 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 otimizar seu fluxo de trabalho de i18n no Angular?
Envie seus arquivos i18n e deixe a IA cuidar da tradução com reconhecimento de contexto e formatação adequada
Descubra por que a tradução com IA é melhor para arquivos i18n do que os métodos tradicionais
Integre a localização por IA diretamente ao seu pipeline de CI/CD
Leve a localização por IA para o seu fluxo de trabalho com nossas extensões e plugins
Implementar o i18next no Angular com inicialização e estratégias de carregamento de recursos adequadas garante uma experiência de internacionalização fluida.
Combinado com serviços de tradução via IA como o l10n.dev, você pode criar aplicações verdadeiramente globais mais rapidamente e com menos erros.
Comece a criar aplicações Angular multilíngues hoje mesmo!