Internasionalisasi (i18n) sangat penting untuk membangun aplikasi Angular global. Panduan ini menunjukkan cara mengimplementasikan i18next di Angular dengan pemuatan sumber daya, inisialisasi, dan pola penggunaan yang tepat.
i18next adalah salah satu framework i18n paling populer, menawarkan fitur canggih dan fleksibilitas:
Instal i18next menggunakan npm atau yarn:
npm install i18nextSelesai! i18next adalah pustaka mandiri tanpa dependensi khusus framework. Anda tidak memerlukan angular-i18next atau wrapper lainnya - cukup gunakan i18next secara langsung di aplikasi Angular Anda.
Ada dua pendekatan utama untuk memuat sumber daya terjemahan di Angular dengan i18next:
Menggunakan impor dinamis memanfaatkan pemisahan kode Webpack untuk memuat terjemahan sesuai permintaan. Pendekatan ini ideal untuk aplikasi dengan banyak bahasa atau file terjemahan yang besar.
Keunggulan:
Contoh: Memuat dengan Impor Dinamis
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`);
}Pendekatan ini mengimpor file terjemahan sebagai modul ES, memungkinkan Webpack untuk secara otomatis membagi kode menjadi bagian-bagian terpisah yang dimuat sesuai permintaan.
Plugin backend HTTP memuat terjemahan melalui permintaan HTTP dari server atau CDN. Ini berguna saat Anda ingin memperbarui terjemahan tanpa membangun ulang aplikasi Anda.
Keunggulan:
Kekurangan:
Contoh: Memuat dengan Backend HTTP
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,
});Pendekatan ini mengambil file terjemahan dari server saat runtime. Perhatikan bahwa ini memerlukan konfigurasi tambahan untuk SSR.
Menginisialisasi i18next dengan benar sangat penting untuk menghindari kesalahan runtime dan memastikan terjemahan tersedia saat aplikasi Anda dirender.
Fungsi provideAppInitializer Angular (diperkenalkan di Angular 18) memastikan i18next sepenuhnya diinisialisasi sebelum aplikasi mulai dirender. Fungsi yang disediakan dijalankan selama bootstrap aplikasi, dan inisialisasi tidak selesai sampai Promise diselesaikan. Ini mencegah kunci terjemahan muncul alih-alih teks yang diterjemahkan.
Contoh: Konfigurasi App Initializer
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
provideAppInitializer(initializeI18n),
// ... more providers
],
};Mengapa Ini Penting:
Fungsi inisialisasi menangani pemuatan sumber daya dan konfigurasi pengaturan i18next.
Contoh: Inisialisasi 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,
},
});
}Poin Utama:
Pipe terjemahan Angular menyediakan cara yang bersih untuk menggunakan terjemahan dalam template.
Contoh: Pipe Terjemahan
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);
}
}Pipe ditandai sebagai pure: false untuk memastikan pipe diperbarui saat bahasa berubah. Ini penting karena perubahan bahasa tidak mengubah kunci terjemahan itu sendiri.
Dalam 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}}." -->
Interpolasi memungkinkan Anda menyisipkan nilai dinamis ke dalam terjemahan Anda. Anda dapat meneruskan variabel, menggunakan pipe Angular untuk pemformatan, dan menggabungkan beberapa nilai dalam satu string terjemahan.
Dalam Kode Komponen:
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' });
}Untuk penggunaan template, sintaks pipe bersih dan mudah dibaca. Untuk akses programatik, panggil t() secara langsung. Ini berguna untuk menampilkan notifikasi, mengatur judul dinamis, atau menangani terjemahan dalam logika komponen.
Gunakan notasi titik yang mencerminkan struktur aplikasi Anda: 'auth:login.title' alih-alih 'loginTitle' atau teks mentah.
Pecah terjemahan ke dalam namespace logis (misalnya, common.json, auth.json, dashboard.json) untuk pemeliharaan yang lebih baik.
Gunakan dukungan pluralisasi bawaan i18next untuk menangani bentuk tunggal/jamak dengan benar dalam semua bahasa.
Selalu pastikan i18next diinisialisasi sebelum merender aplikasi Anda menggunakan provideAppInitializer() untuk menjalankan inisialisasi selama bootstrap aplikasi.
Gunakan TypeScript untuk mengekstrak kunci terjemahan langsung dari file JSON Anda untuk keamanan tipe yang lengkap. Alih-alih memelihara definisi tipe secara manual, manfaatkan typeof dan impor dinamis TypeScript untuk menghasilkan tipe secara otomatis dari file terjemahan Anda yang sebenarnya.
Definisikan tipe yang mengekstrak semua kemungkinan kunci dari file terjemahan JSON Anda menggunakan tipe pembantu NestedKeys rekursif.
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>}`;Ubah metode transform pipe untuk menerima TranslationKey alih-alih string. Ini memberikan keamanan tipe dalam template dan memastikan hanya kunci terjemahan yang valid yang dapat digunakan.
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);
}
}
Sekarang Anda mendapatkan pelengkapan otomatis IntelliSense penuh dan kesalahan waktu kompilasi untuk kunci yang tidak valid baik dalam kode TypeScript maupun 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 errorManfaat Kunci Terjemahan yang Aman Tipe:
Implementasikan deteksi bahasa yang cerdas dan izinkan pengguna untuk beralih bahasa saat runtime dengan pemuatan sumber daya otomatis.
Tentukan bahasa pengguna yang akan digunakan saat aplikasi Anda dimulai dengan memeriksa beberapa sumber dalam urutan prioritas.
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;
}Pendekatan ini memeriksa localStorage terlebih dahulu (preferensi pengguna), kemudian kembali ke bahasa browser (navigator.language), dan akhirnya default ke bahasa default aplikasi.
Beralih bahasa saat runtime sambil memuat sumber daya terjemahan secara otomatis sesuai permintaan.
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);
}
}Saat menggunakan impor dinamis, terjemahan dimuat sesuai permintaan. Metode switchLanguage() memeriksa apakah sumber daya sudah dimuat menggunakan getResourceBundle(). Jika hilang, metode ini secara dinamis mengimpor dan menambahkannya menggunakan addResourceBundle(). Ini mencegah permintaan jaringan yang berlebihan sambil memastikan semua terjemahan yang diperlukan tersedia.
Detail Implementasi Utama:
Mengelola terjemahan secara manual di berbagai bahasa memakan waktu dan rentan kesalahan. Di situlah lokalisasi berbasis AI berperan.
l10n.dev adalah layanan terjemahan berbasis AI yang dirancang khusus untuk file JSON i18next:
Hemat waktu berjam-jam untuk pekerjaan terjemahan manual dan hindari kesalahan umum seperti placeholder yang rusak atau bentuk jamak yang salah.
Siap untuk menyederhanakan alur kerja i18n Angular Anda?
Unggah file i18n Anda dan biarkan AI menangani terjemahan dengan kesadaran konteks dan pemformatan yang tepat
Temukan alasan mengapa terjemahan bertenaga AI lebih baik untuk file i18n dibandingkan metode tradisional
Integrasikan lokalisasi bertenaga AI langsung ke dalam alur kerja CI/CD Anda
Bawa lokalisasi AI ke dalam alur kerja Anda dengan ekstensi dan plugin kami
Mengimplementasikan i18next di Angular dengan inisialisasi dan strategi pemuatan sumber daya yang tepat memastikan pengalaman internasionalisasi yang lancar.
Dikombinasikan dengan layanan terjemahan berbasis AI seperti l10n.dev, Anda dapat membangun aplikasi global dengan lebih cepat dan lebih sedikit kesalahan.
Mulai bangun aplikasi Angular multibahasa hari ini!