@intlayer/core
Version:
Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.
109 lines (108 loc) • 4.25 kB
JavaScript
//#region src/interpreter/getTranslation.ts
/**
* Check if a value is a plain object that can be safely processed.
* Returns false for Promises, React elements, class instances, etc.
*/
const isPlainObject = (value) => {
if (value === null || typeof value !== "object") return false;
if (value instanceof Promise || typeof value.then === "function") return false;
if (value.$$typeof !== void 0) return false;
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null || Array.isArray(value);
};
/**
* Recursively merges two objects.
* Resembles the behavior of `defu` but respects `isPlainObject` to avoid merging React elements.
* Arrays are replaced, not merged.
*/
const deepMergeObjects = (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") continue;
if (Object.hasOwn(target, key)) result[key] = deepMergeObjects(target[key], source[key]);
else result[key] = source[key];
}
return result;
}
return target;
};
/**
* Recursively removes undefined values from an object.
* Handles circular references by tracking visited objects.
*/
const removeUndefinedValues = (object, visited = /* @__PURE__ */ new WeakSet()) => {
if (typeof object !== "object" || object === null) return object;
if (visited.has(object)) return object;
visited.add(object);
if (!isPlainObject(object)) return object;
if (Array.isArray(object)) return object.map((item) => removeUndefinedValues(item, visited));
const result = {};
for (const [key, value] of Object.entries(object)) if (value !== void 0) result[key] = removeUndefinedValues(value, visited);
return result;
};
/**
*
* Allow to pick a content based on a locale.
* If not locale found, it will return the content related to the default locale.
*
* Return either the content editor, or the content itself depending on the configuration.
*
* Usage:
*
* ```ts
* const content = getTranslation<string>({
* en: 'Hello',
* fr: 'Bonjour',
* }, 'fr');
* // 'Bonjour'
* ```
*
* Using TypeScript:
* - this function will require each locale to be defined if defined in the project configuration.
* - If a locale is missing, it will make each existing locale optional and raise an error if the locale is not found.
*/
const getTranslation = (languageContent, locale, fallback) => {
const results = [];
const getContent = (loc) => languageContent[loc];
const content = getContent(locale);
if (typeof content === "string") return content;
else if (content !== void 0) results.push(content);
if (locale.includes("-")) {
const genericLocale = locale.split("-")[0];
if (genericLocale in languageContent) {
const genericContent = getContent(genericLocale);
if (typeof genericContent === "string") {
if (results.length === 0) return genericContent;
} else if (genericContent !== void 0) results.push(genericContent);
}
}
if (fallback !== void 0 && fallback !== locale) {
if (fallback in languageContent) {
const fallbackContent = getContent(fallback);
if (typeof fallbackContent === "string") {
if (results.length === 0) return fallbackContent;
} else if (fallbackContent !== void 0) results.push(fallbackContent);
}
if (fallback.includes("-")) {
const genericFallback = fallback.split("-")[0];
if (genericFallback !== locale.split("-")[0] && genericFallback in languageContent) {
const genericFallbackContent = getContent(genericFallback);
if (typeof genericFallbackContent === "string") {
if (results.length === 0) return genericFallbackContent;
} else if (genericFallbackContent !== void 0) results.push(genericFallbackContent);
}
}
}
if (results.length === 0) return;
const cleanResults = results.map((item) => removeUndefinedValues(item));
if (cleanResults.length === 1) return cleanResults[0];
if (Array.isArray(cleanResults[0])) return cleanResults[0];
return cleanResults.reduce((acc, curr) => deepMergeObjects(acc, curr));
};
//#endregion
export { getTranslation };
//# sourceMappingURL=getTranslation.mjs.map