Files
Reactive-Resume/src/utils/locale.ts
T
Amruth Pillai 192880e416 use vite+
2026-03-18 22:03:24 +01:00

174 lines
4.4 KiB
TypeScript

import { i18n, type MessageDescriptor, type Messages } from "@lingui/core";
import { msg } from "@lingui/core/macro";
import { createIsomorphicFn, createServerFn } from "@tanstack/react-start";
import { getCookie, setCookie } from "@tanstack/react-start/server";
import Cookies from "js-cookie";
import z from "zod";
const localeSchema = z.union([
z.literal("af-ZA"),
z.literal("am-ET"),
z.literal("ar-SA"),
z.literal("az-AZ"),
z.literal("bg-BG"),
z.literal("bn-BD"),
z.literal("ca-ES"),
z.literal("cs-CZ"),
z.literal("da-DK"),
z.literal("de-DE"),
z.literal("el-GR"),
z.literal("en-US"),
z.literal("en-GB"),
z.literal("es-ES"),
z.literal("fa-IR"),
z.literal("fi-FI"),
z.literal("fr-FR"),
z.literal("he-IL"),
z.literal("hi-IN"),
z.literal("hu-HU"),
z.literal("id-ID"),
z.literal("it-IT"),
z.literal("ja-JP"),
z.literal("km-KH"),
z.literal("kn-IN"),
z.literal("ko-KR"),
z.literal("lt-LT"),
z.literal("lv-LV"),
z.literal("ml-IN"),
z.literal("mr-IN"),
z.literal("ms-MY"),
z.literal("ne-NP"),
z.literal("nl-NL"),
z.literal("no-NO"),
z.literal("or-IN"),
z.literal("pl-PL"),
z.literal("pt-BR"),
z.literal("pt-PT"),
z.literal("ro-RO"),
z.literal("ru-RU"),
z.literal("sk-SK"),
z.literal("sl-SI"),
z.literal("sq-AL"),
z.literal("sr-SP"),
z.literal("sv-SE"),
z.literal("ta-IN"),
z.literal("te-IN"),
z.literal("th-TH"),
z.literal("tr-TR"),
z.literal("uk-UA"),
z.literal("uz-UZ"),
z.literal("vi-VN"),
z.literal("zh-CN"),
z.literal("zh-TW"),
z.literal("zu-ZA"),
]);
export type Locale = z.infer<typeof localeSchema>;
const storageKey = "locale";
const defaultLocale: Locale = "en-US";
export const localeMap = {
"af-ZA": msg`Afrikaans`,
"am-ET": msg`Amharic`,
"ar-SA": msg`Arabic`,
"az-AZ": msg`Azerbaijani`,
"bg-BG": msg`Bulgarian`,
"bn-BD": msg`Bengali`,
"ca-ES": msg`Catalan`,
"cs-CZ": msg`Czech`,
"da-DK": msg`Danish`,
"de-DE": msg`German`,
"el-GR": msg`Greek`,
"en-US": msg`English`,
"en-GB": msg`English (United Kingdom)`,
"es-ES": msg`Spanish`,
"fa-IR": msg`Persian`,
"fi-FI": msg`Finnish`,
"fr-FR": msg`French`,
"he-IL": msg`Hebrew`,
"hi-IN": msg`Hindi`,
"hu-HU": msg`Hungarian`,
"id-ID": msg`Indonesian`,
"it-IT": msg`Italian`,
"ja-JP": msg`Japanese`,
"km-KH": msg`Khmer`,
"kn-IN": msg`Kannada`,
"ko-KR": msg`Korean`,
"lt-LT": msg`Lithuanian`,
"lv-LV": msg`Latvian`,
"ml-IN": msg`Malayalam`,
"mr-IN": msg`Marathi`,
"ms-MY": msg`Malay`,
"ne-NP": msg`Nepali`,
"nl-NL": msg`Dutch`,
"no-NO": msg`Norwegian`,
"or-IN": msg`Odia`,
"pl-PL": msg`Polish`,
"pt-BR": msg`Portuguese (Brazil)`,
"pt-PT": msg`Portuguese (Portugal)`,
"ro-RO": msg`Romanian`,
"ru-RU": msg`Russian`,
"sk-SK": msg`Slovak`,
"sl-SI": msg`Slovenian`,
"sq-AL": msg`Albanian`,
"sr-SP": msg`Serbian`,
"sv-SE": msg`Swedish`,
"ta-IN": msg`Tamil`,
"te-IN": msg`Telugu`,
"th-TH": msg`Thai`,
"tr-TR": msg`Turkish`,
"uk-UA": msg`Ukrainian`,
"uz-UZ": msg`Uzbek`,
"vi-VN": msg`Vietnamese`,
"zh-CN": msg`Chinese (Simplified)`,
"zh-TW": msg`Chinese (Traditional)`,
"zu-ZA": msg`Zulu`,
} satisfies Record<Locale, MessageDescriptor>;
export function isLocale(locale: string): locale is Locale {
return localeSchema.safeParse(locale).success;
}
const RTL_LANGUAGES = new Set([
"ar", // Arabic
"ckb", // Kurdish (Sorani)
"dv", // Dhivehi
"fa", // Persian
"he", // Hebrew
"ps", // Pashto
"sd", // Sindhi
"ug", // Uyghur
"ur", // Urdu
"yi", // Yiddish
]);
export function isRTL(locale: string): boolean {
const language = locale.split("-")[0].toLowerCase();
return RTL_LANGUAGES.has(language);
}
export const getLocale = createIsomorphicFn()
.client(() => {
const locale = Cookies.get(storageKey);
if (!locale || !isLocale(locale)) return defaultLocale;
return locale;
})
.server(async () => {
const cookieLocale = getCookie(storageKey);
if (!cookieLocale || !isLocale(cookieLocale)) return defaultLocale;
return cookieLocale;
});
export const setLocaleServerFn = createServerFn({ method: "POST" })
.inputValidator(localeSchema)
.handler(async ({ data }) => {
setCookie(storageKey, data);
});
export const loadLocale = async (locale: string) => {
if (!isLocale(locale)) locale = defaultLocale;
const { messages } = await (import(`../../locales/${locale}.po`) as Promise<{ messages: Messages }>);
i18n.loadAndActivate({ locale, messages });
};