From 8fd2c664414c4f8570fcdd149c7005fd1f858791 Mon Sep 17 00:00:00 2001 From: dumbmoron Date: Wed, 3 Jul 2024 19:28:44 +0000 Subject: [PATCH] web/i18n: dynamically determine languages from i18n folder contents --- web/src/lib/i18n/translations.ts | 151 ++++++++----------------------- web/src/lib/types/generic.ts | 2 + web/src/lib/types/i18n.ts | 11 +++ 3 files changed, 50 insertions(+), 114 deletions(-) create mode 100644 web/src/lib/types/i18n.ts diff --git a/web/src/lib/i18n/translations.ts b/web/src/lib/i18n/translations.ts index 8ddac2d4..ca61e89b 100644 --- a/web/src/lib/i18n/translations.ts +++ b/web/src/lib/i18n/translations.ts @@ -1,125 +1,48 @@ import i18n from 'sveltekit-i18n'; -import type { Config } from 'sveltekit-i18n'; + +import type { Config } from 'sveltekit-i18n' +import type { + GenericImport, + StructuredLocfileInfo, + LocalizationContent +} from '$lib/types/i18n'; import languages from '$i18n/languages.json'; -export const defaultLocale = 'en'; +const locFiles = import.meta.glob('$i18n/*/**/*.json'); +const parsedLocfiles: StructuredLocfileInfo = {}; -export const config: Config = { - translations: { - en: { languages }, - ru: { languages }, - }, - loaders: [ - { - locale: 'en', - key: 'tabs', - loader: async () => ( - await import(`$i18n/en/tabs.json`) - ).default, - }, - { - locale: 'en', - key: 'a11y.tabs', - loader: async () => ( - await import(`$i18n/en/a11y/tabs.json`) - ).default, - }, - { - locale: 'en', - key: 'save', - loader: async () => ( - await import(`$i18n/en/save.json`) - ).default, - }, - { - locale: 'en', - key: 'a11y.save', - loader: async () => ( - await import(`$i18n/en/a11y/save.json`) - ).default, - }, - { - locale: 'en', - key: 'a11y.meowbalt', - loader: async () => ( - await import(`$i18n/en/a11y/meowbalt.json`) - ).default, - }, - { - locale: 'en', - key: 'settings', - loader: async () => ( - await import(`$i18n/en/settings.json`) - ).default, - }, - { - locale: 'en', - key: 'general', - loader: async () => ( - await import(`$i18n/en/general.json`) - ).default, - }, - { - locale: 'en', - key: 'a11y.general', - loader: async () => ( - await import(`$i18n/en/a11y/general.json`) - ).default, - }, +for (const [ path, loader ] of Object.entries(locFiles)) { + const [,, lang, ...keyComponents ] = path.split('/'); + const key = keyComponents.map(k => k.replace('.json', '')).join('.'); + parsedLocfiles[lang] = { + ...parsedLocfiles[lang], + [key]: loader as GenericImport + }; +} - { - locale: 'ru', - key: 'tabs', - loader: async () => ( - await import(`$i18n/ru/tabs.json`) - ).default, - }, - { - locale: 'ru', - key: 'a11y.tabs', - loader: async () => ( - await import(`$i18n/ru/a11y/tabs.json`) - ).default, - }, - { - locale: 'ru', - key: 'save', - loader: async () => ( - await import(`$i18n/ru/save.json`) - ).default, - }, - { - locale: 'ru', - key: 'a11y.save', - loader: async () => ( - await import(`$i18n/ru/a11y/save.json`) - ).default, - }, - { - locale: 'ru', - key: 'a11y.meowbalt', - loader: async () => ( - await import(`$i18n/ru/a11y/meowbalt.json`) - ).default, - }, - { - locale: 'ru', - key: 'general', - loader: async () => ( - await import(`$i18n/ru/general.json`) - ).default, - }, - { - locale: 'ru', - key: 'a11y.general', - loader: async () => ( - await import(`$i18n/ru/a11y/general.json`) - ).default, - }, - ], +const defaultLocale = 'en'; +const config: Config = { + translations: Object.keys(parsedLocfiles).reduce((obj, lang) => { + return { + ...obj, + [lang]: { languages } + } + }, {}), + loaders: Object.entries(parsedLocfiles).map(([ lang, keys ]) => { + return Object.entries(keys).map(([ key, importer ]) => { + return { + locale: lang, + key, + loader: () => importer().then( + l => l.default as LocalizationContent + ) + } + }); + }).flat() }; +export { defaultLocale }; export const { t, loading, locales, locale, translations, loadTranslations, addTranslations, setLocale, setRoute diff --git a/web/src/lib/types/generic.ts b/web/src/lib/types/generic.ts index c2927964..610354ad 100644 --- a/web/src/lib/types/generic.ts +++ b/web/src/lib/types/generic.ts @@ -6,3 +6,5 @@ export type RecursivePartial = { Type[Key] extends object | undefined ? RecursivePartial : Type[Key]; }; + +export type DefaultImport = () => Promise<{ default: T }>; diff --git a/web/src/lib/types/i18n.ts b/web/src/lib/types/i18n.ts new file mode 100644 index 00000000..7a2a7efc --- /dev/null +++ b/web/src/lib/types/i18n.ts @@ -0,0 +1,11 @@ +import type { DefaultImport } from '$lib/types/generic'; + +type LanguageCode = string; +type KeyPath = string; + +export type GenericImport = DefaultImport; +export type LocalizationContent = Record; +export type StructuredLocfileInfo = Record< + LanguageCode, + Record +>;