feat: implemented new i18n system

This commit is contained in:
Benjamin Singleton 2025-06-14 11:57:28 -05:00
parent 4b4e8b7aa8
commit 032cfb2bfd
11 changed files with 254 additions and 124 deletions

View file

@ -1,17 +1,56 @@
import { createI18n } from "vue-i18n";
import en_US from "../locales/en_US";
import vp_VL from "../locales/vp_VL";
import type { MessageSchema } from "./types";
import { computed, reactive, readonly, ref } from "vue";
import type { Locale } from "./locale";
const locales = { en_US, vp_VL } as const;
export const LOCALE_IDS = ["en_US", "vp_VL"] as const;
export type LocaleId = (typeof LOCALE_IDS)[number];
export type Locale = keyof typeof locales;
const locales = { en_US, vp_VL } as const satisfies Record<LocaleId, Locale>;
const i18n = createI18n<[MessageSchema], Locale>({
legacy: false,
locale: "en_US" satisfies Locale,
fallbackLocale: "en_US" satisfies Locale,
messages: locales,
});
export const localeId = ref<LocaleId>("en_US");
export default i18n;
export function useLocale(opt: UseLocaleOptions = {}) {
const locale = computed<Locale>(() => {
return fallbackProxy(
locales[opt.locale ?? localeId.value],
locales["en_US"],
);
});
return readonly(reactive(locale));
}
export interface UseLocaleOptions {
locale?: LocaleId;
}
function fallbackProxy(obj: any, fallback: any) {
return new Proxy(obj, {
get: (target, key) => {
const value = target[key];
const fallbackValue = fallback[key];
if (value === undefined) {
return fallbackValue;
}
if (value === null && fallbackValue !== null) {
return fallbackValue;
}
if (
value === null
|| fallbackValue === null
|| typeof value !== "object"
|| typeof fallbackValue !== "object"
) {
return value;
}
return fallbackProxy(value, fallbackValue);
},
set: () => {
throw new Error("Cannot mutate locale at runtime");
},
});
}

View file

@ -0,0 +1,39 @@
export interface Locale {
localeName: string;
home: Layout<HomeSections>;
resources: Layout<Resources>;
}
export interface Layout<T> {
layout: (keyof T)[];
data: { [K in keyof T]: T[K] | null };
}
export interface HomeSections {
whatIsViossa: HomeSection;
historyOfViossa: HomeSection;
community: HomeSection;
}
export interface HomeSection {
title: string;
text: string;
image: string | null;
alt: string | null;
}
export interface Resources {
discord: Resource;
}
export interface Resource {
title: string;
subtitle: string;
desc: string;
link: string;
rulesLink: string;
image: string;
alt: string;
joinText: string;
rulesText: string;
}

View file

@ -1,8 +0,0 @@
import en_US from "../locales/en_US";
export interface MessageSchema extends Broaden<typeof en_US> {}
type Broaden<T> = {
[K in keyof T]: T[K] extends object ? Broaden<T[K]>
: T[K] extends string ? string
: T[K];
} & {};