@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
231 lines (230 loc) • 7.26 kB
JavaScript
"use client";
var _br;
import _Object$hasOwn from "core-js-pure/stable/object/has-own.js";
import React, { Fragment, useCallback, useContext, useMemo, useRef } from 'react';
import Context from "./Context.js";
import defaultLocales from "./locales/index.js";
import { isObject, warn } from "./component-helper.js";
export default function useTranslation(messages, args) {
const {
locale,
translation
} = useContext(Context);
const {
translations: contextTranslations
} = useContext(Context);
const {
assignUtils
} = useAdditionalUtils();
const {
extMessages,
fallbackLocale,
baseOverride,
warnLabel
} = useMemo(() => {
var _arg$fallbackLocale;
const defaultLocaleKeys = Object.keys(defaultLocales);
const defaultLocale = defaultLocaleKeys[0];
const arg = isObject(messages) && ('messages' in messages || 'fallbackLocale' in messages) ? messages : {
messages
};
return {
extMessages: arg.messages,
fallbackLocale: (_arg$fallbackLocale = arg.fallbackLocale) !== null && _arg$fallbackLocale !== void 0 ? _arg$fallbackLocale : defaultLocale,
baseOverride: arg.base,
warnLabel: arg.warnLabel || 'useTranslation'
};
}, [messages]);
return useMemo(() => {
var _ref;
const id = typeof messages === 'string' ? messages : undefined;
if (id) {
return formatMessage(id, args, translation);
}
let translationLocale = locale;
if (locale.startsWith('en-') && !Object.keys(defaultLocales).some(l => l === locale)) {
translationLocale = 'en-GB';
}
const base = assignUtils(combineWithExternalTranslations({
translation: baseOverride || translation,
messages: extMessages,
locale: translationLocale
}));
if (!fallbackLocale) {
return base;
}
const explicitMessages = extMessages;
let hasExplicitCurrent = false;
let currentMessages = undefined;
if (explicitMessages && _Object$hasOwn(explicitMessages, locale)) {
hasExplicitCurrent = true;
currentMessages = explicitMessages[locale];
} else if (contextTranslations && _Object$hasOwn(contextTranslations, locale)) {
hasExplicitCurrent = true;
currentMessages = contextTranslations[locale];
}
const fallbackMessages = (_ref = (explicitMessages === null || explicitMessages === void 0 ? void 0 : explicitMessages[fallbackLocale]) || (contextTranslations === null || contextTranslations === void 0 ? void 0 : contextTranslations[fallbackLocale]) || defaultLocales[fallbackLocale]) !== null && _ref !== void 0 ? _ref : undefined;
if (!fallbackMessages || !hasExplicitCurrent) {
return base;
}
const currentHasContent = isObject(currentMessages) && Object.keys(currentMessages).length > 0;
if (!currentHasContent) {
warnMissing(locale, warnLabel);
const obj = generateTranslationKeyReferences('', fallbackMessages);
return withUtils(base, obj);
}
const {
result,
hasMissing
} = mergeMissingKeys(base, fallbackMessages);
if (hasMissing) {
warnMissing(locale, warnLabel);
return withUtils(base, result);
}
return base;
}, [messages, locale, assignUtils, baseOverride, translation, extMessages, fallbackLocale, contextTranslations, args, warnLabel]);
}
function withUtils(base, obj) {
return Object.assign({}, base, obj, {
formatMessage: base.formatMessage,
renderMessage: base.renderMessage,
countries: base.countries
});
}
function mergeMissingKeys(target, source) {
const resultLocal = {
...target
};
let hasMissing = false;
const keys = Object.keys(source);
for (const key of keys) {
const sourceValue = source[key];
const targetValue = resultLocal[key];
if (isObject(sourceValue)) {
if (!targetValue) {
resultLocal[key] = generateTranslationKeyReferences(key, sourceValue);
hasMissing = true;
} else if (isObject(targetValue)) {
const nested = mergeMissingKeys(targetValue, sourceValue);
resultLocal[key] = nested.result;
if (nested.hasMissing) {
hasMissing = true;
}
}
} else if (targetValue === undefined) {
resultLocal[key] = key;
hasMissing = true;
}
}
return {
result: resultLocal,
hasMissing
};
}
function generateTranslationKeyReferences(baseKey, sourceValue) {
if (!isObject(sourceValue)) {
return baseKey ? baseKey : sourceValue;
}
const result = {};
const entries = Object.entries(sourceValue);
for (const [key, value] of entries) {
const translationKey = baseKey ? `${baseKey}.${key}` : key;
result[key] = isObject(value) ? generateTranslationKeyReferences(translationKey, value) : translationKey;
}
return result;
}
function warnMissing(locale, label = 'useTranslation') {
warn(`${label}: No translations found for locale "${locale}"!`);
}
export function useAdditionalUtils() {
const translationsRef = useRef();
const fM = useCallback((id, args) => {
return formatMessage(id, args, translationsRef.current);
}, []);
const rM = useCallback(message => {
return renderMessage(message);
}, []);
const assignUtils = useCallback(translations => {
translationsRef.current = translations;
Object.assign(translations, {
formatMessage: fM,
renderMessage: rM
});
return translations;
}, [fM, rM]);
return {
assignUtils
};
}
export function combineWithExternalTranslations({
translation,
messages,
locale
}) {
let combined = {
...translation
};
if (messages) {
if (Object.keys(defaultLocales).some(locale => messages[locale])) {
if (messages[locale]) {
combined = messages[locale];
}
}
for (const key in messages) {
combined[key] = {
...translation[key],
...messages[key]
};
}
}
return combined;
}
export function formatMessage(id, args, messages) {
let str = undefined;
if (typeof id === 'string') {
var _id$includes;
let found = false;
if (messages[id]) {
str = messages[id];
found = true;
} else if (id !== null && id !== void 0 && (_id$includes = id.includes) !== null && _id$includes !== void 0 && _id$includes.call(id, '.')) {
const keys = id.split('.');
for (const key of keys) {
if (messages[key]) {
messages = messages[key];
} else {
break;
}
}
if (typeof messages === 'string') {
str = messages;
found = true;
}
}
if (!found && typeof id === 'string') {
str = id;
}
} else if (typeof id === 'function') {
str = id(messages);
}
if (typeof str === 'string') {
for (const t in args) {
const regex = new RegExp(`{${t}}`, 'g');
str = str.replace(regex, args[t]);
}
}
return str !== null && str !== void 0 ? str : id;
}
export function renderMessage(text) {
let element = text;
if (typeof text === 'string') {
element = text.split('{br}');
}
if (Array.isArray(element)) {
return element.map((item, index) => React.createElement(Fragment, {
key: index
}, item, _br || (_br = React.createElement("br", null))));
}
return text;
}
//# sourceMappingURL=useTranslation.js.map