@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
161 lines (159 loc) • 5.34 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createIntl, createIntlCache } from 'react-intl';
import { Subject } from 'rxjs';
import { nou } from './object';
/* private */
let currentTranslations = { en: {} };
let fetchedLocales = { en: true };
/* private */
const intl$$ = new Subject();
/* public */
export const intl$ = intl$$.asObservable();
/* private */
let intl = createIntl({ locale: 'en', messages: currentTranslations.en }, createIntlCache());
if (getCurrentLocale() !== 'en') {
createIntlInstance(getCurrentLocale()).then((newIntl) => {
intl = newIntl;
intl$$.next(newIntl);
});
}
async function fetchLocale(locale) {
let translations;
switch (locale) {
case 'de':
translations = await import('../translations/de.json');
break;
case 'es':
translations = await import('../translations/es.json');
break;
case 'ko':
translations = await import('../translations/ko.json');
break;
default:
translations = Promise.resolve({});
break;
}
return translations.default ?? translations;
}
async function createIntlInstance(localeCode) {
if (
!fetchedLocales[localeCode] &&
// Nothing to fetch point if we don't have the locale
['de', 'es', 'ko'].includes(localeCode)
) {
let fetchedTranslations = await fetchLocale(localeCode);
// Plugins may have added translations to a locale that hasn't been fetched.
currentTranslations[localeCode] = { ...currentTranslations[localeCode], ...fetchedTranslations };
fetchedLocales[localeCode] = true;
}
return createIntl(
{
locale: localeCode,
messages: currentTranslations[localeCode] || currentTranslations.en
},
createIntlCache()
);
}
export function augmentTranslations(translations) {
if (translations) {
let currentLocale = intl.locale;
let currentLocaleChanged = false;
Object.entries(translations).forEach(([localeCode, translations]) => {
currentTranslations[localeCode] = { ...currentTranslations[localeCode], ...translations };
currentLocale === localeCode && (currentLocaleChanged = true);
});
if (currentLocaleChanged) {
createIntlInstance(currentLocale).then((newIntl) => {
intl = newIntl;
intl$$.next(newIntl);
});
}
}
}
export function getTranslation(key, table, formatMessage) {
return formatMessage(
table[key] || {
id: 'translationNotAvailable',
defaultMessage: key || '(check configuration)'
}
);
}
export function getPossibleTranslation(
titleOrDescriptor,
formatMessage,
// TODO: Fix FormatXMLElementFn generics
values
) {
if (nou(titleOrDescriptor)) {
return null;
}
return typeof titleOrDescriptor === 'object' ? formatMessage(titleOrDescriptor, values) : titleOrDescriptor;
}
export function getCurrentLocale(username) {
const user = username ?? localStorage.getItem('username');
return getStoredLanguage(user) || 'en';
}
export function getCurrentIntl() {
return intl;
}
export function buildStoredLanguageKey(username) {
return `${username}_crafterStudioLanguage`;
}
export function getStoredLanguage(username) {
return (
(username ? localStorage.getItem(buildStoredLanguageKey(username)) : null) ??
localStorage.getItem(`crafterStudioLanguage`)
);
}
export function setStoredLanguage(language, username) {
// Prevent `null` or `undefined`, or even `"""` from being stored.
if (language) {
username && localStorage.setItem(buildStoredLanguageKey(username), language);
localStorage.setItem('crafterStudioLanguage', language);
}
}
export function dispatchLanguageChange(language) {
let event = new CustomEvent('setlocale', { detail: language });
document.dispatchEvent(event);
}
// @ts-ignore
document.addEventListener(
'setlocale',
async (e) => {
if (e.detail && e.detail !== intl.locale) {
intl = await createIntlInstance(e.detail);
document.documentElement.setAttribute('lang', e.detail);
intl$$.next(intl);
}
},
false
);