L'internazionalizzazione (i18n) è essenziale per creare applicazioni Angular globali. Questa guida ti mostra come implementare i18next in Angular con il corretto caricamento delle risorse, l'inizializzazione e i pattern di utilizzo.
i18next è uno dei framework di i18n più popolari, offrendo funzionalità potenti e flessibilità:
Installa i18next usando npm o yarn:
npm install i18nextTutto qui! i18next è una libreria standalone senza dipendenze specifiche del framework. Non hai bisogno di angular-i18next o di altri wrapper: usa semplicemente i18next direttamente nella tua applicazione Angular.
Esistono due approcci principali per caricare le risorse di traduzione in Angular con i18next:
L'uso delle importazioni dinamiche sfrutta la suddivisione del codice di Webpack per caricare le traduzioni su richiesta. Questo approccio è ideale per applicazioni con molte lingue o file di traduzione di grandi dimensioni.
Vantaggi:
Esempio: caricamento con importazioni dinamiche
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`);
}Questo approccio importa i file di traduzione come moduli ES, consentendo a Webpack di suddividerli automaticamente in chunk separati che vengono caricati su richiesta.
Il plugin HTTP backend carica le traduzioni tramite richieste HTTP da un server o CDN. È utile quando vuoi aggiornare le traduzioni senza ricostruire la tua app.
Vantaggi:
Svantaggi:
Esempio: caricamento con 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,
});Questo approccio recupera i file di traduzione da un server a runtime. Nota che ciò richiede una configurazione aggiuntiva per SSR.
Inizializzare correttamente i18next è fondamentale per evitare errori a runtime e garantire che le traduzioni siano disponibili quando la tua app viene renderizzata.
La funzione provideAppInitializer di Angular (introdotta in Angular 18) assicura che i18next sia completamente inizializzato prima che l'applicazione inizi il rendering. La funzione fornita viene eseguita durante il bootstrap dell'app e l'inizializzazione non si completa finché la Promise non viene risolta. Ciò impedisce che le chiavi di traduzione appaiano al posto del testo tradotto.
Esempio: configurazione dell'App Initializer
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
provideAppInitializer(initializeI18n),
// ... more providers
],
};Perché è importante:
La funzione di inizializzazione gestisce il caricamento delle risorse e la configurazione delle impostazioni di i18next.
Esempio: inizializzazione di 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,
},
});
}Punti chiave:
La pipe di traduzione di Angular fornisce un modo pulito per utilizzare le traduzioni nei template.
Esempio: pipe di traduzione
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);
}
}La pipe è contrassegnata come pure: false per assicurare che si aggiorni quando la lingua cambia. Questo è importante perché i cambi di lingua non modificano la chiave di traduzione stessa.
Nei template:
<!-- 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}}." -->
L'interpolazione ti consente di inserire valori dinamici nelle tue traduzioni. Puoi passare variabili, usare pipe di Angular per la formattazione e combinare più valori in una singola stringa di traduzione.
Nel codice del 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' });
}Per l'utilizzo nei template, la sintassi della pipe è pulita e leggibile. Per l'accesso programmatico, chiama t() direttamente. Questo è utile per mostrare notifiche, impostare titoli dinamici o gestire le traduzioni nella logica del componente.
Usa la notazione con punto che riflette la struttura della tua app: 'auth:login.title' invece di 'loginTitle' o testo grezzo.
Suddividi le traduzioni in namespace logici (es. common.json, auth.json, dashboard.json) per una migliore manutenibilità.
Usa il supporto integrato alla pluralizzazione di i18next per gestire correttamente le forme singolari/plurali in tutte le lingue.
Assicurati sempre che i18next sia inizializzato prima di renderizzare la tua app usando provideAppInitializer() per eseguire l'inizializzazione durante il bootstrap dell'app.
Usa TypeScript per estrarre le chiavi di traduzione direttamente dai tuoi file JSON per una sicurezza dei tipi completa. Invece di mantenere manualmente le definizioni dei tipi, sfrutta typeof di TypeScript e le importazioni dinamiche per generare automaticamente i tipi dai tuoi file di traduzione effettivi.
Definisci un tipo che estrae tutte le possibili chiavi dai tuoi file di traduzione JSON usando un tipo helper ricorsivo NestedKeys.
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>}`;Modifica il metodo transform della pipe per accettare TranslationKey invece di string. Questo fornisce sicurezza dei tipi nei template e assicura che possano essere usate solo chiavi di traduzione valide.
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);
}
}
Ora ottieni l'autocompletamento completo di IntelliSense ed errori in fase di compilazione per chiavi non valide sia nel codice TypeScript che nei template.
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 errorVantaggi delle chiavi di traduzione type-safe:
Implementa un rilevamento intelligente della lingua e consenti agli utenti di cambiare lingua a runtime con il caricamento automatico delle risorse.
Determina la lingua dell'utente da usare all'avvio dell'app controllando più fonti in ordine di priorità.
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;
}Questo approccio controlla prima localStorage (preferenza utente), poi ricade sulla lingua del browser (navigator.language) e infine utilizza la lingua predefinita dell'app.
Cambia lingua a runtime caricando automaticamente le risorse di traduzione su richiesta.
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);
}
}Quando usi le importazioni dinamiche, le traduzioni vengono caricate su richiesta. Il metodo switchLanguage() controlla se le risorse sono già caricate usando getResourceBundle(). Se mancano, le importa dinamicamente e le aggiunge usando addResourceBundle(). Ciò previene richieste di rete ridondanti assicurando che tutte le traduzioni necessarie siano disponibili.
Dettagli di implementazione chiave:
Gestire le traduzioni manualmente in più lingue richiede tempo ed è soggetto a errori. È qui che entra in gioco la localizzazione basata su AI.
l10n.dev è un servizio di traduzione basato su AI progettato specificamente per i file JSON di i18next:
Risparmia ore di lavoro di traduzione manuale ed evita errori comuni come segnaposto rotti o forme plurali errate.
Pronto a semplificare il tuo flusso di lavoro di i18n in Angular?
Carica i tuoi file i18n e lascia che l'IA gestisca la traduzione con consapevolezza del contesto e formattazione corretta
Scopri perché la traduzione basata su IA è migliore per i file i18n rispetto ai metodi tradizionali
Integra la localizzazione tramite IA direttamente nella tua CI/CD
Porta la localizzazione tramite IA nel tuo flusso di lavoro con le nostre estensioni e plugin
Implementare i18next in Angular con una corretta inizializzazione e strategie di caricamento delle risorse garantisce un'esperienza di internazionalizzazione fluida.
Combinato con servizi di traduzione basati su AI come l10n.dev, puoi creare applicazioni veramente globali più velocemente e con meno errori.
Inizia a creare app Angular multilingua oggi stesso!