mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-04 14:22:09 +03:00
chore(i18n): point src/i18n/config.ts to config/i18n.json and deprecate legacy scripts
src/i18n/config.ts is now a thin adapter that reads config/i18n.json (canonical locale list) and exports the same shape — LOCALES, LANGUAGES, RTL_LOCALES, DEFAULT_LOCALE, Locale type, LOCALE_COOKIE — that LanguageSelector, layout.tsx, request.ts, and the rest of the codebase already consume. No call-site changes were required. Adds DOCS_TARGET_LOCALES and getLanguage() helpers for new code. The legacy scripts now print a deprecation warning on stderr at startup: - scripts/i18n/i18n_autotranslate.py (banner + module-level warn) - scripts/i18n/generate-multilang.mjs (banner + console.warn) They keep working for messages and readme modes (UI strings / root README variants), which are still outside the new pipeline's scope. Both will be removed in v3.10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* DEPRECATED 2026-05-13. Use `npm run i18n:run`
|
||||
* (scripts/i18n/run-translation.mjs) for docs translation.
|
||||
*
|
||||
* This Google-Translate-backed generator is kept for the `messages` and
|
||||
* `readme` modes which target `src/i18n/messages/*.json` and root README
|
||||
* variants — those are not yet handled by the new LLM pipeline. The `docs`
|
||||
* mode is superseded and will be removed in v3.10.
|
||||
*/
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
console.warn(
|
||||
"[generate-multilang] DEPRECATED: prefer `npm run i18n:run` for docs (this script will be removed in v3.10)."
|
||||
);
|
||||
|
||||
const ROOT = process.cwd();
|
||||
const MESSAGES_DIR = path.join(ROOT, "src", "i18n", "messages");
|
||||
const DOCS_DIR = path.join(ROOT, "docs");
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
OmniRoute i18n Auto-Translator
|
||||
This script scans all docs/i18n directory markdown files and uses an LLM
|
||||
API (like OmniRoute itself) to translate any English paragraphs into the
|
||||
target language.
|
||||
DEPRECATED 2026-05-13. Use `npm run i18n:run`
|
||||
(scripts/i18n/run-translation.mjs) instead. This Python script will be
|
||||
removed in v3.10.
|
||||
|
||||
Usage:
|
||||
python3 scripts/i18n/i18n_autotranslate.py --api-url http://localhost:20128/v1 --api-key sk-your-omniroute-key --model cx/gpt-5.4
|
||||
The Node-based translator is hash-incremental (only retranslates files
|
||||
whose source SHA-256 changed), runs the OmniRoute Cloud LLM through
|
||||
OMNIROUTE_TRANSLATION_* env vars, and is wired into `npm run i18n:run`
|
||||
and `npm run i18n:check`.
|
||||
|
||||
Historical purpose:
|
||||
Scanned `docs/i18n/` markdown files and translated English paragraphs
|
||||
into the target language by paragraph through an OpenAI-compatible LLM.
|
||||
"""
|
||||
|
||||
import sys
|
||||
print(
|
||||
"WARN: scripts/i18n/i18n_autotranslate.py is deprecated. Use 'npm run i18n:run' instead.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import glob
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
@@ -1,98 +1,68 @@
|
||||
export const LOCALES = [
|
||||
"ar",
|
||||
"bg",
|
||||
"bn",
|
||||
"cs",
|
||||
"da",
|
||||
"de",
|
||||
"en",
|
||||
"es",
|
||||
"fa",
|
||||
"fi",
|
||||
"fr",
|
||||
"gu",
|
||||
"he",
|
||||
"hi",
|
||||
"hu",
|
||||
"id",
|
||||
"in",
|
||||
"it",
|
||||
"ja",
|
||||
"ko",
|
||||
"mr",
|
||||
"ms",
|
||||
"nl",
|
||||
"no",
|
||||
"phi",
|
||||
"pl",
|
||||
"pt",
|
||||
"pt-BR",
|
||||
"ro",
|
||||
"ru",
|
||||
"sk",
|
||||
"sv",
|
||||
"sw",
|
||||
"ta",
|
||||
"te",
|
||||
"th",
|
||||
"tr",
|
||||
"uk-UA",
|
||||
"ur",
|
||||
"vi",
|
||||
"zh-CN",
|
||||
] as const;
|
||||
export type Locale = (typeof LOCALES)[number];
|
||||
export const DEFAULT_LOCALE: Locale = "en";
|
||||
// SOURCE OF TRUTH: `config/i18n.json` (also consumed by the docs translation
|
||||
// pipeline in `scripts/i18n/run-translation.mjs`). Keep this file as a thin
|
||||
// typed adapter — do NOT add hand-maintained locale lists here.
|
||||
|
||||
import i18nConfig from "../../config/i18n.json" with { type: "json" };
|
||||
|
||||
type RawLocaleEntry = {
|
||||
code: string;
|
||||
label: string;
|
||||
name: string;
|
||||
native?: string;
|
||||
english?: string;
|
||||
flag: string;
|
||||
};
|
||||
|
||||
type RawI18nConfig = {
|
||||
default: string;
|
||||
rtl: readonly string[];
|
||||
uiOnly?: readonly string[];
|
||||
docsExcluded?: readonly string[];
|
||||
locales: readonly RawLocaleEntry[];
|
||||
};
|
||||
|
||||
const config = i18nConfig as RawI18nConfig;
|
||||
|
||||
export const LOCALES = config.locales.map((l) => l.code) as readonly string[];
|
||||
export type Locale = (typeof LOCALES)[number];
|
||||
export const DEFAULT_LOCALE: Locale = config.default as Locale;
|
||||
|
||||
/**
|
||||
* Display metadata for every locale, kept in the same shape the codebase has
|
||||
* historically consumed (`code`, `label`, `name`, `flag`). We additionally
|
||||
* expose `native` and `english` as aliases for new call sites that want a
|
||||
* stable field name regardless of the underlying display string.
|
||||
*/
|
||||
export const LANGUAGES: readonly {
|
||||
code: Locale;
|
||||
label: string;
|
||||
name: string;
|
||||
native: string;
|
||||
english: string;
|
||||
flag: string;
|
||||
}[] = [
|
||||
{ code: "ar", label: "AR", name: "العربية", flag: "🇸🇦" },
|
||||
{ code: "bg", label: "BG", name: "Български", flag: "🇧🇬" },
|
||||
{ code: "bn", label: "BN", name: "বাংলা", flag: "🇧🇩" },
|
||||
{ code: "cs", label: "CS", name: "Čeština", flag: "🇨🇿" },
|
||||
{ code: "da", label: "DA", name: "Dansk", flag: "🇩🇰" },
|
||||
{ code: "de", label: "DE", name: "Deutsch", flag: "🇩🇪" },
|
||||
{ code: "en", label: "EN", name: "English", flag: "🇺🇸" },
|
||||
{ code: "es", label: "ES", name: "Español", flag: "🇪🇸" },
|
||||
{ code: "fa", label: "FA", name: "فارسی", flag: "🇮🇷" },
|
||||
{ code: "fi", label: "FI", name: "Suomi", flag: "🇫🇮" },
|
||||
{ code: "fr", label: "FR", name: "Français", flag: "🇫🇷" },
|
||||
{ code: "gu", label: "GU", name: "ગુજરાતી", flag: "🇮🇳" },
|
||||
{ code: "he", label: "HE", name: "עברית", flag: "🇮🇱" },
|
||||
{ code: "hi", label: "HI", name: "हिन्दी", flag: "🇮🇳" },
|
||||
{ code: "hu", label: "HU", name: "Magyar", flag: "🇭🇺" },
|
||||
{ code: "id", label: "ID", name: "Bahasa Indonesia", flag: "🇮🇩" },
|
||||
{ code: "in", label: "IN", name: "Bahasa Indonesia (Alt)", flag: "🇮🇩" },
|
||||
{ code: "it", label: "IT", name: "Italiano", flag: "🇮🇹" },
|
||||
{ code: "ja", label: "JA", name: "日本語", flag: "🇯🇵" },
|
||||
{ code: "ko", label: "KO", name: "한국어", flag: "🇰🇷" },
|
||||
{ code: "mr", label: "MR", name: "मराठी", flag: "🇮🇳" },
|
||||
{ code: "ms", label: "MS", name: "Bahasa Melayu", flag: "🇲🇾" },
|
||||
{ code: "nl", label: "NL", name: "Nederlands", flag: "🇳🇱" },
|
||||
{ code: "no", label: "NO", name: "Norsk", flag: "🇳🇴" },
|
||||
{ code: "phi", label: "PHI", name: "Filipino", flag: "🇵🇭" },
|
||||
{ code: "pl", label: "PL", name: "Polski", flag: "🇵🇱" },
|
||||
{ code: "pt-BR", label: "PT-BR", name: "Português (Brasil)", flag: "🇧🇷" },
|
||||
{ code: "pt", label: "PT", name: "Português (Portugal)", flag: "🇵🇹" },
|
||||
{ code: "ro", label: "RO", name: "Română", flag: "🇷🇴" },
|
||||
{ code: "ru", label: "RU", name: "Русский", flag: "🇷🇺" },
|
||||
{ code: "sk", label: "SK", name: "Slovenčina", flag: "🇸🇰" },
|
||||
{ code: "sv", label: "SV", name: "Svenska", flag: "🇸🇪" },
|
||||
{ code: "sw", label: "SW", name: "Kiswahili", flag: "🇰🇪" },
|
||||
{ code: "ta", label: "TA", name: "தமிழ்", flag: "🇮🇳" },
|
||||
{ code: "te", label: "TE", name: "తెలుగు", flag: "🇮🇳" },
|
||||
{ code: "th", label: "TH", name: "ไทย", flag: "🇹🇭" },
|
||||
{ code: "tr", label: "TR", name: "Türkçe", flag: "🇹🇷" },
|
||||
{ code: "uk-UA", label: "UK-UA", name: "Українська", flag: "🇺🇦" },
|
||||
{ code: "ur", label: "UR", name: "اردو", flag: "🇵🇰" },
|
||||
{ code: "vi", label: "VI", name: "Tiếng Việt", flag: "🇻🇳" },
|
||||
{ code: "zh-CN", label: "ZH-CN", name: "中文 (简体)", flag: "🇨🇳" },
|
||||
] as const;
|
||||
}[] = config.locales.map((entry) => ({
|
||||
code: entry.code as Locale,
|
||||
label: entry.label,
|
||||
name: entry.name,
|
||||
native: entry.native ?? entry.name,
|
||||
english: entry.english ?? entry.name,
|
||||
flag: entry.flag,
|
||||
}));
|
||||
|
||||
export const RTL_LOCALES = ["ar", "fa", "he", "ur"] as const;
|
||||
export const RTL_LOCALES: readonly Locale[] = config.rtl as readonly Locale[];
|
||||
|
||||
export const LOCALE_COOKIE = "NEXT_LOCALE";
|
||||
|
||||
// Convenience helpers --------------------------------------------------------
|
||||
|
||||
/** Locales that the docs translation pipeline writes to (excludes the source). */
|
||||
export const DOCS_TARGET_LOCALES: readonly Locale[] = LANGUAGES.map((l) => l.code).filter(
|
||||
(code) => !(config.docsExcluded ?? []).includes(code)
|
||||
) as readonly Locale[];
|
||||
|
||||
/** Lookup by code; falls back to the default locale entry if not found. */
|
||||
export function getLanguage(code: string) {
|
||||
return (
|
||||
LANGUAGES.find((l) => l.code === code) ?? LANGUAGES.find((l) => l.code === DEFAULT_LOCALE)!
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user