Spaces:
Runtime error
Runtime error
| import { readFileSync, existsSync } from "node:fs"; | |
| import { dirname, join } from "node:path"; | |
| import { fileURLToPath } from "node:url"; | |
| const __dirname = dirname(fileURLToPath(import.meta.url)); | |
| const LOCALES_DIR = join(__dirname, "locales"); | |
| const FALLBACK_LOCALE = "en"; | |
| const cache = new Map(); | |
| let activeLocale = null; | |
| let fallbackCatalog = null; | |
| export function detectLocale() { | |
| const raw = | |
| process.env.OMNIROUTE_LANG || | |
| process.env.LC_ALL || | |
| process.env.LC_MESSAGES || | |
| process.env.LANG || | |
| FALLBACK_LOCALE; | |
| return normalize(raw); | |
| } | |
| function normalize(raw) { | |
| const stripped = String(raw).split(".")[0].replaceAll("_", "-"); | |
| if (!stripped || !/^[a-zA-Z0-9-]+$/.test(stripped)) return FALLBACK_LOCALE; | |
| if (hasCatalog(stripped)) return stripped; | |
| const base = stripped.split("-")[0]; | |
| if (hasCatalog(base)) return base; | |
| return FALLBACK_LOCALE; | |
| } | |
| function hasCatalog(locale) { | |
| return existsSync(join(LOCALES_DIR, `${locale}.json`)); | |
| } | |
| function flattenToMap(obj, prefix, result) { | |
| for (const [key, value] of Object.entries(obj)) { | |
| const fullKey = prefix ? `${prefix}.${key}` : key; | |
| if (value !== null && typeof value === "object" && !Array.isArray(value)) { | |
| flattenToMap(value, fullKey, result); | |
| } else if (typeof value === "string") { | |
| result.set(fullKey, value); | |
| } | |
| } | |
| } | |
| function loadCatalog(locale) { | |
| if (cache.has(locale)) return cache.get(locale); | |
| const file = join(LOCALES_DIR, `${locale}.json`); | |
| if (!existsSync(file)) { | |
| cache.set(locale, null); | |
| return null; | |
| } | |
| try { | |
| const parsed = JSON.parse(readFileSync(file, "utf8")); | |
| const flat = new Map(); | |
| flattenToMap(parsed, "", flat); | |
| cache.set(locale, flat); | |
| return flat; | |
| } catch { | |
| cache.set(locale, null); | |
| return null; | |
| } | |
| } | |
| export function setLocale(locale) { | |
| activeLocale = normalize(locale); | |
| loadCatalog(activeLocale); | |
| return activeLocale; | |
| } | |
| export function getLocale() { | |
| if (!activeLocale) activeLocale = detectLocale(); | |
| return activeLocale; | |
| } | |
| function interpolate(template, vars) { | |
| if (!vars) return template; | |
| const entries = Object.entries(vars); | |
| if (entries.length === 0) return template; | |
| const varMap = new Map(entries); | |
| return template.replace(/\{(\w+)\}/g, (match, name) => { | |
| const v = varMap.get(name); | |
| return v !== undefined ? String(v) : match; | |
| }); | |
| } | |
| export function t(key, vars) { | |
| if (!activeLocale) activeLocale = detectLocale(); | |
| const primary = loadCatalog(activeLocale); | |
| const fromPrimary = primary?.get(key); | |
| if (fromPrimary !== undefined) return interpolate(fromPrimary, vars); | |
| if (activeLocale !== FALLBACK_LOCALE) { | |
| if (!fallbackCatalog) fallbackCatalog = loadCatalog(FALLBACK_LOCALE); | |
| const fromFallback = fallbackCatalog?.get(key); | |
| if (fromFallback !== undefined) return interpolate(fromFallback, vars); | |
| } | |
| return key; | |
| } | |
| export function resetForTests() { | |
| cache.clear(); | |
| activeLocale = null; | |
| fallbackCatalog = null; | |
| } | |