From 982c5b809d2b302ea537392d7ed329c237a7c1b7 Mon Sep 17 00:00:00 2001 From: hrx <18603305412@163.com> Date: Fri, 3 Jul 2026 14:30:24 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- f/web-kboss/package.json | 6 +- f/web-kboss/scripts/i18n-extract.js | 191 +++++ f/web-kboss/src/i18n/index.js | 36 + f/web-kboss/src/i18n/lang/en-US.auto.json | 660 ++++++++++++++++++ f/web-kboss/src/i18n/lang/en-US.js | 36 + f/web-kboss/src/i18n/lang/zh-CN.auto.json | 660 ++++++++++++++++++ f/web-kboss/src/i18n/lang/zh-CN.js | 36 + f/web-kboss/src/main.js | 2 + .../homePage/components/topBox/index.vue | 64 +- .../src/views/homePage/mainPage/index.vue | 28 +- 10 files changed, 1696 insertions(+), 23 deletions(-) create mode 100644 f/web-kboss/scripts/i18n-extract.js create mode 100644 f/web-kboss/src/i18n/index.js create mode 100644 f/web-kboss/src/i18n/lang/en-US.auto.json create mode 100644 f/web-kboss/src/i18n/lang/en-US.js create mode 100644 f/web-kboss/src/i18n/lang/zh-CN.auto.json create mode 100644 f/web-kboss/src/i18n/lang/zh-CN.js diff --git a/f/web-kboss/package.json b/f/web-kboss/package.json index c8d672e..d874234 100644 --- a/f/web-kboss/package.json +++ b/f/web-kboss/package.json @@ -14,7 +14,10 @@ "new": "plop", "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", "test:unit": "jest --clearCache && vue-cli-service test:unit", - "test:ci": "npm run lint && npm run test:unit" + "test:ci": "npm run lint && npm run test:unit", + "i18n:extract": "node scripts/i18n-extract.js --dir src/views/homePage", + "i18n:extract:all": "node scripts/i18n-extract.js --dir src", + "i18n:replace:home": "node scripts/i18n-extract.js --dir src/views/homePage --replace" }, "dependencies": { "@form-create/element-ui": "^2.5.30", @@ -55,6 +58,7 @@ "vue-count-to": "^1.0.13", "vue-cropper": "^0.6.5", "vue-device-detector": "^1.1.6", + "vue-i18n": "^8.28.2", "vue-infinite-scroll": "^2.0.2", "vue-router": "^3.0.2", "vue-splitpane": "1.0.4", diff --git a/f/web-kboss/scripts/i18n-extract.js b/f/web-kboss/scripts/i18n-extract.js new file mode 100644 index 0000000..f8fbc81 --- /dev/null +++ b/f/web-kboss/scripts/i18n-extract.js @@ -0,0 +1,191 @@ +/* eslint-disable no-console */ +const fs = require('fs') +const path = require('path') + +const projectRoot = process.cwd() +const args = process.argv.slice(2) + +const getArg = (name, defaultValue = '') => { + const full = `--${name}` + const hit = args.find((item) => item.startsWith(`${full}=`)) + if (hit) return hit.slice(full.length + 1) + const idx = args.indexOf(full) + if (idx !== -1 && args[idx + 1]) return args[idx + 1] + return defaultValue +} + +const hasFlag = (flag) => args.includes(`--${flag}`) + +const targetDirArg = getArg('dir', 'src/views/homePage') +const replaceMode = hasFlag('replace') + +const targetDir = path.resolve(projectRoot, targetDirArg) +const zhAutoPath = path.resolve(projectRoot, 'src/i18n/lang/zh-CN.auto.json') +const enAutoPath = path.resolve(projectRoot, 'src/i18n/lang/en-US.auto.json') + +const chinesePattern = /[\u4e00-\u9fa5]/ +const ignorePattern = /^(\s*|[-:,.(){}\[\]/\\]+)$/ + +const readJsonSafe = (filePath) => { + if (!fs.existsSync(filePath)) return {} + try { + return JSON.parse(fs.readFileSync(filePath, 'utf8')) + } catch (error) { + console.warn(`[warn] JSON parse failed: ${filePath}`) + return {} + } +} + +const writeJson = (filePath, value) => { + const content = JSON.stringify(value, null, 2) + '\n' + fs.writeFileSync(filePath, content, 'utf8') +} + +const walkFiles = (dir, bucket) => { + const entries = fs.readdirSync(dir, { withFileTypes: true }) + entries.forEach((entry) => { + const fullPath = path.join(dir, entry.name) + if (entry.isDirectory()) { + if (['node_modules', '.git', 'dist'].includes(entry.name)) return + walkFiles(fullPath, bucket) + return + } + if (!/\.(vue|js)$/.test(entry.name)) return + bucket.push(fullPath) + }) +} + +const normalizeText = (text) => + text + .replace(/\s+/g, ' ') + .replace(/ /g, ' ') + .trim() + +const keyFromText = (text) => { + let hash = 0 + for (let i = 0; i < text.length; i += 1) { + hash = (hash * 131 + text.charCodeAt(i)) >>> 0 + } + return `auto.k_${hash.toString(16)}` +} + +const zhMessages = readJsonSafe(zhAutoPath) +const enMessages = readJsonSafe(enAutoPath) + +const reverseMap = new Map() +Object.keys(zhMessages).forEach((key) => { + reverseMap.set(zhMessages[key], key) +}) + +const ensureKey = (rawText) => { + const text = normalizeText(rawText) + if (!text || !chinesePattern.test(text) || ignorePattern.test(text)) return null + + if (reverseMap.has(text)) return reverseMap.get(text) + + let key = keyFromText(text) + while (zhMessages[key] && zhMessages[key] !== text) { + key = `${key}_${Math.floor(Math.random() * 10000)}` + } + + zhMessages[key] = text + if (!Object.prototype.hasOwnProperty.call(enMessages, key)) { + enMessages[key] = '' + } + reverseMap.set(text, key) + return key +} + +const transformTemplate = (template) => { + let replacedCount = 0 + + const textNodeRegex = />([^<>{}\n]*[\u4e00-\u9fa5][^<>{}\n]*) { + const key = ensureKey(inner) + if (!key || !replaceMode) return full + replacedCount += 1 + return `>{{ $t('${key}') }}<` + }) + + const attrRegex = /\s([a-zA-Z_][\w-]*)=(["'])([^"']*[\u4e00-\u9fa5][^"']*)\2/g + updated = updated.replace(attrRegex, (full, attr, quote, value) => { + const key = ensureKey(value) + if (!key || !replaceMode) return full + replacedCount += 1 + return ` :${attr}="$t('${key}')"` + }) + + return { updated, replacedCount } +} + +const processVueFile = (filePath) => { + const raw = fs.readFileSync(filePath, 'utf8') + const templateMatch = raw.match(/