优化vite翻译插件
This commit is contained in:
parent
99de35ce6d
commit
4ad23c57ab
@ -304,7 +304,7 @@
|
|||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
$route.name == 'Login'
|
$route.name == 'Login'
|
||||||
? $t('Don\'t have an account? Create one.')
|
? $t("Don't have an account? Create one.")
|
||||||
: $t('Already have an account? Log in.')
|
: $t('Already have an account? Log in.')
|
||||||
}}
|
}}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -68,11 +68,11 @@ function processNestedTranslations(paramsCode, translations, pattern) {
|
|||||||
// 格式1:带前缀的 (ctxPrefix, quote, key)
|
// 格式1:带前缀的 (ctxPrefix, quote, key)
|
||||||
ctxPrefix = captureGroups[0] || '';
|
ctxPrefix = captureGroups[0] || '';
|
||||||
quote = captureGroups[1];
|
quote = captureGroups[1];
|
||||||
key = captureGroups[2];
|
key = unescapeString(captureGroups[2]);
|
||||||
} else if (captureGroups.length === 2) {
|
} else if (captureGroups.length === 2) {
|
||||||
// 格式2或3:不带前缀的 (quote, key)
|
// 格式2或3:不带前缀的 (quote, key)
|
||||||
quote = captureGroups[0];
|
quote = captureGroups[0];
|
||||||
key = captureGroups[1];
|
key = unescapeString(captureGroups[1]);
|
||||||
} else {
|
} else {
|
||||||
// 无法解析,返回原匹配
|
// 无法解析,返回原匹配
|
||||||
return match;
|
return match;
|
||||||
@ -137,9 +137,10 @@ function vitePluginTranslate(options = {}) {
|
|||||||
} else {
|
} else {
|
||||||
// 非 Vue 文件
|
// 非 Vue 文件
|
||||||
code = code.replace(
|
code = code.replace(
|
||||||
/\bt\((['"])([^'"]+)\1\)/g,
|
/\bt\((['"])((?:\\.|(?!\1).)*)\1\)/g,
|
||||||
(match, quote, key) => {
|
(match, quote, key) => {
|
||||||
const translation = translations[key];
|
const unescapedKey = unescapeString(key);
|
||||||
|
const translation = translations[unescapedKey];
|
||||||
return translation ? quote + escapeString(translation, quote) + quote : match;
|
return translation ? quote + escapeString(translation, quote) + quote : match;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -202,9 +203,10 @@ function processVueSFC(code, translations) {
|
|||||||
/(<script[^>]*>)([\s\S]*?)(<\/script>)/gi,
|
/(<script[^>]*>)([\s\S]*?)(<\/script>)/gi,
|
||||||
(match, openTag, scriptContent, closeTag) => {
|
(match, openTag, scriptContent, closeTag) => {
|
||||||
const replacedContent = scriptContent.replace(
|
const replacedContent = scriptContent.replace(
|
||||||
/\$t\((['"])([^'"]+)\1\)/g,
|
/\$t\((['"])((?:\\.|(?!\1).)*)\1\)/g,
|
||||||
(match, quote, key) => {
|
(match, quote, key) => {
|
||||||
const translation = translations[key];
|
const unescapedKey = unescapeString(key);
|
||||||
|
const translation = translations[unescapedKey];
|
||||||
return translation ? `$t(${quote}${escapeString(translation, quote)}${quote})` : match;
|
return translation ? `$t(${quote}${escapeString(translation, quote)}${quote})` : match;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -221,19 +223,43 @@ function processVueSFC(code, translations) {
|
|||||||
function replaceInterpolations(code, translations) {
|
function replaceInterpolations(code, translations) {
|
||||||
// 先处理不带参数的调用:{{ $t('xxx') }}
|
// 先处理不带参数的调用:{{ $t('xxx') }}
|
||||||
code = code.replace(
|
code = code.replace(
|
||||||
/\{\{\s*[\$]t\s*\(\s*(['"])([^'"]+)\1\s*\)\s*\}\}/g,
|
/\{\{\s*[\$]t\s*\(\s*(['"])((?:\\.|(?!\1).)*)\1\s*\)\s*\}\}/g,
|
||||||
(match, quote, key) => translations[key] || match
|
(match, quote, key) => {
|
||||||
|
const unescapedKey = unescapeString(key);
|
||||||
|
return translations[unescapedKey] || match;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 处理插值表达式内部的 $t() 调用(不在单独的 {{ $t(...) }} 中)
|
||||||
|
// 例如:{{ condition ? $t('key1') : $t('key2') }}
|
||||||
|
code = code.replace(
|
||||||
|
/\{\{[\s\S]*?\}\}/g,
|
||||||
|
(interpolation) => {
|
||||||
|
// 如果这个插值已经是一个完整的 {{ $t(...) }},跳过
|
||||||
|
if (/^\{\{\s*[\$]t\s*\(/.test(interpolation.trim())) {
|
||||||
|
return interpolation;
|
||||||
|
}
|
||||||
|
// 否则,处理其中的 $t() 调用
|
||||||
|
return interpolation.replace(
|
||||||
|
/\$t\((['"])((?:\\.|(?!\1).)*)\1\)/g,
|
||||||
|
(match, quote, key) => {
|
||||||
|
const unescapedKey = unescapeString(key);
|
||||||
|
const translation = translations[unescapedKey];
|
||||||
|
return translation ? `$t(${quote}${escapeString(translation, quote)}${quote})` : match;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 处理带参数的调用:{{ $t('key', { params }) }}
|
// 处理带参数的调用:{{ $t('key', { params }) }}
|
||||||
const matches = [];
|
const matches = [];
|
||||||
const pattern = /\{\{\s*[\$]t\s*\(\s*(['"])([^'"]+)\1\s*,\s*/g;
|
const pattern = /\{\{\s*[\$]t\s*\(\s*(['"])((?:\\.|(?!\1).)*)\1\s*,\s*/g;
|
||||||
let match;
|
let match;
|
||||||
|
|
||||||
while ((match = pattern.exec(code)) !== null) {
|
while ((match = pattern.exec(code)) !== null) {
|
||||||
const startIndex = match.index;
|
const startIndex = match.index;
|
||||||
const quote = match[1];
|
const quote = match[1];
|
||||||
const key = match[2];
|
const key = unescapeString(match[2]);
|
||||||
const afterKeyIndex = match.index + match[0].length;
|
const afterKeyIndex = match.index + match[0].length;
|
||||||
|
|
||||||
// 找到参数部分的结束位置
|
// 找到参数部分的结束位置
|
||||||
@ -261,13 +287,13 @@ function replaceInterpolations(code, translations) {
|
|||||||
paramsPart = processNestedTranslations(
|
paramsPart = processNestedTranslations(
|
||||||
paramsPart,
|
paramsPart,
|
||||||
translations,
|
translations,
|
||||||
/\{\{\s*[\$]t\s*\(\s*(['"])([^'"]+)\1\s*\)\s*\}\}/g
|
/\{\{\s*[\$]t\s*\(\s*(['"])((?:\\.|(?!\1).)*)\1\s*\)\s*\}\}/g
|
||||||
);
|
);
|
||||||
// 再处理 $t(...) 格式(参数对象中的直接调用)
|
// 再处理 $t(...) 格式(参数对象中的直接调用)
|
||||||
paramsPart = processNestedTranslations(
|
paramsPart = processNestedTranslations(
|
||||||
paramsPart,
|
paramsPart,
|
||||||
translations,
|
translations,
|
||||||
/\$t\((['"])([^'"]+)\1\)/g
|
/\$t\((['"])((?:\\.|(?!\1).)*)\1\)/g
|
||||||
);
|
);
|
||||||
|
|
||||||
const translation = translations[m.key];
|
const translation = translations[m.key];
|
||||||
@ -286,14 +312,14 @@ function replaceInterpolations(code, translations) {
|
|||||||
function replaceCompiledFormat(code, translations) {
|
function replaceCompiledFormat(code, translations) {
|
||||||
// 处理带参数的调用
|
// 处理带参数的调用
|
||||||
const matches = [];
|
const matches = [];
|
||||||
const pattern = /([a-zA-Z_$][a-zA-Z0-9_$]*\.)?[\$]t\((['"])([^'"]+)\2\s*,\s*/g;
|
const pattern = /([a-zA-Z_$][a-zA-Z0-9_$]*\.)?[\$]t\((['"])((?:\\.|(?!\2).)*)\2\s*,\s*/g;
|
||||||
let match;
|
let match;
|
||||||
|
|
||||||
while ((match = pattern.exec(code)) !== null) {
|
while ((match = pattern.exec(code)) !== null) {
|
||||||
const startIndex = match.index;
|
const startIndex = match.index;
|
||||||
const ctxPrefix = match[1] || '';
|
const ctxPrefix = match[1] || '';
|
||||||
const quote = match[2];
|
const quote = match[2];
|
||||||
const key = match[3];
|
const key = unescapeString(match[3]);
|
||||||
const afterKeyIndex = match.index + match[0].length;
|
const afterKeyIndex = match.index + match[0].length;
|
||||||
|
|
||||||
const paramsEnd = findBalancedBracket(code, afterKeyIndex);
|
const paramsEnd = findBalancedBracket(code, afterKeyIndex);
|
||||||
@ -311,7 +337,7 @@ function replaceCompiledFormat(code, translations) {
|
|||||||
paramsPart = processNestedTranslations(
|
paramsPart = processNestedTranslations(
|
||||||
paramsPart,
|
paramsPart,
|
||||||
translations,
|
translations,
|
||||||
/([a-zA-Z_$][a-zA-Z0-9_$]*\.)?[\$]t\((['"])([^'"]+)\2\)/g
|
/([a-zA-Z_$][a-zA-Z0-9_$]*\.)?[\$]t\((['"])((?:\\.|(?!\2).)*)\2\)/g
|
||||||
);
|
);
|
||||||
|
|
||||||
const translation = translations[m.key];
|
const translation = translations[m.key];
|
||||||
@ -323,9 +349,10 @@ function replaceCompiledFormat(code, translations) {
|
|||||||
|
|
||||||
// 处理不带参数的调用
|
// 处理不带参数的调用
|
||||||
code = code.replace(
|
code = code.replace(
|
||||||
/([a-zA-Z_$][a-zA-Z0-9_$]*\.)?[\$]t\((['"])([^'"]+)\2\)/g,
|
/([a-zA-Z_$][a-zA-Z0-9_$]*\.)?[\$]t\((['"])((?:\\.|(?!\2).)*)\2\)/g,
|
||||||
(match, ctxPrefix, quote, key) => {
|
(match, ctxPrefix, quote, key) => {
|
||||||
const translation = translations[key];
|
const unescapedKey = unescapeString(key);
|
||||||
|
const translation = translations[unescapedKey];
|
||||||
return translation ? `${ctxPrefix || ''}$t(${quote}${escapeString(translation, quote)}${quote})` : match;
|
return translation ? `${ctxPrefix || ''}$t(${quote}${escapeString(translation, quote)}${quote})` : match;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -338,9 +365,10 @@ function replaceCompiledFormat(code, translations) {
|
|||||||
*/
|
*/
|
||||||
function replaceAttributeBindings(code, translations) {
|
function replaceAttributeBindings(code, translations) {
|
||||||
return code.replace(
|
return code.replace(
|
||||||
/([:@]|v-bind:|v-on:)([a-zA-Z0-9_-]+)=(["'])[\$]?t\((['"])([^'"]+)\4\)\3/g,
|
/([:@]|v-bind:|v-on:)([a-zA-Z0-9_-]+)=(["'])[\$]?t\((['"])((?:\\.|(?!\4).)*)\4\)\3/g,
|
||||||
(match, prefix, attrName, outerQuote, innerQuote, key) => {
|
(match, prefix, attrName, outerQuote, innerQuote, key) => {
|
||||||
const translation = translations[key];
|
const unescapedKey = unescapeString(key);
|
||||||
|
const translation = translations[unescapedKey];
|
||||||
if (!translation || !translation.trim()) return match;
|
if (!translation || !translation.trim()) return match;
|
||||||
|
|
||||||
let escaped = escapeString(translation, outerQuote);
|
let escaped = escapeString(translation, outerQuote);
|
||||||
@ -355,6 +383,14 @@ function replaceAttributeBindings(code, translations) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去除字符串中的转义字符(将 \' 转换为 ',\" 转换为 " 等)
|
||||||
|
*/
|
||||||
|
function unescapeString(text) {
|
||||||
|
return text
|
||||||
|
.replace(/\\(.)/g, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转义字符串
|
* 转义字符串
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { sentryVitePlugin } from '@sentry/vite-plugin';
|
|||||||
import vitePluginTranslate from './vite-plugin-translate.mjs';
|
import vitePluginTranslate from './vite-plugin-translate.mjs';
|
||||||
|
|
||||||
// 语言配置:设置目标语言,默认为 'en'(英文),可设置为 'zh'(中文)等
|
// 语言配置:设置目标语言,默认为 'en'(英文),可设置为 'zh'(中文)等
|
||||||
const locale = process.env.DASHBOARD_LOCALE || 'en';
|
const locale = process.env.DASHBOARD_LOCALE || 'zh';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user