Add i18n support

This commit is contained in:
2023-05-28 11:44:01 +08:00
parent 8f0ed03117
commit affe85f81c
11 changed files with 140 additions and 10 deletions

16
server/i18n.ts Normal file
View File

@@ -0,0 +1,16 @@
import { signal } from "@preact/signals";
export type I18NMap = { [x: string]: string | I18NMap };
export const i18n_map = signal<I18NMap>({});
const NOT_FOUND = "__NOT_FOUND__";
export default function t(key: string) {
const keys = key.split(".");
let map: string | I18NMap = i18n_map.value;
for (const k of keys) {
if (typeof map === "string") return NOT_FOUND;
else map = map[k];
}
return typeof map === "string" ? map : NOT_FOUND;
}

72
server/i18ns.ts Normal file
View File

@@ -0,0 +1,72 @@
import { exists } from "std/fs/exists.ts";
import { parse } from "std/jsonc/mod.ts";
import { join } from "std/path/mod.ts";
import { I18NMap } from "./i18n.ts";
import { pick } from "accept-language-parser/";
const whole_maps = new Map<string, I18NMap>();
const LANGUAGES = ["zh-cn"];
type MODULE = "common";
const MODULES: MODULE[] = ["common"];
export async function load_translation(signal?: AbortSignal) {
const base = import.meta.resolve("../translation").slice(8);
const enmap: I18NMap = {};
for (const m of MODULES) {
const t = await Deno.readTextFile(join(base, "en", m + ".jsonc"), {
signal,
});
const v = <I18NMap> <unknown> parse(t);
enmap[m] = v;
}
whole_maps.set("en", enmap);
for (const l of LANGUAGES) {
const map: I18NMap = {};
for (const m of MODULES) {
const p = join(base, l, m + ".jsonc");
if (await exists(p)) {
const t = await Deno.readTextFile(join(base, l, m + ".jsonc"), {
signal,
});
const v = <I18NMap> <unknown> Object.assign(
structuredClone(enmap[m]),
parse(t),
);
map[m] = v;
} else map[m] = enmap[m];
}
whole_maps.set(l, map);
}
}
export function get_i18nmap(lang: string, ...modules: MODULE[]) {
const m = whole_maps.get(lang);
if (!m) throw Error(`Language ${lang} is not supported.`);
if (!modules.length) return m;
const r: I18NMap = {};
for (const n of modules) {
r[n] = m[n];
}
return r;
}
export function i18n_handle_request(req: Request) {
const u = new URL(req.url);
const lang = u.searchParams.get("lang");
if (lang && (lang === "en" || LANGUAGES.includes(lang))) {
return lang;
} else {
const a = req.headers.get("Accept-Language");
const l = (a
? pick(LANGUAGES, a) || pick(LANGUAGES, a, { loose: true })
: null) || "en";
const params = new URLSearchParams();
params.append("lang", l);
for (const p of u.searchParams.entries()) {
if (p[0] !== "lang") {
params.append(p[0], p[1]);
}
}
return Response.redirect(`${u.origin}${u.pathname}?${params}`);
}
}