mnfst-render 0.4.7 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mnfst-render.js +0 -0
- package/manifest.render.mjs +20 -0
- package/package.json +1 -1
package/bin/mnfst-render.js
CHANGED
|
File without changes
|
package/manifest.render.mjs
CHANGED
|
@@ -1144,6 +1144,9 @@ function loadAllLocaleContentData(manifest, rootDir, locales) {
|
|
|
1144
1144
|
target[key] = (target[key] && typeof target[key] === 'object') ? target[key] : {};
|
|
1145
1145
|
deepMerge(target[key], source[key]);
|
|
1146
1146
|
} else {
|
|
1147
|
+
// Don't overwrite an existing nested object with a primitive — that creates
|
|
1148
|
+
// type asymmetry across locales and causes '[object Object]' in substitution pairs
|
|
1149
|
+
if (target[key] && typeof target[key] === 'object') continue;
|
|
1147
1150
|
target[key] = source[key];
|
|
1148
1151
|
}
|
|
1149
1152
|
}
|
|
@@ -1152,12 +1155,25 @@ function loadAllLocaleContentData(manifest, rootDir, locales) {
|
|
|
1152
1155
|
const result = new Map();
|
|
1153
1156
|
for (const locale of locales) result.set(locale, {});
|
|
1154
1157
|
|
|
1158
|
+
// Read just the header row of a CSV to check which locale columns it contains.
|
|
1159
|
+
function csvLocaleColumns(csvPath) {
|
|
1160
|
+
if (!existsSync(csvPath)) return new Set();
|
|
1161
|
+
try {
|
|
1162
|
+
const firstLine = readFileSync(csvPath, 'utf8').split(/\r?\n/)[0] || '';
|
|
1163
|
+
return new Set(splitCsvLine(firstLine).slice(1)); // skip key column
|
|
1164
|
+
} catch { return new Set(); }
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1155
1167
|
for (const [, value] of Object.entries(data)) {
|
|
1156
1168
|
if (typeof value === 'string') {
|
|
1157
1169
|
// Single CSV with locale columns (all locales in one file)
|
|
1158
1170
|
if (value.endsWith('.csv')) {
|
|
1159
1171
|
const csvPath = join(rootDir, value.startsWith('/') ? value.slice(1) : value);
|
|
1172
|
+
const cols = csvLocaleColumns(csvPath);
|
|
1160
1173
|
for (const locale of locales) {
|
|
1174
|
+
// Only include locales the CSV actually declares; falling back to the English
|
|
1175
|
+
// column for a missing locale silently poisons substitution pairs with English values.
|
|
1176
|
+
if (!cols.has(locale)) continue;
|
|
1161
1177
|
deepMerge(result.get(locale), parseCsvToKeyValue(csvPath, locale));
|
|
1162
1178
|
}
|
|
1163
1179
|
}
|
|
@@ -1168,7 +1184,9 @@ function loadAllLocaleContentData(manifest, rootDir, locales) {
|
|
|
1168
1184
|
for (const ref of refs) {
|
|
1169
1185
|
if (typeof ref !== 'string' || !ref.endsWith('.csv')) continue;
|
|
1170
1186
|
const csvPath = join(rootDir, ref.startsWith('/') ? ref.slice(1) : ref);
|
|
1187
|
+
const cols = csvLocaleColumns(csvPath);
|
|
1171
1188
|
for (const locale of locales) {
|
|
1189
|
+
if (!cols.has(locale)) continue;
|
|
1172
1190
|
deepMerge(result.get(locale), parseCsvToKeyValue(csvPath, locale));
|
|
1173
1191
|
}
|
|
1174
1192
|
}
|
|
@@ -1215,6 +1233,8 @@ function buildSubstitutionPairs(defaultLocaleData, targetLocaleData) {
|
|
|
1215
1233
|
// Recurse into nested objects (produced by setNestedKey for dotted CSV keys)
|
|
1216
1234
|
collectPairs(defaultVal, targetVal && typeof targetVal === 'object' ? targetVal : {});
|
|
1217
1235
|
} else {
|
|
1236
|
+
// Skip if target is a non-primitive — String(obj) === '[object Object]' is never useful
|
|
1237
|
+
if (targetVal !== null && typeof targetVal === 'object') continue;
|
|
1218
1238
|
const from = String(defaultVal ?? '').trim();
|
|
1219
1239
|
const to = String(targetVal ?? '').trim();
|
|
1220
1240
|
if (!from || from === to) continue;
|