1 import type { Maybe, MaybePromise } from '@proton/pass/types';
2 import { logger } from '@proton/pass/utils/logger';
3 import type { Subscriber } from '@proton/pass/utils/pubsub/factory';
4 import { createPubSub } from '@proton/pass/utils/pubsub/factory';
5 import { DEFAULT_LOCALE } from '@proton/shared/lib/constants';
6 import { localeCode } from '@proton/shared/lib/i18n';
7 import { getClosestLocaleCode, getLanguageCode } from '@proton/shared/lib/i18n/helper';
8 import { loadDateLocale, loadLocale } from '@proton/shared/lib/i18n/loadLocale';
9 import { setTtagLocales } from '@proton/shared/lib/i18n/locales';
10 import { type TtagLocaleMap } from '@proton/shared/lib/interfaces/Locale';
11 import noop from '@proton/utils/noop';
13 type I18nServiceOptions = {
14 locales: TtagLocaleMap;
15 loadDateLocale: boolean;
16 getLocale: () => MaybePromise<Maybe<string>>;
17 onLocaleChange?: (locale: string) => void;
20 type LocaleEvent = { locale: string };
22 export const createI18nService = (options: I18nServiceOptions) => {
23 setTtagLocales(options.locales);
24 const pubsub = createPubSub<LocaleEvent>();
26 const hasRegion = (locale: string) => /[_-]/.test(locale);
28 const getFallbackLocale = (): string => {
29 const [fst, snd] = navigator.languages;
30 if (!fst && !snd) return DEFAULT_LOCALE;
32 return !hasRegion(fst) && hasRegion(snd) && getLanguageCode(fst) === getLanguageCode(snd) ? snd : fst;
35 const getLocale = async () => (await options.getLocale()) ?? getFallbackLocale();
37 const setLocale = async (locale?: string) => {
39 const nextLocale = getClosestLocaleCode(locale ?? (await getLocale()), options.locales);
41 if (options.loadDateLocale) await loadDateLocale(nextLocale).catch(noop);
43 await loadLocale(nextLocale, options.locales);
44 options.onLocaleChange?.(nextLocale);
45 pubsub.publish({ locale: nextLocale });
47 if (nextLocale !== localeCode) logger.info(`[I18nService] changing locale to ${locale}`);
55 subscribe: (fn: Subscriber<LocaleEvent>) => pubsub.subscribe(fn),
56 unsubscribe: () => pubsub.unsubscribe(),
60 export type I18nService = ReturnType<typeof createI18nService>;