refactor(common/lang): add shared component lang pack support

add shared language pack system for cross-page components, normalize component and page lang packs automatically, inject shared packs during language merge
This commit is contained in:
2026-06-26 18:26:21 +08:00
parent 4ae21c5d7a
commit 84f5cd4568

View File

@@ -20,6 +20,95 @@ const _fieldResultCache = {};
let _cachedLangPath = '';
let _cachedLangPathPage = null;
// 组件级共享语言包。
// 这些语言包不隶属于某个页面,但组件会在任意页面中直接调用
// $lang('components.xxx') / $lang('components-diy.xxx')。
// 因此必须在每个页面的合并语言包中统一注入,否则运行时会出现 raw key。
const SHARED_LANG_PACKS = [
'components/img-cropping',
'components/mescroll',
'components/ns-birthday-gift',
'components/ns-form',
'components/ns-login',
'components/ns-new-gift',
'components/ns-newform',
'components/ns-payment',
'components/ns-select-time',
'components/nsChatOrder',
'components/nsContact',
'components/nsGoodsPromotion',
'components/payment',
'components/privacy-popup',
'components/register-reward',
'components/wxwork-contact',
'components/yuyue-date',
'components-diy/diy-article',
'components-diy/diy-bargain',
'components-diy/diy-category',
'components-diy/diy-category-item',
'components-diy/diy-coupon',
'components-diy/diy-fenxiao-goods-list',
'components-diy/diy-goods-list',
'components-diy/diy-index-page',
'components-diy/diy-member-info',
'components-diy/diy-notice',
'components-diy/diy-payment-qrcode',
'components-diy/diy-pinfan',
'components-diy/diy-pintuan',
'components-diy/diy-seckill',
'components-diy/diy-store',
'components-diy/diy-video',
];
function toCamelCaseName(name) {
return String(name || '').replace(/-([a-z])/g, function(_, letter) {
return letter.toUpperCase();
});
}
function normalizeSharedLangPack(path, langData) {
if (!langData || typeof langData !== 'object') return {};
const segments = String(path || '').split('/');
const group = segments[0];
const fileName = segments[segments.length - 1];
if (group !== 'components' && group !== 'components-diy') return langData;
if (langData[group]) return langData;
const componentName = toCamelCaseName(fileName);
const keys = Object.keys(langData);
if (keys.length === 1 && langData[keys[0]] && typeof langData[keys[0]] === 'object') {
return {
[group]: langData
};
}
return {
[group]: {
[componentName]: langData
}
};
}
function normalizePageLangPack(path, langData) {
if (!path || !langData || typeof langData !== 'object') return langData || {};
const segments = String(path).split('/').filter(Boolean);
if (!segments.length) return langData;
let namespaced = {};
let cursor = namespaced;
for (let i = 0; i < segments.length; i++) {
const segment = toCamelCaseName(segments[i]);
cursor[segment] = i === segments.length - 1 ? deepCloneLang(langData) : {};
cursor = cursor[segment];
}
return deepMergeLang(deepCloneLang(langData), namespaced);
}
// 清除所有语言缓存(切语言/切租户/远端覆写更新时调用)
function invalidateLangCaches() {
for (const k in _mergedLangCache) { if (Object.prototype.hasOwnProperty.call(_mergedLangCache, k)) delete _mergedLangCache[k]; }
@@ -715,8 +804,15 @@ export default {
if (!mergedLang) {
try {
const lang = loadLangPackSync(locale, 'common');
const currentPageLang = langPath ? loadLangPackSync(locale, langPath) : {};
mergedLang = deepMergeLang(deepCloneLang(lang), deepCloneLang(currentPageLang));
const currentPageLang = langPath ? normalizePageLangPack(langPath, loadLangPackSync(locale, langPath)) : {};
mergedLang = deepCloneLang(lang);
for (const sharedPath of SHARED_LANG_PACKS) {
const sharedLang = normalizeSharedLangPack(sharedPath, loadLangPackSync(locale, sharedPath));
if (sharedLang && typeof sharedLang === 'object') {
mergedLang = deepMergeLang(mergedLang, deepCloneLang(sharedLang));
}
}
mergedLang = deepMergeLang(mergedLang, deepCloneLang(currentPageLang));
const ovr = overrideCache[getOverrideMemKey(locale)];
if (ovr && ovr.map) applyOverrides(mergedLang, ovr.map);
} catch (e) {