# i18n — Panduan Internasionalisasi (Bahasa Indonesia)

🌐 **Languages:** 🇺🇸 [English](../../../../docs/I18N.md) · 🇸🇦 [ar](../../ar/docs/I18N.md) · 🇧🇬 [bg](../../bg/docs/I18N.md) · 🇧🇩 [bn](../../bn/docs/I18N.md) · 🇨🇿 [cs](../../cs/docs/I18N.md) · 🇩🇰 [da](../../da/docs/I18N.md) · 🇩🇪 [de](../../de/docs/I18N.md) · 🇪🇸 [es](../../es/docs/I18N.md) · 🇮🇷 [fa](../../fa/docs/I18N.md) · 🇫🇮 [fi](../../fi/docs/I18N.md) · 🇫🇷 [fr](../../fr/docs/I18N.md) · 🇮🇳 [gu](../../gu/docs/I18N.md) · 🇮🇱 [he](../../he/docs/I18N.md) · 🇮🇳 [hi](../../hi/docs/I18N.md) · 🇭🇺 [hu](../../hu/docs/I18N.md) · 🇮🇩 [id](../../id/docs/I18N.md) · 🇮🇹 [it](../../it/docs/I18N.md) · 🇯🇵 [ja](../../ja/docs/I18N.md) · 🇰🇷 [ko](../../ko/docs/I18N.md) · 🇮🇳 [mr](../../mr/docs/I18N.md) · 🇲🇾 [ms](../../ms/docs/I18N.md) · 🇳🇱 [nl](../../nl/docs/I18N.md) · 🇳🇴 [no](../../no/docs/I18N.md) · 🇵🇭 [phi](../../phi/docs/I18N.md) · 🇵🇱 [pl](../../pl/docs/I18N.md) · 🇵🇹 [pt](../../pt/docs/I18N.md) · 🇧🇷 [pt-BR](../../pt-BR/docs/I18N.md) · 🇷🇴 [ro](../../ro/docs/I18N.md) · 🇷🇺 [ru](../../ru/docs/I18N.md) · 🇸🇰 [sk](../../sk/docs/I18N.md) · 🇸🇪 [sv](../../sv/docs/I18N.md) · 🇰🇪 [sw](../../sw/docs/I18N.md) · 🇮🇳 [ta](../../ta/docs/I18N.md) · 🇮🇳 [te](../../te/docs/I18N.md) · 🇹🇭 [th](../../th/docs/I18N.md) · 🇹🇷 [tr](../../tr/docs/I18N.md) · 🇺🇦 [uk-UA](../../uk-UA/docs/I18N.md) · 🇵🇰 [ur](../../ur/docs/I18N.md) · 🇻🇳 [vi](../../vi/docs/I18N.md) · 🇨🇳 [zh-CN](../../zh-CN/docs/I18N.md)

---

OmniRoute mendukung **30 bahasa** dengan terjemahan UI dashboard penuh, dokumentasi yang diterjemahkan, dan dukungan RTL untuk bahasa Arab dan Ibrani.

## Referensi Cepat

| Tugas                          | Perintah                                                                                |
| ------------------------------ | --------------------------------------------------------------------------------------- |
| Hasilkan terjemahan            | `node scripts/i18n/generate-multilang.mjs messages`                                     |
| Terjemahkan dokumentasi (LLM)  | `python3 scripts/i18n_autotranslate.py --api-url <url> --api-key <key> --model <model>` |
| Validasi lokal                 | `python3 scripts/validate_translation.py quick -l cs`                                   |
| Periksa kunci kode             | `python3 scripts/check_translations.py`                                                 |
| Hasilkan laporan QA            | `node scripts/i18n/generate-qa-checklist.mjs`                                           |
| QA Visual (Playwright)         | `node scripts/i18n/run-visual-qa.mjs`                                                   |

## Arsitektur

### Sumber Kebenaran

- **String UI**: `src/i18n/messages/en.json` (sumber bahasa Inggris, ~2800 kunci)
- **File lokal**: `src/i18n/messages/{locale}.json` (30 terjemahan)
- **Framework**: `next-intl` dengan resolusi lokal berbasis cookie
- **Konfigurasi**: `src/i18n/config.ts` — mendefinisikan semua 30 lokal, nama bahasa, bendera

### Alur Runtime

1. Pengguna memilih bahasa → cookie `NEXT_LOCALE` disetel
2. `src/i18n/request.ts` menyelesaikan lokal: cookie → header `Accept-Language` → fallback `en`
3. Import dinamis memuat `messages/{locale}.json`
4. Komponen menggunakan `useTranslations("namespace")` dan `t("key")`

### Lokal yang Didukung

| Kode    | Bahasa               | RTL | Kode Google Translate |
| ------- | -------------------- | --- | --------------------- |
| `ar`    | العربية              | Ya  | `ar`                  |
| `bg`    | Български            | Tidak | `bg`                |
| `cs`    | Čeština              | Tidak | `cs`                |
| `da`    | Dansk                | Tidak | `da`                |
| `de`    | Deutsch              | Tidak | `de`                |
| `es`    | Español              | Tidak | `es`                |
| `fi`    | Suomi                | Tidak | `fi`                |
| `fr`    | Français             | Tidak | `fr`                |
| `he`    | עברית                | Ya  | `iw`                  |
| `hi`    | हिन्दी               | Tidak | `hi`                |
| `hu`    | Magyar               | Tidak | `hu`                |
| `id`    | Bahasa Indonesia     | Tidak | `id`                |
| `it`    | Italiano             | Tidak | `it`                |
| `ja`    | 日本語               | Tidak | `ja`                |
| `ko`    | 한국어               | Tidak | `ko`                |
| `ms`    | Bahasa Melayu        | Tidak | `ms`                |
| `nl`    | Nederlands           | Tidak | `nl`                |
| `no`    | Norsk                | Tidak | `no`                |
| `phi`   | Filipino             | Tidak | `tl`                |
| `pl`    | Polski               | Tidak | `pl`                |
| `pt`    | Português (Portugal) | Tidak | `pt`                |
| `pt-BR` | Português (Brasil)   | Tidak | `pt`                |
| `ro`    | Română               | Tidak | `ro`                |
| `ru`    | Русский              | Tidak | `ru`                |
| `sk`    | Slovenčina           | Tidak | `sk`                |
| `sv`    | Svenska              | Tidak | `sv`                |
| `th`    | ไทย                  | Tidak | `th`                |
| `tr`    | Türkçe               | Tidak | `tr`                |
| `uk-UA` | Українська           | Tidak | `uk`                |
| `vi`    | Tiếng Việt           | Tidak | `vi`                |
| `zh-CN` | 中文 (简体)          | Tidak | `zh-CN`             |

## Menambahkan Bahasa Baru

### 1. Daftarkan Lokal

Edit `src/i18n/config.ts`:

```ts
// Add to LOCALES array
"xx",
// Add to LANGUAGES array
{ code: "xx", label: "XX", name: "Language Name", flag: "🏳️" },
```

### 2. Tambahkan ke Generator

Edit `scripts/i18n/generate-multilang.mjs` — tambahkan entri ke `LOCALE_SPECS`:

```js
{
  code: "xx",
  googleTl: "xx",
  label: "XX",
  flag: "🏳️",
  languageName: "Language Name",
  readmeName: "Language Name",
  docsName: "Language Name",
},
```

### 3. Hasilkan Terjemahan Awal

```bash
node scripts/i18n/generate-multilang.mjs messages
```

Perintah ini membuat `src/i18n/messages/xx.json` yang diterjemahkan secara otomatis dari `en.json` melalui Google Translate.

### 4. Tinjau & Perbaiki Terjemahan Otomatis

Terjemahan otomatis hanyalah titik awal. Tinjau secara manual untuk:

- Ketepatan teknis
- Terminologi yang sesuai konteks
- Penanganan placeholder yang benar (`{count}`, `{value}`, dll.)

### 5. Validasi

```bash
python3 scripts/validate_translation.py quick -l xx
python3 scripts/validate_translation.py diff common -l xx
```

### 6. Hasilkan Dokumentasi yang Diterjemahkan

```bash
node scripts/i18n/generate-multilang.mjs docs
```

## Pipeline Terjemahan Otomatis

### generate-multilang.mjs (Google Translate)

**Mesin terjemahan otomatis utama** — menggunakan API gratis Google Translate untuk menghasilkan terjemahan string UI, README, dan dokumentasi.

```bash
node scripts/i18n/generate-multilang.mjs [messages|readme|docs|all]
```

| Mode       | Yang dilakukan                                                                |
| ---------- | ----------------------------------------------------------------------------- |
| `messages` | Menerjemahkan kunci yang hilang di `src/i18n/messages/{locale}.json` dari `en.json` |
| `readme`   | Menerjemahkan `README.md` ke semua lokal sebagai `README.{code}.md` di root proyek |
| `docs`     | Menerjemahkan `DOC_SOURCE_FILES` ke `docs/i18n/{locale}/{docName}`           |
| `all`      | Menjalankan ketiga mode sekaligus                                             |

**Fitur:**

- **Perlindungan teks**: Menyembunyikan blok kode (` ``` `), kode inline (`` ` ``), tautan/gambar markdown (`[text](url)`), tag HTML, tabel, dan placeholder ICU (`{count}`, `{value}`, `{total}`, dll.) sebelum penerjemahan, lalu memulihkannya
- **Pemrosesan bertahap**: Menggabungkan beberapa string dengan pemisah `__OMNIROUTE_I18N_SEPARATOR__` untuk meminimalkan panggilan API (maks 1800 karakter per permintaan)
- **Cache dalam memori**: Menghindari panggilan API yang redundan untuk string yang berulang dalam satu sesi
- **Logika percobaan ulang**: Backoff eksponensial (hingga 5 percobaan dengan penundaan 300ms × percobaan) untuk error 429/5xx
- **Batas waktu**: 20 detik per permintaan
- **Lewati yang sudah ada**: Jika file target sudah ada, file tersebut TIDAK akan ditimpa

**Perilaku penting:**

- `docs/i18n/README.md` **dihasilkan ulang** setiap kali dijalankan — ini adalah indeks dokumentasi yang dibuat otomatis
- File `README.{code}.md` di root hanya dibuat jika belum ada (melewati lokal yang ada di `EXISTING_README_CODES`)
- Bilah bahasa (`🌐 **Languages:** ...`) disisipkan/diperbarui secara otomatis di semua dokumen yang diterjemahkan

### i18n_autotranslate.py (berbasis LLM)

**Penerjemah sekunder** — menggunakan API LLM yang kompatibel dengan OpenAI (termasuk OmniRoute sendiri) untuk menerjemahkan file markdown `docs/i18n/` yang sudah ada. Paling baik digunakan untuk menyempurnakan atau menerjemahkan ulang dokumen dengan kualitas yang lebih baik dari Google Translate.

```bash
python3 scripts/i18n_autotranslate.py \
  --api-url http://localhost:20128/v1 \
  --api-key sk-your-key \
  --model gpt-4o
```

**Fitur:**

- Memindai file markdown `docs/i18n/` untuk paragraf berbahasa Inggris
- Melewati blok kode, tabel, dan konten yang sudah diterjemahkan
- Mengirimkan paragraf ke LLM dengan prompt sistem penerjemahan teknis
- Mendukung semua 30 bahasa

## Validasi & QA

### validate_translation.py

**Validator terjemahan** — membandingkan JSON lokal mana pun dengan `en.json` dan melaporkan masalah yang ditemukan.

```bash
# Quick check (counts only)
python3 scripts/validate_translation.py quick -l cs
# Output:
# Missing: 0
# Untranslated: 0
# Ignored (UNTRANSLATABLE_KEYS): 236

# Detailed diff by category
python3 scripts/validate_translation.py diff common -l cs
python3 scripts/validate_translation.py diff settings -l cs

# Export to CSV
python3 scripts/validate_translation.py csv -l cs > report.csv

# Export to Markdown
python3 scripts/validate_translation.py md -l cs > report.md

# Full report (default)
python3 scripts/validate_translation.py -l cs
```

**Yang dideteksi:**

- **Kunci yang hilang** — kunci yang ada di `en.json` tetapi tidak ada di file lokal
- **Kunci tambahan** — kunci yang ada di file lokal tetapi tidak ada di `en.json`
- **Kunci yang belum diterjemahkan** — kunci yang nilai lokalnya sama dengan sumber bahasa Inggris (tidak termasuk daftar yang diizinkan)
- **Ketidaksesuaian placeholder** — placeholder ICU yang tidak cocok antara sumber dan terjemahan

**Kode keluar:**
| Kode | Makna |
|------|-------|
| 0 | OK |
| 1 | Error umum |
| 2 | String yang hilang (error kritis) |
| 3 | Peringatan belum diterjemahkan (lunak) |

**Lingkungan:** Setel `TRANSLATION_LANG=cs` atau gunakan flag `-l cs`.

### check_translations.py

**Pemeriksa kunci kode ke JSON** — memindai `src/**/*.tsx` dan `src/**/*.ts` untuk panggilan `useTranslations()` dan memverifikasi bahwa semua kunci yang direferensikan ada di `en.json`.

```bash
# Basic check
python3 scripts/check_translations.py

# Verbose output
python3 scripts/check_translations.py --verbose

# Auto-fix (adds missing keys to en.json)
python3 scripts/check_translations.py --fix
```

### generate-qa-checklist.mjs

**QA analisis statis** — memindai file halaman Next.js untuk metrik risiko i18n dan menghasilkan laporan Markdown.

```bash
node scripts/i18n/generate-qa-checklist.mjs
```

**Yang diperiksa:**

- Penggunaan kelas lebar tetap (risiko overflow)
- Kelas arah kiri/kanan (risiko RTL)
- Pola rentan terpotong
- Paritas lokal (kunci yang hilang/tambahan vs `en.json`)
- Bilah pemilih bahasa README di lokal prioritas (`es`, `fr`, `de`, `ja`, `ar`)

**Keluaran:** `docs/reports/i18n-qa-checklist-{date}.md`

### run-visual-qa.mjs

**QA visual melalui Playwright** — mengambil tangkapan layar semua rute dashboard dalam beberapa lokal dan viewport, lalu mengevaluasi kesehatan halaman.

```bash
# Default: es, fr, de, ja, ar on localhost:20128
node scripts/i18n/run-visual-qa.mjs

# Custom base URL and locales
QA_BASE_URL=http://staging.example.com QA_LOCALES=de,fr node scripts/i18n/run-visual-qa.mjs

# Custom routes
QA_ROUTES=/dashboard/settings,/dashboard/providers node scripts/i18n/run-visual-qa.mjs
```

**Yang dideteksi:**

- Teks yang meluap (text overflow)
- Elemen yang terpotong
- Ketidaksesuaian tata letak RTL

**Keluaran:** `docs/reports/i18n-visual-qa-{date}.md` + laporan JSON

## Mengelola Kunci yang Tidak Dapat Diterjemahkan

### untranslatable-keys.json

**File:** `scripts/i18n/untranslatable-keys.json`

Daftar yang diizinkan berisi kunci yang harus tetap identik dengan sumber bahasa Inggris. Digunakan oleh `validate_translation.py` untuk menghindari peringatan "belum diterjemahkan" yang merupakan positif palsu.

```json
{
  "description": "Keys that should remain untranslated...",
  "keys": [
    "common.model",
    "common.oauth",
    "health.cpu",
    ...
  ]
}
```

**Yang termasuk di sini:**

- Nama merek/produk: `landing.brandName`, `common.social-github`
- Istilah teknis/akronim: `health.cpu`, `mcpDashboard.pid`, `settings.ai`
- String ICU/format: `apiManager.modelsCount`, `health.millisecondsShort`
- Nilai placeholder: `providers.openaiBaseUrlPlaceholder`, `cliTools.baseUrlPlaceholder`
- Nama protokol: `common.http`, `common.oauth`, `providers.oauth2Label`
- Bagian navigasi: `sidebar.primarySection`, `sidebar.cliSection`

**Untuk menambahkan kunci:** Edit array `keys` di `scripts/i18n/untranslatable-keys.json` dan jalankan ulang validasi.

## Integrasi CI

### GitHub Actions (`.github/workflows/ci.yml`)

Pipeline CI memvalidasi semua lokal pada setiap push dan PR:

1. **Job `i18n-matrix`** — secara dinamis menemukan semua file lokal (tidak termasuk `en.json`)
2. **Job `i18n`** — menjalankan `validate_translation.py quick -l '<lang>'` untuk setiap lokal secara paralel
3. **Job `ci-summary`** — mengagregasi hasil menjadi ringkasan dashboard

```yaml
# i18n-matrix: discovers languages
LANGS=$(ls src/i18n/messages/*.json | xargs -n1 basename | sed 's/.json$//' | grep -v '^en$')

# i18n: validates each language
python3 scripts/validate_translation.py quick -l '${{ matrix.lang }}'
```

**Keluaran dashboard:**

```
## 🌍 Translations
| Metric | Value |
|--------|------|
| Languages checked | 30 |
| Total untranslated | 0 |

✅ All translations complete
```

## Struktur File

```
src/i18n/
├── config.ts                    # Definisi lokal (30 lokal, konfigurasi RTL)
├── request.ts                   # Resolusi lokal saat runtime
└── messages/
    ├── en.json                  # Sumber kebenaran (~2800 kunci)
    ├── cs.json                  # Terjemahan bahasa Ceko
    ├── de.json                  # Terjemahan bahasa Jerman
    └── ...                      # Total 30 file lokal

scripts/
├── i18n/
│   ├── generate-multilang.mjs   # Mesin terjemahan otomatis (Google Translate, 888 baris)
│   ├── generate-qa-checklist.mjs # QA analisis statis
│   ├── run-visual-qa.mjs        # QA visual Playwright
│   └── untranslatable-keys.json # Daftar yang diizinkan untuk validasi (236 kunci)
├── validate_translation.py      # Validator terjemahan
├── check_translations.py        # Pemeriksa kunci kode ke JSON
└── i18n_autotranslate.py        # Penerjemah dokumentasi berbasis LLM

.github/workflows/
└── ci.yml                       # Validasi i18n dalam matriks CI

docs/
├── I18N.md                      # File ini — dokumentasi toolchain i18n
├── i18n/
│   ├── README.md                # Indeks bahasa yang dibuat otomatis
│   ├── cs/                      # Dokumentasi bahasa Ceko
│   │   └── docs/
│   │       ├── I18N.md          # Terjemahan bahasa Ceko dari file ini
│   │       └── ...
│   ├── de/                      # Dokumentasi bahasa Jerman
│   └── ...                      # 30 direktori lokal
└── reports/
    ├── i18n-qa-checklist-*.md   # Laporan analisis statis
    └── i18n-visual-qa-*.md      # Laporan QA visual
```

## Praktik Terbaik

### Saat Mengedit Terjemahan

1. **Selalu edit `en.json` terlebih dahulu** — itulah sumber kebenaran
2. **Jalankan `generate-multilang.mjs messages`** untuk menyebarkan kunci baru ke semua lokal
3. **Tinjau terjemahan otomatis** — Google Translate hanyalah titik awal, bukan hasil akhir
4. **Validasi sebelum melakukan commit** — `python3 scripts/validate_translation.py quick -l <lang>`
5. **Perbarui `untranslatable-keys.json`** jika sebuah kunci harus tetap dalam bahasa Inggris

### Keamanan Placeholder

- Placeholder ICU (`{count}`, `{value}`, `{total}`, `{seconds}`) harus dipertahankan persis sama
- Format jamak (`{count, plural, one {# model} other {# models}}`) harus mempertahankan strukturnya
- Validator mendeteksi ketidaksesuaian placeholder secara otomatis

### Menambahkan Kunci Terjemahan Baru dalam Kode

```tsx
// Use namespaced keys
const t = useTranslations("settings");
t("cacheSettings"); // maps to settings.cacheSettings in JSON

// Run check_translations.py to verify keys exist
python3 scripts/check_translations.py --verbose
```

### Pertimbangan RTL

- Bahasa Arab (`ar`) dan Ibrani (`he`) adalah lokal RTL
- Hindari `left`/`right` CSS yang dikodekan keras — gunakan properti logis `start`/`end`
- QA visual menangkap ketidaksesuaian tata letak RTL melalui `run-visual-qa.mjs`

## Masalah yang Diketahui & Riwayat

### Perbaikan `in.json` → `hi.json`

Generator awalnya menggunakan `code: "in"` (kode Google Translate yang sudah usang) untuk bahasa Hindi, bukan ISO 639-1 yang benar yaitu `hi`. Hal ini menciptakan duplikat `in.json` yang tidak terhubung dari `hi.json`. Diperbaiki dengan mengubah `code: "in"` menjadi `code: "hi"` di `generate-multilang.mjs` dan menghapus file yang tidak terhubung tersebut.

### `docs/i18n/README.md` Dibuat Secara Otomatis

File `docs/i18n/README.md` sepenuhnya dihasilkan ulang oleh `generate-multilang.mjs docs`. Setiap pengeditan manual akan hilang. Gunakan `docs/guides/I18N.md` (file ini) untuk dokumentasi yang ditulis tangan yang harus tetap ada.

### Daftar Kunci yang Tidak Dapat Diterjemahkan Eksternal

Daftar yang diizinkan `untranslatable-keys.json` dipindahkan dari set Python inline di `validate_translation.py` ke file JSON eksternal agar lebih mudah dipelihara. Validator memuatnya saat runtime.

### Perbaikan Kode Hindi di `generate-multilang.mjs`

Generator awalnya menggunakan `code: "in"` (kode Google Translate yang sudah usang) untuk bahasa Hindi, bukan ISO 639-1 yang benar yaitu `hi`. Ini diperkenalkan dalam commit upstream `952b0b22c` oleh `diegosouzapw`. Diperbaiki dengan mengubah `code: "in"` menjadi `code: "hi"` di array `LOCALE_SPECS` dan menghapus file `in.json` yang tidak terhubung.

### Keluaran Jumlah Kunci yang Diabaikan di `validate_translation.py`

Pemeriksaan `quick` kini menampilkan jumlah kunci yang diabaikan dari `untranslatable-keys.json`:

```
Missing: 0
Untranslated: 0
Ignored (UNTRANSLATABLE_KEYS): 236
```
