2025-11-13 08:38:25 +00:00
|
|
|
/*
|
|
|
|
|
将现有的 copy-audit.xlsx 转换为 i18next 格式的翻译文件
|
|
|
|
|
*/
|
|
|
|
|
|
2025-11-28 06:31:36 +00:00
|
|
|
const fs = require('fs')
|
|
|
|
|
const path = require('path')
|
|
|
|
|
const XLSX = require('xlsx')
|
2025-11-13 08:38:25 +00:00
|
|
|
|
2025-11-28 06:31:36 +00:00
|
|
|
const WORKDIR = process.cwd()
|
2025-11-13 08:38:25 +00:00
|
|
|
|
|
|
|
|
function generateI18nKey(item) {
|
|
|
|
|
// 生成 i18next 格式的键名
|
2025-11-28 06:31:36 +00:00
|
|
|
const route = item.route === 'shared' ? 'common' : item.route.replace(/[^a-zA-Z0-9]/g, '_')
|
|
|
|
|
const component = item.componentOrFn.replace(/[^a-zA-Z0-9]/g, '_')
|
|
|
|
|
const kind = item.kind
|
|
|
|
|
const locator = item.keyOrLocator.replace(/[^a-zA-Z0-9]/g, '_')
|
|
|
|
|
|
|
|
|
|
return `${route}.${component}.${kind}.${locator}`.toLowerCase()
|
2025-11-13 08:38:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function main() {
|
|
|
|
|
// 读取现有的 Excel 文件
|
2025-11-28 06:31:36 +00:00
|
|
|
const excelFile = path.join(WORKDIR, 'docs', 'copy-audit.xlsx')
|
2025-11-13 08:38:25 +00:00
|
|
|
if (!fs.existsSync(excelFile)) {
|
2025-11-28 06:31:36 +00:00
|
|
|
console.error('❌ 找不到 copy-audit.xlsx 文件,请先运行 extract-copy 脚本')
|
|
|
|
|
process.exit(1)
|
2025-11-13 08:38:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 06:31:36 +00:00
|
|
|
const workbook = XLSX.readFile(excelFile)
|
|
|
|
|
const sheetName = workbook.SheetNames[0]
|
|
|
|
|
const worksheet = workbook.Sheets[sheetName]
|
|
|
|
|
const data = XLSX.utils.sheet_to_json(worksheet)
|
2025-11-13 08:38:25 +00:00
|
|
|
|
2025-11-28 06:31:36 +00:00
|
|
|
console.log(`📊 读取到 ${data.length} 条记录`)
|
2025-11-13 08:38:25 +00:00
|
|
|
|
|
|
|
|
// 生成 i18next 格式的翻译文件
|
2025-11-28 06:31:36 +00:00
|
|
|
const translation = {}
|
|
|
|
|
const i18nKeys = []
|
|
|
|
|
|
2025-11-13 08:38:25 +00:00
|
|
|
data.forEach((item, index) => {
|
|
|
|
|
if (item.text && item.text.trim()) {
|
2025-11-28 06:31:36 +00:00
|
|
|
const key = generateI18nKey(item)
|
|
|
|
|
translation[key] = item.text
|
2025-11-13 08:38:25 +00:00
|
|
|
i18nKeys.push({
|
|
|
|
|
key,
|
|
|
|
|
value: item.text,
|
|
|
|
|
route: item.route,
|
|
|
|
|
file: item.file,
|
|
|
|
|
line: item.line,
|
2025-11-28 06:31:36 +00:00
|
|
|
kind: item.kind,
|
|
|
|
|
})
|
2025-11-13 08:38:25 +00:00
|
|
|
}
|
2025-11-28 06:31:36 +00:00
|
|
|
})
|
2025-11-13 08:38:25 +00:00
|
|
|
|
|
|
|
|
// 确保目录存在
|
2025-11-28 06:31:36 +00:00
|
|
|
const localesDir = path.join(WORKDIR, 'public', 'locales', 'en')
|
2025-11-13 08:38:25 +00:00
|
|
|
if (!fs.existsSync(localesDir)) {
|
2025-11-28 06:31:36 +00:00
|
|
|
fs.mkdirSync(localesDir, { recursive: true })
|
2025-11-13 08:38:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 写入翻译文件
|
2025-11-28 06:31:36 +00:00
|
|
|
const translationFile = path.join(localesDir, 'translation.json')
|
|
|
|
|
fs.writeFileSync(translationFile, JSON.stringify(translation, null, 2))
|
2025-11-13 08:38:25 +00:00
|
|
|
|
|
|
|
|
// 生成详细的 i18n 扫描报告
|
|
|
|
|
const report = {
|
|
|
|
|
totalItems: data.length,
|
2025-11-28 06:31:36 +00:00
|
|
|
uniqueTexts: new Set(data.map((item) => item.text)).size,
|
2025-11-13 08:38:25 +00:00
|
|
|
translationKeys: Object.keys(translation).length,
|
|
|
|
|
byRoute: data.reduce((acc, item) => {
|
2025-11-28 06:31:36 +00:00
|
|
|
acc[item.route] = (acc[item.route] || 0) + 1
|
|
|
|
|
return acc
|
2025-11-13 08:38:25 +00:00
|
|
|
}, {}),
|
|
|
|
|
byKind: data.reduce((acc, item) => {
|
2025-11-28 06:31:36 +00:00
|
|
|
acc[item.kind] = (acc[item.kind] || 0) + 1
|
|
|
|
|
return acc
|
2025-11-13 08:38:25 +00:00
|
|
|
}, {}),
|
2025-11-28 06:31:36 +00:00
|
|
|
sampleKeys: Object.keys(translation).slice(0, 10),
|
|
|
|
|
}
|
2025-11-13 08:38:25 +00:00
|
|
|
|
|
|
|
|
// 生成 Excel 格式的 i18n 报告
|
2025-11-28 06:31:36 +00:00
|
|
|
const i18nWorkbook = XLSX.utils.book_new()
|
|
|
|
|
const i18nSheet = XLSX.utils.json_to_sheet(i18nKeys)
|
|
|
|
|
XLSX.utils.book_append_sheet(i18nWorkbook, i18nSheet, 'i18n-keys')
|
|
|
|
|
|
|
|
|
|
const i18nReportFile = path.join(WORKDIR, 'docs', 'i18n-scan-report.xlsx')
|
|
|
|
|
XLSX.writeFile(i18nWorkbook, i18nReportFile)
|
2025-11-13 08:38:25 +00:00
|
|
|
|
|
|
|
|
// 生成 JSON 报告
|
2025-11-28 06:31:36 +00:00
|
|
|
const reportFile = path.join(WORKDIR, 'docs', 'i18n-scan-report.json')
|
|
|
|
|
fs.writeFileSync(reportFile, JSON.stringify(report, null, 2))
|
|
|
|
|
|
|
|
|
|
console.log('✅ i18next 扫描转换完成!')
|
|
|
|
|
console.log(`📊 总扫描条目: ${data.length}`)
|
|
|
|
|
console.log(`🔑 生成翻译键: ${Object.keys(translation).length}`)
|
|
|
|
|
console.log(`📁 翻译文件: ${translationFile}`)
|
|
|
|
|
console.log(`📋 i18n Excel 报告: ${i18nReportFile}`)
|
|
|
|
|
console.log(`📄 JSON 报告: ${reportFile}`)
|
|
|
|
|
console.log('\n📝 示例翻译键:')
|
|
|
|
|
report.sampleKeys.forEach((key) => {
|
|
|
|
|
console.log(` ${key}: "${translation[key]}"`)
|
|
|
|
|
})
|
2025-11-13 08:38:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 06:31:36 +00:00
|
|
|
main()
|