mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-30 03:42:12 +03:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a23dc8b04 | ||
|
|
ba13e44720 | ||
|
|
e80420f6db | ||
|
|
21ddcfc866 | ||
|
|
20f82cb22c | ||
|
|
7ef75bab23 | ||
|
|
7224e03590 | ||
|
|
cf4f2991a5 | ||
|
|
9eb3c23494 | ||
|
|
c80d8898cc | ||
|
|
bc74dd88e0 | ||
|
|
da87c461ef | ||
|
|
bf2e694f2c | ||
|
|
e5150487c4 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -4,6 +4,16 @@
|
||||
|
||||
---
|
||||
|
||||
## [3.1.3] — 2026-03-26
|
||||
|
||||
### 🌍 i18n & Community
|
||||
|
||||
- **~70 missing translation keys** added to `en.json` and 12 languages (PR #652 by @zen0bit)
|
||||
- **Czech documentation updated** — CLI-TOOLS, API_REFERENCE, VM_DEPLOYMENT guides (PR #652)
|
||||
- **Translation validation scripts** — `check_translations.py` and `validate_translation.py` for CI/QA (PR #651 by @zen0bit)
|
||||
|
||||
---
|
||||
|
||||
## [3.1.2] — 2026-03-26
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
@@ -48,6 +48,8 @@ Content-Type: application/json
|
||||
| `X-OmniRoute-Idempotent` | Odpověď | `true` , pokud je odstraněna duplikace |
|
||||
| `X-OmniRoute-Progress` | Odpověď | `enabled` pokud je zapnuto sledování průběhu |
|
||||
|
||||
> Poznámka Nginx: pokud spoléháte na hlavičky s podtržítkem (například `x_session_id`), povolte `underscores_in_headers on;`.
|
||||
|
||||
---
|
||||
|
||||
## Vložení
|
||||
|
||||
@@ -1,60 +1,79 @@
|
||||
# Průvodce nastavením nástrojů CLI — OmniRoute
|
||||
|
||||
Tato příručka vysvětluje, jak nainstalovat a nakonfigurovat všechny podporované nástroje CLI pro kódování umělé inteligence tak, aby **OmniRoute** fungoval jako jednotný backend, což vám umožní centralizovanou správu klíčů, sledování nákladů, přepínání modelů a protokolování požadavků napříč všemi nástroji.
|
||||
Tato příručka vysvětluje, jak nainstalovat a nakonfigurovat všechny podporované nástroje CLI pro kódování umělé inteligence
|
||||
tak, aby **OmniRoute** fungoval jako jednotný backend, což vám umožní centralizovanou správu klíčů,
|
||||
sledování nákladů, přepínání modelů a protokolování požadavků napříč všemi nástroji.
|
||||
|
||||
---
|
||||
|
||||
## Jak to funguje
|
||||
|
||||
```
|
||||
Claude / Codex / Gemini CLI / OpenCode / Cline / KiloCode / Continue / Kiro CLI
|
||||
│
|
||||
▼ (all point to OmniRoute)
|
||||
http://YOUR_SERVER:20128/v1
|
||||
│
|
||||
▼ (OmniRoute routes to the right provider)
|
||||
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
|
||||
Claude / Codex / OpenCode / Cline / KiloCode / Continue / Kiro / Cursor / Copilot
|
||||
│
|
||||
▼ (všechny ukazují na OmniRoute)
|
||||
http://VASE_SERVER:20128/v1
|
||||
│
|
||||
▼ (OmniRoute směruje ke správnému poskytovateli)
|
||||
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
|
||||
```
|
||||
|
||||
**Výhody:**
|
||||
|
||||
- Jeden klíč API pro správu všech nástrojů
|
||||
- Sledování nákladů napříč všemi rozhraními příkazového řádku v dashboardu
|
||||
- Jeden API klíč pro správu všech nástrojů
|
||||
- Sledování nákladů napříč všemi CLI v dashboardu
|
||||
- Přepínání modelů bez nutnosti překonfigurování každého nástroje
|
||||
- Funguje lokálně i na vzdálených serverech (VPS)
|
||||
|
||||
---
|
||||
|
||||
## Podporované nástroje
|
||||
## Podporované nástroje (Zdroj pravdy v dashboardu)
|
||||
|
||||
| Nástroj | Příkaz | Typ | Instalace |
|
||||
| ---------------- | ------------------- | --------------- | -------------- |
|
||||
| **Claude Code** | `claude` | CLI | npm |
|
||||
| **OpenAI Codex** | `codex` | CLI | npm |
|
||||
| **Gemini CLI** | `gemini` | CLI | npm |
|
||||
| **OpenCode** | `opencode` | CLI | npm |
|
||||
| **Cline** | `cline` | CLI + VS Code | npm |
|
||||
| **KiloCode** | `kilocode` / `kilo` | CLI + VS Code | npm |
|
||||
| **Continue** | průvodce | VS Code ext | VS kód |
|
||||
| **Kiro CLI** | `kiro-cli` | CLI | curl instalace |
|
||||
| **Kurzor** | `cursor` | Aplikace pro PC | Download |
|
||||
| **Droid** | webový | Built-in agent | OmniRoute |
|
||||
| **OpenClaw** | webový | Built-in agent | OmniRoute |
|
||||
Karty dashboardu v `/dashboard/cli-tools` jsou generovány z `src/shared/constants/cliTools.ts`.
|
||||
Aktuální seznam (v3.0.0-rc.16):
|
||||
|
||||
| Nástroj | ID | Příkaz | Režim nastavení | Metoda instalace |
|
||||
| ------------------ | ------------- | ------------ | --------------- | ---------------- |
|
||||
| **Claude Code** | `claude` | `claude` | env | npm |
|
||||
| **OpenAI Codex** | `codex` | `codex` | custom | npm |
|
||||
| **Factory Droid** | `droid` | `droid` | custom | bundled/CLI |
|
||||
| **OpenClaw** | `openclaw` | `openclaw` | custom | bundled/CLI |
|
||||
| **Cursor** | `cursor` | aplikace | guide | desktop app |
|
||||
| **Cline** | `cline` | `cline` | custom | npm |
|
||||
| **Kilo Code** | `kilo` | `kilocode` | custom | npm |
|
||||
| **Continue** | `continue` | rozšíření | guide | VS Code |
|
||||
| **Antigravity** | `antigravity` | interní | mitm | OmniRoute |
|
||||
| **GitHub Copilot** | `copilot` | rozšíření | custom | VS Code |
|
||||
| **OpenCode** | `opencode` | `opencode` | guide | npm |
|
||||
| **Kiro AI** | `kiro` | aplikace/CLI | mitm | desktop/CLI |
|
||||
|
||||
### Synchronizace otisků CLI (Agenti + Nastavení)
|
||||
|
||||
`/dashboard/agents` a `Nastavení > CLI Otisk` používají `src/shared/constants/cliCompatProviders.ts`.
|
||||
To udržuje ID poskytovatelů v souladu s kartami CLI a staršími ID.
|
||||
|
||||
| CLI ID | ID poskytovatele otisku |
|
||||
| ---------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| `kilo` | `kilocode` |
|
||||
| `copilot` | `github` |
|
||||
| `claude` / `codex` / `antigravity` / `kiro` / `cursor` / `cline` / `opencode` / `droid` / `openclaw` | stejné ID |
|
||||
|
||||
Starší ID jsou stále přijímána pro kompatibilitu: `copilot`, `kimi-coding`, `qwen`.
|
||||
|
||||
---
|
||||
|
||||
## Krok 1 – Získejte klíč OmniRoute API
|
||||
## Krok 1 — Získejte OmniRoute API klíč
|
||||
|
||||
1. Otevřete dashboard OmniRoute → **Správce API** ( `/dashboard/api-manager` )
|
||||
2. Klikněte na **Vytvořit klíč API**
|
||||
3. Pojmenujte to (např. `cli-tools` ) a vyberte všechna oprávnění.
|
||||
4. Zkopírujte klíč – budete ho potřebovat pro každé níže uvedené rozhraní příkazového řádku.
|
||||
1. Otevřete OmniRoute dashboard → **Správce API** (`/dashboard/api-manager`)
|
||||
2. Klikněte na **Vytvořit API klíč**
|
||||
3. Dejte mu název (např. `cli-tools`) a vyberte všechna oprávnění
|
||||
4. Zkopírujte klíč — budete ho potřebovat pro každý CLI níže
|
||||
|
||||
> Váš klíč vypadá takto: `sk-xxxxxxxxxxxxxxxx-xxxxxxxxx`
|
||||
|
||||
---
|
||||
|
||||
## Krok 2 – Instalace nástrojů CLI
|
||||
## Krok 2 — Nainstalujte nástroje CLI
|
||||
|
||||
Všechny nástroje založené na npm vyžadují Node.js 18+:
|
||||
|
||||
@@ -65,9 +84,6 @@ npm install -g @anthropic-ai/claude-code
|
||||
# OpenAI Codex
|
||||
npm install -g @openai/codex
|
||||
|
||||
# Gemini CLI (Google)
|
||||
npm install -g @google/gemini-cli
|
||||
|
||||
# OpenCode
|
||||
npm install -g opencode-ai
|
||||
|
||||
@@ -75,47 +91,47 @@ npm install -g opencode-ai
|
||||
npm install -g cline
|
||||
|
||||
# KiloCode
|
||||
npm install -g kilecode
|
||||
npm install -g kilocode
|
||||
|
||||
# Kiro CLI (Amazon — requires curl + unzip)
|
||||
apt-get install -y unzip # on Debian/Ubuntu
|
||||
# Kiro CLI (Amazon — vyžaduje curl + unzip)
|
||||
apt-get install -y unzip # na Debian/Ubuntu
|
||||
curl -fsSL https://cli.kiro.dev/install | bash
|
||||
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc
|
||||
export PATH="$HOME/.local/bin:$PATH" # přidat do ~/.bashrc
|
||||
```
|
||||
|
||||
**Ověřit:**
|
||||
**Ověření:**
|
||||
|
||||
```bash
|
||||
claude --version # 2.x.x
|
||||
codex --version # 0.x.x
|
||||
gemini --version # 0.x.x
|
||||
opencode --version # x.x.x
|
||||
cline --version # 2.x.x
|
||||
kilocode --version # x.x.x (or: kilo --version)
|
||||
kilocode --version # x.x.x (nebo: kilo --version)
|
||||
kiro-cli --version # 1.x.x
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Krok 3 – Nastavení globálních proměnných prostředí
|
||||
## Krok 3 — Nastavte globální proměnné prostředí
|
||||
|
||||
Přidejte do `~/.bashrc` (nebo `~/.zshrc` ) a poté spusťte `source ~/.bashrc` :
|
||||
Přidejte do `~/.bashrc` (nebo `~/.zshrc`), pak spusťte `source ~/.bashrc`:
|
||||
|
||||
```bash
|
||||
# OmniRoute Universal Endpoint
|
||||
# OmniRoute Univerzální koncový bod
|
||||
export OPENAI_BASE_URL="http://localhost:20128/v1"
|
||||
export OPENAI_API_KEY="sk-your-omniroute-key"
|
||||
export OPENAI_API_KEY="sk-vase-omniroute-klic"
|
||||
export ANTHROPIC_BASE_URL="http://localhost:20128/v1"
|
||||
export ANTHROPIC_API_KEY="sk-your-omniroute-key"
|
||||
export ANTHROPIC_API_KEY="sk-vase-omniroute-klic"
|
||||
export GEMINI_BASE_URL="http://localhost:20128/v1"
|
||||
export GEMINI_API_KEY="sk-your-omniroute-key"
|
||||
export GEMINI_API_KEY="sk-vase-omniroute-klic"
|
||||
```
|
||||
|
||||
> Pro **vzdálený server** nahraďte `localhost:20128` IP adresou nebo doménou serveru, např. `http://192.168.0.15:20128` .
|
||||
> Pro **vzdálený server** nahraďte `localhost:20128` IP adresou nebo doménou serveru,
|
||||
> např. `http://192.168.0.15:20128`.
|
||||
|
||||
---
|
||||
|
||||
## Krok 4 – Konfigurace jednotlivých nástrojů
|
||||
## Krok 4 — Nakonfigurujte každý nástroj
|
||||
|
||||
### Claude Code
|
||||
|
||||
@@ -123,11 +139,11 @@ export GEMINI_API_KEY="sk-your-omniroute-key"
|
||||
# Via CLI:
|
||||
claude config set --global api-base-url http://localhost:20128/v1
|
||||
|
||||
# Or create ~/.claude/settings.json:
|
||||
# Nebo vytvořte ~/.claude/settings.json:
|
||||
mkdir -p ~/.claude && cat > ~/.claude/settings.json << EOF
|
||||
{
|
||||
"apiBaseUrl": "http://localhost:20128/v1",
|
||||
"apiKey": "sk-your-omniroute-key"
|
||||
"apiKey": "sk-vase-omniroute-klic"
|
||||
}
|
||||
EOF
|
||||
```
|
||||
@@ -141,7 +157,7 @@ EOF
|
||||
```bash
|
||||
mkdir -p ~/.codex && cat > ~/.codex/config.yaml << EOF
|
||||
model: auto
|
||||
apiKey: sk-your-omniroute-key
|
||||
apiKey: sk-vase-omniroute-klic
|
||||
apiBaseUrl: http://localhost:20128/v1
|
||||
EOF
|
||||
```
|
||||
@@ -150,28 +166,13 @@ EOF
|
||||
|
||||
---
|
||||
|
||||
### Gemini CLI
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.gemini && cat > ~/.gemini/settings.json << EOF
|
||||
{
|
||||
"apiKey": "sk-your-omniroute-key",
|
||||
"baseUrl": "http://localhost:20128/v1"
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**Test:** `gemini "hello"`
|
||||
|
||||
---
|
||||
|
||||
### OpenCode
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/config.toml << EOF
|
||||
[provider.openai]
|
||||
base_url = "http://localhost:20128/v1"
|
||||
api_key = "sk-your-omniroute-key"
|
||||
api_key = "sk-vase-omniroute-klic"
|
||||
EOF
|
||||
```
|
||||
|
||||
@@ -179,7 +180,7 @@ EOF
|
||||
|
||||
---
|
||||
|
||||
### Cline (CLI nebo VS kód)
|
||||
### Cline (CLI nebo VS Code)
|
||||
|
||||
**Režim CLI:**
|
||||
|
||||
@@ -188,41 +189,42 @@ mkdir -p ~/.cline/data && cat > ~/.cline/data/globalState.json << EOF
|
||||
{
|
||||
"apiProvider": "openai",
|
||||
"openAiBaseUrl": "http://localhost:20128/v1",
|
||||
"openAiApiKey": "sk-your-omniroute-key"
|
||||
"openAiApiKey": "sk-vase-omniroute-klic"
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**Režim VS Code:** Nastavení rozšíření Cline → Poskytovatel API: `OpenAI Compatible` → Základní URL: `http://localhost:20128/v1`
|
||||
**Režim VS Code:**
|
||||
Nastavení rozšíření Cline → API Provider: `OpenAI Compatible` → Base URL: `http://localhost:20128/v1`
|
||||
|
||||
Nebo použijte dashboard OmniRoute → **CLI Tools → Cline → Apply Config** .
|
||||
Nebo použijte OmniRoute dashboard → **CLI Nástroje → Cline → Použít konfiguraci**.
|
||||
|
||||
---
|
||||
|
||||
### KiloCode (CLI nebo VS kód)
|
||||
### KiloCode (CLI nebo VS Code)
|
||||
|
||||
**Režim CLI:**
|
||||
|
||||
```bash
|
||||
kilocode --api-base http://localhost:20128/v1 --api-key sk-your-omniroute-key
|
||||
kilocode --api-base http://localhost:20128/v1 --api-key sk-vase-omniroute-klic
|
||||
```
|
||||
|
||||
**Nastavení VS kódu:**
|
||||
**Nastavení VS Code:**
|
||||
|
||||
```json
|
||||
{
|
||||
"kilo-code.openAiBaseUrl": "http://localhost:20128/v1",
|
||||
"kilo-code.apiKey": "sk-your-omniroute-key"
|
||||
"kilo-code.apiKey": "sk-vase-omniroute-klic"
|
||||
}
|
||||
```
|
||||
|
||||
Nebo použijte dashboard OmniRoute → **CLI Tools → KiloCode → Apply Config** .
|
||||
Nebo použijte OmniRoute dashboard → **CLI Nástroje → KiloCode → Použít konfiguraci**.
|
||||
|
||||
---
|
||||
|
||||
### Continue (rozšíření kódu VS)
|
||||
### Continue (Rozšíření VS Code)
|
||||
|
||||
Upravit `~/.continue/config.yaml` :
|
||||
Upravte `~/.continue/config.yaml`:
|
||||
|
||||
```yaml
|
||||
models:
|
||||
@@ -230,7 +232,7 @@ models:
|
||||
provider: openai
|
||||
model: auto
|
||||
apiBase: http://localhost:20128/v1
|
||||
apiKey: sk-your-omniroute-key
|
||||
apiKey: sk-vase-omniroute-klic
|
||||
default: true
|
||||
```
|
||||
|
||||
@@ -241,94 +243,95 @@ Po úpravě restartujte VS Code.
|
||||
### Kiro CLI (Amazon)
|
||||
|
||||
```bash
|
||||
# Login to your AWS/Kiro account:
|
||||
# Přihlaste se ke svému AWS/Kiro účtu:
|
||||
kiro-cli login
|
||||
|
||||
# The CLI uses its own auth — OmniRoute is not needed as backend for Kiro CLI itself.
|
||||
# Use kiro-cli alongside OmniRoute for other tools.
|
||||
# CLI používá vlastní autentifikaci — OmniRoute není potřeba jako backend pro samotný Kiro CLI.
|
||||
# Používejte kiro-cli společně s OmniRoute pro ostatní nástroje.
|
||||
kiro-cli status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Kurzor (aplikace pro stolní počítače)
|
||||
### Cursor (Desktop aplikace)
|
||||
|
||||
> **Poznámka:** Cursor směruje požadavky přes svůj cloud. Pro integraci OmniRoute povolte **cloudový koncový bod** v nastavení OmniRoute a použijte URL adresu vaší veřejné domény.
|
||||
> **Poznámka:** Cursor směruje požadavky přes svůj cloud. Pro integraci s OmniRoute,
|
||||
> povolte **Cloud Endpoint** v nastavení OmniRoute a použijte vaši veřejnou doménu.
|
||||
|
||||
Přes GUI: **Nastavení → Modely → Klíč OpenAI API**
|
||||
Via GUI: **Settings → Models → OpenAI API Key**
|
||||
|
||||
- Základní URL: `https://your-domain.com/v1`
|
||||
- Klíč API: váš klíč OmniRoute
|
||||
- Base URL: `https://vase-domena.com/v1`
|
||||
- API Key: váš OmniRoute klíč
|
||||
|
||||
---
|
||||
|
||||
## Automatická konfigurace řídicího panelu
|
||||
## Automatická konfigurace v dashboardu
|
||||
|
||||
Ovládací panel OmniRoute automatizuje konfiguraci většiny nástrojů:
|
||||
OmniRoute dashboard automatizuje konfiguraci většiny nástrojů:
|
||||
|
||||
1. Přejděte na `http://localhost:20128/dashboard/cli-tools`
|
||||
2. Rozbalit libovolnou kartu nástroje
|
||||
3. Vyberte klíč API z rozbalovací nabídky
|
||||
4. Klikněte **na Použít konfiguraci** (pokud je nástroj detekován jako nainstalovaný)
|
||||
5. Nebo zkopírujte vygenerovaný konfigurační úryvek ručně
|
||||
1. Jděte na `http://localhost:20128/dashboard/cli-tools`
|
||||
2. Rozbalte libovolnou kartu nástroje
|
||||
3. Vyberte svůj API klíč z rozbalovacího seznamu
|
||||
4. Klikněte na **Použít konfiguraci** (pokud je nástroj detekován jako nainstalovaný)
|
||||
5. Nebo ručně zkopírujte vygenerovaný konfigurační snippet
|
||||
|
||||
---
|
||||
|
||||
## Vestavění agenti: Droid a OpenClaw
|
||||
## Vestavěný agenti: Droid & OpenClaw
|
||||
|
||||
**Droid** a **OpenClaw** jsou agenti umělé inteligence zabudovaní přímo do OmniRoute – není nutná žádná instalace. Běží jako interní trasy a automaticky používají modelové směrování OmniRoute.
|
||||
**Droid** a **OpenClaw** jsou AI agenti vestavění přímo do OmniRoute — není potřeba žádná instalace.
|
||||
Běží jako interní trasy a automaticky používají směrování modelů OmniRoute.
|
||||
|
||||
- Přístup: `http://localhost:20128/dashboard/agents`
|
||||
- Konfigurace: stejné kombinace a poskytovatelé jako u všech ostatních nástrojů
|
||||
- Není vyžadována instalace klíče API ani příkazového řádku
|
||||
- Konfigurace: stejné kombinace a poskytovatelé jako všechny ostatní nástroje
|
||||
- Není potřeba API klíč ani instalace CLI
|
||||
|
||||
---
|
||||
|
||||
## Dostupné koncové body API
|
||||
## Dostupné API koncové body
|
||||
|
||||
| Koncový bod | Popis | Použití pro |
|
||||
| -------------------------- | --------------------------------------- | ------------------------------------- |
|
||||
| `/v1/chat/completions` | Standardní chat (všichni poskytovatelé) | Všechny moderní nástroje |
|
||||
| `/v1/responses` | API pro odpovědi (formát OpenAI) | Kodex, agentické pracovní postupy |
|
||||
| `/v1/completions` | Doplňování starších textů | Starší nástroje používající `prompt:` |
|
||||
| `/v1/embeddings` | Vkládání textu | RAG, vyhledávání |
|
||||
| `/v1/images/generations` | Generování obrázků | DALL-E, Flux atd. |
|
||||
| `/v1/audio/speech` | Převod textu na řeč | ElevenLabs, OpenAI TTS |
|
||||
| `/v1/audio/transcriptions` | Převod řeči na text | Deepgram, AssemblyAI |
|
||||
| `/v1/responses` | Responses API (formát OpenAI) | Codex, agentní workflowy |
|
||||
| `/v1/completions` | Legacy textové dokončení | Starší nástroje používající `prompt:` |
|
||||
| `/v1/embeddings` | Textové vložení | RAG, vyhledávání |
|
||||
| `/v1/images/generations` | Generování obrázků | DALL-E, Flux, atd. |
|
||||
| `/v1/audio/speech` | Text-to-speech | ElevenLabs, OpenAI TTS |
|
||||
| `/v1/audio/transcriptions` | Speech-to-text | Deepgram, AssemblyAI |
|
||||
|
||||
---
|
||||
|
||||
## Odstraňování problémů
|
||||
## Řešení problémů
|
||||
|
||||
| Chyba | Příčina | Opravit |
|
||||
| ---------------------------------- | ---------------------------------- | -------------------------------------------------------- |
|
||||
| `Connection refused` | OmniRoute neběží | `pm2 start omniroute` |
|
||||
| `401 Unauthorized` | Chybný klíč API | Zkontrolovat `/dashboard/api-manager` |
|
||||
| `No combo configured` | Žádná aktivní routingová kombinace | Nastavení v `/dashboard/combos` |
|
||||
| `invalid model` | Model není v katalogu | Použijte `auto` nebo zkontrolujte `/dashboard/providers` |
|
||||
| CLI zobrazuje „není nainstalováno“ | Binární soubor není v cestě PATH | Zkontrolujte, `which <command>` |
|
||||
| `kiro-cli: not found` | Není v PATH | `export PATH="$HOME/.local/bin:$PATH"` |
|
||||
| Chyba | Příčina | Oprava |
|
||||
| ----------------------------- | ----------------------- | -------------------------------------------------------- |
|
||||
| `Connection refused` | OmniRoute neběží | `pm2 start omniroute` |
|
||||
| `401 Unauthorized` | Špatný API klíč | Zkontrolujte v `/dashboard/api-manager` |
|
||||
| `No combo configured` | Žádná aktivní kombinace | Nastavte v `/dashboard/combos` |
|
||||
| `invalid model` | Model není v katalogu | Použijte `auto` nebo zkontrolujte `/dashboard/providers` |
|
||||
| CLI zobrazuje "not installed" | Binárka není v PATH | Zkontrolujte `which <příkaz>` |
|
||||
| `kiro-cli: not found` | Není v PATH | `export PATH="$HOME/.local/bin:$PATH"` |
|
||||
|
||||
---
|
||||
|
||||
## Skript pro rychlé nastavení (jeden příkaz)
|
||||
## Rychlý skript pro nastavení (jeden příkaz)
|
||||
|
||||
```bash
|
||||
# Install all CLIs and configure for OmniRoute (replace with your key and server URL)
|
||||
# Nainstalujte všechny CLI a nakonfigurujte pro OmniRoute (nahraďte svým klíčem a URL serveru)
|
||||
OMNIROUTE_URL="http://localhost:20128/v1"
|
||||
OMNIROUTE_KEY="sk-your-omniroute-key"
|
||||
OMNIROUTE_KEY="sk-vase-omniroute-klic"
|
||||
|
||||
npm install -g @anthropic-ai/claude-code @openai/codex @google/gemini-cli opencode-ai cline kilecode
|
||||
npm install -g @anthropic-ai/claude-code @openai/codex opencode-ai cline kilocode
|
||||
|
||||
# Kiro CLI
|
||||
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
|
||||
|
||||
# Write configs
|
||||
mkdir -p ~/.claude ~/.codex ~/.gemini ~/.config/opencode ~/.continue
|
||||
# Zápis konfigurací
|
||||
mkdir -p ~/.claude ~/.codex ~/.config/opencode ~/.continue
|
||||
|
||||
cat > ~/.claude/settings.json <<< "{\"apiBaseUrl\":\"$OMNIROUTE_URL\",\"apiKey\":\"$OMNIROUTE_KEY\"}"
|
||||
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
|
||||
cat > ~/.gemini/settings.json <<< "{\"apiKey\":\"$OMNIROUTE_KEY\",\"baseUrl\":\"$OMNIROUTE_URL\"}"
|
||||
cat >> ~/.bashrc << EOF
|
||||
export OPENAI_BASE_URL="$OMNIROUTE_URL"
|
||||
export OPENAI_API_KEY="$OMNIROUTE_KEY"
|
||||
@@ -337,5 +340,5 @@ export ANTHROPIC_API_KEY="$OMNIROUTE_KEY"
|
||||
EOF
|
||||
|
||||
source ~/.bashrc
|
||||
echo "✅ All CLIs installed and configured for OmniRoute"
|
||||
echo "✅ Všechny CLI nainstalovány a nakonfigurovány pro OmniRoute"
|
||||
```
|
||||
|
||||
@@ -1590,7 +1590,6 @@ opencode
|
||||
### 🔐 OAuth na vzdáleném serveru
|
||||
|
||||
<a name="oauth-on-a-remote-server"></a>
|
||||
<a name="oauth-em-servidor-remoto"></a>
|
||||
|
||||
> **⚠️ Důležité pro uživatele, kteří provozují OmniRoute na VPS, Dockeru nebo jakémkoli vzdáleném serveru**
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
# OmniRoute — Guia de Deploy em VM com Cloudflare
|
||||
# Průvodce nasazením OmniRoute na VM s Cloudflare
|
||||
|
||||
Kompletní instalace a konfigurace OmniRoute u VM (VPS) s gerenciou přes Cloudflare.
|
||||
🌐 **Jazyky:** 🇺🇸 [English](VM_DEPLOYMENT_GUIDE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/VM_DEPLOYMENT_GUIDE.md) | 🇪🇸 [Español](i18n/es/VM_DEPLOYMENT_GUIDE.md) | 🇫🇷 [Français](i18n/fr/VM_DEPLOYMENT_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/VM_DEPLOYMENT_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/VM_DEPLOYMENT_GUIDE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/VM_DEPLOYMENT_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/VM_DEPLOYMENT_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/VM_DEPLOYMENT_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/VM_DEPLOYMENT_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/VM_DEPLOYMENT_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/VM_DEPLOYMENT_GUIDE.md) | 🇯🇵 [日本語](i18n/ja/VM_DEPLOYMENT_GUIDE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/VM_DEPLOYMENT_GUIDE.md) | 🇧🇬 [Български](i18n/bg/VM_DEPLOYMENT_GUIDE.md) | 🇩🇰 [Dansk](i18n/da/VM_DEPLOYMENT_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/VM_DEPLOYMENT_GUIDE.md) | 🇮🇱 [עברית](i18n/he/VM_DEPLOYMENT_GUIDE.md) | 🇭🇺 [Magyar](i18n/hu/VM_DEPLOYMENT_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/VM_DEPLOYMENT_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/VM_DEPLOYMENT_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/VM_DEPLOYMENT_GUIDE.md) | 🇳🇱 [Nederlands](i18n/nl/VM_DEPLOYMENT_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/VM_DEPLOYMENT_GUIDE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/VM_DEPLOYMENT_GUIDE.md) | 🇷🇴 [Română](i18n/ro/VM_DEPLOYMENT_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/VM_DEPLOYMENT_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/VM_DEPLOYMENT_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/VM_DEPLOYMENT_GUIDE.md) | 🇵🇭 [Filipino](i18n/phi/VM_DEPLOYMENT_GUIDE.md) | 🇨🇿 [Čeština](i18n/cs/VM_DEPLOYMENT_GUIDE.md)
|
||||
|
||||
Kompletní průvodce instalací a konfigurací OmniRoute na virtuálním stroji (VPS) se správou domény prostřednictvím Cloudflare.
|
||||
|
||||
---
|
||||
|
||||
## Předpoklady
|
||||
|
||||
Položka | Mínimo | Doporučeno
|
||||
--- | --- | ---
|
||||
**Procesor** | 1 virtuální procesor | 2 vCPU
|
||||
**BERAN** | 1 GB | 2 GB
|
||||
**Disko** | 10GB SSD | 25GB SSD
|
||||
**TAK** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS
|
||||
**Domínio** | Registrován v Cloudflare | —
|
||||
**Přístavní dělník** | Docker Engine 24+ | Docker 27+
|
||||
| Položka | Minimální | Doporučeno |
|
||||
| ------------ | --------------------------- | ---------------- |
|
||||
| **Procesor** | 1 virtuální procesor | 2 vCPU |
|
||||
| **RAM** | 1 GB | 2 GB |
|
||||
| **Disk** | 10GB SSD | 25GB SSD |
|
||||
| **CPU** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
|
||||
| **Doména** | Zaregistrována v Cloudflare | — |
|
||||
| **Docker** | Docker Engine 24+ | Docker 27+ |
|
||||
|
||||
**Testados poskytovatelů** : Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
|
||||
**Testovaní poskytovatelé**: Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
|
||||
|
||||
---
|
||||
|
||||
@@ -23,12 +25,12 @@ Položka | Mínimo | Doporučeno
|
||||
|
||||
### 1.1 Vytvořit ihned
|
||||
|
||||
Žádný preferovaný poskytovatel seu VPS:
|
||||
Žádný preferovaný poskytovatel VPS:
|
||||
|
||||
- Vyberte si Ubuntu 24.04 LTS
|
||||
- Výběr nebo plano minimo (1 vCPU / 1 GB RAM)
|
||||
- Definujte sílu pro root nebo konfiguraci klíče SSH
|
||||
- Anote o **IP público** (např.: `203.0.113.10` )
|
||||
- Vyberte minimální plán (1 vCPU / 1 GB RAM)
|
||||
- Nastavte silné heslo pro root nebo konfiguraci SSH klíče
|
||||
- Poznamenejte si **veřejnou IP** (např.: `203.0.113.10`)
|
||||
|
||||
### 1.2 Připojení přes SSH
|
||||
|
||||
@@ -45,10 +47,10 @@ apt update && apt upgrade -y
|
||||
### 1.4 Instalace Dockeru
|
||||
|
||||
```bash
|
||||
# Instalar dependências
|
||||
# Nainstalovat závislosti
|
||||
apt install -y ca-certificates curl gnupg
|
||||
|
||||
# Adicionar repositório oficial do Docker
|
||||
# Přidat oficiální Docker repository
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
@@ -74,29 +76,29 @@ ufw allow 443/tcp # HTTPS
|
||||
ufw enable
|
||||
```
|
||||
|
||||
> **Dica** : Maximální zabezpečení, omezení jako porty 80 a 443 přístupů pro IP Cloudflare. Veja a seção [Segurança Avançada](#seguran%C3%A7a-avan%C3%A7ada) .
|
||||
> **Tip**: Pro maximální zabezpečení omezte porty 80 a 443 pouze na IP Cloudflare. Viz sekce [Pokročilé zabezpečení](#pokrocilé-zabezpečení).
|
||||
|
||||
---
|
||||
|
||||
## 2. Instalace OmniRoute
|
||||
|
||||
### 2.1 Criar diretório de configuração
|
||||
### 2.1 Vytvořit konfigurační adresář
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/omniroute
|
||||
```
|
||||
|
||||
### 2.2 Criar arquivo de variáveis de ambiente
|
||||
### 2.2 Vytvořit soubor s proměnnými prostředí
|
||||
|
||||
```bash
|
||||
cat > /opt/omniroute/.env << 'EOF'
|
||||
# === Segurança ===
|
||||
JWT_SECRET=ALTERE-PARA-CHAVE-SECRETA-UNICA-64-CHARS
|
||||
INITIAL_PASSWORD=SuaSenhaSegura123!
|
||||
API_KEY_SECRET=ALTERE-PARA-OUTRA-CHAVE-SECRETA
|
||||
STORAGE_ENCRYPTION_KEY=ALTERE-PARA-TERCEIRA-CHAVE-SECRETA
|
||||
# === Bezpečnost ===
|
||||
JWT_SECRET=CHANGE-TO-A-UNIQUE-64-CHAR-SECRET-KEY
|
||||
INITIAL_PASSWORD=YourSecurePassword123!
|
||||
API_KEY_SECRET=REPLACE-WITH-ANOTHER-SECRET-KEY
|
||||
STORAGE_ENCRYPTION_KEY=REPLACE-WITH-THIRD-SECRET-KEY
|
||||
STORAGE_ENCRYPTION_KEY_VERSION=v1
|
||||
MACHINE_ID_SALT=ALTERE-PARA-SALT-UNICO
|
||||
MACHINE_ID_SALT=CHANGE-TO-A-UNIQUE-SALT
|
||||
|
||||
# === App ===
|
||||
PORT=20128
|
||||
@@ -108,9 +110,9 @@ ENABLE_REQUEST_LOGS=true
|
||||
AUTH_COOKIE_SECURE=false
|
||||
REQUIRE_API_KEY=false
|
||||
|
||||
# === Domain (altere para seu domínio) ===
|
||||
BASE_URL=https://llms.seudominio.com
|
||||
NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
|
||||
# === Doména (změňte na vaši doménu) ===
|
||||
BASE_URL=https://llms.vasedomena.com
|
||||
NEXT_PUBLIC_BASE_URL=https://llms.vasedomena.com
|
||||
|
||||
# === Cloud Sync (opcional) ===
|
||||
# CLOUD_URL=https://cloud.omniroute.online
|
||||
@@ -118,7 +120,7 @@ NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
|
||||
EOF
|
||||
```
|
||||
|
||||
> ⚠️ **DŮLEŽITÉ** : Gere chaves secretas únicas! Použijte `openssl rand -hex 32` para cada chave.
|
||||
> ⚠️ **DŮLEŽITÉ**: Vygenerujte jedinečné tajné klíče! Použijte `openssl rand -hex 32` pro každý klíč.
|
||||
|
||||
### 2.3 Spuštění kontejneru
|
||||
|
||||
@@ -147,19 +149,19 @@ Vývojový příklad: `[DB] SQLite database ready` a `listening on port 20128` .
|
||||
|
||||
## 3. Konfigurace nginx (reverzní proxy)
|
||||
|
||||
### 3.1 Gerar Certificado SSL (Cloudflare Origin)
|
||||
### 3.1 Vygenerovat SSL certifikát (Cloudflare Origin)
|
||||
|
||||
Cloudflare nic neřeší:
|
||||
|
||||
1. Používá **SSL/TLS → Origin Server**
|
||||
2. **Certifikát Clique Create**
|
||||
3. Deixe os padrões (15 ano, *.seudominio.com)
|
||||
2. Klikněte na **Vytvořit certifikát**
|
||||
3. Ponechte výchozí nastavení (15 let, \*.vasedomena.com)
|
||||
4. Zkopírujte nebo zkopírujte **certifikát původu** a **soukromý klíč**
|
||||
|
||||
```bash
|
||||
mkdir -p /etc/nginx/ssl
|
||||
|
||||
# Colar o certificado
|
||||
# Vložit certifikát
|
||||
nano /etc/nginx/ssl/origin.crt
|
||||
|
||||
# Colar a chave privada
|
||||
@@ -188,7 +190,7 @@ server {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name llms.seudominio.com; # Altere para seu domínio
|
||||
server_name llms.vasedomena.com; # Změňte na vaši doménu
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/origin.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/origin.key;
|
||||
@@ -220,7 +222,7 @@ server {
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name llms.seudominio.com;
|
||||
server_name llms.vasedomena.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
NGINX
|
||||
@@ -245,11 +247,11 @@ nginx -t && systemctl reload nginx
|
||||
|
||||
### 4.1 Další DNS registr
|
||||
|
||||
No painel da Cloudflare → DNS:
|
||||
V dashboardu Cloudflare → DNS:
|
||||
|
||||
Typ | Jméno | Obsah | Proxy
|
||||
--- | --- | --- | ---
|
||||
A | `llms` | `203.0.113.10` (IP adresa virtuálního počítače) | ✅ Proxy
|
||||
| Typ | Jméno | Obsah | Proxy |
|
||||
| --- | ------ | ----------------------------------------------- | -------- |
|
||||
| A | `llms` | `203.0.113.10` (IP adresa virtuálního počítače) | ✅ Proxy |
|
||||
|
||||
### 4.2 Konfigurace SSL
|
||||
|
||||
@@ -257,7 +259,7 @@ Em **SSL/TLS → Přehled** :
|
||||
|
||||
- Režim: **Plný (Přísný)**
|
||||
|
||||
Em **SSL/TLS → Edge certifikáty** :
|
||||
V **SSL/TLS → Edge Certificates**:
|
||||
|
||||
- Vždy používat HTTPS: ✅ Zapnuto
|
||||
- Minimální verze TLS: TLS 1.2
|
||||
@@ -266,7 +268,7 @@ Em **SSL/TLS → Edge certifikáty** :
|
||||
### 4.3 Testar
|
||||
|
||||
```bash
|
||||
curl -sI https://llms.seudominio.com/health
|
||||
curl -sI https://llms.vasedomena.com/health
|
||||
# Deve retornar HTTP/2 200
|
||||
```
|
||||
|
||||
@@ -289,14 +291,14 @@ docker run -d --name omniroute --restart unless-stopped \
|
||||
### Verzovní protokoly
|
||||
|
||||
```bash
|
||||
docker logs -f omniroute # Stream em tempo real
|
||||
docker logs -f omniroute # Živý stream
|
||||
docker logs omniroute --tail 50 # Últimas 50 linhas
|
||||
```
|
||||
|
||||
### Ruční zálohování banky
|
||||
|
||||
```bash
|
||||
# Copiar dados do volume para o host
|
||||
# Kopírovat data z volume do hostitele
|
||||
docker cp omniroute:/app/data ./backup-$(date +%F)
|
||||
|
||||
# Ou comprimir todo o volume
|
||||
@@ -321,7 +323,7 @@ docker start omniroute
|
||||
|
||||
```bash
|
||||
cat > /etc/nginx/cloudflare-ips.conf << 'CF'
|
||||
# Cloudflare IPv4 ranges — atualizar periodicamente
|
||||
# Cloudflare IPv4 ranges — aktualizovat pravidelně
|
||||
# https://www.cloudflare.com/ips-v4/
|
||||
set_real_ip_from 173.245.48.0/20;
|
||||
set_real_ip_from 103.21.244.0/22;
|
||||
@@ -342,7 +344,7 @@ real_ip_header CF-Connecting-IP;
|
||||
CF
|
||||
```
|
||||
|
||||
Přidat `nginx.conf` dentro do bloco `http {}` :
|
||||
Přidat do `nginx.conf` do bloku `http {}`:
|
||||
|
||||
```nginx
|
||||
include /etc/nginx/cloudflare-ips.conf;
|
||||
@@ -362,7 +364,7 @@ fail2ban-client status sshd
|
||||
### Bloquear accesso direto na port do Docker
|
||||
|
||||
```bash
|
||||
# Impedir acesso externo direto à porta 20128
|
||||
# Zamezit přímému externímu přístupu k portu 20128
|
||||
iptables -I DOCKER-USER -p tcp --dport 20128 -j DROP
|
||||
iptables -I DOCKER-USER -i lo -p tcp --dport 20128 -j ACCEPT
|
||||
|
||||
@@ -389,11 +391,11 @@ Dokumenty jsou kompletní pro [omnirouteCloud/README.md](../omnirouteCloud/READM
|
||||
|
||||
---
|
||||
|
||||
## Resumo de Portas
|
||||
## Přehled portů
|
||||
|
||||
Porta | Služba | Přístup
|
||||
--- | --- | ---
|
||||
22 | SSH | Veřejné (s fail2ban)
|
||||
80 | nginx HTTP | Přesměrování → HTTPS
|
||||
443 | nginx HTTPS | Prostřednictvím proxy serveru Cloudflare
|
||||
20128 | OmniRoute | Někdy na localhostu (přes nginx)
|
||||
| Port | Služba | Přístup |
|
||||
| ----- | ----------- | ---------------------------------------- |
|
||||
| 22 | SSH | Veřejné (s fail2ban) |
|
||||
| 80 | nginx HTTP | Přesměrování → HTTPS |
|
||||
| 443 | nginx HTTPS | Prostřednictvím proxy serveru Cloudflare |
|
||||
| 20128 | OmniRoute | Někdy na localhostu (přes nginx) |
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Vícejazyčná dokumentace</title>
|
||||
<style>
|
||||
/* From extension vscode.github */
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.vscode-dark img[src$=\#gh-light-mode-only],
|
||||
.vscode-light img[src$=\#gh-dark-mode-only],
|
||||
.vscode-high-contrast:not(.vscode-high-contrast-light) img[src$=\#gh-light-mode-only],
|
||||
.vscode-high-contrast-light img[src$=\#gh-dark-mode-only] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.task-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.task-list-item-checkbox {
|
||||
margin-left: -20px;
|
||||
vertical-align: middle;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
:root {
|
||||
--color-note: #0969da;
|
||||
--color-tip: #1a7f37;
|
||||
--color-warning: #9a6700;
|
||||
--color-severe: #bc4c00;
|
||||
--color-caution: #d1242f;
|
||||
--color-important: #8250df;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-note: #2f81f7;
|
||||
--color-tip: #3fb950;
|
||||
--color-warning: #d29922;
|
||||
--color-severe: #db6d28;
|
||||
--color-caution: #f85149;
|
||||
--color-important: #a371f7;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style>
|
||||
.markdown-alert {
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: 16px;
|
||||
color: inherit;
|
||||
border-left: .25em solid #888;
|
||||
}
|
||||
|
||||
.markdown-alert>:first-child {
|
||||
margin-top: 0
|
||||
}
|
||||
|
||||
.markdown-alert>:last-child {
|
||||
margin-bottom: 0
|
||||
}
|
||||
|
||||
.markdown-alert .markdown-alert-title {
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
align-items: center;
|
||||
line-height: 1
|
||||
}
|
||||
|
||||
.markdown-alert .markdown-alert-title .octicon {
|
||||
margin-right: 0.5rem;
|
||||
display: inline-block;
|
||||
overflow: visible !important;
|
||||
vertical-align: text-bottom;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-note {
|
||||
border-left-color: var(--color-note);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-note .markdown-alert-title {
|
||||
color: var(--color-note);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-important {
|
||||
border-left-color: var(--color-important);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-important .markdown-alert-title {
|
||||
color: var(--color-important);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-warning {
|
||||
border-left-color: var(--color-warning);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-warning .markdown-alert-title {
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-tip {
|
||||
border-left-color: var(--color-tip);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-tip .markdown-alert-title {
|
||||
color: var(--color-tip);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-caution {
|
||||
border-left-color: var(--color-caution);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-caution .markdown-alert-title {
|
||||
color: var(--color-caution);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body class="vscode-body vscode-light">
|
||||
<h1 id="vícejazyčná-dokumentace">Vícejazyčná dokumentace</h1>
|
||||
<p>Tento adresář obsahuje strojově asistované překlady založené na anglické dokumentaci.</p>
|
||||
<ul>
|
||||
<li><strong>API_REFERENCE.md</strong> : 🇺🇸 <a href="../API_REFERENCE.html">Česky</a> | 🇧🇷 <a href="./pt-BR/API_REFERENCE.html">Português (Brazílie)</a> | 🇪🇸 <a href="./es/API_REFERENCE.html">Español</a> | 🇫🇷 <a href="./fr/API_REFERENCE.html">Français</a> | 🇮🇹 <a href="./it/API_REFERENCE.html">Italiano</a> | 🇷🇺 <a href="./ru/API_REFERENCE.html">Русский</a> | 🇨🇳<a href="./zh-CN/API_REFERENCE.html">中文 (简体)</a> | 🇩🇪 <a href="./de/API_REFERENCE.html">Deutsch</a> | 🇮🇳 <a href="./in/API_REFERENCE.html">हिन्दी</a> | 🇹🇭 <a href="./th/API_REFERENCE.html">ไทย</a> | 🇺🇦 <a href="./uk-UA/API_REFERENCE.html">Українська</a> | 🇸🇦 <a href="./ar/API_REFERENCE.html">العربية</a> | 🇯🇵<a href="./ja/API_REFERENCE.html">日本語</a>| 🇻🇳 <a href="./vi/API_REFERENCE.html">Tiếng Việt</a> | 🇧🇬 <a href="./bg/API_REFERENCE.html">Български</a> | 🇩🇰 <a href="./da/API_REFERENCE.html">Dánsko</a> | 🇫🇮 <a href="./fi/API_REFERENCE.html">Suomi</a> | 🇮🇱 <a href="./he/API_REFERENCE.html">עברית</a> | 🇭🇺 <a href="./hu/API_REFERENCE.html">maďarština</a> | 🇮🇩 <a href="./id/API_REFERENCE.html">Bahasa Indonésie</a> | 🇰🇷 <a href="./ko/API_REFERENCE.html">한국어</a> | 🇲🇾 <a href="./ms/API_REFERENCE.html">Bahasa Melayu</a> | 🇳🇱 <a href="./nl/API_REFERENCE.html">Nizozemsko</a> | 🇳🇴 <a href="./no/API_REFERENCE.html">Norsk</a> | 🇵🇹 <a href="./pt/API_REFERENCE.html">Português (Portugalsko)</a> | 🇷🇴 <a href="./ro/API_REFERENCE.html">Română</a> | 🇵🇱 <a href="./pl/API_REFERENCE.html">Polski</a> | 🇸🇰 <a href="./sk/API_REFERENCE.html">Slovenčina</a> | 🇸🇪 <a href="./sv/API_REFERENCE.html">Svenska</a> | 🇵🇭 <a href="./phi/API_REFERENCE.html">Filipínec</a></li>
|
||||
<li><strong><a href="http://ARCHITECTURE.html">ARCHITECTURE.md</a></strong> : 🇺🇸 <a href="../ARCHITECTURE.html">anglicky</a> | 🇧🇷 <a href="./pt-BR/ARCHITECTURE.html">Português (Brazílie)</a> | 🇪🇸 <a href="./es/ARCHITECTURE.html">Español</a> | 🇫🇷 <a href="./fr/ARCHITECTURE.html">Français</a> | 🇮🇹 <a href="./it/ARCHITECTURE.html">Italiano</a> | 🇷🇺 <a href="./ru/ARCHITECTURE.html">Русский</a> | 🇨🇳<a href="./zh-CN/ARCHITECTURE.html">中文 (简体)</a> | 🇩🇪 <a href="./de/ARCHITECTURE.html">Deutsch</a> | 🇮🇳 <a href="./in/ARCHITECTURE.html">हिन्दी</a> | 🇹🇭 <a href="./th/ARCHITECTURE.html">ไทย</a> | 🇺🇦 <a href="./uk-UA/ARCHITECTURE.html">Українська</a> | 🇸🇦 <a href="./ar/ARCHITECTURE.html">العربية</a> | 🇯🇵<a href="./ja/ARCHITECTURE.html">日本語</a>| 🇻🇳 <a href="./vi/ARCHITECTURE.html">Tiếng Việt</a> | 🇧🇬 <a href="./bg/ARCHITECTURE.html">Български</a> | 🇩🇰 <a href="./da/ARCHITECTURE.html">Dánsko</a> | 🇫🇮 <a href="./fi/ARCHITECTURE.html">Suomi</a> | 🇮🇱 <a href="./he/ARCHITECTURE.html">עברית</a> | 🇭🇺 <a href="./hu/ARCHITECTURE.html">maďarština</a> | 🇮🇩 <a href="./id/ARCHITECTURE.html">Bahasa Indonésie</a> | 🇰🇷 <a href="./ko/ARCHITECTURE.html">한국어</a> | 🇲🇾 <a href="./ms/ARCHITECTURE.html">Bahasa Melayu</a> | 🇳🇱 <a href="./nl/ARCHITECTURE.html">Nizozemsko</a> | 🇳🇴 <a href="./no/ARCHITECTURE.html">Norsk</a> | 🇵🇹 <a href="./pt/ARCHITECTURE.html">Português (Portugalsko)</a> | 🇷🇴 <a href="./ro/ARCHITECTURE.html">Română</a> | 🇵🇱 <a href="./pl/ARCHITECTURE.html">Polski</a> | 🇸🇰 <a href="./sk/ARCHITECTURE.html">Slovenčina</a> | 🇸🇪 <a href="./sv/ARCHITECTURE.html">Svenska</a> | 🇵🇭 <a href="./phi/ARCHITECTURE.html">Filipínec</a></li>
|
||||
<li><strong>CODEBASE_DOCUMENTATION.md</strong> : 🇺🇸 <a href="../CODEBASE_DOCUMENTATION.html">anglicky</a> | 🇧🇷 <a href="./pt-BR/CODEBASE_DOCUMENTATION.html">Português (Brazílie)</a> | 🇪🇸 <a href="./es/CODEBASE_DOCUMENTATION.html">Español</a> | 🇫🇷 <a href="./fr/CODEBASE_DOCUMENTATION.html">Français</a> | 🇮🇹 <a href="./it/CODEBASE_DOCUMENTATION.html">Italiano</a> | 🇷🇺 <a href="./ru/CODEBASE_DOCUMENTATION.html">Русский</a> | 🇨🇳<a href="./zh-CN/CODEBASE_DOCUMENTATION.html">中文 (简体)</a> | 🇩🇪 <a href="./de/CODEBASE_DOCUMENTATION.html">Deutsch</a> | 🇮🇳 <a href="./in/CODEBASE_DOCUMENTATION.html">हिन्दी</a> | 🇹🇭 <a href="./th/CODEBASE_DOCUMENTATION.html">ไทย</a> | 🇺🇦 <a href="./uk-UA/CODEBASE_DOCUMENTATION.html">Українська</a> | 🇸🇦 <a href="./ar/CODEBASE_DOCUMENTATION.html">العربية</a> | 🇯🇵<a href="./ja/CODEBASE_DOCUMENTATION.html">日本語</a>| 🇻🇳 <a href="./vi/CODEBASE_DOCUMENTATION.html">Tiếng Việt</a> | 🇧🇬 <a href="./bg/CODEBASE_DOCUMENTATION.html">Български</a> | 🇩🇰 <a href="./da/CODEBASE_DOCUMENTATION.html">Dánsko</a> | 🇫🇮 <a href="./fi/CODEBASE_DOCUMENTATION.html">Suomi</a> | 🇮🇱 <a href="./he/CODEBASE_DOCUMENTATION.html">עברית</a> | 🇭🇺 <a href="./hu/CODEBASE_DOCUMENTATION.html">maďarština</a> | 🇮🇩 <a href="./id/CODEBASE_DOCUMENTATION.html">Bahasa Indonésie</a> | 🇰🇷 <a href="./ko/CODEBASE_DOCUMENTATION.html">한국어</a> | 🇲🇾 <a href="./ms/CODEBASE_DOCUMENTATION.html">Bahasa Melayu</a> | 🇳🇱 <a href="./nl/CODEBASE_DOCUMENTATION.html">Nizozemsko</a> | 🇳🇴 <a href="./no/CODEBASE_DOCUMENTATION.html">Norsk</a> | 🇵🇹 <a href="./pt/CODEBASE_DOCUMENTATION.html">Português (Portugalsko)</a> | 🇷🇴 <a href="./ro/CODEBASE_DOCUMENTATION.html">Română</a> | 🇵🇱 <a href="./pl/CODEBASE_DOCUMENTATION.html">Polski</a> | 🇸🇰 <a href="./sk/CODEBASE_DOCUMENTATION.html">Slovenčina</a> | 🇸🇪 <a href="./sv/CODEBASE_DOCUMENTATION.html">Svenska</a> | 🇵🇭 <a href="./phi/CODEBASE_DOCUMENTATION.html">Filipínec</a></li>
|
||||
<li><strong><a href="http://FEATURES.html">FEATURES.md</a></strong> : 🇺🇸 <a href="../FEATURES.html">anglicky</a> | 🇧🇷 <a href="./pt-BR/FEATURES.html">Português (Brazílie)</a> | 🇪🇸 <a href="./es/FEATURES.html">Español</a> | 🇫🇷 <a href="./fr/FEATURES.html">Français</a> | 🇮🇹 <a href="./it/FEATURES.html">Italiano</a> | 🇷🇺 <a href="./ru/FEATURES.html">Русский</a> | 🇨🇳<a href="./zh-CN/FEATURES.html">中文 (简体)</a> | 🇩🇪 <a href="./de/FEATURES.html">Deutsch</a> | 🇮🇳 <a href="./in/FEATURES.html">हिन्दी</a> | 🇹🇭 <a href="./th/FEATURES.html">ไทย</a> | 🇺🇦 <a href="./uk-UA/FEATURES.html">Українська</a> | 🇸🇦 <a href="./ar/FEATURES.html">العربية</a> | 🇯🇵<a href="./ja/FEATURES.html">日本語</a>| 🇻🇳 <a href="./vi/FEATURES.html">Tiếng Việt</a> | 🇧🇬 <a href="./bg/FEATURES.html">Български</a> | 🇩🇰 <a href="./da/FEATURES.html">Dánsko</a> | 🇫🇮 <a href="./fi/FEATURES.html">Suomi</a> | 🇮🇱 <a href="./he/FEATURES.html">עברית</a> | 🇭🇺 <a href="./hu/FEATURES.html">maďarština</a> | 🇮🇩 <a href="./id/FEATURES.html">Bahasa Indonésie</a> | 🇰🇷 <a href="./ko/FEATURES.html">한국어</a> | 🇲🇾 <a href="./ms/FEATURES.html">Bahasa Melayu</a> | 🇳🇱 <a href="./nl/FEATURES.html">Nizozemsko</a> | 🇳🇴 <a href="./no/FEATURES.html">Norsk</a> | 🇵🇹 <a href="./pt/FEATURES.html">Português (Portugalsko)</a> | 🇷🇴 <a href="./ro/FEATURES.html">Română</a> | 🇵🇱 <a href="./pl/FEATURES.html">Polski</a> | 🇸🇰 <a href="./sk/FEATURES.html">Slovenčina</a> | 🇸🇪 <a href="./sv/FEATURES.html">Svenska</a> | 🇵🇭 <a href="./phi/FEATURES.html">Filipínec</a></li>
|
||||
<li><strong><a href="http://TOUBLESHOOTING.html">TOUBLESHOOTING.md</a></strong> : 🇺🇸 <a href="../TROUBLESHOOTING.html">anglicky</a> | 🇧🇷 <a href="./pt-BR/TROUBLESHOOTING.html">Português (Brazílie)</a> | 🇪🇸 <a href="./es/TROUBLESHOOTING.html">Español</a> | 🇫🇷 <a href="./fr/TROUBLESHOOTING.html">Français</a> | 🇮🇹 <a href="./it/TROUBLESHOOTING.html">Italiano</a> | 🇷🇺 <a href="./ru/TROUBLESHOOTING.html">Русский</a> | 🇨🇳<a href="./zh-CN/TROUBLESHOOTING.html">中文 (简体)</a> | 🇩🇪 <a href="./de/TROUBLESHOOTING.html">Deutsch</a> | 🇮🇳 <a href="./in/TROUBLESHOOTING.html">हिन्दी</a> | 🇹🇭 <a href="./th/TROUBLESHOOTING.html">ไทย</a> | 🇺🇦 <a href="./uk-UA/TROUBLESHOOTING.html">Українська</a> | 🇸🇦 <a href="./ar/TROUBLESHOOTING.html">العربية</a> | 🇯🇵<a href="./ja/TROUBLESHOOTING.html">日本語</a>| 🇻🇳 <a href="./vi/TROUBLESHOOTING.html">Tiếng Việt</a> | 🇧🇬 <a href="./bg/TROUBLESHOOTING.html">Български</a> | 🇩🇰 <a href="./da/TROUBLESHOOTING.html">Dánsko</a> | 🇫🇮 <a href="./fi/TROUBLESHOOTING.html">Suomi</a> | 🇮🇱 <a href="./he/TROUBLESHOOTING.html">עברית</a> | 🇭🇺 <a href="./hu/TROUBLESHOOTING.html">maďarština</a> | 🇮🇩 <a href="./id/TROUBLESHOOTING.html">Bahasa Indonésie</a> | 🇰🇷 <a href="./ko/TROUBLESHOOTING.html">한국어</a> | 🇲🇾 <a href="./ms/TROUBLESHOOTING.html">Bahasa Melayu</a> | 🇳🇱 <a href="./nl/TROUBLESHOOTING.html">Nizozemsko</a> | 🇳🇴 <a href="./no/TROUBLESHOOTING.html">Norsk</a> | 🇵🇹 <a href="./pt/TROUBLESHOOTING.html">Português (Portugalsko)</a> | 🇷🇴 <a href="./ro/TROUBLESHOOTING.html">Română</a> | 🇵🇱 <a href="./pl/TROUBLESHOOTING.html">Polski</a> | 🇸🇰 <a href="./sk/TROUBLESHOOTING.html">Slovenčina</a> | 🇸🇪 <a href="./sv/TROUBLESHOOTING.html">Svenska</a> | 🇵🇭 <a href="./phi/TROUBLESHOOTING.html">Filipínec</a></li>
|
||||
<li><strong>USER_GUIDE.md</strong> : 🇺🇸 <a href="../USER_GUIDE.html">anglicky</a> | 🇧🇷 <a href="./pt-BR/USER_GUIDE.html">Português (Brazílie)</a> | 🇪🇸 <a href="./es/USER_GUIDE.html">Español</a> | 🇫🇷 <a href="./fr/USER_GUIDE.html">Français</a> | 🇮🇹 <a href="./it/USER_GUIDE.html">Italiano</a> | 🇷🇺 <a href="./ru/USER_GUIDE.html">Русский</a> | 🇨🇳<a href="./zh-CN/USER_GUIDE.html">中文 (简体)</a> | 🇩🇪 <a href="./de/USER_GUIDE.html">Deutsch</a> | 🇮🇳 <a href="./in/USER_GUIDE.html">हिन्दी</a> | 🇹🇭 <a href="./th/USER_GUIDE.html">ไทย</a> | 🇺🇦 <a href="./uk-UA/USER_GUIDE.html">Українська</a> | 🇸🇦 <a href="./ar/USER_GUIDE.html">العربية</a> | 🇯🇵<a href="./ja/USER_GUIDE.html">日本語</a>| 🇻🇳 <a href="./vi/USER_GUIDE.html">Tiếng Việt</a> | 🇧🇬 <a href="./bg/USER_GUIDE.html">Български</a> | 🇩🇰 <a href="./da/USER_GUIDE.html">Dánsko</a> | 🇫🇮 <a href="./fi/USER_GUIDE.html">Suomi</a> | 🇮🇱 <a href="./he/USER_GUIDE.html">עברית</a> | 🇭🇺 <a href="./hu/USER_GUIDE.html">maďarština</a> | 🇮🇩 <a href="./id/USER_GUIDE.html">Bahasa Indonésie</a> | 🇰🇷 <a href="./ko/USER_GUIDE.html">한국어</a> | 🇲🇾 <a href="./ms/USER_GUIDE.html">Bahasa Melayu</a> | 🇳🇱 <a href="./nl/USER_GUIDE.html">Nizozemsko</a> | 🇳🇴 <a href="./no/USER_GUIDE.html">Norsk</a> | 🇵🇹 <a href="./pt/USER_GUIDE.html">Português (Portugalsko)</a> | 🇷🇴 <a href="./ro/USER_GUIDE.html">Română</a> | 🇵🇱 <a href="./pl/USER_GUIDE.html">Polski</a> | 🇸🇰 <a href="./sk/USER_GUIDE.html">Slovenčina</a> | 🇸🇪 <a href="./sv/USER_GUIDE.html">Svenska</a> | 🇵🇭 <a href="./phi/USER_GUIDE.html">Filipínec</a></li>
|
||||
</ul>
|
||||
<h2 id="nedávná-poznámka-zásady-limitů-pro-účty-codex">Nedávná poznámka: Zásady limitů pro účty Codex</h2>
|
||||
<p>Dokumentace nyní zahrnuje chování zásad kvót na úrovni účtu Codex:</p>
|
||||
<ul>
|
||||
<li>Přepínání pro jednotlivé účty: <code>5h</code> a <code>Weekly</code> (ZAP/VYP).</li>
|
||||
<li>Zásady prahových hodnot: povolené okno dosahující >=90 % označuje účet jako nezpůsobilý k výběru.</li>
|
||||
<li>Automatická rotace: provoz se přesune na další způsobilý účet Codex.</li>
|
||||
<li>Automatické opětovné použití: účet se opět stane způsobilým po úspěšném <code>resetAt</code> poskytovatele.</li>
|
||||
</ul>
|
||||
<p>Vygenerováno 26. února 2026.</p>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: OmniRoute API
|
||||
version: 3.1.2
|
||||
version: 3.1.3
|
||||
description: |
|
||||
OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible
|
||||
endpoint that routes requests to multiple AI providers with load balancing,
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "omniroute",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
173
scripts/check_translations.py
Executable file
173
scripts/check_translations.py
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Translation check script for OmniRoute.
|
||||
Checks if all translation keys used in code exist in en.json.
|
||||
|
||||
Usage:
|
||||
python scripts/check_translations.py
|
||||
python scripts/check_translations.py --verbose
|
||||
python scripts/check_translations.py --fix
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
|
||||
def get_namespaces_in_code(src_dir='src'):
|
||||
"""Find all namespaces used in code via useTranslations()."""
|
||||
used_ns = set()
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
for f in files:
|
||||
if not (f.endswith('.tsx') or f.endswith('.ts')):
|
||||
continue
|
||||
try:
|
||||
content = open(os.path.join(root, f), 'r', encoding='utf-8').read()
|
||||
matches = re.findall(r'useTranslations\(["\']+([^"\']+)["\']+\)', content)
|
||||
used_ns.update(matches)
|
||||
except (IOError, UnicodeDecodeError) as e:
|
||||
print(f"Warning: could not process file {os.path.join(root, f)}: {e}", file=sys.stderr)
|
||||
return used_ns
|
||||
|
||||
|
||||
def get_keys_in_json(json_path):
|
||||
"""Get all keys (including nested) from a JSON file."""
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
keys = set()
|
||||
|
||||
def traverse(obj, prefix=''):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
key = f"{prefix}.{k}" if prefix else k
|
||||
keys.add(key)
|
||||
if isinstance(v, dict):
|
||||
traverse(v, key)
|
||||
elif isinstance(obj, list):
|
||||
for item in obj:
|
||||
traverse(item, prefix)
|
||||
|
||||
traverse(data)
|
||||
return keys
|
||||
|
||||
|
||||
def check_translations(src_dir='src', en_json_path='src/i18n/messages/en.json', verbose=False):
|
||||
"""Check if all translation keys used in code exist in en.json."""
|
||||
# Get namespaces used in code
|
||||
used_ns = get_namespaces_in_code(src_dir)
|
||||
|
||||
# Get namespaces in en.json
|
||||
with open(en_json_path, 'r', encoding='utf-8') as f:
|
||||
en_data = json.load(f)
|
||||
en_ns = set(en_data.keys())
|
||||
|
||||
# Find missing namespaces
|
||||
missing_ns = sorted(used_ns - en_ns)
|
||||
|
||||
# Get all keys from en.json
|
||||
en_keys = get_keys_in_json(en_json_path)
|
||||
|
||||
# Get all keys used in code
|
||||
used_keys = set()
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
for f in files:
|
||||
if not (f.endswith('.tsx') or f.endswith('.ts')):
|
||||
continue
|
||||
try:
|
||||
content = open(os.path.join(root, f), 'r', encoding='utf-8').read()
|
||||
matches = re.findall(r't\([\'"]+([^\'")]+)[\'"]+\)', content)
|
||||
used_keys.update(matches)
|
||||
except (IOError, UnicodeDecodeError) as e:
|
||||
print(f"Warning: could not process file {os.path.join(root, f)}: {e}", file=sys.stderr)
|
||||
|
||||
# Filter out non-translation keys
|
||||
# Note: check if key IS a path or ends with extension, not just contains it
|
||||
# e.g., "invoice.ts.description" (ts = timestamp) should NOT be filtered
|
||||
# but "components/Button.tsx" or "utils.ts" should be
|
||||
def is_likely_file_path(key: str) -> bool:
|
||||
if key.endswith('.ts') or key.endswith('.tsx') or key.endswith('.js') or key.endswith('.json'):
|
||||
return True
|
||||
if '/.ts' in key or '/.tsx' in key or '/.js' in key or '/.json' in key:
|
||||
return True
|
||||
if '\\.ts' in key or '\\.tsx' in key or '\\.js' in key or '\\.json' in key:
|
||||
return True
|
||||
return False
|
||||
|
||||
filtered = {k for k in used_keys if len(k) > 1
|
||||
and not any(x in k for x in ['../', '@', '\\', '#', '?'])
|
||||
and not is_likely_file_path(k)
|
||||
and k not in ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH']
|
||||
and not k.startswith('#')
|
||||
and k not in [',', '-', '.', ':', '?', ' ', '']}
|
||||
|
||||
# Find missing keys
|
||||
real_missing = []
|
||||
for k in filtered:
|
||||
if k in en_keys:
|
||||
continue
|
||||
|
||||
# Check if key matches any full key in en.json
|
||||
matched = False
|
||||
for ek in en_keys:
|
||||
if k in ek or ek.endswith(k):
|
||||
matched = True
|
||||
break
|
||||
|
||||
if matched:
|
||||
continue
|
||||
|
||||
# Filter out paths and obvious non-translations
|
||||
if k.startswith('./') or k.startswith('/') or k.startswith('x-') or k.startswith('user-'):
|
||||
continue
|
||||
# Use same logic - check if key IS a path or ends with extension
|
||||
if is_likely_file_path(k):
|
||||
continue
|
||||
if k in ['Authorization', 'Content-Disposition', 'IOPlatformUUID', 'REG_SZ']:
|
||||
continue
|
||||
|
||||
real_missing.append(k)
|
||||
|
||||
return missing_ns, sorted(real_missing)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Check translation keys in en.json')
|
||||
parser.add_argument('--verbose', '-v', action='store_true', help='Show detailed output')
|
||||
parser.add_argument('--fix', action='store_true', help='Generate fix suggestions')
|
||||
parser.add_argument('--src', default='src', help='Source directory')
|
||||
parser.add_argument('--json', default='src/i18n/messages/en.json', help='Path to en.json')
|
||||
args = parser.parse_args()
|
||||
|
||||
missing_ns, missing_keys = check_translations(args.src, args.json, args.verbose)
|
||||
|
||||
has_issues = False
|
||||
|
||||
if missing_ns:
|
||||
has_issues = True
|
||||
print("=== MISSING NAMESPACES ===")
|
||||
for ns in missing_ns:
|
||||
print(f" - {ns}")
|
||||
if args.fix:
|
||||
print(f" → Add '{ns}' section to en.json")
|
||||
|
||||
if missing_keys:
|
||||
has_issues = True
|
||||
print("\n=== MISSING TRANSLATION KEYS ===")
|
||||
for k in missing_keys:
|
||||
print(f" - {k}")
|
||||
if args.fix:
|
||||
print(f" → Add to appropriate namespace in en.json")
|
||||
|
||||
if not has_issues:
|
||||
print("✓ All translation namespaces and keys are present in en.json")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(f"\nTotal: {len(missing_ns)} namespace(s), {len(missing_keys)} key(s) missing")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
584
scripts/validate_translation.py
Executable file
584
scripts/validate_translation.py
Executable file
@@ -0,0 +1,584 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
OmniRoute i18n Translation Validator
|
||||
Script for comparing source (en.json) with any translation
|
||||
Detects missing translations and source changes needing updates
|
||||
|
||||
Usage:
|
||||
python validate_translation.py # Uses TRANSLATION_LANG env or --lang argument
|
||||
python validate_translation.py --lang cs # Validate Czech (cs.json)
|
||||
python validate_translation.py -l de # Validate German (de.json)
|
||||
TRANSLATION_LANG=fr python validate_translation.py # Validate French
|
||||
|
||||
Environment variables:
|
||||
TRANSLATION_LANG Target language code (e.g., cs, de, fr)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Set, Tuple, Any
|
||||
import argparse
|
||||
|
||||
# Colors (ANSI)
|
||||
RED = '\033[0;31m'
|
||||
GREEN = '\033[0;32m'
|
||||
YELLOW = '\033[1;33m'
|
||||
BLUE = '\033[0;34m'
|
||||
NC = '\033[0m'
|
||||
|
||||
# Configuration - find repo root relative to this script
|
||||
_script_dir = Path(__file__).parent.resolve()
|
||||
# If script is in scripts/ subfolder, go up one level to repo root
|
||||
if _script_dir.name == "scripts":
|
||||
SCRIPT_DIR = _script_dir.parent
|
||||
else:
|
||||
SCRIPT_DIR = _script_dir
|
||||
|
||||
MESSAGES_DIR = SCRIPT_DIR / "src" / "i18n" / "messages"
|
||||
SOURCE_FILE = MESSAGES_DIR / "en.json"
|
||||
|
||||
# Get target language from env or argument
|
||||
def get_target_lang() -> str:
|
||||
"""Get target language from ENV or CLI argument."""
|
||||
# First check environment variable
|
||||
env_lang = os.environ.get('TRANSLATION_LANG')
|
||||
if env_lang:
|
||||
return env_lang
|
||||
|
||||
# Then check command line argument (will be set in main)
|
||||
if hasattr(get_target_lang, 'cli_lang'):
|
||||
return get_target_lang.cli_lang
|
||||
|
||||
# Default to cs for backwards compatibility
|
||||
return "cs"
|
||||
|
||||
# Keys that should NOT be translated (technical terms, proper names, etc.)
|
||||
UNTRANSLATABLE_KEYS = {
|
||||
# ICU/Plural formats
|
||||
"apiManager.modelsCount",
|
||||
# Technical/Protocol names
|
||||
"a2aDashboard.metadata",
|
||||
"a2aDashboard.ok",
|
||||
"a2aDashboard.url",
|
||||
"cliTools.baseUrlPlaceholder",
|
||||
"cliTools.platforms",
|
||||
"cliTools.toolDescriptions.claude",
|
||||
"cliTools.toolDescriptions.codex",
|
||||
"cliTools.toolDescriptions.cursor",
|
||||
"combos.roundRobin",
|
||||
"common.model",
|
||||
"docs.clientCherryStudioTitle",
|
||||
"docs.clientClaudeTitle",
|
||||
"docs.clientCursorTitle",
|
||||
"docs.github",
|
||||
"docs.protocolA2aTitle",
|
||||
"docs.protocolMcpTitle",
|
||||
"endpoint.chat",
|
||||
"endpoint.chatCompletions",
|
||||
"endpoint.cloudProxy",
|
||||
"endpoint.mcpCardTitle",
|
||||
"endpoint.rerank",
|
||||
"header.a2a",
|
||||
"header.mcp",
|
||||
"health.cpu",
|
||||
"health.latencyP50",
|
||||
"health.latencyP95",
|
||||
"health.latencyP99",
|
||||
"health.millisecondsShort",
|
||||
"health.notAvailable",
|
||||
"health.ok",
|
||||
"home.aliasLabel",
|
||||
"home.oauthLabel",
|
||||
"landing.brandName",
|
||||
"landing.flowProviderAnthropic",
|
||||
"landing.flowProviderGemini",
|
||||
"landing.flowProviderGithubCopilot",
|
||||
"landing.flowProviderOpenAI",
|
||||
"landing.flowToolClaudeCode",
|
||||
"landing.flowToolCline",
|
||||
"landing.flowToolCursor",
|
||||
"landing.flowToolOpenAICodex",
|
||||
"landing.github",
|
||||
"legal.terms",
|
||||
"legal.privacy",
|
||||
"logs.endpoint",
|
||||
"logs.proxy",
|
||||
"logs.console",
|
||||
"logs.request",
|
||||
"logs.audit",
|
||||
"media.interpolation",
|
||||
"media.upscale",
|
||||
"media.samples",
|
||||
"search.search",
|
||||
"search.searchTools",
|
||||
"search.webSearch",
|
||||
"search.fileSearch",
|
||||
"settings.theme",
|
||||
"settings.language",
|
||||
"settings.currency",
|
||||
"settings.timezone",
|
||||
"stats.requests",
|
||||
"stats.tokens",
|
||||
"stats.latency",
|
||||
"stats.errors",
|
||||
"themesPage.dark",
|
||||
"themesPage.light",
|
||||
"themesPage.system",
|
||||
"translator.translate",
|
||||
"translator.translateFrom",
|
||||
"translator.translateTo",
|
||||
"translator.detect",
|
||||
"translator.detectedLanguage",
|
||||
"usage.totalRequests",
|
||||
"usage.totalTokens",
|
||||
"usage.inputTokens",
|
||||
"usage.outputTokens",
|
||||
"usage.promptTokens",
|
||||
"usage.completionTokens",
|
||||
"usage.cacheReadTokens",
|
||||
"usage.cacheWriteTokens",
|
||||
}
|
||||
|
||||
|
||||
def print_header(msg: str) -> None:
|
||||
print(f"\n{BLUE}{'='*50}{NC}")
|
||||
print(f"{BLUE}{msg}{NC}")
|
||||
print(f"{BLUE}{'='*50}{NC}")
|
||||
|
||||
|
||||
def print_success(msg: str) -> None:
|
||||
print(f"{GREEN}✓ {msg}{NC}")
|
||||
|
||||
|
||||
def print_warning(msg: str) -> None:
|
||||
print(f"{YELLOW}⚠ {msg}{NC}")
|
||||
|
||||
|
||||
def print_error(msg: str) -> None:
|
||||
print(f"{RED}✗ {msg}{NC}")
|
||||
|
||||
|
||||
def load_json(path: Path) -> Dict:
|
||||
"""Load JSON file"""
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print_error(f"Invalid JSON in {path}: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_all_keys(obj: Any, prefix: str = "") -> Set[str]:
|
||||
"""Recursively get all leaf keys from JSON object"""
|
||||
keys = set()
|
||||
if isinstance(obj, dict):
|
||||
for key, value in obj.items():
|
||||
new_prefix = f"{prefix}.{key}" if prefix else key
|
||||
if isinstance(value, dict):
|
||||
keys.update(get_all_keys(value, new_prefix))
|
||||
elif isinstance(value, list):
|
||||
# Handle arrays - check first element for structure
|
||||
if value and isinstance(value[0], dict):
|
||||
for i, item in enumerate(value):
|
||||
keys.update(get_all_keys(item, f"{new_prefix}[{i}]"))
|
||||
else:
|
||||
keys.add(new_prefix)
|
||||
else:
|
||||
keys.add(new_prefix)
|
||||
return keys
|
||||
|
||||
|
||||
def find_missing_keys(source: Dict, trans: Dict) -> Set[str]:
|
||||
"""Keys in source but not in translation"""
|
||||
source_keys = get_all_keys(source)
|
||||
trans_keys = get_all_keys(trans)
|
||||
return source_keys - trans_keys
|
||||
|
||||
|
||||
def find_extra_keys(source: Dict, trans: Dict) -> Set[str]:
|
||||
"""Keys in translation but not in source"""
|
||||
source_keys = get_all_keys(source)
|
||||
trans_keys = get_all_keys(trans)
|
||||
return trans_keys - source_keys
|
||||
|
||||
|
||||
def get_value_by_path(obj: Dict, path: str) -> Any:
|
||||
"""Get value from nested dict using dot notation"""
|
||||
keys = path.replace('[', '.').replace(']', '').split('.')
|
||||
current = obj
|
||||
for key in keys:
|
||||
if key.isdigit():
|
||||
idx = int(key)
|
||||
if isinstance(current, list) and idx < len(current):
|
||||
current = current[idx]
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(current, dict) and key in current:
|
||||
current = current[key]
|
||||
else:
|
||||
return None
|
||||
return current
|
||||
|
||||
|
||||
def find_untranslated(source: Dict, trans: Dict) -> Set[str]:
|
||||
"""Keys where source value equals translation (not translated), excluding untranslatable keys"""
|
||||
source_keys = get_all_keys(source)
|
||||
untranslated = set()
|
||||
|
||||
for key in source_keys:
|
||||
# Skip keys that are in the untranslatable list
|
||||
if key in UNTRANSLATABLE_KEYS:
|
||||
continue
|
||||
|
||||
source_val = get_value_by_path(source, key)
|
||||
trans_val = get_value_by_path(trans, key)
|
||||
|
||||
if source_val is not None and source_val == trans_val:
|
||||
untranslated.add(key)
|
||||
|
||||
return untranslated
|
||||
|
||||
|
||||
def compare_category(source: Dict, trans: Dict, category: str) -> Tuple[bool, List[str]]:
|
||||
"""Compare a specific category, return (complete, missing_keys)"""
|
||||
if category not in source:
|
||||
return False, [f"Category '{category}' not in source"]
|
||||
|
||||
if category not in trans:
|
||||
return False, [f"Category '{category}' missing in translation"]
|
||||
|
||||
source_keys = get_all_keys(source[category])
|
||||
trans_keys = get_all_keys(trans[category])
|
||||
missing = source_keys - trans_keys
|
||||
|
||||
return len(missing) == 0, list(missing)
|
||||
|
||||
|
||||
def get_translation_file() -> Path:
|
||||
"""Get the translation file path based on target language."""
|
||||
lang = get_target_lang()
|
||||
return MESSAGES_DIR / f"{lang}.json"
|
||||
|
||||
|
||||
def generate_report():
|
||||
"""Generate full translation report"""
|
||||
translation_file = get_translation_file()
|
||||
print_header("OmniRoute Translation Report")
|
||||
print(f"Source: {SOURCE_FILE}")
|
||||
print(f"Translation: {translation_file}\n")
|
||||
|
||||
source = load_json(SOURCE_FILE)
|
||||
trans = load_json(translation_file)
|
||||
|
||||
# Count keys
|
||||
source_count = len(get_all_keys(source))
|
||||
trans_count = len(get_all_keys(trans))
|
||||
|
||||
print(f"{BLUE}Key Statistics:{NC}")
|
||||
print(f" Source keys: {source_count}")
|
||||
print(f" Translation keys: {trans_count}\n")
|
||||
|
||||
# Missing keys
|
||||
print_header("Missing Translations")
|
||||
missing = find_missing_keys(source, trans)
|
||||
if missing:
|
||||
print(f"{RED}Found {len(missing)} missing keys:{NC}")
|
||||
for key in sorted(missing)[:50]: # Limit output
|
||||
print(f" - {key}")
|
||||
if len(missing) > 50:
|
||||
print(f" ... and {len(missing) - 50} more")
|
||||
else:
|
||||
print_success("No missing translations!")
|
||||
|
||||
# Extra keys
|
||||
print_header("Extra Keys")
|
||||
extra = find_extra_keys(source, trans)
|
||||
if extra:
|
||||
print(f"{YELLOW}Found {len(extra)} extra keys:{NC}")
|
||||
for key in sorted(extra)[:50]:
|
||||
print(f" - {key}")
|
||||
else:
|
||||
print_success("No extra keys!")
|
||||
|
||||
# Untranslated
|
||||
print_header("Untranslated Keys (same as source)")
|
||||
untranslated = find_untranslated(source, trans)
|
||||
if untranslated:
|
||||
print(f"{YELLOW}Found {len(untranslated)} untranslated keys:{NC}")
|
||||
for key in sorted(untranslated)[:50]:
|
||||
print(f" - {key}")
|
||||
if len(untranslated) > 50:
|
||||
print(f" ... and {len(untranslated) - 50} more")
|
||||
else:
|
||||
print_success("All keys appear to be translated!")
|
||||
|
||||
# Per-category status
|
||||
print_header("Per-Category Status")
|
||||
for category in sorted(source.keys()):
|
||||
complete, missing = compare_category(source, trans, category)
|
||||
if complete:
|
||||
print_success(f"{category} - complete")
|
||||
else:
|
||||
print_error(f"{category} - missing {len(missing)} keys")
|
||||
|
||||
# Summary
|
||||
print_header("Summary")
|
||||
if not missing and not extra and not untranslated:
|
||||
print(f"{GREEN}🎉 Translation is fully synchronized!{NC}")
|
||||
return 0
|
||||
else:
|
||||
print(f"{RED}Translation needs attention:{NC}")
|
||||
print(f" - Missing: {len(missing)}")
|
||||
print(f" - Extra: {len(extra)}")
|
||||
print(f" - Untranslated: {len(untranslated)}")
|
||||
return 1
|
||||
|
||||
|
||||
def quick_check() -> int:
|
||||
"""Quick check - just show counts"""
|
||||
translation_file = get_translation_file()
|
||||
source = load_json(SOURCE_FILE)
|
||||
trans = load_json(translation_file)
|
||||
|
||||
missing = find_missing_keys(source, trans)
|
||||
untranslated = find_untranslated(source, trans)
|
||||
|
||||
print(f"Missing: {len(missing)}")
|
||||
print(f"Untranslated: {len(untranslated)}")
|
||||
|
||||
return 0 if not missing and not untranslated else 1
|
||||
|
||||
|
||||
def show_diff(category: str) -> int:
|
||||
"""Show detailed diff for a category"""
|
||||
translation_file = get_translation_file()
|
||||
source = load_json(SOURCE_FILE)
|
||||
trans = load_json(translation_file)
|
||||
|
||||
if category not in source:
|
||||
print_error(f"Category '{category}' not found in source")
|
||||
print("Available categories:")
|
||||
for cat in sorted(source.keys()):
|
||||
print(f" - {cat}")
|
||||
return 1
|
||||
|
||||
print_header(f"Diff for category: {category}")
|
||||
|
||||
print(f"{BLUE}{'Key':<30} | {'Source':<25} | {'Translation':<25}{NC}")
|
||||
print("-" * 85)
|
||||
|
||||
source_keys = get_all_keys(source[category])
|
||||
|
||||
for key in sorted(source_keys):
|
||||
source_val = get_value_by_path(source[category], key)
|
||||
trans_val = get_value_by_path(trans.get(category, {}), key)
|
||||
|
||||
# Truncate long values
|
||||
source_str = str(source_val)[:25] if source_val else "(null)"
|
||||
trans_str = str(trans_val)[:25] if trans_val else "(missing)"
|
||||
|
||||
if source_val == trans_val:
|
||||
status = f"{YELLOW}(same){NC}"
|
||||
elif trans_val is None:
|
||||
status = f"{RED}(missing){NC}"
|
||||
else:
|
||||
status = f"{GREEN}(ok){NC}"
|
||||
|
||||
print(f"{key:<30} | {source_str:<25} | {trans_str:<25} {status}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def export_csv(output_file: str) -> int:
|
||||
"""Export to CSV"""
|
||||
translation_file = get_translation_file()
|
||||
source = load_json(SOURCE_FILE)
|
||||
trans = load_json(translation_file)
|
||||
|
||||
print_header(f"Exporting to CSV: {output_file}")
|
||||
|
||||
source_keys = get_all_keys(source)
|
||||
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write("key,source_value,translation_value,status\n")
|
||||
|
||||
for key in sorted(source_keys):
|
||||
source_val = get_value_by_path(source, key)
|
||||
trans_val = get_value_by_path(trans, key)
|
||||
|
||||
# Escape commas
|
||||
source_str = str(source_val).replace(',', ';')
|
||||
trans_str = str(trans_val).replace(',', ';') if trans_val else ""
|
||||
|
||||
if trans_val is None:
|
||||
status = "MISSING"
|
||||
elif source_val == trans_val:
|
||||
status = "UNTRANSLATED"
|
||||
else:
|
||||
status = "OK"
|
||||
|
||||
f.write(f'"{key}","{source_str}","{trans_str}",{status}\n')
|
||||
|
||||
print_success(f"Exported to {output_file}")
|
||||
return 0
|
||||
|
||||
|
||||
def export_markdown(output_file: str) -> int:
|
||||
"""Export all keys to separate Markdown files - translated and untranslated"""
|
||||
translation_file = get_translation_file()
|
||||
source = load_json(SOURCE_FILE)
|
||||
trans = load_json(translation_file)
|
||||
|
||||
print_header(f"Exporting to Markdown: {output_file}")
|
||||
|
||||
source_keys = get_all_keys(source)
|
||||
missing = find_missing_keys(source, trans)
|
||||
untranslated = find_untranslated(source, trans)
|
||||
|
||||
# Separate translated and untranslated
|
||||
translated_keys = []
|
||||
untranslated_sorted = sorted(untranslated)
|
||||
|
||||
for key in sorted(source_keys):
|
||||
if key not in missing and key not in untranslated:
|
||||
translated_keys.append(key)
|
||||
|
||||
translated_count = len(translated_keys)
|
||||
untranslated_count = len(untranslated_sorted)
|
||||
|
||||
# Export untranslated (main output file)
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write("# Nepřeložené klíče (Untranslated Keys)\n\n")
|
||||
f.write(f"Zdroj: `{SOURCE_FILE.name}` | Překlad: `{TRANSLATION_FILE.name}`\n\n")
|
||||
|
||||
f.write(f"**Celkem: {untranslated_count} nepreložených klíčů**\n\n")
|
||||
|
||||
f.write("| # | Klíč (Key) | Originál | Nepřeloženo |\n")
|
||||
f.write("|---|------------|----------|------------|\n")
|
||||
|
||||
for i, key in enumerate(untranslated_sorted, 1):
|
||||
source_val = get_value_by_path(source, key)
|
||||
trans_val = get_value_by_path(trans, key)
|
||||
|
||||
source_str = str(source_val).replace('|', '\\|')[:60]
|
||||
trans_str = str(trans_val).replace('|', '\\|')[:60]
|
||||
|
||||
f.write(f"| {i} | `{key}` | {source_str} | {trans_str} |\n")
|
||||
|
||||
f.write("\n## Shrnutí (Summary)\n\n")
|
||||
f.write(f"- Celkem klíčů: {len(source_keys)}\n")
|
||||
f.write(f"- Chybějících: {len(missing)}\n")
|
||||
f.write(f"- Nepřeložených: {untranslated_count}\n")
|
||||
f.write(f"- Přeložených: {translated_count}\n")
|
||||
|
||||
# Export translated to separate file
|
||||
translated_file = output_file.replace('.md', '_translated.md')
|
||||
translation_filename = translation_file.name
|
||||
with open(translated_file, 'w', encoding='utf-8') as f:
|
||||
f.write("# Přeložené klíče (Translated Keys)\n\n")
|
||||
f.write(f"Zdroj: `{SOURCE_FILE.name}` | Překlad: `{translation_filename}`\n\n")
|
||||
|
||||
f.write(f"**Celkem: {translated_count} přeložených klíčů**\n\n")
|
||||
|
||||
f.write("| # | Klíč (Key) | Originál | Překlad |\n")
|
||||
f.write("|---|------------|----------|---------|\n")
|
||||
|
||||
for i, key in enumerate(translated_keys, 1):
|
||||
source_val = get_value_by_path(source, key)
|
||||
trans_val = get_value_by_path(trans, key)
|
||||
|
||||
source_str = str(source_val).replace('|', '\\|')[:40]
|
||||
trans_str = str(trans_val).replace('|', '\\|')[:40]
|
||||
|
||||
f.write(f"| {i} | `{key}` | {source_str} | {trans_str} |\n")
|
||||
|
||||
print_success(f"Exported: {output_file} ({untranslated_count} keys)")
|
||||
print_success(f"Exported: {translated_file} ({translated_count} keys)")
|
||||
return 0
|
||||
|
||||
|
||||
def usage():
|
||||
print("""
|
||||
OmniRoute i18n Translation Validator
|
||||
|
||||
Usage: validate_translation.py [command] [options]
|
||||
|
||||
Options:
|
||||
-l, --lang <code> Target language code (e.g., cs, de, fr)
|
||||
Default: cs or TRANSLATION_LANG env variable
|
||||
|
||||
Commands:
|
||||
(default) Generate full report
|
||||
quick Quick check - just show counts
|
||||
diff <category> Show detailed diff for a category
|
||||
csv [file] Export to CSV (default: translation_report.csv)
|
||||
md [file] Export to Markdown (default: translation_report.md)
|
||||
|
||||
Examples:
|
||||
python validate_translation.py # Full report (default: cs)
|
||||
python validate_translation.py --lang de # Validate German
|
||||
python validate_translation.py -l fr # Validate French
|
||||
TRANSLATION_LANG=es python validate_translation.py # Validate Spanish
|
||||
python validate_translation.py quick # Quick status check
|
||||
python validate_translation.py diff common # Diff common category
|
||||
python validate_translation.py csv # Export to CSV
|
||||
python validate_translation.py md # Export to Markdown
|
||||
""")
|
||||
|
||||
|
||||
def main():
|
||||
# Parse global arguments first
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('-l', '--lang', dest='lang', default=None)
|
||||
parser.add_argument('command', nargs='?')
|
||||
parser.add_argument('arg', nargs='?')
|
||||
|
||||
# Parse known args only to allow commands to handle their own args
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
# Set language from argument or use default
|
||||
if args.lang:
|
||||
get_target_lang.cli_lang = args.lang
|
||||
elif not os.environ.get('TRANSLATION_LANG'):
|
||||
# Default to cs for backwards compatibility
|
||||
get_target_lang.cli_lang = "cs"
|
||||
|
||||
# Check if translation file exists
|
||||
translation_file = get_translation_file()
|
||||
if not translation_file.exists():
|
||||
print_error(f"Translation file not found: {translation_file}")
|
||||
print(f"Available languages:")
|
||||
for f in sorted(MESSAGES_DIR.glob("*.json")):
|
||||
if f.name != "en.json":
|
||||
print(f" - {f.stem}")
|
||||
return 1
|
||||
|
||||
# Execute command
|
||||
if not args.command or args.command in ('help', '--help', '-h'):
|
||||
return generate_report()
|
||||
|
||||
if args.command == "quick":
|
||||
return quick_check()
|
||||
elif args.command == "diff":
|
||||
if not args.arg:
|
||||
print_error("Please specify category")
|
||||
usage()
|
||||
return 1
|
||||
return show_diff(args.arg)
|
||||
elif args.command == "csv":
|
||||
output = args.arg if args.arg else "translation_report.csv"
|
||||
return export_csv(output)
|
||||
elif args.command == "md":
|
||||
output = args.arg if args.arg else "translation_report.md"
|
||||
return export_markdown(output)
|
||||
else:
|
||||
print_error(f"Unknown command: {args.command}")
|
||||
usage()
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -58,7 +58,85 @@
|
||||
"free": "Uvolnit",
|
||||
"skipToContent": "Přejít na obsah",
|
||||
"maintenanceServerIssues": "Server má problémy. Některé funkce nemusí být dostupné.",
|
||||
"maintenanceServerUnreachable": "Server je nedostupný. Připojuji znovu..."
|
||||
"maintenanceServerUnreachable": "Server je nedostupný. Připojuji znovu...",
|
||||
"accept": "Přijmout",
|
||||
"accountId": "ID účtu",
|
||||
"alias": "Alias",
|
||||
"apiKeyId": "ID API klíče",
|
||||
"apiKeyName": "Název API klíče",
|
||||
"apiKeySecret": "Tajný klíč API",
|
||||
"authorization": "Autorizace",
|
||||
"content-type": "Typ obsahu",
|
||||
"content-length": "Délka obsahu",
|
||||
"cookie": "Cookie",
|
||||
"file": "Soubor",
|
||||
"host": "Hostitel",
|
||||
"id": "ID",
|
||||
"import": "Importovat",
|
||||
"limit": "Limit",
|
||||
"offset": "Offset",
|
||||
"open": "Otevřít",
|
||||
"origin": "Původ",
|
||||
"promptTokens": "Prompt tokeny",
|
||||
"completionTokens": "Completion tokeny",
|
||||
"totalTokens": "Celkem tokenů",
|
||||
"rawModel": "Raw model",
|
||||
"scope": "Rozsah",
|
||||
"skill": "Dovednost",
|
||||
"sortBy": "Řadit podle",
|
||||
"sortOrder": "Pořadí",
|
||||
"tab": "Záložka",
|
||||
"text": "Text",
|
||||
"textarea": "Textové pole",
|
||||
"tool": "Nástroj",
|
||||
"toolId": "ID nástroje",
|
||||
"web": "Web",
|
||||
"whereUsed": "Kde použito",
|
||||
"whitelist": "Povolený seznam",
|
||||
"blacklist": "Blokovaný seznam",
|
||||
"resolve": "Vyřešit",
|
||||
"force": "Vynutit",
|
||||
"base64url": "Base64 URL",
|
||||
"hex": "Hex",
|
||||
"range": "Rozsah",
|
||||
"component": "Komponenta",
|
||||
"redirect_uri": "Přesměrovací URI",
|
||||
"idempotency-key": "Klíč idempotence",
|
||||
"error_description": "Popis chyby",
|
||||
"code": "Kód",
|
||||
"compatible": "Kompatibilní",
|
||||
"chat-completions": "Chat completions",
|
||||
"oauth": "OAuth",
|
||||
"auth_token": "Auth token",
|
||||
"crypto": "Kryptografie",
|
||||
"hours": "Hodiny",
|
||||
"selfsigned": "Self-signed",
|
||||
"proxy_id": "ID proxy",
|
||||
"proxyId": "ID proxy",
|
||||
"connectionId": "ID připojení",
|
||||
"resolveConnectionId": "Vyřešit ID připojení",
|
||||
"resolve_connection_id": "Vyřešit ID připojení",
|
||||
"scope_id": "ID rozsahu",
|
||||
"scopeId": "ID rozsahu",
|
||||
"jwtSecret": "JWT tajemství",
|
||||
"keytar": "Keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "Builder ID",
|
||||
"musicDesc": "Popis hudby",
|
||||
"musicGeneration": "Generování hudby",
|
||||
"idc": "IDC",
|
||||
"cloud-status-changed": "Změna stavu cloudu",
|
||||
"where_used": "Kde použito",
|
||||
"windowMs": "Okno (ms)",
|
||||
"social-github": "GitHub",
|
||||
"social-google": "Google",
|
||||
"TOOL_ALLOWLIST": "Povolené nástroje",
|
||||
"TOOL_DENYLIST": "Blokované nástroje",
|
||||
"Failed to save pricing": "Nepodařilo se uložit ceny",
|
||||
"Failed to reset pricing": "Nepodařilo se resetovat ceny",
|
||||
"apikey": "API klíč",
|
||||
"http": "HTTP"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Domov",
|
||||
@@ -179,7 +257,11 @@
|
||||
"requestsShort": "{count} požadavků",
|
||||
"providerModelsTitle": "{provider} - Modely",
|
||||
"copiedModel": "Zkopírován: {model}",
|
||||
"aliasLabel": "alias"
|
||||
"aliasLabel": "alias",
|
||||
"updateNow": "Aktualizovat",
|
||||
"updating": "Aktualizuji...",
|
||||
"updateAvailableDesc": "K dispozici je nová verze. Kliknutím aktualizujte.",
|
||||
"updateStarted": "Aktualizace začala..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analytika",
|
||||
@@ -607,6 +689,9 @@
|
||||
"title": "Přidat nastavení modelu",
|
||||
"desc": "Přidejte do pole modely následující nastavení:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue používá konfigurační soubor JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -625,6 +710,10 @@
|
||||
"4": {
|
||||
"title": "Vybrat model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode vyžaduje konfiguraci API klíče.",
|
||||
"1": "Nastavte základní URL na váš OmniRoute endpoint."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -643,6 +732,9 @@
|
||||
"4": {
|
||||
"title": "Vyberte model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro vyžaduje Amazon účet."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1540,7 +1632,16 @@
|
||||
"chatPathHint": "Vlastní chat cesta pro poskytovatele s nestandardí API (např. /v4/chat/completions)",
|
||||
"modelsPathLabel": "Cesta koncového bodu modelu",
|
||||
"modelsPathPlaceholder": "/models",
|
||||
"modelsPathHint": "Cesta k vlastním modelům pro validaci (např. /v4/models)"
|
||||
"modelsPathHint": "Cesta k vlastním modelům pro validaci (např. /v4/models)",
|
||||
"autoSync": "Automatická synchronizace",
|
||||
"autoSyncTooltip": "Automaticky obnovuje seznam modelů každých 24 hodin (lze konfigurovat přes MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Automatická synchronizace povolena – modely se budou pravidelně obnovovat",
|
||||
"autoSyncDisabled": "Automatická synchronizace zakázána",
|
||||
"autoSyncToggleFailed": "Nepodařilo se přepnout automatickou synchronizaci",
|
||||
"clearAllModels": "Vymazat všechny modely",
|
||||
"clearAllModelsConfirm": "Opravdu chcete odstranit všechny modely pro tohoto poskytovatele?",
|
||||
"clearAllModelsSuccess": "Všechny modely vymazány",
|
||||
"clearAllModelsFailed": "Nepodařilo se vymazat modely"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Nastavení",
|
||||
@@ -2367,7 +2468,13 @@
|
||||
"restartServerWithNewPassword": "Restartujte server - použije se nové heslo.",
|
||||
"backToLogin": "Zpět na přihlášení",
|
||||
"forgotPassword": "Zapomněli jste heslo?",
|
||||
"defaultPasswordHint": "Výchozí heslo: 123456 (pokud nebylo nastaveno INITIAL_PASSWORD)"
|
||||
"defaultPasswordHint": "Výchozí heslo: 123456 (pokud nebylo nastaveno INITIAL_PASSWORD)",
|
||||
"waitingForAuthorization": "Čekám na autorizaci...",
|
||||
"waitingForGoogleAuthorization": "Čekám na Google autorizaci...",
|
||||
"waitingForOpenAIAuthorization": "Čekám na OpenAI autorizaci...",
|
||||
"waitingForAntigravityAuthorization": "Čekám na Antigravity autorizaci...",
|
||||
"waitingForIFlowAuthorization": "Čekám na iFlow autorizaci...",
|
||||
"exchangingCodeForTokens": "Vyměňuji kód za tokeny..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2691,5 +2798,21 @@
|
||||
"modePackCostSaver": "Úspora nákladů",
|
||||
"modePackQualityFirst": "Kvalita na prvním místě",
|
||||
"modePackOfflineFriendly": "Offline přátelské"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Jednoduchý chat",
|
||||
"streaming": "Streamování",
|
||||
"system-prompt": "Systémový prompt",
|
||||
"thinking": "Přemýšlení",
|
||||
"tool-calling": "Volání nástrojů",
|
||||
"multi-turn": "Multitah"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Základní šablona chatu se systémovou zprávou",
|
||||
"streaming": "Šablona pro streamování odpovědí",
|
||||
"system-prompt": "Šablona s vlastním systémovým promptem",
|
||||
"thinking": "Šablona s rozpočtem na přemýšlení/odůvodňování",
|
||||
"tool-calling": "Šablona pro volání nástrojů/funkcí",
|
||||
"multi-turn": "Šablona pro konverzace s Multitahy"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,85 @@
|
||||
"free": "Kostenlos",
|
||||
"skipToContent": "Zum Inhalt springen",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "Akzeptieren",
|
||||
"accountId": "Konto-ID",
|
||||
"alias": "Alias",
|
||||
"apiKeyId": "API-Schlüssel-ID",
|
||||
"apiKeyName": "API-Schlüsselname",
|
||||
"apiKeySecret": "API-Schlüsselgeheimnis",
|
||||
"authorization": "Autorisierung",
|
||||
"content-type": "Inhaltstyp",
|
||||
"content-length": "Inhaltslänge",
|
||||
"cookie": "Cookie",
|
||||
"file": "Datei",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"import": "Importieren",
|
||||
"limit": "Limit",
|
||||
"offset": "Offset",
|
||||
"open": "Öffnen",
|
||||
"origin": "Herkunft",
|
||||
"promptTokens": "Prompt-Token",
|
||||
"completionTokens": "Completion-Token",
|
||||
"totalTokens": "Gesamte Token",
|
||||
"rawModel": "Raw-Modell",
|
||||
"scope": "Umfang",
|
||||
"skill": "Fertigkeit",
|
||||
"sortBy": "Sortieren nach",
|
||||
"sortOrder": "Sortierreihenfolge",
|
||||
"tab": "Tab",
|
||||
"text": "Text",
|
||||
"textarea": "Textfeld",
|
||||
"tool": "Werkzeug",
|
||||
"toolId": "Werkzeug-ID",
|
||||
"web": "Web",
|
||||
"whereUsed": "Wo verwendet",
|
||||
"whitelist": "Whitelist",
|
||||
"blacklist": "Blacklist",
|
||||
"resolve": "Auflösen",
|
||||
"force": "Erzwingen",
|
||||
"base64url": "Base64 URL",
|
||||
"hex": "Hex",
|
||||
"range": "Bereich",
|
||||
"component": "Komponente",
|
||||
"redirect_uri": "Umleitungs-URI",
|
||||
"idempotency-key": "Idempotenz-Schlüssel",
|
||||
"error_description": "Fehlerbeschreibung",
|
||||
"code": "Code",
|
||||
"compatible": "Kompatibel",
|
||||
"chat-completions": "Chat-Completions",
|
||||
"oauth": "OAuth",
|
||||
"auth_token": "Auth-Token",
|
||||
"crypto": "Krypto",
|
||||
"hours": "Stunden",
|
||||
"selfsigned": "Selbstsigniert",
|
||||
"proxy_id": "Proxy-ID",
|
||||
"proxyId": "Proxy-ID",
|
||||
"connectionId": "Verbindungs-ID",
|
||||
"resolveConnectionId": "Verbindungs-ID auflösen",
|
||||
"resolve_connection_id": "Verbindungs-ID auflösen",
|
||||
"scope_id": "Umfang-ID",
|
||||
"scopeId": "Umfang-ID",
|
||||
"jwtSecret": "JWT-Geheimnis",
|
||||
"keytar": "Keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "Builder-ID",
|
||||
"musicDesc": "Musikbeschreibung",
|
||||
"musicGeneration": "Musikgenerierung",
|
||||
"idc": "IDC",
|
||||
"cloud-status-changed": "Cloud-Status geändert",
|
||||
"where_used": "Wo verwendet",
|
||||
"windowMs": "Fenster (ms)",
|
||||
"social-github": "GitHub",
|
||||
"social-google": "Google",
|
||||
"TOOL_ALLOWLIST": "Werkzeug-Whitelist",
|
||||
"TOOL_DENYLIST": "Werkzeug-Blacklist",
|
||||
"Failed to save pricing": "Preise speichern fehlgeschlagen",
|
||||
"Failed to reset pricing": "Preise zurücksetzen fehlgeschlagen",
|
||||
"apikey": "API-Schlüssel",
|
||||
"http": "HTTP"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Zuhause",
|
||||
@@ -179,7 +257,11 @@
|
||||
"requestsShort": "{count} Anfr.",
|
||||
"providerModelsTitle": "{provider} – Modelle",
|
||||
"copiedModel": "Kopiert: {model}",
|
||||
"aliasLabel": "Alias"
|
||||
"aliasLabel": "Alias",
|
||||
"updateNow": "Jetzt aktualisieren",
|
||||
"updating": "Aktualisiere...",
|
||||
"updateAvailableDesc": "Eine neue Version ist verfügbar. Klicken Sie zum Aktualisieren.",
|
||||
"updateStarted": "Aktualisierung gestartet..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analytik",
|
||||
@@ -535,6 +617,9 @@
|
||||
"title": "Modellkonfiguration hinzufügen",
|
||||
"desc": "Fügen Sie Ihrem Modellarray die folgende Konfiguration hinzu:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue verwendet eine JSON-Konfigurationsdatei."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +638,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode erfordert API-Schlüssel-Konfiguration.",
|
||||
"1": "Base URL auf Ihren OmniRoute-Endpunkt setzen."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +660,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro erfordert ein Amazon-Konto."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1569,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Auto-Sync",
|
||||
"autoSyncTooltip": "Modellliste automatisch alle 24 Stunden aktualisieren (konfigurierbar über MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Auto-Sync aktiviert — Modelle werden regelmäßig aktualisiert",
|
||||
"autoSyncDisabled": "Auto-Sync deaktiviert",
|
||||
"autoSyncToggleFailed": "Auto-Sync umschalten fehlgeschlagen",
|
||||
"clearAllModels": "Alle Modelle löschen",
|
||||
"clearAllModelsConfirm": "Möchten Sie wirklich alle Modelle für diesen Anbieter löschen?",
|
||||
"clearAllModelsSuccess": "Alle Modelle gelöscht",
|
||||
"clearAllModelsFailed": "Modelle löschen fehlgeschlagen"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Einstellungen",
|
||||
@@ -2304,7 +2405,13 @@
|
||||
"restartServerWithNewPassword": "Starten Sie den Server neu – er verwendet das neue Passwort",
|
||||
"backToLogin": "Zurück zum Anmelden",
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Warte auf Autorisierung...",
|
||||
"waitingForGoogleAuthorization": "Warte auf Google-Autorisierung...",
|
||||
"waitingForOpenAIAuthorization": "Warte auf OpenAI-Autorisierung...",
|
||||
"waitingForAntigravityAuthorization": "Warte auf Antigravity-Autorisierung...",
|
||||
"waitingForIFlowAuthorization": "Warte auf iFlow-Autorisierung...",
|
||||
"exchangingCodeForTokens": "Tausche Code gegen Token aus..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2511,7 +2618,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Sprachsynthese (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Text-Embedding-Generierung (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Datenschutzrichtlinie",
|
||||
@@ -2689,5 +2798,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Einfacher Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System-Prompt",
|
||||
"thinking": "Denken",
|
||||
"tool-calling": "Werkzeugaufruf",
|
||||
"multi-turn": "Mehrere Runden"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Einfache Chat-Vorlage mit Systemnachricht",
|
||||
"streaming": "Vorlage für Streaming-Antworten",
|
||||
"system-prompt": "Vorlage mit benutzerdefiniertem System-Prompt",
|
||||
"thinking": "Vorlage mit Denk-/Argumentationsbudget",
|
||||
"tool-calling": "Vorlage für Werkzeug-/Funktionsaufrufe",
|
||||
"multi-turn": "Vorlage für mehrstufige Konversationen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,85 @@
|
||||
"free": "Free",
|
||||
"skipToContent": "Skip to content",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "Accept",
|
||||
"accountId": "Account ID",
|
||||
"alias": "Alias",
|
||||
"apiKeyId": "API Key ID",
|
||||
"apiKeyName": "API Key Name",
|
||||
"apiKeySecret": "API Key Secret",
|
||||
"authorization": "Authorization",
|
||||
"content-type": "Content Type",
|
||||
"content-length": "Content Length",
|
||||
"cookie": "Cookie",
|
||||
"file": "File",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"import": "Import",
|
||||
"limit": "Limit",
|
||||
"offset": "Offset",
|
||||
"open": "Open",
|
||||
"origin": "Origin",
|
||||
"promptTokens": "Prompt Tokens",
|
||||
"completionTokens": "Completion Tokens",
|
||||
"totalTokens": "Total Tokens",
|
||||
"rawModel": "Raw Model",
|
||||
"scope": "Scope",
|
||||
"skill": "Skill",
|
||||
"sortBy": "Sort By",
|
||||
"sortOrder": "Sort Order",
|
||||
"tab": "Tab",
|
||||
"text": "Text",
|
||||
"textarea": "Textarea",
|
||||
"tool": "Tool",
|
||||
"toolId": "Tool ID",
|
||||
"web": "Web",
|
||||
"whereUsed": "Where Used",
|
||||
"whitelist": "Whitelist",
|
||||
"blacklist": "Blacklist",
|
||||
"resolve": "Resolve",
|
||||
"force": "Force",
|
||||
"base64url": "Base64 URL",
|
||||
"hex": "Hex",
|
||||
"range": "Range",
|
||||
"component": "Component",
|
||||
"redirect_uri": "Redirect URI",
|
||||
"idempotency-key": "Idempotency Key",
|
||||
"error_description": "Error Description",
|
||||
"code": "Code",
|
||||
"compatible": "Compatible",
|
||||
"chat-completions": "Chat Completions",
|
||||
"oauth": "OAuth",
|
||||
"auth_token": "Auth Token",
|
||||
"crypto": "Crypto",
|
||||
"hours": "Hours",
|
||||
"selfsigned": "Self-signed",
|
||||
"proxy_id": "Proxy ID",
|
||||
"proxyId": "Proxy ID",
|
||||
"connectionId": "Connection ID",
|
||||
"resolveConnectionId": "Resolve Connection ID",
|
||||
"resolve_connection_id": "Resolve Connection ID",
|
||||
"scope_id": "Scope ID",
|
||||
"scopeId": "Scope ID",
|
||||
"jwtSecret": "JWT Secret",
|
||||
"keytar": "Keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "Builder ID",
|
||||
"musicDesc": "Music Description",
|
||||
"musicGeneration": "Music Generation",
|
||||
"idc": "IDC",
|
||||
"cloud-status-changed": "Cloud status changed",
|
||||
"where_used": "Where Used",
|
||||
"windowMs": "Window (ms)",
|
||||
"social-github": "GitHub",
|
||||
"social-google": "Google",
|
||||
"TOOL_ALLOWLIST": "Tool Allowlist",
|
||||
"TOOL_DENYLIST": "Tool Denylist",
|
||||
"Failed to save pricing": "Failed to save pricing",
|
||||
"Failed to reset pricing": "Failed to reset pricing",
|
||||
"apikey": "API Key",
|
||||
"http": "HTTP"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Home",
|
||||
@@ -179,7 +257,11 @@
|
||||
"requestsShort": "{count} reqs",
|
||||
"providerModelsTitle": "{provider} - Models",
|
||||
"copiedModel": "Copied: {model}",
|
||||
"aliasLabel": "alias"
|
||||
"aliasLabel": "alias",
|
||||
"updateNow": "Update Now",
|
||||
"updating": "Updating...",
|
||||
"updateAvailableDesc": "A new version is available. Click to update.",
|
||||
"updateStarted": "Update started..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analytics",
|
||||
@@ -607,6 +689,9 @@
|
||||
"title": "Add Model Config",
|
||||
"desc": "Add the following configuration to your models array:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue uses JSON config file."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -625,6 +710,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode requires API key configuration.",
|
||||
"1": "Set the base URL to your OmniRoute endpoint."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -643,6 +732,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro requires Amazon account."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2376,7 +2468,15 @@
|
||||
"restartServerWithNewPassword": "Restart the server - it will use the new password",
|
||||
"backToLogin": "Back to Login",
|
||||
"forgotPassword": "Forgot password?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"Authorization": "Authorization",
|
||||
"Content-Disposition": "Content-Disposition",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2700,5 +2800,48 @@
|
||||
"modePackCostSaver": "Cost Saver",
|
||||
"modePackQualityFirst": "Quality First",
|
||||
"modePackOfflineFriendly": "Offline Friendly"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template with system message",
|
||||
"streaming": "Template for streaming responses",
|
||||
"system-prompt": "Template with custom system prompt",
|
||||
"thinking": "Template with reasoning/thinking budget",
|
||||
"tool-calling": "Template for tool/function calling",
|
||||
"multi-turn": "Template for multi-turn conversations"
|
||||
},
|
||||
"templatePayloads": {
|
||||
"simpleChat": {
|
||||
"system": "You are a helpful AI assistant.",
|
||||
"userGreeting": "Hello! How can I help you today?"
|
||||
},
|
||||
"streaming": {
|
||||
"prompt": "Write a story about"
|
||||
},
|
||||
"systemPrompt": {
|
||||
"question": "What is the meaning of life?",
|
||||
"systemInstruction": "Provide a thoughtful, philosophical answer."
|
||||
},
|
||||
"thinking": {
|
||||
"question": "Explain quantum computing"
|
||||
},
|
||||
"toolCalling": {
|
||||
"cityNameDescription": "The name of the city to get weather for",
|
||||
"toolDescription": "Get current weather for a location",
|
||||
"userWeather": "What's the weather in Tokyo?"
|
||||
},
|
||||
"multiTurn": {
|
||||
"system": "You are a helpful assistant.",
|
||||
"assistantExample": "I'd be happy to help you with that.",
|
||||
"userInitial": "I need help with",
|
||||
"userFollowUp": "Can you elaborate on that?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Gratis",
|
||||
"skipToContent": "Saltar al contenido",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Inicio",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} reqs",
|
||||
"providerModelsTitle": "{provider} - Modelos",
|
||||
"copiedModel": "Copiado: {model}",
|
||||
"aliasLabel": "alias"
|
||||
"aliasLabel": "alias",
|
||||
"updateNow": "Actualizar ahora",
|
||||
"updating": "Actualizando...",
|
||||
"updateAvailableDesc": "Hay una nueva versión disponible. Haga clic para actualizar.",
|
||||
"updateStarted": "Actualización iniciada..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analítica",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Agregar configuración de modelo",
|
||||
"desc": "Agregue la siguiente configuración a su matriz de modelos:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue usa un archivo de configuración JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode requiere configuración de clave API.",
|
||||
"1": "Establece la URL base a tu endpoint de OmniRoute."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro requiere cuenta de Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Sincronización automática",
|
||||
"autoSyncTooltip": "Actualiza automáticamente la lista de modelos cada 24 horas (configurable vía MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Sincronización automática activada — los modelos se actualizarán periódicamente",
|
||||
"autoSyncDisabled": "Sincronización automática desactivada",
|
||||
"autoSyncToggleFailed": "Error al alternar sincronización automática",
|
||||
"clearAllModels": "Borrar todos los modelos",
|
||||
"clearAllModelsConfirm": "¿Estás seguro de que quieres eliminar todos los modelos de este proveedor?",
|
||||
"clearAllModelsSuccess": "Todos los modelos borrados",
|
||||
"clearAllModelsFailed": "Error al borrar modelos"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Configuración",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "Reinicia el servidor; usará la nueva contraseña",
|
||||
"backToLogin": "Volver a iniciar sesión",
|
||||
"forgotPassword": "¿Olvidaste tu contraseña?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRuta",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Generación de texto a voz (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Generación de embeddings de texto (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Política de privacidad",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Gratuit",
|
||||
"skipToContent": "Passer au contenu",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Accueil",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} reqs",
|
||||
"providerModelsTitle": "{provider} - Modèles",
|
||||
"copiedModel": "Copié : {model}",
|
||||
"aliasLabel": "pseudonyme"
|
||||
"aliasLabel": "pseudonyme",
|
||||
"updateNow": "Mettre à jour",
|
||||
"updating": "Mise à jour...",
|
||||
"updateAvailableDesc": "Une nouvelle version est disponible. Cliquez pour mettre à jour.",
|
||||
"updateStarted": "Mise à jour démarrée..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analyse",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Ajouter une configuration de modèle",
|
||||
"desc": "Ajoutez la configuration suivante à votre tableau models :"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue utilise un fichier de configuration JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode nécessite la configuration de la clé API.",
|
||||
"1": "Définissez l'URL de base sur votre endpoint OmniRoute."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro nécessite un compte Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Synchronisation automatique",
|
||||
"autoSyncTooltip": "Actualise automatiquement la liste des modèles toutes les 24h (configurable via MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Synchronisation automatique activée — les modèles seront actualisés périodiquement",
|
||||
"autoSyncDisabled": "Synchronisation automatique désactivée",
|
||||
"autoSyncToggleFailed": "Échec de l'activation de la synchronisation automatique",
|
||||
"clearAllModels": "Effacer tous les modèles",
|
||||
"clearAllModelsConfirm": "Êtes-vous sûr de vouloir supprimer tous les modèles pour ce fournisseur?",
|
||||
"clearAllModelsSuccess": "Tous les modèles effacés",
|
||||
"clearAllModelsFailed": "Échec de l'effacement des modèles"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Paramètres",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "Redémarrez le serveur - il utilisera le nouveau mot de passe",
|
||||
"backToLogin": "Retour à la connexion",
|
||||
"forgotPassword": "Mot de passe oublié ?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Génération texte-vers-discours (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Génération d'embeddings texte (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Politique de confidentialité",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Gratis",
|
||||
"skipToContent": "Lewati ke konten",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Rumah",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} permintaan",
|
||||
"providerModelsTitle": "{provider} - Model",
|
||||
"copiedModel": "Disalin: {model}",
|
||||
"aliasLabel": "alias"
|
||||
"aliasLabel": "alias",
|
||||
"updateNow": "Perbarui sekarang",
|
||||
"updating": "Memperbarui...",
|
||||
"updateAvailableDesc": "Versi baru tersedia. Klik untuk memperbarui.",
|
||||
"updateStarted": "Pembaruan dimulai..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analisis",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Tambahkan Konfigurasi Model",
|
||||
"desc": "Tambahkan konfigurasi berikut ke array model Anda:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue menggunakan file konfigurasi JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode memerlukan konfigurasi API key.",
|
||||
"1": "Setel base URL ke endpoint OmniRoute Anda."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro memerlukan akun Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Sinkronisasi Otomatis",
|
||||
"autoSyncTooltip": "Segarkan daftar model secara otomatis setiap 24 jam (dapat dikonfigurasi melalui MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Sinkronisasi otomatis diaktifkan — model akan disegarkan secara berkala",
|
||||
"autoSyncDisabled": "Sinkronisasi otomatis dinonaktifkan",
|
||||
"autoSyncToggleFailed": "Gagal mengaktifkan sinkronisasi otomatis",
|
||||
"clearAllModels": "Hapus Semua Model",
|
||||
"clearAllModelsConfirm": "Apakah Anda yakin ingin menghapus semua model untuk penyedia ini?",
|
||||
"clearAllModelsSuccess": "Semua model dihapus",
|
||||
"clearAllModelsFailed": "Gagal menghapus model"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Pengaturan",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "Mulai ulang server - server akan menggunakan kata sandi baru",
|
||||
"backToLogin": "Kembali ke Masuk",
|
||||
"forgotPassword": "Lupa kata sandi?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"troubleshootingCodexFamily": "Untuk model keluarga GitHub Codex, pertahankan model sebagai gh/codex-model; router memilih / merespons secara otomatis.",
|
||||
"troubleshootingTestConnection": "Gunakan Dasbor > Penyedia > Uji Koneksi sebelum menguji dari IDE atau klien eksternal.",
|
||||
"troubleshootingCircuitBreaker": "Jika penyedia menunjukkan pemutus sirkuit terbuka, tunggu hingga cooldown atau periksa halaman Kesehatan untuk detailnya.",
|
||||
"troubleshootingOAuth": "Untuk penyedia OAuth, autentikasi ulang jika masa berlaku token habis. Periksa indikator status kartu penyedia."
|
||||
"troubleshootingOAuth": "Untuk penyedia OAuth, autentikasi ulang jika masa berlaku token habis. Periksa indikator status kartu penyedia.",
|
||||
"endpointSpeechNote": "Generasi text-to-speech (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Generasi embedding teks (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Kebijakan Privasi",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Gratuito",
|
||||
"skipToContent": "Vai al contenuto",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Casa",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} richieste",
|
||||
"providerModelsTitle": "{provider} - Modelli",
|
||||
"copiedModel": "Copiato: {model}",
|
||||
"aliasLabel": "alias"
|
||||
"aliasLabel": "alias",
|
||||
"updateNow": "Aggiorna ora",
|
||||
"updating": "Aggiornamento...",
|
||||
"updateAvailableDesc": "Una nuova versione è disponibile. Fai clic per aggiornare.",
|
||||
"updateStarted": "Aggiornamento avviato..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analitica",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Aggiungi configurazione modello",
|
||||
"desc": "Aggiungi la seguente configurazione all'array dei modelli:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue usa un file di configurazione JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode richiede la configurazione della chiave API.",
|
||||
"1": "Imposta l'URL base sul tuo endpoint OmniRoute."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro richiede un account Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Sincronizzazione automatica",
|
||||
"autoSyncTooltip": "Aggiorna automaticamente l'elenco dei modelli ogni 24 ore (configurabile tramite MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Sincronizzazione automatica abilitata — i modelli verranno aggiornati periodicamente",
|
||||
"autoSyncDisabled": "Sincronizzazione automatica disabilitata",
|
||||
"autoSyncToggleFailed": "Impossibile attivare la sincronizzazione automatica",
|
||||
"clearAllModels": "Cancella tutti i modelli",
|
||||
"clearAllModelsConfirm": "Sei sicuro di voler rimuovere tutti i modelli per questo provider?",
|
||||
"clearAllModelsSuccess": "Tutti i modelli cancellati",
|
||||
"clearAllModelsFailed": "Impossibile cancellare i modelli"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Impostazioni",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "Riavvia il server: utilizzerà la nuova password",
|
||||
"backToLogin": "Torna all'accesso",
|
||||
"forgotPassword": "Ha dimenticato la password?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Generazione sintesi vocale (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Generazione embedding di testo (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "politica sulla riservatezza",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "無料",
|
||||
"skipToContent": "コンテンツにスキップ",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "ホーム",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} 件",
|
||||
"providerModelsTitle": "{provider} - モデル",
|
||||
"copiedModel": "コピーしました: {model}",
|
||||
"aliasLabel": "別名"
|
||||
"aliasLabel": "別名",
|
||||
"updateNow": "今すぐ更新",
|
||||
"updating": "更新中...",
|
||||
"updateAvailableDesc": "新しいバージョンが利用可能です。クリックして更新。",
|
||||
"updateStarted": "更新を開始しました..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "分析",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "モデル構成の追加",
|
||||
"desc": "次の構成をモデル配列に追加します。"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "ContinueはJSON設定ファイルを使用します。"
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCodeはAPIキー設定が必要です。",
|
||||
"1": "ベースURLをOmniRouteエンドポイントに設定してください。"
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "KiroはAmazonアカウントが必要です。"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "自動同期",
|
||||
"autoSyncTooltip": "24時間ごとにモデルリストを自動更新(MODEL_SYNC_INTERVAL_HOURSで設定可能)",
|
||||
"autoSyncEnabled": "自動同期有効 — モデルは定期的に更新されます",
|
||||
"autoSyncDisabled": "自動同期無効",
|
||||
"autoSyncToggleFailed": "自動同期の切り替えに失敗",
|
||||
"clearAllModels": "すべてのモデルを削除",
|
||||
"clearAllModelsConfirm": "このプロバイダーのすべてのモデルを削除してもよろしいですか?",
|
||||
"clearAllModelsSuccess": "すべてのモデルを削除しました",
|
||||
"clearAllModelsFailed": "モデルの削除に失敗"
|
||||
},
|
||||
"settings": {
|
||||
"title": "設定",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "サーバーを再起動すると新しいパスワードが適用されます",
|
||||
"backToLogin": "ログインに戻る",
|
||||
"forgotPassword": "パスワードをお忘れですか?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "オムニルート",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "テキスト読み上げ(ElevenLabs、OpenAI TTS)。",
|
||||
"endpointEmbeddingsNote": "テキスト埋め込み生成(OpenAI、Cohere、Voyage)。"
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "プライバシーポリシー",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "무료",
|
||||
"skipToContent": "콘텐츠로 건너뛰기",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "홈",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} 요청",
|
||||
"providerModelsTitle": "{provider} - 모델",
|
||||
"copiedModel": "복사됨: {model}",
|
||||
"aliasLabel": "별칭"
|
||||
"aliasLabel": "별칭",
|
||||
"updateNow": "지금 업데이트",
|
||||
"updating": "업데이트 중...",
|
||||
"updateAvailableDesc": "새 버전을 사용할 수 있습니다. 클릭하여 업데이트하세요.",
|
||||
"updateStarted": "업데이트 시작됨..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "분석",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "모델 구성 추가",
|
||||
"desc": "모델 배열에 다음 구성을 추가합니다."
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue는 JSON 설정 파일을 사용합니다."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode는 API 키 구성이 필요합니다.",
|
||||
"1": "기본 URL을 OmniRoute 엔드포인트로 설정하세요."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro는 Amazon 계정이 필요합니다."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "자동 동기화",
|
||||
"autoSyncTooltip": "24시간마다 모델 목록 자동 업데이트 (MODEL_SYNC_INTERVAL_HOURS로 구성 가능)",
|
||||
"autoSyncEnabled": "자동 동기화 활성화 — 모델이 주기적으로 업데이트됩니다",
|
||||
"autoSyncDisabled": "자동 동기화 비활성화",
|
||||
"autoSyncToggleFailed": "자동 동기화 전환 실패",
|
||||
"clearAllModels": "모든 모델 삭제",
|
||||
"clearAllModelsConfirm": "이 공급자의 모든 모델을 제거하시겠습니까?",
|
||||
"clearAllModelsSuccess": "모든 모델 삭제됨",
|
||||
"clearAllModelsFailed": "모델 삭제 실패"
|
||||
},
|
||||
"settings": {
|
||||
"title": "설정",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "서버를 다시 시작하세요. 새 비밀번호가 사용됩니다.",
|
||||
"backToLogin": "로그인으로 돌아가기",
|
||||
"forgotPassword": "비밀번호를 잊으셨나요?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "옴니루트",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "음성 합성 (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "텍스트 임베딩 생성 (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "개인 정보 보호 정책",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Bezpłatny",
|
||||
"skipToContent": "Przejdź do treści",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Dom",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} wymagania",
|
||||
"providerModelsTitle": "{provider} - Modele",
|
||||
"copiedModel": "Skopiowano: {model}",
|
||||
"aliasLabel": "pseudonim"
|
||||
"aliasLabel": "pseudonim",
|
||||
"updateNow": "Zaktualizuj",
|
||||
"updating": "Aktualizowanie...",
|
||||
"updateAvailableDesc": "Dostępna jest nowa wersja. Kliknij, aby zaktualizować.",
|
||||
"updateStarted": "Aktualizacja rozpoczęta..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Analityka",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Dodaj konfigurację modelu",
|
||||
"desc": "Dodaj następującą konfigurację do tablicy modeli:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue używa pliku konfiguracyjnego JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode wymaga konfiguracji klucza API.",
|
||||
"1": "Ustaw URL bazowy na swój endpoint OmniRoute."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro wymaga konta Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Automatyczna synchronizacja",
|
||||
"autoSyncTooltip": "Automatycznie odświeża listę modeli co 24 godziny (konfigurowalne przez MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Automatyczna synchronizacja włączona — modele będą okresowo odświeżane",
|
||||
"autoSyncDisabled": "Automatyczna synchronizacja wyłączona",
|
||||
"autoSyncToggleFailed": "Nie udało się przełączyć automatycznej synchronizacji",
|
||||
"clearAllModels": "Wyczyść wszystkie modele",
|
||||
"clearAllModelsConfirm": "Czy na pewno chcesz usunąć wszystkie modele dla tego dostawcy?",
|
||||
"clearAllModelsSuccess": "Wszystkie modele wyczyszczone",
|
||||
"clearAllModelsFailed": "Nie udało się wyczyścić modeli"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Ustawienia",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "Zrestartuj serwer - będzie używał nowego hasła",
|
||||
"backToLogin": "Powrót do logowania",
|
||||
"forgotPassword": "Zapomniałeś hasła?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Generowanie mowy tekstowej (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Generowanie osadzeń tekstu (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Polityka prywatności",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Grátis",
|
||||
"skipToContent": "Pular para o conteúdo",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Página inicial",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} requisitos",
|
||||
"providerModelsTitle": "{provider} - Modelos",
|
||||
"copiedModel": "Copiado: {model}",
|
||||
"aliasLabel": "apelido"
|
||||
"aliasLabel": "apelido",
|
||||
"updateNow": "Atualizar agora",
|
||||
"updating": "Atualizando...",
|
||||
"updateAvailableDesc": "Uma nova versão está disponível. Clique para atualizar.",
|
||||
"updateStarted": "Atualização iniciada..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Análise",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Adicionar configuração de modelo",
|
||||
"desc": "Adicione a seguinte configuração ao seu array de modelos:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue usa um arquivo de configuração JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode requer configuração de chave de API.",
|
||||
"1": "Defina a URL base para seu endpoint OmniRoute."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro requer conta Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1489,7 +1573,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Sincronização automática",
|
||||
"autoSyncTooltip": "Atualiza automaticamente a lista de modelos a cada 24 horas (configurável via MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Sincronização automática ativada — modelos serão atualizados periodicamente",
|
||||
"autoSyncDisabled": "Sincronização automática desativada",
|
||||
"autoSyncToggleFailed": "Falha ao alternar sincronização automática",
|
||||
"clearAllModels": "Limpar todos os modelos",
|
||||
"clearAllModelsConfirm": "Tem certeza que deseja remover todos os modelos deste provedor?",
|
||||
"clearAllModelsSuccess": "Todos os modelos limpos",
|
||||
"clearAllModelsFailed": "Falha ao limpar modelos"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Configurações",
|
||||
@@ -2316,7 +2409,13 @@
|
||||
"restartServerWithNewPassword": "Reinicie o servidor - ele usará a nova senha",
|
||||
"backToLogin": "Voltar ao login",
|
||||
"forgotPassword": "Esqueceu a senha?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "OmniRoute",
|
||||
@@ -2523,7 +2622,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Geração de texto para fala (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Geração de embeddings de texto (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Política de Privacidade",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "Бесплатно",
|
||||
"skipToContent": "Перейти к содержимому",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "Главная",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} требуется",
|
||||
"providerModelsTitle": "{provider} — Модели",
|
||||
"copiedModel": "Скопировано: {model}",
|
||||
"aliasLabel": "псевдоним"
|
||||
"aliasLabel": "псевдоним",
|
||||
"updateNow": "Обновить",
|
||||
"updating": "Обновление...",
|
||||
"updateAvailableDesc": "Доступна новая версия. Нажмите для обновления.",
|
||||
"updateStarted": "Обновление начато..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "Аналитика",
|
||||
@@ -535,6 +609,9 @@
|
||||
"title": "Добавить конфигурацию модели",
|
||||
"desc": "Добавьте следующую конфигурацию в массив моделей:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue использует файл конфигурации JSON."
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -553,6 +630,10 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode требует настройки API-ключа.",
|
||||
"1": "Установите базовый URL на ваш endpoint OmniRoute."
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -571,6 +652,9 @@
|
||||
"4": {
|
||||
"title": "Select Model"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro требует аккаунт Amazon."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1477,7 +1561,16 @@
|
||||
"compatUpstreamHeaderValue": "Value",
|
||||
"compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.",
|
||||
"compatUpstreamHeadersLabel": "Extra upstream headers",
|
||||
"compatUpstreamRemoveRow": "Remove row"
|
||||
"compatUpstreamRemoveRow": "Remove row",
|
||||
"autoSync": "Автосинхронизация",
|
||||
"autoSyncTooltip": "Автоматически обновляет список моделей каждые 24 часа (настраивается через MODEL_SYNC_INTERVAL_HOURS)",
|
||||
"autoSyncEnabled": "Автосинхронизация включена — модели будут периодически обновляться",
|
||||
"autoSyncDisabled": "Автосинхронизация отключена",
|
||||
"autoSyncToggleFailed": "Не удалось переключить автосинхронизацию",
|
||||
"clearAllModels": "Очистить все модели",
|
||||
"clearAllModelsConfirm": "Вы уверены, что хотите удалить все модели для этого провайдера?",
|
||||
"clearAllModelsSuccess": "Все модели очищены",
|
||||
"clearAllModelsFailed": "Не удалось очистить модели"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Настройки",
|
||||
@@ -2304,7 +2397,13 @@
|
||||
"restartServerWithNewPassword": "Перезагрузите сервер - он будет использовать новый пароль.",
|
||||
"backToLogin": "Вернуться к входу",
|
||||
"forgotPassword": "Забыли пароль?",
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)"
|
||||
"defaultPasswordHint": "Default password: 123456 (unless INITIAL_PASSWORD was set)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "ОмниРоут",
|
||||
@@ -2511,7 +2610,9 @@
|
||||
"mgmtProxiesBulkAssignNote": "Assign or clear one proxy across many scope IDs in one request.",
|
||||
"mgmtAssignmentsListNote": "List proxy assignments by scope, scope_id, or proxy_id.",
|
||||
"mgmtAssignmentsUpdateNote": "Assign or clear proxy for global/provider/account/combo scope.",
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments."
|
||||
"mgmtLegacyMigrationNote": "Import legacy proxyConfig maps into registry assignments.",
|
||||
"endpointSpeechNote": "Генерация речи из текста (ElevenLabs, OpenAI TTS).",
|
||||
"endpointEmbeddingsNote": "Генерация текстовых эмбеддингов (OpenAI, Cohere, Voyage)."
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "Политика конфиденциальности",
|
||||
@@ -2689,5 +2790,21 @@
|
||||
"domainPlaceholder": "example.com",
|
||||
"requestTimedOut": "Request timed out ({seconds}s)",
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,77 @@
|
||||
"free": "免费",
|
||||
"skipToContent": "跳至内容",
|
||||
"maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.",
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting..."
|
||||
"maintenanceServerUnreachable": "Server is unreachable. Reconnecting...",
|
||||
"accept": "accept",
|
||||
"accountId": "accountId",
|
||||
"alias": "alias",
|
||||
"apiKeyId": "apiKeyId",
|
||||
"apiKeyName": "apiKeyName",
|
||||
"apiKeySecret": "apiKeySecret",
|
||||
"authorization": "authorization",
|
||||
"content-type": "content-type",
|
||||
"content-length": "content-length",
|
||||
"cookie": "cookie",
|
||||
"file": "file",
|
||||
"host": "host",
|
||||
"id": "id",
|
||||
"import": "import",
|
||||
"limit": "limit",
|
||||
"offset": "offset",
|
||||
"open": "open",
|
||||
"origin": "origin",
|
||||
"promptTokens": "promptTokens",
|
||||
"completionTokens": "completionTokens",
|
||||
"totalTokens": "totalTokens",
|
||||
"rawModel": "rawModel",
|
||||
"scope": "scope",
|
||||
"skill": "skill",
|
||||
"sortBy": "sortBy",
|
||||
"sortOrder": "sortOrder",
|
||||
"tab": "tab",
|
||||
"text": "text",
|
||||
"textarea": "textarea",
|
||||
"tool": "tool",
|
||||
"toolId": "toolId",
|
||||
"web": "web",
|
||||
"whereUsed": "whereUsed",
|
||||
"whitelist": "whitelist",
|
||||
"blacklist": "blacklist",
|
||||
"resolve": "resolve",
|
||||
"force": "force",
|
||||
"base64url": "base64url",
|
||||
"hex": "hex",
|
||||
"range": "range",
|
||||
"component": "component",
|
||||
"redirect_uri": "redirect_uri",
|
||||
"idempotency-key": "idempotency-key",
|
||||
"error_description": "error_description",
|
||||
"code": "code",
|
||||
"compatible": "compatible",
|
||||
"chat-completions": "chat-completions",
|
||||
"oauth": "oauth",
|
||||
"auth_token": "auth_token",
|
||||
"crypto": "crypto",
|
||||
"hours": "hours",
|
||||
"selfsigned": "selfsigned",
|
||||
"proxy_id": "proxy_id",
|
||||
"proxyId": "proxyId",
|
||||
"connectionId": "connectionId",
|
||||
"resolveConnectionId": "resolveConnectionId",
|
||||
"resolve_connection_id": "resolve_connection_id",
|
||||
"scope_id": "scope_id",
|
||||
"scopeId": "scopeId",
|
||||
"jwtSecret": "jwtSecret",
|
||||
"keytar": "keytar",
|
||||
"better-sqlite3": "better-sqlite3",
|
||||
"undici": "undici",
|
||||
"builder-id": "builder-id",
|
||||
"musicDesc": "musicDesc",
|
||||
"musicGeneration": "musicGeneration",
|
||||
"idc": "idc",
|
||||
"cloud-status-changed": "cloud-status-changed",
|
||||
"where_used": "where_used",
|
||||
"windowMs": "windowMs"
|
||||
},
|
||||
"sidebar": {
|
||||
"home": "首页",
|
||||
@@ -179,7 +249,11 @@
|
||||
"requestsShort": "{count} 次请求",
|
||||
"providerModelsTitle": "{provider} - 模型",
|
||||
"copiedModel": "已复制:{model}",
|
||||
"aliasLabel": "别名"
|
||||
"aliasLabel": "别名",
|
||||
"updateNow": "立即更新",
|
||||
"updating": "更新中...",
|
||||
"updateAvailableDesc": "有新版本可用。点击更新。",
|
||||
"updateStarted": "更新已开始..."
|
||||
},
|
||||
"analytics": {
|
||||
"title": "分析",
|
||||
@@ -586,6 +660,9 @@
|
||||
"title": "添加模型配置",
|
||||
"desc": "将以下配置添加到您的模型数组中:"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Continue 使用 JSON 配置文件。"
|
||||
}
|
||||
},
|
||||
"opencode": {
|
||||
@@ -604,6 +681,10 @@
|
||||
"4": {
|
||||
"title": "选择模型"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "OpenCode 需要配置 API 密钥。",
|
||||
"1": "将基础 URL 设置为您的 OmniRoute 端点。"
|
||||
}
|
||||
},
|
||||
"kiro": {
|
||||
@@ -622,6 +703,9 @@
|
||||
"4": {
|
||||
"title": "选择模型"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"0": "Kiro 需要 Amazon 账户。"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1379,13 +1463,13 @@
|
||||
"importingModels": "正在导入...",
|
||||
"importFromModels": "从 /models 导入",
|
||||
"autoSync": "自动同步",
|
||||
"autoSyncTooltip": "每24小时自动刷新模型列表(可通过 MODEL_SYNC_INTERVAL_HOURS 配置)",
|
||||
"autoSyncEnabled": "已启用自动同步 — 模型列表将定期刷新",
|
||||
"autoSyncDisabled": "已禁用自动同步",
|
||||
"autoSyncTooltip": "每 24 小时自动刷新模型列表(可通过 MODEL_SYNC_INTERVAL_HOURS 配置)",
|
||||
"autoSyncEnabled": "自动同步已启用 — 模型将定期刷新",
|
||||
"autoSyncDisabled": "自动同步已禁用",
|
||||
"autoSyncToggleFailed": "切换自动同步失败",
|
||||
"clearAllModels": "清除所有模型",
|
||||
"clearAllModelsConfirm": "确定要删除此提供商的所有模型吗?此操作不可撤销。",
|
||||
"clearAllModelsSuccess": "已清除所有模型",
|
||||
"clearAllModelsConfirm": "您确定要删除此提供商的所有模型吗?",
|
||||
"clearAllModelsSuccess": "所有模型已清除",
|
||||
"clearAllModelsFailed": "清除模型失败",
|
||||
"addConnectionToImport": "添加连接以启用导入。",
|
||||
"noModelsConfigured": "尚未配置模型",
|
||||
@@ -2376,7 +2460,13 @@
|
||||
"restartServerWithNewPassword": "重新启动服务器 - 它将使用新密码",
|
||||
"backToLogin": "返回登录",
|
||||
"forgotPassword": "忘记密码?",
|
||||
"defaultPasswordHint": "默认密码:123456(除非已设置 INITIAL_PASSWORD)"
|
||||
"defaultPasswordHint": "默认密码:123456(除非已设置 INITIAL_PASSWORD)",
|
||||
"waitingForAuthorization": "Waiting for authorization...",
|
||||
"waitingForGoogleAuthorization": "Waiting for Google authorization...",
|
||||
"waitingForOpenAIAuthorization": "Waiting for OpenAI authorization...",
|
||||
"waitingForAntigravityAuthorization": "Waiting for Antigravity authorization...",
|
||||
"waitingForIFlowAuthorization": "Waiting for iFlow authorization...",
|
||||
"exchangingCodeForTokens": "Exchanging code for tokens..."
|
||||
},
|
||||
"landing": {
|
||||
"brandName": "全方位路由",
|
||||
@@ -2583,7 +2673,9 @@
|
||||
"troubleshootingCodexFamily": "对于 GitHub Codex 系列模型,请保持模型名为 `gh/codex-model`;路由器会自动选择 `/responses`。",
|
||||
"troubleshootingTestConnection": "在从 IDE 或外部客户端进行测试之前,请使用仪表板 > 提供商 > 测试连接。",
|
||||
"troubleshootingCircuitBreaker": "如果提供商显示断路器已打开,请等待冷却或查看运行状况页面以了解详细信息。",
|
||||
"troubleshootingOAuth": "对于 OAuth 提供商,如果 Token 过期,请重新认证,并检查提供商卡片上的状态指示器。"
|
||||
"troubleshootingOAuth": "对于 OAuth 提供商,如果 Token 过期,请重新认证,并检查提供商卡片上的状态指示器。",
|
||||
"endpointSpeechNote": "语音生成(ElevenLabs、OpenAI TTS)。",
|
||||
"endpointEmbeddingsNote": "文本嵌入生成(OpenAI、Cohere、Voyage)。"
|
||||
},
|
||||
"legal": {
|
||||
"privacyPolicy": "隐私政策",
|
||||
@@ -2698,5 +2790,21 @@
|
||||
"modePackCostSaver": "节省成本",
|
||||
"modePackQualityFirst": "质量优先",
|
||||
"modePackOfflineFriendly": "离线友好"
|
||||
},
|
||||
"templateNames": {
|
||||
"simple-chat": "Simple Chat",
|
||||
"streaming": "Streaming",
|
||||
"system-prompt": "System Prompt",
|
||||
"thinking": "Thinking",
|
||||
"tool-calling": "Tool Calling",
|
||||
"multi-turn": "Multi-turn"
|
||||
},
|
||||
"templateDescriptions": {
|
||||
"simple-chat": "Basic chat template",
|
||||
"streaming": "Streaming template",
|
||||
"system-prompt": "System prompt template",
|
||||
"thinking": "Thinking template",
|
||||
"tool-calling": "Tool calling template",
|
||||
"multi-turn": "Multi-turn template"
|
||||
}
|
||||
}
|
||||
|
||||
8
validate-translation.sh
Executable file
8
validate-translation.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
# Wrapper for OmniRoute translation validator
|
||||
# Provides easy CLI access to the Python validation script
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Run the Python script with all arguments
|
||||
exec python3 "$SCRIPT_DIR/scripts/validate_translation.py" "$@"
|
||||
Reference in New Issue
Block a user