| | |
| | | import zh from "./zh.json"; |
| | | import en from "./en.json"; |
| | | import fr from "./fr.json"; |
| | | import de from "./de.json"; |
| | | import es from "./es.json"; |
| | | import it from "./it.json"; |
| | | import pt from "./pt.json"; |
| | | import ja from "./ja.json"; |
| | | import ko from "./ko.json"; |
| | | import { writable } from "svelte/store"; |
| | | |
| | | export type Locale = "zh" | "en"; |
| | | export type Locale = "zh" | "en" | "fr" | "de" | "es" | "it" | "pt" | "ja" | "ko"; |
| | | |
| | | const translations: Record<Locale, Record<string, any>> = { zh, en }; |
| | | const translations: Record<Locale, Record<string, any>> = { zh, en, fr, de, es, it, pt, ja, ko }; |
| | | export const localeRevision = writable(0); |
| | | |
| | | // Detect system language, default to Chinese |
| | | function detectLocale(): Locale { |
| | | const lang = navigator.language.toLowerCase(); |
| | | if (lang.startsWith("zh")) return "zh"; |
| | | if (lang.startsWith("fr")) return "fr"; |
| | | if (lang.startsWith("de")) return "de"; |
| | | if (lang.startsWith("es")) return "es"; |
| | | if (lang.startsWith("it")) return "it"; |
| | | if (lang.startsWith("pt")) return "pt"; |
| | | if (lang.startsWith("ja")) return "ja"; |
| | | if (lang.startsWith("ko")) return "ko"; |
| | | return "en"; |
| | | } |
| | | |
| | | let currentLocale: Locale = detectLocale(); |
| | | |
| | | function normalizeLocale(locale: string): Locale { |
| | | return locale.toLowerCase().startsWith("zh") ? "zh" : "en"; |
| | | const normalized = locale.toLowerCase(); |
| | | if (normalized.startsWith("zh")) return "zh"; |
| | | for (const candidate of ["fr", "de", "es", "it", "pt", "ja", "ko"] as Locale[]) { |
| | | if (normalized.startsWith(candidate)) return candidate; |
| | | } |
| | | return "en"; |
| | | } |
| | | |
| | | export function setLocale(locale: Locale | string) { |
| | |
| | | */ |
| | | export function t(key: string, params?: Record<string, string>): string { |
| | | const parts = key.split("."); |
| | | let value: any = translations[currentLocale]; |
| | | let value: any = readPath(translations[currentLocale], parts); |
| | | |
| | | for (const part of parts) { |
| | | if (value == null) return key; |
| | | value = value[part]; |
| | | if (typeof value !== "string" && currentLocale !== "en") { |
| | | value = readPath(translations.en, parts); |
| | | } |
| | | |
| | | if (typeof value !== "string") return key; |
| | |
| | | |
| | | return value; |
| | | } |
| | | |
| | | function readPath(source: Record<string, any>, parts: string[]): any { |
| | | let value: any = source; |
| | | for (const part of parts) { |
| | | if (value == null) return undefined; |
| | | value = value[part]; |
| | | } |
| | | return value; |
| | | } |