修复用户信息下拉菜单无法翻译的问题
This commit is contained in:
parent
c6067d0a9f
commit
114f6211c7
@ -10,7 +10,7 @@
|
||||
<JLogo class="h-8 w-8 rounded" />
|
||||
<div class="ml-2 flex flex-col">
|
||||
<div class="text-base font-medium leading-none text-gray-900">
|
||||
今果 Jingrow
|
||||
Jingrow
|
||||
</div>
|
||||
<div
|
||||
v-if="$account.user"
|
||||
@ -37,7 +37,7 @@
|
||||
<span class="mr-1.5">
|
||||
<FeatherIcon name="search" class="h-5 w-5 text-gray-700" />
|
||||
</span>
|
||||
<span class="text-sm">Search</span>
|
||||
<span class="text-sm">{{ $t('Search') }}</span>
|
||||
<span class="ml-auto text-sm text-gray-500">
|
||||
<template v-if="$platform === 'mac'">⌘K</template>
|
||||
<template v-else>Ctrl+K</template>
|
||||
@ -124,26 +124,29 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showCommandPalette: false,
|
||||
showTeamSwitcher: false,
|
||||
dropdownItems: [
|
||||
showTeamSwitcher: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dropdownItems() {
|
||||
return [
|
||||
{
|
||||
label: 'Switch Team',
|
||||
label: this.$t('Switch Team'),
|
||||
icon: 'command',
|
||||
onClick: () => (this.showTeamSwitcher = true)
|
||||
},
|
||||
{
|
||||
label: 'Support & Docs',
|
||||
label: this.$t('Support & Docs'),
|
||||
icon: 'help-circle',
|
||||
onClick: () => (window.location.href = '/support')
|
||||
},
|
||||
{
|
||||
label: 'Logout',
|
||||
label: this.$t('Logout'),
|
||||
icon: 'log-out',
|
||||
onClick: () => this.$auth.logout()
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
];
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('keydown', e => {
|
||||
if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
|
||||
|
||||
@ -13,6 +13,7 @@ const CONSTANTS = {
|
||||
VUE_TEMPLATE_TAG_LEN: 9,
|
||||
VUE_TEMPLATE_CLOSE_TAG_LEN: 11,
|
||||
VUE_TEMPLATE_MODULE: '?vue&type=template',
|
||||
VUE_SCRIPT_MODULE: '?vue&type=script',
|
||||
VUE_STYLE_MODULE: '?vue&type=style',
|
||||
FILE_EXTENSIONS: /\.(vue|js|ts|jsx|tsx)(\?.*)?$/,
|
||||
NON_ASCII_REGEX: /[^\x00-\x7F]/,
|
||||
@ -127,16 +128,29 @@ function processNestedTranslations(paramsCode, translations, pattern) {
|
||||
* @param {string} options.defaultLocale - 默认语言代码
|
||||
*/
|
||||
function vitePluginTranslate(options = {}) {
|
||||
let translations = {};
|
||||
const locale = options.locale || 'en';
|
||||
const defaultLocale = options.defaultLocale || 'en';
|
||||
const translationsPath = options.translationsPath || '../jcloud/translations';
|
||||
|
||||
// 在插件初始化时立即加载翻译数据,而不是等到 configResolved
|
||||
let translations = {};
|
||||
if (locale && locale !== defaultLocale) {
|
||||
const csvPath = path.resolve(__dirname, `${translationsPath}/${locale}.csv`);
|
||||
if (fs.existsSync(csvPath)) {
|
||||
try {
|
||||
translations = parseCSV(csvPath);
|
||||
} catch (error) {
|
||||
console.warn(`[vite-plugin-translate] Failed to load translations from ${csvPath}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-translate',
|
||||
enforce: 'pre',
|
||||
configResolved(config) {
|
||||
if (locale && locale !== defaultLocale) {
|
||||
// 确保翻译数据已加载(双重检查)
|
||||
if (locale && locale !== defaultLocale && Object.keys(translations).length === 0) {
|
||||
const csvPath = path.resolve(__dirname, `${translationsPath}/${locale}.csv`);
|
||||
if (fs.existsSync(csvPath)) {
|
||||
try {
|
||||
@ -158,12 +172,44 @@ function vitePluginTranslate(options = {}) {
|
||||
|
||||
if (isVueFile) {
|
||||
const isTemplateModule = id.includes(CONSTANTS.VUE_TEMPLATE_MODULE);
|
||||
const isScriptModule = id.includes(CONSTANTS.VUE_SCRIPT_MODULE);
|
||||
|
||||
if (isTemplateModule) {
|
||||
// Vue 编译后的模板模块
|
||||
code = replaceInterpolations(code, translations);
|
||||
code = replaceCompiledFormat(code, translations);
|
||||
code = replaceAttributeBindings(code, translations);
|
||||
} else if (isScriptModule) {
|
||||
// Vue 编译后的 script 模块 - 需要处理 this.$t()、$t() 以及编译后的函数调用(如 le()、t())
|
||||
// 先处理 this.$t() 和 $t()
|
||||
code = code.replace(
|
||||
/(?:this\.)?\$t\((['"])((?:\\.|(?!\1).)*)\1\)/g,
|
||||
(match, quote, key) => {
|
||||
const unescapedKey = unescapeString(key);
|
||||
const translation = translations[unescapedKey];
|
||||
if (translation) {
|
||||
return quote + escapeString(translation, quote) + quote;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
);
|
||||
// 再处理编译后的函数调用(如 le("key")、t("key"))
|
||||
// 匹配函数名后跟括号和字符串参数
|
||||
code = code.replace(
|
||||
/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\((['"])((?:\\.|(?!\2).)*)\2\)/g,
|
||||
(match, funcName, quote, key) => {
|
||||
// 只处理可能是翻译函数的调用(通常是单字母或短名称,如 t, le, i 等)
|
||||
// 但排除明显的非翻译函数(如 console.log, JSON.parse 等)
|
||||
if (funcName.length <= 3 && !['log', 'warn', 'error', 'parse', 'stringify', 'keys', 'values', 'entries'].includes(funcName)) {
|
||||
const unescapedKey = unescapeString(key);
|
||||
const translation = translations[unescapedKey];
|
||||
if (translation) {
|
||||
return funcName + '(' + quote + escapeString(translation, quote) + quote + ')';
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// 原始 Vue SFC 文件
|
||||
code = processVueSFC(code, translations);
|
||||
@ -242,17 +288,39 @@ function processVueSFC(code, translations) {
|
||||
code = code.replace(
|
||||
/(<script[^>]*>)([\s\S]*?)(<\/script>)/gi,
|
||||
(match, openTag, scriptContent, closeTag) => {
|
||||
const replacedContent = scriptContent.replace(
|
||||
// 先处理 $t() 和 this.$t() 调用
|
||||
let replacedContent = scriptContent.replace(
|
||||
/(?:this\.)?\$t\((['"])((?:\\.|(?!\1).)*)\1\)/g,
|
||||
(match, quote, key) => {
|
||||
const unescapedKey = unescapeString(key);
|
||||
const translation = translations[unescapedKey];
|
||||
// 如果匹配包含 this.,保留它
|
||||
const hasThis = match.startsWith('this.');
|
||||
const prefix = hasThis ? 'this.' : '';
|
||||
return translation ? `${prefix}$t(${quote}${escapeString(translation, quote)}${quote})` : match;
|
||||
if (translation) {
|
||||
return quote + escapeString(translation, quote) + quote;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
);
|
||||
|
||||
// 再处理 t() 函数调用(从 i18n.js 导入的翻译函数)
|
||||
// 检查是否有从 i18n 导入 t 函数
|
||||
const hasTImport = /import\s*\{[^}]*\bt\b[^}]*\}\s*from\s*['"]\.\.?\/.*i18n['"]/i.test(scriptContent) ||
|
||||
/import\s*\{[^}]*\bt\b[^}]*\}\s*from\s*['"]@\/.*i18n['"]/i.test(scriptContent);
|
||||
|
||||
if (hasTImport) {
|
||||
// 匹配 t('key') 或 t("key"),但排除 t.something() 或 t['something']()
|
||||
replacedContent = replacedContent.replace(
|
||||
/\bt\((['"])((?:\\.|(?!\1).)*)\1\)/g,
|
||||
(match, quote, key) => {
|
||||
const unescapedKey = unescapeString(key);
|
||||
const translation = translations[unescapedKey];
|
||||
if (translation) {
|
||||
return quote + escapeString(translation, quote) + quote;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return openTag + replacedContent + closeTag;
|
||||
}
|
||||
);
|
||||
|
||||
@ -506,6 +506,7 @@ You are not logged in.,您尚未登录。,
|
||||
to access dashboard.,以访问仪表板。,
|
||||
Switch Team,切换团队,
|
||||
Logout,退出登录,
|
||||
Support & Docs,支持与文档,
|
||||
Suspended,已暂停,
|
||||
Broken,损坏,
|
||||
China,中国大陆,
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 401.
|
Loading…
x
Reference in New Issue
Block a user