wuchale
Version:
Protobuf-like i18n from plain code
74 lines (73 loc) • 2.17 kB
JavaScript
import { resolve } from "node:path";
import {} from "./adapters.js";
import { defaultGemini } from "./ai/gemini.js";
export const defaultConfig = {
sourceLocale: 'en',
otherLocales: [],
adapters: {},
hmr: true,
ai: defaultGemini,
logLevel: 'info',
};
function deepAssign(fromObj, toObj) {
for (const [key, value] of Object.entries(fromObj)) {
if (value === undefined) {
delete toObj[key];
}
if (!value || Array.isArray(value) || typeof value !== 'object') {
toObj[key] = value;
continue;
}
// objects
if (!toObj[key] || Array.isArray(toObj[key]) || typeof toObj[key] !== 'object') {
toObj[key] = {};
}
deepAssign(fromObj[key], toObj[key]);
}
}
export function defineConfig(config) {
return config;
}
export function deepMergeObjects(source, target) {
const full = { ...target };
deepAssign(source, full);
return full;
}
export const defaultConfigNames = ['js', 'mjs'].map(ext => `wuchale.config.${ext}`);
const displayName = new Intl.DisplayNames(['en'], { type: 'language' });
export const getLanguageName = (code) => displayName.of(code) ?? code;
function checkValidLocale(locale) {
try {
getLanguageName(locale);
}
catch {
throw new Error(`Invalid locale identifier: ${locale}`);
}
}
export async function getConfig(configPath) {
let module = null;
for (const confName of [configPath, ...defaultConfigNames]) {
if (!confName) {
continue;
}
const fileUrl = `file://${resolve(confName)}`;
try {
module = await import(fileUrl);
break;
}
catch (err) {
if (err.code !== 'ERR_MODULE_NOT_FOUND' || err.url != fileUrl) {
throw err;
}
}
}
if (module == null) {
throw new Error('Config file not found');
}
const config = deepMergeObjects(module.default, defaultConfig);
checkValidLocale(config.sourceLocale);
for (const loc of config.otherLocales) {
checkValidLocale(loc);
}
return config;
}