diff --git a/web/src/lib/components/shared-components/settings/SettingsLanguageSelector.svelte b/web/src/lib/components/shared-components/settings/SettingsLanguageSelector.svelte index 269edb2204..146c37b7ec 100644 --- a/web/src/lib/components/shared-components/settings/SettingsLanguageSelector.svelte +++ b/web/src/lib/components/shared-components/settings/SettingsLanguageSelector.svelte @@ -3,7 +3,7 @@ import Combobox from '$lib/components/shared-components/Combobox.svelte'; import { defaultLang } from '$lib/constants'; import { lang } from '$lib/stores/preferences.store'; - import { getClosestAvailableLocale, langCodes, langs } from '$lib/utils/i18n'; + import { convertBCP47, getClosestAvailableLocale, langCodes, langs } from '$lib/utils/i18n'; import { Label, Text } from '@immich/ui'; import { locale as i18nLocale, t } from 'svelte-i18n'; @@ -13,14 +13,14 @@ let { showSettingDescription = false }: Props = $props(); - const langOptions = langs.map((lang) => ({ label: lang.name, value: lang.code })); + const langOptions = langs.map((lang) => ({ label: lang.name, value: convertBCP47(lang.code) })); const defaultLangOption = { label: defaultLang.name, value: defaultLang.code }; const handleLanguageChange = async (newLang: string | undefined) => { if (newLang) { $lang = newLang; - await i18nLocale.set(newLang); + await i18nLocale.set(convertBCP47(newLang)); await invalidateAll(); } }; diff --git a/web/src/lib/stores/preferences.store.ts b/web/src/lib/stores/preferences.store.ts index d08dfc0475..2584312220 100644 --- a/web/src/lib/stores/preferences.store.ts +++ b/web/src/lib/stores/preferences.store.ts @@ -1,12 +1,12 @@ import { persisted } from 'svelte-persisted-store'; import { browser } from '$app/environment'; import { defaultLang } from '$lib/constants'; -import { getPreferredLocale } from '$lib/utils/i18n'; +import { convertBCP47, getPreferredLocale } from '$lib/utils/i18n'; // Locale to use for formatting dates, numbers, etc. export const locale = persisted('locale', 'default', { serializer: { - parse: (text) => text || 'default', + parse: (text) => convertBCP47(text) || 'default', stringify: (object) => object ?? '', }, }); @@ -14,7 +14,7 @@ export const locale = persisted('locale', 'default', { const preferredLocale = browser ? getPreferredLocale() : undefined; export const lang = persisted('lang', preferredLocale || defaultLang.code, { serializer: { - parse: (text) => text, + parse: (text) => convertBCP47(text), stringify: (object) => object ?? '', }, }); diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 4ff3564ffa..0e31782164 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -28,7 +28,7 @@ import { downloadManager } from '$lib/managers/download-manager.svelte'; import { alwaysLoadOriginalFile, lang } from '$lib/stores/preferences.store'; import { isWebCompatibleImage } from '$lib/utils/asset-utils'; import { handleError } from '$lib/utils/handle-error'; -import { langs } from '$lib/utils/i18n'; +import { convertBCP47, langs } from '$lib/utils/i18n'; interface DownloadRequestOptions { method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; @@ -47,7 +47,7 @@ interface DateFormatter { export const initLanguage = async () => { const preferenceLang = get(lang); for (const { code, loader } of langs) { - register(code, loader); + register(convertBCP47(code), loader); } await init({ fallbackLocale: preferenceLang === 'dev' ? 'dev' : defaultLang.code, initialLocale: preferenceLang }); diff --git a/web/src/lib/utils/i18n.ts b/web/src/lib/utils/i18n.ts index d179efb5bd..85331ddf7c 100644 --- a/web/src/lib/utils/i18n.ts +++ b/web/src/lib/utils/i18n.ts @@ -19,7 +19,7 @@ const fileCodes = Object.keys(modules) .map((path) => path.match(/\/(\w+)\.json$/)?.[1]) .filter(Boolean) as string[]; -const convertBCP47 = (code: string) => code.replaceAll('_', '-'); +export const convertBCP47 = (code: string) => code.replaceAll('_', '-'); export const langCodes = fileCodes.map((code) => convertBCP47(code));