fix(remote lang tree): 修复命名空间被基本类型值覆盖的bug
修复remote-only模式下语言包归一化的历史bug:当页面leaf顶层存在与命名空间同名的字符串键时,会覆盖整个namespace导致子key失效。通过对齐normalizePageLangPack的两层合并逻辑来修复: 1. 先将页面语言包按路径段转为命名空间结构再合并 2. 额外平铺leaf的基本类型键到根节点以兼容短key调用
This commit is contained in:
@@ -170,11 +170,35 @@ function normalizePageLangPack(path, langData) {
|
||||
}
|
||||
|
||||
let namespaced = {};
|
||||
let cursor = namespaced;
|
||||
{
|
||||
let cursor = namespaced;
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const camelSegment = toCamelCaseName(segments[i]);
|
||||
cursor[camelSegment] = i === segments.length - 1 ? deepCloneLang(currentPageLeaf) : {};
|
||||
cursor = cursor[camelSegment];
|
||||
}
|
||||
}
|
||||
|
||||
// 同步建立 snake_case 镜像:让 camelCase 与 snake_case 路径都能解析到同一份 leaf
|
||||
// (与 bundle 服务器侧 emit 形式对齐 —— bundle 用 snake_case 段名,如 point.order_list.statusAll)
|
||||
// 实现:在每个 namespace 节点同时挂一个 snake 别名键,与 camel 节点共享 leaf 引用(0 拷贝)
|
||||
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) : {};
|
||||
}
|
||||
}
|
||||
|
||||
return deepMergeLang(result, namespaced);
|
||||
@@ -811,6 +835,19 @@ function emitUpdated(lang) {
|
||||
/**
|
||||
* remote-only 模式下,为当前页面做 tree 归一化
|
||||
* 把页面路径对应的 subtree 合并到顶层,兼容 $lang('title') 等短 key 调用
|
||||
*
|
||||
* 历史 bug: 之前直接 `deepMergeLang(tree, currentPageLeaf)`,
|
||||
* 如果 currentPageLeaf 顶层有一个与 `tree.login` 命名空间同名(key)且值为字符串的键
|
||||
* (例如 `login.login.js` 里的 `login: '登录/注册'` 会出现在 leaf 顶层),
|
||||
* 会触发 `merge` 的"基本类型覆盖对象"分支,把 `tree.login` 整个 namespace 替换为字符串,
|
||||
* 导致 `tree.login.login.welcomeText` 等所有子页 key 全部失效。
|
||||
*
|
||||
* 修复方案(对齐 `normalizePageLangPack` 的两层合并):
|
||||
* 1) namespaced merge: 把 currentPageLeaf 按 langPath 段逐层包成 `{seg1: {seg2: leaf}}`,
|
||||
* 再 merge 进 tree —— 同样的 key 仍能递归合并,而 namespace 不会被字符串覆盖。
|
||||
* 2) 在 result 上额外"轻量 overlay":把 leaf 里的 SCALAR key 平铺到 root,
|
||||
* 但跳过 target 已经是 namespace 对象的 key,避免再次触发 clobber。
|
||||
* 这一步让 `$lang('title')` / `$lang('welcomeText')` 这类短 key 仍能在 root 命中页面副本。
|
||||
*/
|
||||
function normalizeRemoteTreeForPage(tree, langPath) {
|
||||
if (!tree || typeof tree !== 'object') return tree || {};
|
||||
@@ -839,8 +876,37 @@ function normalizeRemoteTreeForPage(tree, langPath) {
|
||||
|
||||
if (!currentPageLeaf) return tree;
|
||||
|
||||
// 页面 leaf 合并到顶层,同时也保留完整路径
|
||||
return deepMergeLang(deepCloneLang(tree), deepCloneLang(currentPageLeaf));
|
||||
// (1) namespaced merge
|
||||
const namespaced = {};
|
||||
let cursor = namespaced;
|
||||
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 merged = deepMergeLang(deepCloneLang(tree), namespaced);
|
||||
|
||||
// (2) 短 key 兼容: 把 leaf 里的 SCALAR 平铺到 root,但跳过 target 已有 namespace 的 key
|
||||
try {
|
||||
for (const k of Object.prototype.hasOwnProperty.call(currentPageLeaf, '__proto__') ? [] : Object.keys(currentPageLeaf)) {
|
||||
if (FORBIDDEN_KEYS.has(k)) continue;
|
||||
const srcVal = currentPageLeaf[k];
|
||||
const tgtVal = merged[k];
|
||||
// 源非对象(基本类型)才平铺;源是对象则让上一步 namespaced merge 处理
|
||||
if (srcVal === null || typeof srcVal !== 'object' || Array.isArray(srcVal)) {
|
||||
// 若 target 已是 namespace 对象,跳过,避免 string-vs-object clobber
|
||||
if (tgtVal && typeof tgtVal === 'object' && !Array.isArray(tgtVal)) continue;
|
||||
merged[k] = srcVal;
|
||||
} else {
|
||||
// 源是对象 —— 递归合并到 merged[k](若存在)或跳过
|
||||
if (tgtVal && typeof tgtVal === 'object' && !Array.isArray(tgtVal)) {
|
||||
merged[k] = deepMergeLang(deepCloneLang(tgtVal), deepCloneLang(srcVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) { /* 静默 */ }
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
// 导出主体
|
||||
|
||||
24
scripts/audit_lang_bundle.js
Normal file
24
scripts/audit_lang_bundle.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Node script: load all lang files via require and dump as JSON for Python to consume.
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const langDir = path.resolve(process.cwd(), 'lang', process.argv[2]);
|
||||
function walk(dir) {
|
||||
const out = {};
|
||||
if (!fs.existsSync(dir)) return out;
|
||||
for (const f of fs.readdirSync(dir)) {
|
||||
const full = path.join(dir, f);
|
||||
const stat = fs.statSync(full);
|
||||
if (stat.isDirectory()) {
|
||||
Object.assign(out, walk(full));
|
||||
} else if (f.endsWith('.js')) {
|
||||
try {
|
||||
const m = require(full);
|
||||
if (m && m.lang && typeof m.lang === 'object') {
|
||||
out[full] = m.lang;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
console.log(JSON.stringify(walk(langDir), null, 2));
|
||||
231
scripts/audit_lang_bundle.py
Normal file
231
scripts/audit_lang_bundle.py
Normal file
@@ -0,0 +1,231 @@
|
||||
"""Full $lang vs bundle audit.
|
||||
|
||||
Steps:
|
||||
1. Load /api/lang/bundle (lang-bundle.json) tree
|
||||
2. Extract every $lang('xxx'[, ...]) first-arg string from .vue/.js files
|
||||
3. Locate each key in bundle tree (and a small set of structural fallbacks)
|
||||
4. Classify: FOUND / MISSING / SYNTAX_ERROR
|
||||
5. For MISSING: also check local lang files (zh-cn, en-us) to determine
|
||||
whether the key exists locally but bundle missed it
|
||||
"""
|
||||
import json, os, re, subprocess
|
||||
from collections import defaultdict, Counter
|
||||
|
||||
ROOT = r'D:\projects\shop-projects\frontend'
|
||||
BUNDLE_PATH = os.path.join(ROOT, 'lang-bundle.json')
|
||||
NODE_SCRIPT = os.path.join(ROOT, 'scripts', 'audit_lang_bundle.js')
|
||||
|
||||
# ---------- 1. Load bundle ----------
|
||||
with open(BUNDLE_PATH, 'r', encoding='utf-8') as f:
|
||||
bundle = json.load(f)
|
||||
tree = bundle['data']['tree']
|
||||
print(f'[bundle] version={bundle["data"].get("version")} lang={bundle["data"].get("lang")} source={bundle["data"].get("source")}')
|
||||
|
||||
# Flatten bundle keys (leaf string values)
|
||||
bundle_leaves = set()
|
||||
bundle_nodes = set() # intermediate nodes too, for fallback lookups
|
||||
|
||||
def walk(obj, prefix=''):
|
||||
if isinstance(obj, dict):
|
||||
if prefix:
|
||||
bundle_nodes.add(prefix)
|
||||
for k, v in obj.items():
|
||||
nk = f'{prefix}.{k}' if prefix else k
|
||||
if isinstance(v, dict):
|
||||
walk(v, nk)
|
||||
else:
|
||||
bundle_leaves.add(nk)
|
||||
elif prefix:
|
||||
bundle_leaves.add(prefix)
|
||||
walk(tree)
|
||||
print(f'[bundle] {len(bundle_leaves)} leaf keys, {len(bundle_nodes)} intermediate nodes')
|
||||
|
||||
# ---------- 2. Extract $lang() calls ----------
|
||||
SKIP_DIRS = {'node_modules', '.unpackage', 'unpackage', '.git', 'dist', 'stub-app-projects'}
|
||||
all_files = []
|
||||
for dirpath, dirnames, filenames in os.walk(ROOT):
|
||||
if any(s in dirpath for s in SKIP_DIRS):
|
||||
continue
|
||||
for fn in filenames:
|
||||
if fn.endswith(('.vue', '.js')):
|
||||
all_files.append(os.path.join(dirpath, fn))
|
||||
|
||||
# Match $lang('key'[, ...]) - first string arg, single OR double quotes
|
||||
# $lang() can span many lines but first arg is generally on same line
|
||||
call_re = re.compile(r"\$lang\(\s*(['\"])([^'\"]+)\1")
|
||||
all_calls = []
|
||||
for fp in all_files:
|
||||
rel = os.path.relpath(fp, ROOT)
|
||||
with open(fp, 'r', encoding='utf-8') as fh:
|
||||
try:
|
||||
content = fh.read()
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
for m in call_re.finditer(content):
|
||||
all_calls.append({'file': rel, 'key': m.group(2), 'pos': m.start()})
|
||||
|
||||
print(f'[code] {len(all_calls)} $lang calls across {len(set(c["file"] for c in all_calls))} files')
|
||||
unique_keys = sorted(set(c['key'] for c in all_calls))
|
||||
print(f'[code] {len(unique_keys)} unique keys called')
|
||||
|
||||
# ---------- 3. Classify ----------
|
||||
found, missing = [], []
|
||||
for k in unique_keys:
|
||||
if k in bundle_leaves:
|
||||
found.append(k)
|
||||
else:
|
||||
missing.append(k)
|
||||
|
||||
print(f'[match] FOUND={len(found)} MISSING={len(missing)}')
|
||||
|
||||
# ---------- 4. For MISSING keys: check local lang files too ----------
|
||||
print()
|
||||
print('Loading local lang files via Node...')
|
||||
def load_locale(locale):
|
||||
res = subprocess.run(['node', NODE_SCRIPT, locale], cwd=ROOT,
|
||||
capture_output=True, text=True, encoding='utf-8')
|
||||
if res.returncode != 0:
|
||||
print(f' node {locale} stderr: {res.stderr[:200]}')
|
||||
return {}
|
||||
parsed = json.loads(res.stdout)
|
||||
cleaned = {}
|
||||
for full, langobj in parsed.items():
|
||||
rel = os.path.relpath(full, os.path.join(ROOT, 'lang', locale))
|
||||
rel_no_ext = rel[:-3] if rel.endswith('.js') else rel
|
||||
cleaned[rel_no_ext] = langobj
|
||||
return cleaned
|
||||
|
||||
zh_cn = load_locale('zh-cn')
|
||||
en_us = load_locale('en-us')
|
||||
print(f' zh-cn: {len(zh_cn)} files; en-us: {len(en_us)} files')
|
||||
|
||||
def lookup_full(key, data):
|
||||
"""Walk dotted segments in nested map."""
|
||||
cur = data
|
||||
for seg in key.split('.'):
|
||||
if not isinstance(cur, dict) or seg not in cur:
|
||||
return None
|
||||
cur = cur[seg]
|
||||
return cur if isinstance(cur, str) else None
|
||||
|
||||
def local_lookup(key, locale_map):
|
||||
arr = key.split('.')
|
||||
last = arr[-1]
|
||||
fname_segments = '/'.join(arr[:-1])
|
||||
matches = []
|
||||
# 1) Short key in flat page file: e.g. fenxiao/bill.js exports {billNoPrefix}
|
||||
for fname, data in locale_map.items():
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
if (fname.endswith('/' + fname_segments) or fname == fname_segments) and \
|
||||
last in data and isinstance(data[last], str):
|
||||
matches.append(('short:' + last, fname, data[last]))
|
||||
# 2) Full dotted in any nested file
|
||||
for fname, data in locale_map.items():
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
v = lookup_full(key, data)
|
||||
if isinstance(v, str):
|
||||
matches.append(('nested:' + key, fname, v))
|
||||
break
|
||||
return matches
|
||||
|
||||
def classify_missing(key):
|
||||
"""Returns (category, evidence). category in {LOCALLY_DEFINED, SYNTAX_BUG, TRULY_MISSING}"""
|
||||
# Syntax error heuristics
|
||||
if key.endswith('.') or key in ('key', 'title', 'xxx'):
|
||||
return 'SYNTAX_BUG', 'trailing dot or generic identifier'
|
||||
if 'xxx' in key.lower() and not (key.startswith('xxx') and key.count('.') == 0):
|
||||
# 'components.foo.title' / 'components-diy.xxx' style placeholders in mixin
|
||||
return 'SYNTAX_BUG', "placeholder/example string (e.g. 'components.foo.title')"
|
||||
# Check local files
|
||||
zh = local_lookup(key, zh_cn)
|
||||
en = local_lookup(key, en_us)
|
||||
if zh or en:
|
||||
# Capture the actual found path in local file for evidence
|
||||
ev = ''
|
||||
if zh:
|
||||
ev += f'zh-cn: {zh[0][1]} {zh[0][0]}={zh[0][2]!r}'
|
||||
if en:
|
||||
ev += (' | ' if ev else '') + f'en-us: {en[0][1]} {en[0][0]}'
|
||||
return 'LOCALLY_DEFINED', ev
|
||||
return 'TRULY_MISSING', 'not in zh-cn / en-us / bundle'
|
||||
|
||||
cat_counts = Counter()
|
||||
locally_defined = []
|
||||
syntax_bugs = []
|
||||
truly_missing = []
|
||||
for k in missing:
|
||||
cat, ev = classify_missing(k)
|
||||
cat_counts[cat] += 1
|
||||
usage = [c for c in all_calls if c['key'] == k]
|
||||
entry = {
|
||||
'key': k, 'category': cat, 'evidence': ev,
|
||||
'usage_count': len(usage), 'files': sorted(set(c['file'] for c in usage))[:6],
|
||||
}
|
||||
if cat == 'LOCALLY_DEFINED':
|
||||
locally_defined.append(entry)
|
||||
elif cat == 'SYNTAX_BUG':
|
||||
syntax_bugs.append(entry)
|
||||
else:
|
||||
truly_missing.append(entry)
|
||||
|
||||
print()
|
||||
print('=== Classification of missing keys ===')
|
||||
for cat, n in cat_counts.most_common():
|
||||
print(f' {cat}: {n}')
|
||||
|
||||
# ---------- 5. Inspect a few interesting key paths in bundle ----------
|
||||
# Find for each "locally defined" key, the actual structure in bundle (closest match)
|
||||
def closest_in_bundle(key):
|
||||
"""Return bundle path segment that contains parts of key."""
|
||||
parts = key.split('.')
|
||||
cur = tree
|
||||
best = tree
|
||||
path = []
|
||||
for p in parts:
|
||||
if isinstance(cur, dict):
|
||||
cand = cur.get(p)
|
||||
if cand is None:
|
||||
# Try camelCase
|
||||
cc = re.sub(r'[-_]([a-z])', lambda m: m.group(1).upper(), p)
|
||||
cand = cur.get(cc)
|
||||
if cand is not None:
|
||||
path.append(cc)
|
||||
cur = cand
|
||||
continue
|
||||
if cand is not None:
|
||||
path.append(p)
|
||||
cur = cand
|
||||
else:
|
||||
return '.'.join(path), type(cur).__name__
|
||||
else:
|
||||
return '.'.join(path), type(cur).__name__
|
||||
return '.'.join(path), type(cur).__name__
|
||||
|
||||
print()
|
||||
print('=== For LOCALLY_DEFINED keys: real bundle structure check ===')
|
||||
for e in locally_defined[:10]:
|
||||
actual = closest_in_bundle(e['key'])
|
||||
print(f' $lang({e["key"]})')
|
||||
print(f' call: {e["files"][0]}')
|
||||
print(f' bundle partial walk stopped at: {actual[0]} ({actual[1]})')
|
||||
|
||||
# ---------- 6. Save report ----------
|
||||
report = {
|
||||
'bundle_version': bundle['data'].get('version'),
|
||||
'bundle_lang': bundle['data'].get('lang'),
|
||||
'bundle_source': bundle['data'].get('source'),
|
||||
'bundle_leaves': len(bundle_leaves),
|
||||
'code_calls_total': len(all_calls),
|
||||
'code_unique_keys': len(unique_keys),
|
||||
'found_in_bundle': len(found),
|
||||
'missing_summary': dict(cat_counts),
|
||||
'missing_locally_defined': locally_defined,
|
||||
'missing_syntax_bugs': syntax_bugs,
|
||||
'missing_truly_missing': truly_missing,
|
||||
}
|
||||
out_path = os.path.join(ROOT, 'scripts', 'lang_audit_report.json')
|
||||
with open(out_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(report, f, ensure_ascii=False, indent=2)
|
||||
print(f'\nReport saved to {out_path}')
|
||||
91
scripts/lang_audit_report.json
Normal file
91
scripts/lang_audit_report.json
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"bundle_version": "1782901586",
|
||||
"bundle_lang": "zh-cn",
|
||||
"bundle_source": "merged",
|
||||
"bundle_leaves": 2649,
|
||||
"code_calls_total": 2692,
|
||||
"code_unique_keys": 2092,
|
||||
"found_in_bundle": 2084,
|
||||
"missing_summary": {
|
||||
"SYNTAX_BUG": 7,
|
||||
"LOCALLY_DEFINED": 1
|
||||
},
|
||||
"missing_locally_defined": [
|
||||
{
|
||||
"key": "welcomeText",
|
||||
"category": "LOCALLY_DEFINED",
|
||||
"evidence": "zh-cn: login\\login nested:welcomeText='您好,<br />欢迎使用' | en-us: login\\login nested:welcomeText",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"missing_syntax_bugs": [
|
||||
{
|
||||
"key": "components-diy.xxx",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "placeholder/example string (e.g. 'components.foo.title')",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "components.privacyPopup.xxx",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "placeholder/example string (e.g. 'components.foo.title')",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "components.xxx",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "placeholder/example string (e.g. 'components.foo.title')",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "key",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "trailing dot or generic identifier",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "order.list.status.",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "trailing dot or generic identifier",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_order\\list.vue"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "title",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "trailing dot or generic identifier",
|
||||
"usage_count": 3,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "xxx",
|
||||
"category": "SYNTAX_BUG",
|
||||
"evidence": "trailing dot or generic identifier",
|
||||
"usage_count": 3,
|
||||
"files": [
|
||||
"common\\js\\lang.js",
|
||||
"main.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"missing_truly_missing": []
|
||||
}
|
||||
10782
scripts/lang_calls_extracted.json
Normal file
10782
scripts/lang_calls_extracted.json
Normal file
File diff suppressed because it is too large
Load Diff
987
scripts/lang_missing_local_check.json
Normal file
987
scripts/lang_missing_local_check.json
Normal file
@@ -0,0 +1,987 @@
|
||||
{
|
||||
"summary": {
|
||||
"total_missing": 117,
|
||||
"truly_missing_count": 105,
|
||||
"defined_locally_only_count": 1,
|
||||
"syntax_error_count": 11
|
||||
},
|
||||
"defined_locally_only": [
|
||||
{
|
||||
"key": "title",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"common\\js\\lang.js",
|
||||
"common\\js\\lang.js"
|
||||
],
|
||||
"local_match": [
|
||||
[
|
||||
"zh-cn",
|
||||
"agreement\\contenr",
|
||||
"nested:title",
|
||||
"协议"
|
||||
],
|
||||
[
|
||||
"en-us",
|
||||
"agreement\\contenr",
|
||||
"nested:title",
|
||||
"Agreement"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"syntax_error": [
|
||||
{
|
||||
"key": "components-diy.xxx",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "components.foo.default",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\mixin\\i18n-lazy.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "components.foo.title",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\mixin\\i18n-lazy.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "components.payment.",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"components\\payment\\payment.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "components.privacyPopup.xxx",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "components.xxx",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"common\\js\\lang.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "key",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"common\\js\\lang.js",
|
||||
"common\\js\\lang.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "point.order_list.",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\point\\order_list.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "status.",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_order\\list.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "xxx",
|
||||
"usage_count": 3,
|
||||
"files": [
|
||||
"main.js",
|
||||
"common\\js\\lang.js",
|
||||
"common\\js\\lang.js"
|
||||
],
|
||||
"local_match": []
|
||||
}
|
||||
],
|
||||
"truly_missing": [
|
||||
{
|
||||
"key": "agreement.contenr.noContent",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\agreement\\contenr.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "agreement.contenr.noContentDesc",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\agreement\\contenr.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "agreement.contenr.reload",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\agreement\\contenr.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.bill.addonClosed",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\bill.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.bill.billNoPrefix",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\bill.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.bill.noBill",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\bill.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.applyTime",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.auditTime",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.bankName",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.currentStatus",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.receivingAccount",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.refuseReason",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.serviceFee",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.transactionNo",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.transferTime",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "fenxiao.withdrawal_detail.transferTypeName",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_promotion\\fenxiao\\withdrawal_detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "file-preview.file-preview.fileUrlNotExist",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\file-preview\\file-preview.vue",
|
||||
"pages_tool\\file-preview\\file-preview.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "file-preview.file-preview.unsupportedFileType",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\file-preview\\file-preview.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "file-preview.file-preview.videoUrlNotExist",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\file-preview\\file-preview.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.form.noFormInfo",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\form\\form.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.form.submitSuccess",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\form\\form.vue",
|
||||
"pages_tool\\form\\form.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.form.title",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\form\\form.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.formdata.formTipPlaceholder",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\form\\formdata.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.formdata.noFormInfo",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\form\\formdata.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.formdata.paramError",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\form\\formdata.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.formdata.submitSuccess",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\form\\formdata.vue",
|
||||
"pages_tool\\form\\formdata.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "form.formdata.tip",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\form\\formdata.vue",
|
||||
"pages_tool\\form\\formdata.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "goods.brand.noMoreBrand",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\goods\\brand.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.complexityLowercase",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.complexityNumber",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.complexitySymbol",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.complexityUppercase",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.mobileInvalid",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.mobileNotRegistered",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.passwordComplexityPrefix",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.passwordMismatch",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.passwordRequired",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.passwordTooShort",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.resendCode",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue",
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.resendCountdown",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.step0Tip",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.step0Title",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.step1Tip",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.step1Title",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.step2Tip",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "login.find.step2Title",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\login\\find.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.alikePhone",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.animateCodeInput",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.bindBenefitTip",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.bindSuccess",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.codeSent",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.confirmCode",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.confirmCodeInput",
|
||||
"usage_count": 3,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.doNotRepeatedlyClick",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.findanimateCode",
|
||||
"usage_count": 3,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.manualBind",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.oneClickAuthBind",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.phoneNumber",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.pleInputMobile",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.save",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.smsCode",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.surePhoneNumber",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue",
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.bind_mobile.tipTitle",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\bind_mobile.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.index.iKnow",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\index.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.info.avatar",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\info.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.info.gender",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\info.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.public.cancelAccountConfirm",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\public\\js\\member-public.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "member.public.riskWarningTitle",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\member\\public\\js\\member-public.js"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.confirmPay",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.noPayInfo",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.noPayMethodConfigured",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.orderAlreadyPaid",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.paying",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.paymentCancelled",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.paymentFailed",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.cashier.pleaseSelectPayMethod",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\cashier.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.congratulations",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.couponsCount",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.goHome",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.growthValue",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.memberCard",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.noPayInfo",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.paymentFail",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.paymentSuccess",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.points",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.rechargeRecords",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "pay.result.viewOrder",
|
||||
"usage_count": 4,
|
||||
"files": [
|
||||
"pages_tool\\pay\\result.vue",
|
||||
"pages_tool\\pay\\result.vue",
|
||||
"pages_tool\\pay\\result.vue",
|
||||
"pages_tool\\pay\\result.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.downloadFailed",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue",
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.exportImage",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.exportPdf",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.fileNotExist",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.loading",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue",
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.saveFailed",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.saveSuccess",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.detail.title",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\detail.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.search.confirmDeleteAllHistory",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\search.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.search.confirmDeleteHistory",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\search.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.search.noData",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\search.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.search.placeholder",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\search.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.search.searchResult",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\search.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.medium.search.tip",
|
||||
"usage_count": 2,
|
||||
"files": [
|
||||
"pages_tool\\seal\\medium\\search.vue",
|
||||
"pages_tool\\seal\\medium\\search.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.structure.currentChoicePrefix",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\structure.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.structure.pleaseSelect",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\structure.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.structure.resultFile",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\structure.vue"
|
||||
],
|
||||
"local_match": []
|
||||
},
|
||||
{
|
||||
"key": "seal.structure.resultPrefix",
|
||||
"usage_count": 1,
|
||||
"files": [
|
||||
"pages_tool\\seal\\structure.vue"
|
||||
],
|
||||
"local_match": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -150,11 +150,34 @@ function normalizePageLangPack(packPath, langData) {
|
||||
}
|
||||
|
||||
let namespaced = {};
|
||||
let cursor = namespaced;
|
||||
{
|
||||
let cursor = namespaced;
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const segment = toCamelCaseName(segments[i]);
|
||||
cursor[segment] = i === segments.length - 1 ? deepCloneLang(currentPageLeaf) : {};
|
||||
cursor = cursor[segment];
|
||||
}
|
||||
}
|
||||
|
||||
// 同步建立 snake_case 镜像:让 camelCase 与 snake_case 路径都能解析到同一份 leaf
|
||||
// 与 bundle 服务器侧 emit 形式对齐(bundle 用 snake_case 段名,如 point.order_list.statusAll)
|
||||
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 = raw.replace(/([A-Z])/g, '_$1').replace(/-/g, '_').toLowerCase();
|
||||
if (snake !== camel) {
|
||||
const isLeaf = i === segments.length - 1;
|
||||
nested[i][snake] = isLeaf ? deepCloneLang(currentPageLeaf) : {};
|
||||
}
|
||||
}
|
||||
|
||||
return deepMergeLang(result, namespaced);
|
||||
@@ -190,25 +213,25 @@ const P2_CASES = [
|
||||
file: 'components/payment/payment.vue',
|
||||
locale: 'zh-cn',
|
||||
shared: ['components/payment'],
|
||||
keys: ['components.payment.alipay', 'components.payment.wechatpay']
|
||||
keys: ['components.payment.alipay', 'components.payment.wechatpay', 'components.payment.balancePay']
|
||||
},
|
||||
{
|
||||
file: 'components/payment/payment.vue',
|
||||
locale: 'en-us',
|
||||
shared: ['components/payment'],
|
||||
keys: ['components.payment.alipay', 'components.payment.wechatpay']
|
||||
keys: ['components.payment.alipay', 'components.payment.wechatpay', 'components.payment.balancePay']
|
||||
},
|
||||
{
|
||||
file: 'pages_order/list.vue',
|
||||
locale: 'zh-cn',
|
||||
page: 'order/list',
|
||||
keys: ['status.all', 'status.waitpay', 'status.waitsend', 'status.waitconfirm', 'status.waitrate']
|
||||
keys: ['order.list.status.all', 'order.list.status.waitpay', 'order.list.status.waitsend', 'order.list.status.waitconfirm', 'order.list.status.waitrate']
|
||||
},
|
||||
{
|
||||
file: 'pages_order/list.vue',
|
||||
locale: 'en-us',
|
||||
page: 'order/list',
|
||||
keys: ['status.all', 'status.waitpay', 'status.waitsend', 'status.waitconfirm', 'status.waitrate']
|
||||
keys: ['order.list.status.all', 'order.list.status.waitpay', 'order.list.status.waitsend', 'order.list.status.waitconfirm', 'order.list.status.waitrate']
|
||||
},
|
||||
{
|
||||
file: 'pages_promotion/fenxiao/order.vue',
|
||||
@@ -238,13 +261,13 @@ const P2_CASES = [
|
||||
file: 'pages_promotion/point/order_list.vue',
|
||||
locale: 'zh-cn',
|
||||
page: 'point/order_list',
|
||||
keys: ['point.orderList.statusAll', 'point.orderList.statusPendingPayment', 'point.orderList.statusCompleted']
|
||||
keys: ['point.order_list.statusAll', 'point.order_list.statusPendingPayment', 'point.order_list.statusCompleted']
|
||||
},
|
||||
{
|
||||
file: 'pages_promotion/point/order_list.vue',
|
||||
locale: 'en-us',
|
||||
page: 'point/order_list',
|
||||
keys: ['point.orderList.statusAll', 'point.orderList.statusPendingPayment', 'point.orderList.statusCompleted']
|
||||
keys: ['point.order_list.statusAll', 'point.order_list.statusPendingPayment', 'point.order_list.statusCompleted']
|
||||
},
|
||||
{
|
||||
file: 'pages_tool/goods/evaluate.vue',
|
||||
|
||||
Reference in New Issue
Block a user