feat: add vue-template-tolerant plugin for error handling in translation pages

- Implemented a new Vite plugin that detects HTML errors in Vue translation pages and logs detailed error messages to the console.
- The plugin replaces the content of pages with a placeholder if errors are found, improving the robustness of the translation process.
- Integrated the plugin into the Vite bundler configuration for enhanced localization support.
This commit is contained in:
BruceChen 2026-04-08 22:28:41 +08:00
parent b69708c637
commit 906d66a713

View file

@ -9,11 +9,70 @@ import { shikiPlugin } from '@vuepress/plugin-shiki'
import { defaultTheme } from '@vuepress/theme-default'
import { defineUserConfig } from 'vuepress'
import type { Plugin } from 'vite'
import { headConfig } from './configs/head.js'
import { mainConfig, defaultThemeConfig } from './configs/locales_config.js'
const isProd = process.env.NODE_ENV === 'production'
function vueTemplateTolerantPlugin(): Plugin {
let compilerSfc: typeof import('@vue/compiler-sfc') | undefined
return {
name: 'vue-template-tolerant',
enforce: 'pre',
async transform(code, id) {
if (!id.endsWith('.html.vue') || !id.includes('/l10n/')) return
compilerSfc ??= await import('@vue/compiler-sfc')
const { errors } = compilerSfc.parse(code, { filename: id })
if (errors.length === 0) return
const lines = code.split('\n')
const mdPath = id
.replace(/\.vuepress\/\.temp\/pages\//, '')
.replace(/\.html\.vue$/, '.md')
const yellow = '\x1b[33m'
const red = '\x1b[31m'
const dim = '\x1b[2m'
const cyan = '\x1b[36m'
const reset = '\x1b[0m'
let output = `${yellow}[vue-template-tolerant]${reset} ${errors.length} error(s) in translation page (replaced with placeholder)\n`
output += ` ${dim}source:${reset} ${cyan}${mdPath}${reset}\n`
for (const err of errors as any[]) {
const msg = err.message ?? String(err)
const loc = err.loc as { start: { line: number; column: number }; end: { line: number; column: number }; source?: string } | undefined
if (loc) {
output += `\n ${red}error${reset} ${msg}\n`
output += ` ${dim}at ${id}:${loc.start.line}:${loc.start.column}${reset}\n`
const startLine = Math.max(0, loc.start.line - 3)
const endLine = Math.min(lines.length, loc.start.line + 2)
for (let i = startLine; i < endLine; i++) {
const lineNum = String(i + 1).padStart(5)
const marker = i + 1 === loc.start.line ? `${red}>${reset}` : ' '
const lineContent = lines[i].length > 200 ? lines[i].slice(0, 200) + '...' : lines[i]
output += ` ${marker} ${dim}${lineNum}${reset} | ${lineContent}\n`
if (i + 1 === loc.start.line) {
const col = loc.start.column
output += ` ${' '.repeat(5)} | ${' '.repeat(col)}${red}^${reset}\n`
}
}
} else {
output += `\n ${red}error${reset} ${msg}\n`
}
}
console.warn(output)
return {
code: '<template><div><p>This page has HTML errors in its translation source and could not be rendered.</p></div></template>',
map: null,
}
},
}
}
export default defineUserConfig({
// set site base to default value
base: '/',
@ -25,7 +84,14 @@ export default defineUserConfig({
locales: mainConfig,
// specify bundler via environment variable
bundler: process.env.DOCS_BUNDLER === 'webpack' ? webpackBundler() : viteBundler(),
bundler:
process.env.DOCS_BUNDLER === 'webpack'
? webpackBundler()
: viteBundler({
viteOptions: {
plugins: [vueTemplateTolerantPlugin()],
},
}),
// configure default theme
theme: defaultTheme({