UNPKG

@hug/ngx-g11n

Version:

Angular helpers for internationalizing and localizing your application

214 lines (208 loc) 8.02 kB
import { inject, LOCALE_ID, DEFAULT_CURRENCY_CODE, APP_INITIALIZER, InjectionToken } from '@angular/core'; import { registerLocaleData } from '@angular/common'; import { loadTranslations } from '@angular/localize'; var G11nDebug; (function (G11nDebug) { G11nDebug[G11nDebug["SHOW_KEYS"] = 0] = "SHOW_KEYS"; G11nDebug[G11nDebug["DUMMY_TRANSLATIONS"] = 1] = "DUMMY_TRANSLATIONS"; G11nDebug[G11nDebug["NO_DEBUG"] = 2] = "NO_DEBUG"; })(G11nDebug || (G11nDebug = {})); /* eslint-disable @typescript-eslint/no-non-null-assertion */ const STORAGE_KEY = 'hug-ngx-g11n:lang'; let QUERY_PARAM_NAME = 'lang'; let FORCE_DEBUG = G11nDebug.NO_DEBUG; /** * @internal */ const DEFAULT_OPTIONS = { defaultLanguage: 'fr-CH', defaultCurrency: 'CHF', useNavigatorLanguage: true, loadLocaleExtra: false, useTranslations: true, translationsPath: '/translations', queryParamName: QUERY_PARAM_NAME, storage: localStorage, debug: G11nDebug.NO_DEBUG }; // --- const currentLanguage = () => inject(LOCALE_ID); const setLanguage = (value) => { refreshUrl(value); location.reload(); }; // --- HELPER(s) --- const loadTranslationFile = async (filePath, debug = G11nDebug.NO_DEBUG) => { const debugMode = FORCE_DEBUG !== G11nDebug.NO_DEBUG ? FORCE_DEBUG : debug; const response = await fetch(filePath); if (response.status === 200) { const { translations } = (await response.json()); if (translations) { if (debugMode === G11nDebug.SHOW_KEYS) { Object.entries(translations).forEach(([key, value]) => { translations[key] = `${value} (@${key})`; }); } else if (debugMode === G11nDebug.DUMMY_TRANSLATIONS) { Object.keys(translations).forEach(key => { translations[key] = '-'; }); } loadTranslations(translations); } else { throw new Error(`[@hug/ngx-g11n] No translations found in file: ${filePath}`); } } }; const refreshUrl = (localeId) => { const newUrl = new URL(location.href); newUrl.searchParams.set(QUERY_PARAM_NAME, localeId); history.pushState({}, '', newUrl); // update URL without reload }; const loadLanguage = async (localeId, locales, options) => { // Sync language document.documentElement.lang = localeId; options.storage?.setItem(STORAGE_KEY, localeId); refreshUrl(localeId); // Register locale data const locale = locales[localeId]; const localeBase = (await locale.base()).default; const localeExtra = options.loadLocaleExtra && locale.extra ? (await locale.extra()).default : undefined; registerLocaleData(localeBase, localeId, localeExtra); // Load translations if (options.useTranslations) { const filename = locale.translationFilename ?? `${localeId}.json`; await loadTranslationFile(`${options.translationsPath}/${filename}`, options.debug); } }; const getLocaleToUse = (locales, options) => { const getSupportedLocaleId = (localeId) => { // Priority 1: exact match if (localeId in locales) { return localeId; } // Priority 2: match on base language only const locale = new Intl.Locale(localeId); if (locale.language in locales) { console.warn(`[@hug/ngx-g11n] Locale "${localeId}" was not found in given locales (will use "${locale.language}" instead)`); return locale.language; } // Priority 3: match on base language with any region const matchedLocale = Object.keys(locales).find(key => new Intl.Locale(key).language === locale.language); if (matchedLocale) { console.warn(`[@hug/ngx-g11n] Locale "${localeId}" was not found in given locales (will use "${matchedLocale}" instead)`); return matchedLocale; } return undefined; }; /** * Initialize query param name * We do it here as getLocaleToUse is called first in the injection tree (cf. provide: LOCALE_ID) */ initQueryParamName(options); // Priority 1: query param const localeIdFromUrl = new URL(location.href).searchParams.get(QUERY_PARAM_NAME); if (localeIdFromUrl) { if (localeIdFromUrl === 'keys') { FORCE_DEBUG = G11nDebug.SHOW_KEYS; } else if (localeIdFromUrl === 'dummy') { FORCE_DEBUG = G11nDebug.DUMMY_TRANSLATIONS; } else { const supportedLocaleId = getSupportedLocaleId(localeIdFromUrl); if (supportedLocaleId) { return supportedLocaleId; } else { console.warn(`[@hug/ngx-g11n] Locale "${localeIdFromUrl}" from url was not found in given locales (will use storage if found)`); } } } // Priority 2: storage const localeIdFromStorage = options.storage?.getItem(STORAGE_KEY); if (localeIdFromStorage) { const supportedLocaleId = getSupportedLocaleId(localeIdFromStorage); if (supportedLocaleId) { return supportedLocaleId; } else { console.warn(`[@hug/ngx-g11n] Locale "${localeIdFromStorage}" from storage was not found in given locales (will use navigator if enabled)`); } } // Priority 3: browser if (options.useNavigatorLanguage) { const supportedLocaleId = getSupportedLocaleId(navigator.language); if (supportedLocaleId) { return supportedLocaleId; } else { console.warn(`[@hug/ngx-g11n] Locale "${navigator.language}" from browser was not found in given locales (will use default setting)`); } } // Priority 4: user's setting if (options.defaultLanguage) { const supportedLocaleId = getSupportedLocaleId(options.defaultLanguage); if (supportedLocaleId) { return supportedLocaleId; } else { console.warn(`[@hug/ngx-g11n] Locale "${options.defaultLanguage}" from user's setting was not found in given locales`); } } throw new Error('[@hug/ngx-g11n] No provided locale was found'); }; /** * We have to determine the query param name and export it globally as it will be used by the refreshUrl function, which * do not have access to the option object. We also have to support case-insensitive cases (ex: lang, Lang, LANG, etc.). * @param options The G11N options. * @internal */ const initQueryParamName = (options) => { let value = options.queryParamName ?? DEFAULT_OPTIONS.queryParamName; // eslint-disable-next-line no-loops/no-loops for (const key of new URL(location.href).searchParams.keys()) { if (key.toLowerCase() === value.toLowerCase()) { value = key; } } QUERY_PARAM_NAME = value; }; /** * Initializes G11N providers. * @internal * @returns An array of Angular providers for G11N initialization. */ const init = () => [ { provide: G11N_OPTIONS, useValue: DEFAULT_OPTIONS }, { provide: LOCALE_ID, useFactory: getLocaleToUse, deps: [LOCALES, G11N_OPTIONS] }, { provide: DEFAULT_CURRENCY_CODE, useFactory: (options) => options.defaultCurrency ?? DEFAULT_OPTIONS.defaultCurrency, deps: [G11N_OPTIONS] }, { // eslint-disable-next-line @typescript-eslint/no-deprecated provide: APP_INITIALIZER, useFactory: (localeId, locales, options) => async () => { await loadLanguage(localeId, locales, options); }, deps: [LOCALE_ID, LOCALES, G11N_OPTIONS], multi: true } ]; const LOCALES = new InjectionToken('LOCALES'); const G11N_OPTIONS = new InjectionToken('G11N_OPTIONS'); /** * Generated bundle index. Do not edit. */ export { DEFAULT_OPTIONS, G11N_OPTIONS, G11nDebug, LOCALES, currentLanguage, init, setLanguage }; //# sourceMappingURL=hug-ngx-g11n-internal.mjs.map