mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 18:50:56 +08:00
docs(scripts): translate comments and error messages to english
Update documentation and error messages in i18n-related scripts from Chinese to English to improve codebase accessibility for international teams.
This commit is contained in:
parent
16a69e240b
commit
7365c1ca1a
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* 该脚本用于少量自动翻译所有baseLocale以外的文本。待翻译文案必须以[to be translated]开头
|
||||
* This script is used for automatic translation of all text except baseLocale.
|
||||
* Text to be translated must start with [to be translated]
|
||||
*
|
||||
*/
|
||||
import OpenAI from '@cherrystudio/openai'
|
||||
@ -72,10 +73,10 @@ const translate = async (systemPrompt: string) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归翻译对象中的字符串值
|
||||
* @param originObj - 原始国际化对象
|
||||
* @param systemPrompt - 系统提示词
|
||||
* @returns 翻译后的新对象
|
||||
* Recursively translate string values in objects
|
||||
* @param originObj - Original internationalization object
|
||||
* @param systemPrompt - System prompt
|
||||
* @returns Translated new object
|
||||
*/
|
||||
const translateRecursively = async (originObj: I18N, systemPrompt: string): Promise<I18N> => {
|
||||
const newObj = {}
|
||||
@ -90,7 +91,7 @@ const translateRecursively = async (originObj: I18N, systemPrompt: string): Prom
|
||||
newObj[key] = result
|
||||
} catch (e) {
|
||||
newObj[key] = text
|
||||
console.error('translate failed.', text)
|
||||
console.error('Translation failed.', text)
|
||||
}
|
||||
} else {
|
||||
newObj[key] = text
|
||||
@ -131,7 +132,7 @@ const main = async () => {
|
||||
const fileContent = fs.readFileSync(filePath, 'utf-8')
|
||||
targetJson = JSON.parse(fileContent)
|
||||
} catch (error) {
|
||||
console.error(`解析 ${filename} 出错,跳过此文件。`, error)
|
||||
console.error(`Error parsing ${filename}, skipping this file.`, error)
|
||||
continue
|
||||
}
|
||||
const systemPrompt = PROMPT.replace('{{target_language}}', languageMap[filename])
|
||||
@ -142,9 +143,9 @@ const main = async () => {
|
||||
|
||||
try {
|
||||
fs.writeFileSync(filePath, JSON.stringify(result, null, 2) + '\n', 'utf-8')
|
||||
console.log(`文件 ${filename} 已翻译完毕`)
|
||||
console.log(`File ${filename} translation completed`)
|
||||
} catch (error) {
|
||||
console.error(`写入 ${filename} 出错。${error}`)
|
||||
console.error(`Error writing ${filename}. ${error}`)
|
||||
}
|
||||
}
|
||||
bar.stop()
|
||||
|
||||
@ -12,39 +12,41 @@ type I18NValue = string | { [key: string]: I18NValue }
|
||||
type I18N = { [key: string]: I18NValue }
|
||||
|
||||
/**
|
||||
* 递归检查并同步目标对象与模板对象的键值结构
|
||||
* 1. 如果目标对象缺少模板对象中的键,抛出错误
|
||||
* 2. 如果目标对象存在模板对象中不存在的键,抛出错误
|
||||
* 3. 对于嵌套对象,递归执行同步操作
|
||||
* Recursively check and synchronize the key-value structure of target object with template object
|
||||
* 1. If target object is missing keys from template object, throw error
|
||||
* 2. If target object has keys that don't exist in template object, throw error
|
||||
* 3. For nested objects, recursively perform synchronization operation
|
||||
*
|
||||
* 该函数用于确保所有翻译文件与基准模板(通常是中文翻译文件)保持完全一致的键值结构。
|
||||
* 任何结构上的差异都会导致错误被抛出,以便及时发现和修复翻译文件中的问题。
|
||||
* This function ensures all translation files maintain completely consistent key-value structure
|
||||
* with the base template (usually the base translation file).
|
||||
* Any structural differences will cause errors to be thrown for timely detection and fixing
|
||||
* of translation file issues.
|
||||
*
|
||||
* @param target 需要检查的目标翻译对象
|
||||
* @param template 作为基准的模板对象(通常是中文翻译文件)
|
||||
* @throws {Error} 当发现键值结构不匹配时抛出错误
|
||||
* @param target The target translation object to check
|
||||
* @param template The template object used as base (usually the base translation file)
|
||||
* @throws {Error} Thrown when key-value structure mismatch is found
|
||||
*/
|
||||
function checkRecursively(target: I18N, template: I18N): void {
|
||||
for (const key in template) {
|
||||
if (!(key in target)) {
|
||||
throw new Error(`缺少属性 ${key}`)
|
||||
throw new Error(`Missing property ${key}`)
|
||||
}
|
||||
if (key.includes('.')) {
|
||||
throw new Error(`应该使用严格嵌套结构 ${key}`)
|
||||
throw new Error(`Should use strict nested structure for key ${key}`)
|
||||
}
|
||||
if (typeof template[key] === 'object' && template[key] !== null) {
|
||||
if (typeof target[key] !== 'object' || target[key] === null) {
|
||||
throw new Error(`属性 ${key} 不是对象`)
|
||||
throw new Error(`Property ${key} is not an object`)
|
||||
}
|
||||
// 递归检查子对象
|
||||
// Recursively check child objects
|
||||
checkRecursively(target[key], template[key])
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 target 中存在但 template 中没有的 key
|
||||
// Remove keys that exist in target but not in template
|
||||
for (const targetKey in target) {
|
||||
if (!(targetKey in template)) {
|
||||
throw new Error(`多余属性 ${targetKey}`)
|
||||
throw new Error(`Extra property ${targetKey}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,9 +58,9 @@ function isSortedI18N(obj: I18N): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 JSON 对象中是否存在重复键,并收集所有重复键
|
||||
* @param obj 要检查的对象
|
||||
* @returns 返回重复键的数组(若无重复则返回空数组)
|
||||
* Check for duplicate keys in JSON object and collect all duplicate keys
|
||||
* @param obj The object to check
|
||||
* @returns Array of duplicate keys (returns empty array if no duplicates)
|
||||
*/
|
||||
function checkDuplicateKeys(obj: I18N): string[] {
|
||||
const keys = new Set<string>()
|
||||
@ -69,7 +71,7 @@ function checkDuplicateKeys(obj: I18N): string[] {
|
||||
const fullPath = path ? `${path}.${key}` : key
|
||||
|
||||
if (keys.has(fullPath)) {
|
||||
// 发现重复键时,添加到数组中(避免重复添加)
|
||||
// When duplicate key is found, add to array (avoid duplicate additions)
|
||||
if (!duplicateKeys.includes(fullPath)) {
|
||||
duplicateKeys.push(fullPath)
|
||||
}
|
||||
@ -77,7 +79,7 @@ function checkDuplicateKeys(obj: I18N): string[] {
|
||||
keys.add(fullPath)
|
||||
}
|
||||
|
||||
// 递归检查子对象
|
||||
// Recursively check child objects
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
checkObject(obj[key], fullPath)
|
||||
}
|
||||
@ -90,7 +92,7 @@ function checkDuplicateKeys(obj: I18N): string[] {
|
||||
|
||||
function checkTranslations() {
|
||||
if (!fs.existsSync(baseFilePath)) {
|
||||
throw new Error(`主模板文件 ${baseFileName} 不存在,请检查路径或文件名`)
|
||||
throw new Error(`Base template file ${baseFileName} does not exist, please check path or filename`)
|
||||
}
|
||||
|
||||
const baseContent = fs.readFileSync(baseFilePath, 'utf-8')
|
||||
@ -98,23 +100,23 @@ function checkTranslations() {
|
||||
try {
|
||||
baseJson = JSON.parse(baseContent)
|
||||
} catch (error) {
|
||||
throw new Error(`解析 ${baseFileName} 出错。${error}`)
|
||||
throw new Error(`Error parsing ${baseFileName}. ${error}`)
|
||||
}
|
||||
|
||||
// 检查主模板是否存在重复键
|
||||
// Check if base template has duplicate keys
|
||||
const duplicateKeys = checkDuplicateKeys(baseJson)
|
||||
if (duplicateKeys.length > 0) {
|
||||
throw new Error(`主模板文件 ${baseFileName} 存在以下重复键:\n${duplicateKeys.join('\n')}`)
|
||||
throw new Error(`Base template file ${baseFileName} has the following duplicate keys:\n${duplicateKeys.join('\n')}`)
|
||||
}
|
||||
|
||||
// 检查主模板是否有序
|
||||
// Check if base template is sorted
|
||||
if (!isSortedI18N(baseJson)) {
|
||||
throw new Error(`主模板文件 ${baseFileName} 的键值未按字典序排序。`)
|
||||
throw new Error(`Base template file ${baseFileName} keys are not sorted in dictionary order.`)
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(translationsDir).filter((file) => file.endsWith('.json') && file !== baseFileName)
|
||||
|
||||
// 同步键
|
||||
// Sync keys
|
||||
for (const file of files) {
|
||||
const filePath = path.join(translationsDir, file)
|
||||
let targetJson: I18N = {}
|
||||
@ -122,19 +124,19 @@ function checkTranslations() {
|
||||
const fileContent = fs.readFileSync(filePath, 'utf-8')
|
||||
targetJson = JSON.parse(fileContent)
|
||||
} catch (error) {
|
||||
throw new Error(`解析 ${file} 出错。`)
|
||||
throw new Error(`Error parsing ${file}.`)
|
||||
}
|
||||
|
||||
// 检查有序性
|
||||
// Check if sorted
|
||||
if (!isSortedI18N(targetJson)) {
|
||||
throw new Error(`翻译文件 ${file} 的键值未按字典序排序。`)
|
||||
throw new Error(`Translation file ${file} keys are not sorted.`)
|
||||
}
|
||||
|
||||
try {
|
||||
checkRecursively(targetJson, baseJson)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw new Error(`在检查 ${filePath} 时出错`)
|
||||
throw new Error(`Error while checking ${filePath}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,10 +144,10 @@ function checkTranslations() {
|
||||
export function main() {
|
||||
try {
|
||||
checkTranslations()
|
||||
console.log('i18n 检查已通过')
|
||||
console.log('i18n check passed')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw new Error(`检查未通过。尝试运行 yarn sync:i18n 以解决问题。`)
|
||||
throw new Error(`Check failed. Try running yarn i18n:sync to fix the issue.`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user