UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

231 lines (230 loc) 7.26 kB
"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