Added typescript to workspace devdeps, removed no unused var rules from

tsconfig, made i18n not use top-level await, upgraded packages/made sure
they were on compatible versions
This commit is contained in:
Benjamin Singleton 2026-04-17 20:18:41 -05:00
parent 20a1b867f5
commit 2c63701152
7 changed files with 591 additions and 389 deletions

View file

@ -18,9 +18,8 @@
"axios": "^1.11.0",
"bulma": "^1.0.4",
"tailwindcss": "^4.1.6",
"vue": "^3.5.13",
"vue-i18n": "^11.1.3",
"vue-router": "^4.5.1"
"vue-router": "^5.0.4"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
@ -34,10 +33,11 @@
"sass": "^1.87.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.55.0",
"unplugin-vue-router": "^0.12.0",
"unplugin-vue-router": "^0.19.2",
"vite": "^6.3.5",
"vue": "^3.5.32",
"vue-eslint-parser": "^10.2.0",
"vue-tsc": "^2.2.8"
"vue-tsc": "^3.2.6"
},
"packageManager": "pnpm@10.11.0"
}

View file

@ -13,6 +13,7 @@ import vpVlFtlSrc from "@/assets/locale/vp_VL.ftl";
import wpVlFtlSrc from "@/assets/locale/wp_VL.ftl";
import type { FluentBundle } from "@fluent/bundle";
import { compileLocale } from "@/vi18n-lib/compile";
import type { ComputedRef } from "vue";
export const LOCALE_IDS = ["en-US", "vp-VL", "wp-VL"] as const;
@ -143,42 +144,71 @@ function deepReadonly<T>(value: T): DeepReadonly<T> {
return value as DeepReadonly<T>;
}
const DEFAULT_LOCALE_BUNDLE = unwrap(await loadLocale("en-US", enUsFtlSrc));
const DEFAULT_LOCALE = unwrap(
setupLocale(DEFAULT_LOCALE_ID, DEFAULT_LOCALE_BUNDLE, undefined),
);
interface I18n {
useLocale: (opt?: UseLocaleOptions) => ComputedRef<DeepReadonly<Locale>>;
}
const doItAllForLocale = async (
localeId: LocaleId,
localeFtlSrc: string,
): Promise<DeepReadonly<Locale>> =>
deepReadonly(
unwrap(
setupLocale(
localeId,
unwrap(await loadLocale(localeId, localeFtlSrc)),
{ bundle: DEFAULT_LOCALE_BUNDLE, locale: DEFAULT_LOCALE },
),
),
async function initI18n(): Promise<I18n> {
const defaultLocaleBundle = unwrap(await loadLocale("en-US", enUsFtlSrc));
const defaultLocale = unwrap(
setupLocale(DEFAULT_LOCALE_ID, defaultLocaleBundle, undefined),
);
const [vpVl, wpVl] = await Promise.all([
doItAllForLocale("vp-VL", vpVlFtlSrc),
doItAllForLocale("wp-VL", wpVlFtlSrc),
]);
const doItAllForLocale = async (
localeId: LocaleId,
localeFtlSrc: string,
): Promise<DeepReadonly<Locale>> =>
deepReadonly(
unwrap(
setupLocale(
localeId,
unwrap(await loadLocale(localeId, localeFtlSrc)),
{ bundle: defaultLocaleBundle, locale: defaultLocale },
),
),
);
const localeIdToLocale = {
"en-US": deepReadonly(DEFAULT_LOCALE),
"vp-VL": vpVl,
"wp-VL": wpVl,
} as const satisfies Record<LocaleId, DeepReadonly<Locale>>;
const [vpVl, wpVl] = await Promise.all([
doItAllForLocale("vp-VL", vpVlFtlSrc),
doItAllForLocale("wp-VL", wpVlFtlSrc),
]);
const localeIdToLocale = {
"en-US": deepReadonly(defaultLocale),
"vp-VL": vpVl,
"wp-VL": wpVl,
} as const satisfies Record<LocaleId, DeepReadonly<Locale>>;
const useLocale = (opt: UseLocaleOptions = {}) =>
computed<DeepReadonly<Locale>>(() => {
const localLocaleId = opt.locale ?? localeId.value;
return localeIdToLocale[localLocaleId];
});
return { useLocale };
}
export interface UseLocaleOptions {
locale?: LocaleId;
}
export const useLocale = (opt: UseLocaleOptions = {}) =>
computed<DeepReadonly<Locale>>(() => {
const localLocaleId = opt.locale ?? localeId.value;
return localeIdToLocale[localLocaleId];
});
const initI18nPromise = initI18n();
let i18n: I18n | null = null;
initI18nPromise.then((x) => {
i18n = x;
});
export const onI18nInit = (f: () => void) => {
initI18nPromise.then(f);
};
export const useLocale = (
opt: UseLocaleOptions = {},
): ComputedRef<DeepReadonly<Locale>> => {
if (i18n === null) {
throw new Error("Cannot use i18n before initialized!");
}
return i18n.useLocale(opt);
};

View file

@ -1,5 +1,8 @@
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { onI18nInit } from "./i18n";
createApp(App).use(router).mount("#app");
onI18nInit(() => {
createApp(App).use(router).mount("#app");
});

View file

@ -1,10 +1,15 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
// noinspection ES6UnusedImports
// Generated by unplugin-vue-router. !! DO NOT MODIFY THIS FILE !!
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
declare module 'vue-router/auto-resolver' {
export type ParamParserCustom = never
}
declare module 'vue-router/auto-routes' {
import type {
RouteRecordInfo,
@ -18,9 +23,81 @@ declare module 'vue-router/auto-routes' {
* Route name map generated by unplugin-vue-router
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
'/discord/rules': RouteRecordInfo<'/discord/rules', '/discord/rules', Record<never, never>, Record<never, never>>,
'/kotoba': RouteRecordInfo<'/kotoba', '/kotoba', Record<never, never>, Record<never, never>>,
'/resources': RouteRecordInfo<'/resources', '/resources', Record<never, never>, Record<never, never>>,
'/': RouteRecordInfo<
'/',
'/',
Record<never, never>,
Record<never, never>,
| never
>,
'/discord/rules': RouteRecordInfo<
'/discord/rules',
'/discord/rules',
Record<never, never>,
Record<never, never>,
| never
>,
'/kotoba': RouteRecordInfo<
'/kotoba',
'/kotoba',
Record<never, never>,
Record<never, never>,
| never
>,
'/resources': RouteRecordInfo<
'/resources',
'/resources',
Record<never, never>,
Record<never, never>,
| never
>,
}
/**
* Route file to route info map by unplugin-vue-router.
* Used by the \`sfc-typed-router\` Volar plugin to automatically type \`useRoute()\`.
*
* Each key is a file path relative to the project root with 2 properties:
* - routes: union of route names of the possible routes when in this page (passed to useRoute<...>())
* - views: names of nested views (can be passed to <RouterView name="...">)
*
* @internal
*/
export interface _RouteFileInfoMap {
'pages/index.vue': {
routes:
| '/'
views:
| never
}
'pages/discord/rules.vue': {
routes:
| '/discord/rules'
views:
| never
}
'pages/kotoba.vue': {
routes:
| '/kotoba'
views:
| never
}
'pages/resources.vue': {
routes:
| '/resources'
views:
| never
}
}
/**
* Get a union of possible route names in a certain route component file.
* Used by the \`sfc-typed-router\` Volar plugin to automatically type \`useRoute()\`.
*
* @internal
*/
export type _RouteNamesForFilePath<FilePath extends string> =
_RouteFileInfoMap extends Record<FilePath, infer Info>
? Info['routes']
: keyof RouteNamedMap
}

View file

@ -1,36 +1,23 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"noUncheckedIndexedAccess": true,
"module": "esnext",
"moduleResolution": "bundler",
"target": "esnext",
"lib": [
"ESNext",
"DOM",
],
"rootDir": "src",
"paths": {
"@/*": [
"./src/*"
]
},
},
"vueCompilerOptions": {
"strictTemplates": true,
},
"include": [
"src",
],
"exclude": [
"./eslint.config.js"
]
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
/* Linting */
"strict": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"noUncheckedIndexedAccess": true,
"module": "esnext",
"moduleResolution": "bundler",
"target": "esnext",
"lib": ["ESNext", "DOM"],
"rootDir": "src",
"paths": { "@/*": ["./src/*"] },
},
"vueCompilerOptions": { "strictTemplates": true },
"include": ["src"],
"exclude": ["./eslint.config.js"],
}