From ea504d84346b5f27e19bc00d3e39c1ce3c48bc64 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Sat, 4 Jul 2026 09:32:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor(lang):=20=E4=BC=98=E5=8C=96=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E9=A1=B5=E9=9D=A2=E6=A0=91=E7=9A=84=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复多语言路径同时支持camelCase和snake_case的匹配问题,为每个层级同时维护两种命名格式的镜像键,增强路径兼容性 --- common/js/lang.js | 59 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/common/js/lang.js b/common/js/lang.js index 647fc7b..e6c0500 100644 --- a/common/js/lang.js +++ b/common/js/lang.js @@ -856,33 +856,66 @@ function normalizeRemoteTreeForPage(tree, langPath) { const segments = String(langPath).split('/').filter(Boolean); if (!segments.length) return tree; + // 沿 langPath 段向下找页面 leaf:同一段同时尝试 camelCase 与 snake_case(bundle 服务器侧 + // 对同一段实际可能用任一种命名,例如 point/order_list 在 bundle 里是 `tree.point.order_list.X`, + // 而 login/login 这种 camel 路径又是 `tree.login.login.X`)。 let leaf = tree; let hasLeaf = true; for (const segment of segments) { - const key = toCamelCaseName(segment); - if (leaf && typeof leaf === 'object' && !Array.isArray(leaf) && leaf[key] !== undefined) { - leaf = leaf[key]; - } else { - hasLeaf = false; - break; - } + const camel = toCamelCaseName(segment); + const snake = toSnakeCaseName(segment); + // 优先 camelCase;没有就回退 snake_case;都没有就放弃 + const key = (leaf && typeof leaf === 'object' && !Array.isArray(leaf) && leaf[camel] !== undefined) + ? camel + : (leaf && typeof leaf === 'object' && !Array.isArray(leaf) && leaf[snake] !== undefined + ? snake + : null); + if (key === null) { hasLeaf = false; break; } + leaf = leaf[key]; } const lastSegment = toCamelCaseName(segments[segments.length - 1]); + const lastSegmentSnake = toSnakeCaseName(segments[segments.length - 1]); const currentPageLeaf = hasLeaf && leaf && typeof leaf === 'object' && !Array.isArray(leaf) ? leaf - : (tree[lastSegment] && typeof tree[lastSegment] === 'object' && !Array.isArray(tree[lastSegment]) ? tree[lastSegment] : null); + : (tree[lastSegment] && typeof tree[lastSegment] === 'object' && !Array.isArray(tree[lastSegment]) + ? tree[lastSegment] + : (tree[lastSegmentSnake] && typeof tree[lastSegmentSnake] === 'object' && !Array.isArray(tree[lastSegmentSnake]) + ? tree[lastSegmentSnake] + : null)); if (!currentPageLeaf) return tree; - // (1) namespaced merge + // (1) namespaced merge —— 同时建 camelCase 与 snake_case 镜像键, + // 让两种调用形式都能落到同一份 leaf const namespaced = {}; - let cursor = namespaced; + { + let cursor = namespaced; + for (let i = 0; i < segments.length; i++) { + const camel = toCamelCaseName(segments[i]); + cursor[camel] = i === segments.length - 1 ? deepCloneLang(currentPageLeaf) : {}; + cursor = cursor[camel]; + } + } + // 在 namespaced 的每个层级再挂一份 snake_case 镜像 + const nested = []; + { + let cursor = namespaced; + nested.push(cursor); + for (let i = 0; i < segments.length - 1; i++) { + cursor = cursor[toCamelCaseName(segments[i])]; + nested.push(cursor); + } + } for (let i = 0; i < segments.length; i++) { - const segment = toCamelCaseName(segments[i]); - cursor[segment] = i === segments.length - 1 ? deepCloneLang(currentPageLeaf) : {}; - cursor = cursor[segment]; + const raw = segments[i]; + const camel = toCamelCaseName(raw); + const snake = toSnakeCaseName(raw); + if (snake !== camel) { + const isLeaf = i === segments.length - 1; + nested[i][snake] = isLeaf ? deepCloneLang(currentPageLeaf) : {}; + } } const merged = deepMergeLang(deepCloneLang(tree), namespaced);