@intlayer/core
Version:
Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.
86 lines (85 loc) • 2.88 kB
JavaScript
//#region src/interpreter/getTranslation.ts
/**
* Check if a value is a plain object that can be safely merged.
* Returns false for Promises, React elements, class instances, etc.
*/
const isPlainObject = (value) => {
if (value === null || typeof value !== "object") return false;
if (typeof value.then === "function") return false;
if (value.$$typeof !== void 0 || value.__v_isVNode !== void 0 || value._isVNode !== void 0 || value.isJSX !== void 0) return false;
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null || Array.isArray(value);
};
/**
* Recursively merges two objects, skipping undefined source values.
* First argument takes precedence. Arrays replace rather than merge.
*/
const deepMerge = (target, source) => {
if (target === void 0) return source;
if (source === void 0) return target;
if (Array.isArray(target)) return target;
if (isPlainObject(target) && isPlainObject(source)) {
const result = { ...target };
for (const key of Object.keys(source)) {
if (key === "__proto__" || key === "constructor" || source[key] === void 0) continue;
result[key] = target[key] !== void 0 ? deepMerge(target[key], source[key]) : source[key];
}
return result;
}
return target;
};
/**
* Picks the appropriate content from a locale map based on the provided locale.
*
* It handles:
* 1. Exact locale match (e.g., 'en-US').
* 2. Generic locale fallback (e.g., 'en' if 'en-US' is not found).
* 3. Explicit fallback locale.
* 4. Deep merging of objects to ensure partial translations are complemented by fallbacks.
*
* @param languageContent - A map of locales to content.
* @param locale - The target locale to retrieve.
* @param fallback - Optional fallback locale if the target is not found.
* @returns The translated content.
*
* @example
* ```ts
* const content = getTranslation({
* en: 'Hello',
* fr: 'Bonjour',
* }, 'fr');
* // 'Bonjour'
* ```
*/
const getTranslation = (languageContent, locale, fallback) => {
const get = (loc) => languageContent[loc];
const seen = /* @__PURE__ */ new Set();
const locales = [];
const addLocale = (loc) => {
if (loc && !seen.has(loc)) {
seen.add(loc);
locales.push(loc);
}
};
addLocale(locale);
if (locale.includes("-")) addLocale(locale.split("-")[0]);
addLocale(fallback);
if (fallback?.includes("-")) addLocale(fallback.split("-")[0]);
const results = [];
for (const loc of locales) {
const val = get(loc);
if (val === void 0) continue;
if (typeof val === "string") {
if (results.length === 0) return val;
continue;
}
results.push(val);
}
if (results.length === 0) return void 0;
if (results.length === 1) return results[0];
if (Array.isArray(results[0])) return results[0];
return results.reduce((acc, curr) => deepMerge(acc, curr));
};
//#endregion
export { getTranslation };
//# sourceMappingURL=getTranslation.mjs.map