@sentzunhat/zacatl
Version:
A modular, high-performance TypeScript microservice framework for Node.js, featuring layered architecture, dependency injection, and robust validation for building scalable APIs and distributed systems.
156 lines • 5.77 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.configureI18nNode = exports.mergeCatalogs = exports.resolveBuiltInLocalesDir = exports.loadCatalog = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const error_1 = require("../error/index.js");
const i18n_1 = __importDefault(require("../third-party/i18n.js"));
const isPlainObject = (value) => {
return (typeof value === 'object' &&
value !== null &&
!Array.isArray(value) &&
Object.prototype.toString.call(value) === '[object Object]');
};
const deepMerge = (base, override) => {
const out = { ...base };
for (const [key, overrideValue] of Object.entries(override)) {
const baseValue = out[key];
if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
out[key] = deepMerge(baseValue, overrideValue);
continue;
}
out[key] = overrideValue;
}
return out;
};
const readJsonFile = (filePath) => {
const content = fs_1.default.readFileSync(filePath, 'utf-8');
const parsed = JSON.parse(content);
if (!isPlainObject(parsed)) {
throw new error_1.BadRequestError({
message: `Invalid locale JSON shape in ${filePath}`,
reason: 'Locale file must contain a plain JSON object',
component: 'I18nNode',
operation: 'readJsonFile',
metadata: { filePath },
});
}
return parsed;
};
const findExistingDir = (candidates) => {
for (const candidate of candidates) {
try {
if (fs_1.default.existsSync(candidate) && fs_1.default.statSync(candidate).isDirectory()) {
return candidate;
}
}
catch {
continue;
}
}
return null;
};
const loadCatalog = (input) => {
const { localesDir, supportedLocales } = input;
const catalog = {};
for (const locale of supportedLocales) {
const filePath = path_1.default.join(localesDir, `${locale}.json`);
if (!fs_1.default.existsSync(filePath)) {
continue;
}
catalog[locale] = readJsonFile(filePath);
}
return catalog;
};
exports.loadCatalog = loadCatalog;
const getHere = () => {
if (typeof __dirname !== 'undefined')
return __dirname;
if (typeof process !== 'undefined' &&
Array.isArray(process.argv) &&
typeof process.argv[1] === 'string' &&
process.argv[1].length > 0) {
return path_1.default.dirname(process.argv[1]);
}
return process.cwd();
};
const resolveBuiltInLocalesDir = () => {
const here = getHere();
const candidates = [
path_1.default.resolve(here, 'locales'),
path_1.default.resolve(here, '../../build/localization/locales'),
path_1.default.resolve(here, '../../src/localization/locales'),
path_1.default.resolve(process.cwd(), 'src/localization/locales'),
path_1.default.resolve(process.cwd(), 'localization/locales'),
path_1.default.resolve(process.cwd(), 'locales'),
];
const found = findExistingDir(candidates);
if (found == null) {
throw new error_1.NotFoundError({
message: `Unable to locate built-in locales directory. Tried: ${candidates.join(', ')}`,
reason: 'Built-in locales directory not found in expected paths',
component: 'I18nNode',
operation: 'resolveBuiltInLocalesDir',
metadata: { candidates },
});
}
return found;
};
exports.resolveBuiltInLocalesDir = resolveBuiltInLocalesDir;
const mergeCatalogs = (input) => {
const { base, additions, overrideBuiltIn } = input;
const out = {};
const locales = new Set([
...Object.keys(base),
...additions.flatMap((a) => Object.keys(a)),
]);
for (const locale of locales) {
const baseLocale = base[locale] ?? {};
const additionsLocale = additions.reduce((acc, addition) => {
const addLocale = addition[locale];
if (addLocale == null) {
return acc;
}
return deepMerge(acc, addLocale);
}, {});
out[locale] = overrideBuiltIn
? deepMerge(baseLocale, additionsLocale)
: deepMerge(additionsLocale, baseLocale);
}
return out;
};
exports.mergeCatalogs = mergeCatalogs;
const configureI18nNode = (input = {}) => {
const defaultLocale = input.locales?.default ?? 'en';
const supportedLocales = input.locales?.supported ?? ['en', 'es'];
const objectNotation = input.objectNotation ?? true;
const overrideBuiltIn = input.overrideBuiltIn ?? true;
const builtInLocalesDir = (0, exports.resolveBuiltInLocalesDir)();
const builtInCatalog = (0, exports.loadCatalog)({
localesDir: builtInLocalesDir,
supportedLocales,
});
const additionalCatalogs = (input.locales?.directories ?? [])
.filter((dir) => dir != null && dir.length > 0)
.map((localesDir) => (0, exports.loadCatalog)({ localesDir, supportedLocales }));
const staticCatalog = (0, exports.mergeCatalogs)({
base: builtInCatalog,
additions: additionalCatalogs,
overrideBuiltIn,
});
i18n_1.default.configure({
locales: supportedLocales,
defaultLocale,
objectNotation,
staticCatalog: staticCatalog,
updateFiles: false,
syncFiles: false,
autoReload: false,
});
return i18n_1.default;
};
exports.configureI18nNode = configureI18nNode;
//# sourceMappingURL=i18n-node.js.map