ForgeFlow-ERP/frontend/scripts/test-dictionary-localization.mjs
2026-06-12 16:00:56 +08:00

131 lines
5.2 KiB
JavaScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import path from "node:path";
import * as dictionaries from "../src/utils/dictionaries.js";
const root = process.cwd();
function readSource(relativePath) {
return readFileSync(path.join(root, relativePath), "utf8");
}
function assertFormatter(name, samples) {
assert.equal(typeof dictionaries[name], "function", `${name} should be exported`);
samples.forEach(([value, expected]) => {
assert.equal(dictionaries[name](value), expected, `${name} should translate ${value}`);
});
}
function assertNoRawEnumFallback(name) {
const rawCode = "UNTRANSLATED_SAMPLE_ENUM";
assert.notEqual(dictionaries[name](rawCode), rawCode, `${name} must not render raw English enum fallbacks`);
assert.match(dictionaries[name](rawCode), /未识别/, `${name} fallback should be Chinese`);
}
assertFormatter("formatInventoryTxnTypeLabel", [
["OPENING_IN", "期初入库"],
["PRODUCTION_SURPLUS_IN", "生产余料入库"],
["OUTSOURCING_SURPLUS_IN", "委外余料入库"],
["WIP_IN", "产中入库"],
["WIP_OUT", "产中出库"],
["PRODUCTION_FINISHED_IN", "生产入库"],
["STOCKTAKE_GAIN", "盘库盘盈"],
["STOCKTAKE_LOSS", "盘库盘亏"],
["STOCKTAKE_NEW_LOT", "盘库新增批次"]
]);
assertNoRawEnumFallback("formatInventoryTxnTypeLabel");
assertFormatter("formatSourceDocTypeLabel", [
["OPENING_STOCK", "期初入库"],
["STOCKTAKE", "盘库"],
["PRODUCTION_OUT", "生产出库"],
["OUTSOURCING_OUT", "委外出库"],
["RETURN_OUT", "返工出库"]
]);
assertNoRawEnumFallback("formatSourceDocTypeLabel");
assertFormatter("formatWarehouseTypeLabel", [
["RAW", "原材料库"],
["SEMI", "半成品库"],
["FINISHED", "成品库"],
["AUX", "辅料库"],
["SCRAP", "废料库"],
["RETURN", "退货库"]
]);
assertNoRawEnumFallback("formatWarehouseTypeLabel");
assertFormatter("formatItemTypeLabel", [
["RAW_MATERIAL", "原材料"],
["FINISHED_GOOD", "成品"],
["PRODUCT", "产品"]
]);
assertNoRawEnumFallback("formatItemTypeLabel");
assertFormatter("formatPurchaseSourceTypeLabel", [
["SALES_ORDER", "销售订单采购"],
["STOCKING", "备料采购"]
]);
assertNoRawEnumFallback("formatPurchaseSourceTypeLabel");
assertFormatter("formatMiniappRoleLabel", [
["worker", "员工"],
["manager", "经理"],
["admin", "管理员"]
]);
assertNoRawEnumFallback("formatMiniappRoleLabel");
assertFormatter("formatMaintenanceTypeLabel", [
["PERIODIC", "周期保养"],
["REPAIR", "维修保养"],
["INSPECTION", "点检保养"]
]);
assertNoRawEnumFallback("formatMaintenanceTypeLabel");
assertFormatter("formatStocktakeRowStatusLabel", [
["READY", "可确认"],
["ERROR", "异常"],
["IGNORED", "已忽略"]
]);
assertNoRawEnumFallback("formatStocktakeRowStatusLabel");
const dictionarySource = readSource("src/utils/dictionaries.js");
assert.match(dictionarySource, /function normalizeDictionaryKey/, "dictionary lookup should normalize keys");
assert.match(dictionarySource, /function isEnumLikeValue/, "dictionary lookup should identify enum-like fallbacks");
assert.match(dictionarySource, /未识别/, "dictionary fallback should be Chinese");
const tableControlsSource = readSource("src/utils/tableControls.js");
[
"WAREHOUSE_TYPE_LABELS",
"ITEM_TYPE_LABELS",
"PURCHASE_SOURCE_TYPE_LABELS",
"MAINTENANCE_TYPE_LABELS",
"MINIAPP_ROLE_LABELS",
"STOCKTAKE_ROW_STATUS_LABELS"
].forEach((mapName) => {
assert.match(tableControlsSource, new RegExp(mapName), `TableControls search should include ${mapName}`);
});
const inventorySource = readSource("src/views/InventoryLedgerView.vue");
assert.match(inventorySource, /formatWarehouseTypeLabel/, "inventory view should use warehouse type formatter");
assert.match(inventorySource, /formatItemTypeLabel/, "inventory view should use item type formatter");
assert.doesNotMatch(inventorySource, /placeholder="如 SALES_OUT、RETURN_IN"/, "inventory ledger filter should not show English examples");
const equipmentSource = readSource("src/views/EquipmentManagementView.vue");
assert.match(equipmentSource, /formatMaintenanceTypeLabel/, "equipment view should translate maintenance types");
assert.doesNotMatch(equipmentSource, /\{\{\s*order\.maintenance_type\s*\}\}/, "equipment view must not render raw maintenance_type");
const employeeSource = readSource("src/views/EmployeeManagementView.vue");
assert.match(employeeSource, /formatPersonRoles/, "employee view should centralize role display formatting");
assert.match(employeeSource, /formatMiniappRoleLabel/, "employee view should translate miniapp role codes");
assert.doesNotMatch(employeeSource, /personnel \/ person_roles/, "employee view should not show raw table names");
const stocktakeSource = readSource("src/components/StocktakeDialog.vue");
assert.match(stocktakeSource, /formatStocktakeRowStatusLabel/, "stocktake dialog should have row status formatter available");
const purchaseSource = readSource("src/views/PurchaseOrderView.vue");
assert.match(purchaseSource, /formatPurchaseSourceTypeLabel/, "purchase order view should translate source_type");
assert.doesNotMatch(purchaseSource, /"source_type",\s*$/m, "purchase order search should not rely on raw source_type only");
console.log("dictionary localization checks passed");