diff --git a/.prettierrc b/.prettierrc index 83433021c..85e2eb0ca 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,11 @@ { - "singleQuote": true, - "semi": false, - "printWidth": 120, - "trailingComma": "none", + "bracketSameLine": true, "endOfLine": "lf", - "bracketSameLine": true + "jsonRecursiveSort": true, + "jsonSortOrder": "{\"*\": \"lexical\"}", + "plugins": ["prettier-plugin-sort-json"], + "printWidth": 120, + "semi": false, + "singleQuote": true, + "trailingComma": "none" } diff --git a/package.json b/package.json index a5ea70f0a..c13a65a08 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", "check:i18n": "node scripts/check-i18n.js", + "sync:i18n": "node scripts/sync-i18n.js", "test": "vitest run --silent", "test:main": "vitest run --project main", "test:renderer": "vitest run --project renderer", @@ -53,6 +54,7 @@ "test:watch": "vitest", "test:e2e": "yarn playwright test", "test:lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts", + "test:scripts": "vitest scripts", "format": "prettier --write .", "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix", "prepare": "git config blame.ignoreRevsFile .git-blame-ignore-revs && husky" @@ -198,6 +200,7 @@ "p-queue": "^8.1.0", "playwright": "^1.52.0", "prettier": "^3.5.3", + "prettier-plugin-sort-json": "^4.1.1", "proxy-agent": "^6.5.0", "rc-virtual-list": "^3.18.6", "react": "^19.0.0", diff --git a/scripts/__tests__/sort.test.ts b/scripts/__tests__/sort.test.ts new file mode 100644 index 000000000..0efc5fe41 --- /dev/null +++ b/scripts/__tests__/sort.test.ts @@ -0,0 +1,92 @@ +import { sortedObjectByKeys } from '../sort' + +describe('sortedObjectByKeys', () => { + test('should sort keys of a flat object alphabetically', () => { + const obj = { b: 2, a: 1, c: 3 } + const sortedObj = { a: 1, b: 2, c: 3 } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) + + test('should sort keys of nested objects alphabetically', () => { + const obj = { + c: { z: 3, y: 2, x: 1 }, + a: 1, + b: { f: 6, d: 4, e: 5 } + } + const sortedObj = { + a: 1, + b: { d: 4, e: 5, f: 6 }, + c: { x: 1, y: 2, z: 3 } + } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) + + test('should handle empty objects', () => { + const obj = {} + expect(sortedObjectByKeys(obj)).toEqual({}) + }) + + test('should handle objects with non-object values', () => { + const obj = { b: 'hello', a: 123, c: true } + const sortedObj = { a: 123, b: 'hello', c: true } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) + + test('should handle objects with array values', () => { + const obj = { b: [2, 1], a: [1, 2] } + const sortedObj = { a: [1, 2], b: [2, 1] } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) + + test('should handle objects with null values', () => { + const obj = { b: null, a: 1 } + const sortedObj = { a: 1, b: null } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) + + test('should handle objects with undefined values', () => { + const obj = { b: undefined, a: 1 } + const sortedObj = { a: 1, b: undefined } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) + + test('should not modify the original object', () => { + const obj = { b: 2, a: 1 } + sortedObjectByKeys(obj) + expect(obj).toEqual({ b: 2, a: 1 }) + }) + + test('should handle objects read from i18n JSON files', () => { + const obj = { + translation: { + backup: { + progress: { + writing_data: '写入数据...', + preparing: '准备备份...', + completed: '备份完成' + } + }, + agents: { + 'delete.popup.content': '确定要删除此智能体吗?', + 'edit.model.select.title': '选择模型' + } + } + } + const sortedObj = { + translation: { + agents: { + 'delete.popup.content': '确定要删除此智能体吗?', + 'edit.model.select.title': '选择模型' + }, + backup: { + progress: { + completed: '备份完成', + preparing: '准备备份...', + writing_data: '写入数据...' + } + } + } + } + expect(sortedObjectByKeys(obj)).toEqual(sortedObj) + }) +}) diff --git a/scripts/check-i18n.js b/scripts/check-i18n.js index 9c99fc9ae..3d873cabe 100644 --- a/scripts/check-i18n.js +++ b/scripts/check-i18n.js @@ -1,103 +1,50 @@ 'use strict' -var __createBinding = - (this && this.__createBinding) || - (Object.create - ? function (o, m, k, k2) { - if (k2 === undefined) k2 = k - var desc = Object.getOwnPropertyDescriptor(m, k) - if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { - enumerable: true, - get: function () { - return m[k] - } - } - } - Object.defineProperty(o, k2, desc) - } - : function (o, m, k, k2) { - if (k2 === undefined) k2 = k - o[k2] = m[k] - }) -var __setModuleDefault = - (this && this.__setModuleDefault) || - (Object.create - ? function (o, v) { - Object.defineProperty(o, 'default', { enumerable: true, value: v }) - } - : function (o, v) { - o['default'] = v - }) -var __importStar = - (this && this.__importStar) || - (function () { - var ownKeys = function (o) { - ownKeys = - Object.getOwnPropertyNames || - function (o) { - var ar = [] - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k - return ar - } - return ownKeys(o) - } - return function (mod) { - if (mod && mod.__esModule) return mod - var result = {} - if (mod != null) - for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== 'default') __createBinding(result, mod, k[i]) - __setModuleDefault(result, mod) - return result - } - })() Object.defineProperty(exports, '__esModule', { value: true }) -var fs = __importStar(require('fs')) -var path = __importStar(require('path')) +exports.main = main +var fs = require('fs') +var path = require('path') +var sort_1 = require('./sort') var translationsDir = path.join(__dirname, '../src/renderer/src/i18n/locales') var baseLocale = 'zh-cn' var baseFileName = ''.concat(baseLocale, '.json') var baseFilePath = path.join(translationsDir, baseFileName) /** - * 递归同步 target 对象,使其与 template 对象保持一致 - * 1. 如果 template 中存在 target 中缺少的 key,则添加('[to be translated]') - * 2. 如果 target 中存在 template 中不存在的 key,则删除 - * 3. 对于子对象,递归同步 + * 递归检查并同步目标对象与模板对象的键值结构 + * 1. 如果目标对象缺少模板对象中的键,抛出错误 + * 2. 如果目标对象存在模板对象中不存在的键,抛出错误 + * 3. 对于嵌套对象,递归执行同步操作 * - * @param target 目标对象(需要更新的语言对象) - * @param template 主模板对象(中文) - * @returns 返回是否对 target 进行了更新 + * 该函数用于确保所有翻译文件与基准模板(通常是中文翻译文件)保持完全一致的键值结构。 + * 任何结构上的差异都会导致错误被抛出,以便及时发现和修复翻译文件中的问题。 + * + * @param target 需要检查的目标翻译对象 + * @param template 作为基准的模板对象(通常是中文翻译文件) + * @throws {Error} 当发现键值结构不匹配时抛出错误 */ -function syncRecursively(target, template) { - var isUpdated = false - // 添加 template 中存在但 target 中缺少的 key +function checkRecursively(target, template) { for (var key in template) { if (!(key in target)) { - target[key] = - typeof template[key] === 'object' && template[key] !== null ? {} : '[to be translated]:'.concat(template[key]) - console.log('\u6DFB\u52A0\u65B0\u5C5E\u6027\uFF1A'.concat(key)) - isUpdated = true + throw new Error('\u7F3A\u5C11\u5C5E\u6027 '.concat(key)) } if (typeof template[key] === 'object' && template[key] !== null) { if (typeof target[key] !== 'object' || target[key] === null) { - target[key] = {} - isUpdated = true - } - // 递归同步子对象 - var childUpdated = syncRecursively(target[key], template[key]) - if (childUpdated) { - isUpdated = true + throw new Error('\u5C5E\u6027 '.concat(key, ' \u4E0D\u662F\u5BF9\u8C61')) } + // 递归检查子对象 + checkRecursively(target[key], template[key]) } } // 删除 target 中存在但 template 中没有的 key for (var targetKey in target) { if (!(targetKey in template)) { - console.log('\u79FB\u9664\u591A\u4F59\u5C5E\u6027\uFF1A'.concat(targetKey)) - delete target[targetKey] - isUpdated = true + throw new Error('\u591A\u4F59\u5C5E\u6027 '.concat(targetKey)) } } - return isUpdated +} +function isSortedI18N(obj) { + // fs.writeFileSync('./test_origin.json', JSON.stringify(obj)) + // fs.writeFileSync('./test_sorted.json', JSON.stringify(sortedObjectByKeys(obj))) + return JSON.stringify(obj) === JSON.stringify((0, sort_1.sortedObjectByKeys)(obj)) } /** * 检查 JSON 对象中是否存在重复键,并收集所有重复键 @@ -130,23 +77,21 @@ function checkDuplicateKeys(obj) { checkObject(obj) return duplicateKeys } -function syncTranslations() { +function checkTranslations() { if (!fs.existsSync(baseFilePath)) { - console.error( + throw new Error( '\u4E3B\u6A21\u677F\u6587\u4EF6 '.concat( baseFileName, ' \u4E0D\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u6216\u6587\u4EF6\u540D' ) ) - return } var baseContent = fs.readFileSync(baseFilePath, 'utf-8') var baseJson = {} try { baseJson = JSON.parse(baseContent) } catch (error) { - console.error('\u89E3\u6790 '.concat(baseFileName, ' \u51FA\u9519\u3002').concat(error)) - return + throw new Error('\u89E3\u6790 '.concat(baseFileName, ' \u51FA\u9519\u3002').concat(error)) } // 检查主模板是否存在重复键 var duplicateKeys = checkDuplicateKeys(baseJson) @@ -157,9 +102,19 @@ function syncTranslations() { .concat(duplicateKeys.join('\n')) ) } + // 检查主模板是否有序 + if (!isSortedI18N(baseJson)) { + throw new Error( + '\u4E3B\u6A21\u677F\u6587\u4EF6 '.concat( + baseFileName, + ' \u7684\u952E\u503C\u672A\u6309\u5B57\u5178\u5E8F\u6392\u5E8F\u3002' + ) + ) + } var files = fs.readdirSync(translationsDir).filter(function (file) { return file.endsWith('.json') && file !== baseFileName }) + // 同步键 for (var _i = 0, files_1 = files; _i < files_1.length; _i++) { var file = files_1[_i] var filePath = path.join(translationsDir, file) @@ -168,20 +123,29 @@ function syncTranslations() { var fileContent = fs.readFileSync(filePath, 'utf-8') targetJson = JSON.parse(fileContent) } catch (error) { - console.error('\u89E3\u6790 '.concat(file, ' \u51FA\u9519\uFF0C\u8DF3\u8FC7\u6B64\u6587\u4EF6\u3002'), error) - continue + throw new Error('\u89E3\u6790 '.concat(file, ' \u51FA\u9519\u3002')) } - var isUpdated = syncRecursively(targetJson, baseJson) - if (isUpdated) { - try { - fs.writeFileSync(filePath, JSON.stringify(targetJson, null, 2) + '\n', 'utf-8') - console.log('\u6587\u4EF6 '.concat(file, ' \u5DF2\u66F4\u65B0\u540C\u6B65\u4E3B\u6A21\u677F\u7684\u5185\u5BB9')) - } catch (error) { - console.error('\u5199\u5165 '.concat(file, ' \u51FA\u9519\u3002').concat(error)) - } - } else { - console.log('\u6587\u4EF6 '.concat(file, ' \u65E0\u9700\u66F4\u65B0')) + // 检查有序性 + if (!isSortedI18N(targetJson)) { + throw new Error( + '\u7FFB\u8BD1\u6587\u4EF6 '.concat(file, ' \u7684\u952E\u503C\u672A\u6309\u5B57\u5178\u5E8F\u6392\u5E8F\u3002') + ) + } + try { + checkRecursively(targetJson, baseJson) + } catch (e) { + throw new Error('\u5728\u68C0\u67E5 '.concat(filePath, ' \u65F6\u51FA\u9519\uFF1A').concat(e)) } } } -syncTranslations() +function main() { + try { + checkTranslations() + } catch (e) { + console.error(e) + throw new Error( + '\u68C0\u67E5\u672A\u901A\u8FC7\u3002\u5C1D\u8BD5\u8FD0\u884C yarn sync:i18n \u4EE5\u89E3\u51B3\u95EE\u9898\u3002' + ) + } +} +main() diff --git a/scripts/check-i18n.ts b/scripts/check-i18n.ts index 238b3ca99..d655b49de 100644 --- a/scripts/check-i18n.ts +++ b/scripts/check-i18n.ts @@ -1,55 +1,55 @@ import * as fs from 'fs' import * as path from 'path' +import { sortedObjectByKeys } from './sort' + const translationsDir = path.join(__dirname, '../src/renderer/src/i18n/locales') const baseLocale = 'zh-cn' const baseFileName = `${baseLocale}.json` const baseFilePath = path.join(translationsDir, baseFileName) -/** - * 递归同步 target 对象,使其与 template 对象保持一致 - * 1. 如果 template 中存在 target 中缺少的 key,则添加('[to be translated]') - * 2. 如果 target 中存在 template 中不存在的 key,则删除 - * 3. 对于子对象,递归同步 - * - * @param target 目标对象(需要更新的语言对象) - * @param template 主模板对象(中文) - * @returns 返回是否对 target 进行了更新 - */ -function syncRecursively(target: any, template: any): boolean { - let isUpdated = false +type I18NValue = string | { [key: string]: I18NValue } +type I18N = { [key: string]: I18NValue } - // 添加 template 中存在但 target 中缺少的 key +/** + * 递归检查并同步目标对象与模板对象的键值结构 + * 1. 如果目标对象缺少模板对象中的键,抛出错误 + * 2. 如果目标对象存在模板对象中不存在的键,抛出错误 + * 3. 对于嵌套对象,递归执行同步操作 + * + * 该函数用于确保所有翻译文件与基准模板(通常是中文翻译文件)保持完全一致的键值结构。 + * 任何结构上的差异都会导致错误被抛出,以便及时发现和修复翻译文件中的问题。 + * + * @param target 需要检查的目标翻译对象 + * @param template 作为基准的模板对象(通常是中文翻译文件) + * @throws {Error} 当发现键值结构不匹配时抛出错误 + */ +function checkRecursively(target: I18N, template: I18N): void { for (const key in template) { if (!(key in target)) { - target[key] = - typeof template[key] === 'object' && template[key] !== null ? {} : `[to be translated]:${template[key]}` - console.log(`添加新属性:${key}`) - isUpdated = true + throw new Error(`缺少属性 ${key}`) } if (typeof template[key] === 'object' && template[key] !== null) { if (typeof target[key] !== 'object' || target[key] === null) { - target[key] = {} - isUpdated = true - } - // 递归同步子对象 - const childUpdated = syncRecursively(target[key], template[key]) - if (childUpdated) { - isUpdated = true + throw new Error(`属性 ${key} 不是对象`) } + // 递归检查子对象 + checkRecursively(target[key], template[key]) } } // 删除 target 中存在但 template 中没有的 key for (const targetKey in target) { if (!(targetKey in template)) { - console.log(`移除多余属性:${targetKey}`) - delete target[targetKey] - isUpdated = true + throw new Error(`多余属性 ${targetKey}`) } } +} - return isUpdated +function isSortedI18N(obj: I18N): boolean { + // fs.writeFileSync('./test_origin.json', JSON.stringify(obj)) + // fs.writeFileSync('./test_sorted.json', JSON.stringify(sortedObjectByKeys(obj))) + return JSON.stringify(obj) === JSON.stringify(sortedObjectByKeys(obj)) } /** @@ -57,11 +57,11 @@ function syncRecursively(target: any, template: any): boolean { * @param obj 要检查的对象 * @returns 返回重复键的数组(若无重复则返回空数组) */ -function checkDuplicateKeys(obj: Record): string[] { +function checkDuplicateKeys(obj: I18N): string[] { const keys = new Set() const duplicateKeys: string[] = [] - const checkObject = (obj: Record, path: string = '') => { + const checkObject = (obj: I18N, path: string = '') => { for (const key in obj) { const fullPath = path ? `${path}.${key}` : key @@ -85,19 +85,17 @@ function checkDuplicateKeys(obj: Record): string[] { return duplicateKeys } -function syncTranslations() { +function checkTranslations() { if (!fs.existsSync(baseFilePath)) { - console.error(`主模板文件 ${baseFileName} 不存在,请检查路径或文件名`) - return + throw new Error(`主模板文件 ${baseFileName} 不存在,请检查路径或文件名`) } const baseContent = fs.readFileSync(baseFilePath, 'utf-8') - let baseJson: Record = {} + let baseJson: I18N = {} try { baseJson = JSON.parse(baseContent) } catch (error) { - console.error(`解析 ${baseFileName} 出错。${error}`) - return + throw new Error(`解析 ${baseFileName} 出错。${error}`) } // 检查主模板是否存在重复键 @@ -106,32 +104,44 @@ function syncTranslations() { throw new Error(`主模板文件 ${baseFileName} 存在以下重复键:\n${duplicateKeys.join('\n')}`) } + // 检查主模板是否有序 + if (!isSortedI18N(baseJson)) { + throw new Error(`主模板文件 ${baseFileName} 的键值未按字典序排序。`) + } + const files = fs.readdirSync(translationsDir).filter((file) => file.endsWith('.json') && file !== baseFileName) + // 同步键 for (const file of files) { const filePath = path.join(translationsDir, file) - let targetJson: Record = {} + let targetJson: I18N = {} try { const fileContent = fs.readFileSync(filePath, 'utf-8') targetJson = JSON.parse(fileContent) } catch (error) { - console.error(`解析 ${file} 出错,跳过此文件。`, error) - continue + throw new Error(`解析 ${file} 出错。`) } - const isUpdated = syncRecursively(targetJson, baseJson) + // 检查有序性 + if (!isSortedI18N(targetJson)) { + throw new Error(`翻译文件 ${file} 的键值未按字典序排序。`) + } - if (isUpdated) { - try { - fs.writeFileSync(filePath, JSON.stringify(targetJson, null, 2) + '\n', 'utf-8') - console.log(`文件 ${file} 已更新同步主模板的内容`) - } catch (error) { - console.error(`写入 ${file} 出错。${error}`) - } - } else { - console.log(`文件 ${file} 无需更新`) + try { + checkRecursively(targetJson, baseJson) + } catch (e) { + throw new Error(`在检查 ${filePath} 时出错:${e}`) } } } -syncTranslations() +export function main() { + try { + checkTranslations() + } catch (e) { + console.error(e) + throw new Error(`检查未通过。尝试运行 yarn sync:i18n 以解决问题。`) + } +} + +main() diff --git a/scripts/sort.js b/scripts/sort.js new file mode 100644 index 000000000..05425853f --- /dev/null +++ b/scripts/sort.js @@ -0,0 +1,40 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +exports.sortedObjectByKeys = sortedObjectByKeys +// https://github.com/Gudahtt/prettier-plugin-sort-json/blob/main/src/index.ts +/** + * Lexical sort function for strings, meant to be used as the sort + * function for `Array.prototype.sort`. + * + * @param a - First element to compare. + * @param b - Second element to compare. + * @returns A number indicating which element should come first. + */ +function lexicalSort(a, b) { + if (a > b) { + return 1 + } + if (a < b) { + return -1 + } + return 0 +} +/** + * 对对象的键按照字典序进行排序(支持嵌套对象) + * @param obj 需要排序的对象 + * @returns 返回排序后的新对象 + */ +function sortedObjectByKeys(obj) { + var sortedKeys = Object.keys(obj).sort(lexicalSort) + var sortedObj = {} + for (var _i = 0, sortedKeys_1 = sortedKeys; _i < sortedKeys_1.length; _i++) { + var key = sortedKeys_1[_i] + var value = obj[key] + // 如果值是对象,递归排序 + if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + value = sortedObjectByKeys(value) + } + sortedObj[key] = value + } + return sortedObj +} diff --git a/scripts/sort.ts b/scripts/sort.ts new file mode 100644 index 000000000..adc1fd52b --- /dev/null +++ b/scripts/sort.ts @@ -0,0 +1,39 @@ +// https://github.com/Gudahtt/prettier-plugin-sort-json/blob/main/src/index.ts +/** + * Lexical sort function for strings, meant to be used as the sort + * function for `Array.prototype.sort`. + * + * @param a - First element to compare. + * @param b - Second element to compare. + * @returns A number indicating which element should come first. + */ +function lexicalSort(a: string, b: string): number { + if (a > b) { + return 1 + } + if (a < b) { + return -1 + } + return 0 +} + +/** + * 对对象的键按照字典序进行排序(支持嵌套对象) + * @param obj 需要排序的对象 + * @returns 返回排序后的新对象 + */ +export function sortedObjectByKeys(obj: object): object { + const sortedKeys = Object.keys(obj).sort(lexicalSort) + + const sortedObj = {} + for (const key of sortedKeys) { + let value = obj[key] + // 如果值是对象,递归排序 + if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + value = sortedObjectByKeys(value) + } + sortedObj[key] = value + } + + return sortedObj +} diff --git a/scripts/sync-i18n.js b/scripts/sync-i18n.js new file mode 100644 index 000000000..3f80ba8f5 --- /dev/null +++ b/scripts/sync-i18n.js @@ -0,0 +1,143 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +var fs = require('fs') +var path = require('path') +var sort_1 = require('./sort') +var translationsDir = path.join(__dirname, '../src/renderer/src/i18n/locales') +var baseLocale = 'zh-cn' +var baseFileName = ''.concat(baseLocale, '.json') +var baseFilePath = path.join(translationsDir, baseFileName) +/** + * 递归同步 target 对象,使其与 template 对象保持一致 + * 1. 如果 template 中存在 target 中缺少的 key,则添加('[to be translated]') + * 2. 如果 target 中存在 template 中不存在的 key,则删除 + * 3. 对于子对象,递归同步 + * + * @param target 目标对象(需要更新的语言对象) + * @param template 主模板对象(中文) + * @returns 返回是否对 target 进行了更新 + */ +function syncRecursively(target, template) { + // 添加 template 中存在但 target 中缺少的 key + for (var key in template) { + if (!(key in target)) { + target[key] = + typeof template[key] === 'object' && template[key] !== null ? {} : '[to be translated]:'.concat(template[key]) + console.log('\u6DFB\u52A0\u65B0\u5C5E\u6027\uFF1A'.concat(key)) + } + if (typeof template[key] === 'object' && template[key] !== null) { + if (typeof target[key] !== 'object' || target[key] === null) { + target[key] = {} + } + // 递归同步子对象 + syncRecursively(target[key], template[key]) + } + } + // 删除 target 中存在但 template 中没有的 key + for (var targetKey in target) { + if (!(targetKey in template)) { + console.log('\u79FB\u9664\u591A\u4F59\u5C5E\u6027\uFF1A'.concat(targetKey)) + delete target[targetKey] + } + } +} +/** + * 检查 JSON 对象中是否存在重复键,并收集所有重复键 + * @param obj 要检查的对象 + * @returns 返回重复键的数组(若无重复则返回空数组) + */ +function checkDuplicateKeys(obj) { + var keys = new Set() + var duplicateKeys = [] + var checkObject = function (obj, path) { + if (path === void 0) { + path = '' + } + for (var key in obj) { + var fullPath = path ? ''.concat(path, '.').concat(key) : key + if (keys.has(fullPath)) { + // 发现重复键时,添加到数组中(避免重复添加) + if (!duplicateKeys.includes(fullPath)) { + duplicateKeys.push(fullPath) + } + } else { + keys.add(fullPath) + } + // 递归检查子对象 + if (typeof obj[key] === 'object' && obj[key] !== null) { + checkObject(obj[key], fullPath) + } + } + } + checkObject(obj) + return duplicateKeys +} +function syncTranslations() { + if (!fs.existsSync(baseFilePath)) { + console.error( + '\u4E3B\u6A21\u677F\u6587\u4EF6 '.concat( + baseFileName, + ' \u4E0D\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u6216\u6587\u4EF6\u540D' + ) + ) + return + } + var baseContent = fs.readFileSync(baseFilePath, 'utf-8') + var baseJson = {} + try { + baseJson = JSON.parse(baseContent) + } catch (error) { + console.error('\u89E3\u6790 '.concat(baseFileName, ' \u51FA\u9519\u3002').concat(error)) + return + } + // 检查主模板是否存在重复键 + var duplicateKeys = checkDuplicateKeys(baseJson) + if (duplicateKeys.length > 0) { + throw new Error( + '\u4E3B\u6A21\u677F\u6587\u4EF6 ' + .concat(baseFileName, ' \u5B58\u5728\u4EE5\u4E0B\u91CD\u590D\u952E\uFF1A\n') + .concat(duplicateKeys.join('\n')) + ) + } + // 为主模板排序 + var sortedJson = (0, sort_1.sortedObjectByKeys)(baseJson) + if (JSON.stringify(baseJson) !== JSON.stringify(sortedJson)) { + try { + fs.writeFileSync(baseFilePath, JSON.stringify(sortedJson, null, 2) + '\n', 'utf-8') + console.log('\u4E3B\u6A21\u677F\u5DF2\u6392\u5E8F') + } catch (error) { + console.error('\u5199\u5165 '.concat(baseFilePath, ' \u51FA\u9519\u3002'), error) + return + } + } + var files = fs.readdirSync(translationsDir).filter(function (file) { + return file.endsWith('.json') && file !== baseFileName + }) + // 同步键 + for (var _i = 0, files_1 = files; _i < files_1.length; _i++) { + var file = files_1[_i] + var filePath = path.join(translationsDir, file) + var targetJson = {} + try { + var fileContent = fs.readFileSync(filePath, 'utf-8') + targetJson = JSON.parse(fileContent) + } catch (error) { + console.error('\u89E3\u6790 '.concat(file, ' \u51FA\u9519\uFF0C\u8DF3\u8FC7\u6B64\u6587\u4EF6\u3002'), error) + continue + } + syncRecursively(targetJson, baseJson) + var sortedJson_1 = (0, sort_1.sortedObjectByKeys)(targetJson) + try { + fs.writeFileSync(filePath, JSON.stringify(sortedJson_1, null, 2) + '\n', 'utf-8') + console.log( + '\u6587\u4EF6 '.concat( + file, + ' \u5DF2\u6392\u5E8F\u5E76\u540C\u6B65\u66F4\u65B0\u4E3A\u4E3B\u6A21\u677F\u7684\u5185\u5BB9' + ) + ) + } catch (error) { + console.error('\u5199\u5165 '.concat(file, ' \u51FA\u9519\u3002').concat(error)) + } + } +} +syncTranslations() diff --git a/scripts/sync-i18n.ts b/scripts/sync-i18n.ts new file mode 100644 index 000000000..eadeb7fd9 --- /dev/null +++ b/scripts/sync-i18n.ts @@ -0,0 +1,143 @@ +import * as fs from 'fs' +import * as path from 'path' + +import { sortedObjectByKeys } from './sort' + +const translationsDir = path.join(__dirname, '../src/renderer/src/i18n/locales') +const baseLocale = 'zh-cn' +const baseFileName = `${baseLocale}.json` +const baseFilePath = path.join(translationsDir, baseFileName) + +type I18NValue = string | { [key: string]: I18NValue } +type I18N = { [key: string]: I18NValue } + +/** + * 递归同步 target 对象,使其与 template 对象保持一致 + * 1. 如果 template 中存在 target 中缺少的 key,则添加('[to be translated]') + * 2. 如果 target 中存在 template 中不存在的 key,则删除 + * 3. 对于子对象,递归同步 + * + * @param target 目标对象(需要更新的语言对象) + * @param template 主模板对象(中文) + * @returns 返回是否对 target 进行了更新 + */ +function syncRecursively(target: I18N, template: I18N): void { + // 添加 template 中存在但 target 中缺少的 key + for (const key in template) { + if (!(key in target)) { + target[key] = + typeof template[key] === 'object' && template[key] !== null ? {} : `[to be translated]:${template[key]}` + console.log(`添加新属性:${key}`) + } + if (typeof template[key] === 'object' && template[key] !== null) { + if (typeof target[key] !== 'object' || target[key] === null) { + target[key] = {} + } + // 递归同步子对象 + syncRecursively(target[key], template[key]) + } + } + + // 删除 target 中存在但 template 中没有的 key + for (const targetKey in target) { + if (!(targetKey in template)) { + console.log(`移除多余属性:${targetKey}`) + delete target[targetKey] + } + } +} + +/** + * 检查 JSON 对象中是否存在重复键,并收集所有重复键 + * @param obj 要检查的对象 + * @returns 返回重复键的数组(若无重复则返回空数组) + */ +function checkDuplicateKeys(obj: I18N): string[] { + const keys = new Set() + const duplicateKeys: string[] = [] + + const checkObject = (obj: I18N, path: string = '') => { + for (const key in obj) { + const fullPath = path ? `${path}.${key}` : key + + if (keys.has(fullPath)) { + // 发现重复键时,添加到数组中(避免重复添加) + if (!duplicateKeys.includes(fullPath)) { + duplicateKeys.push(fullPath) + } + } else { + keys.add(fullPath) + } + + // 递归检查子对象 + if (typeof obj[key] === 'object' && obj[key] !== null) { + checkObject(obj[key], fullPath) + } + } + } + + checkObject(obj) + return duplicateKeys +} + +function syncTranslations() { + if (!fs.existsSync(baseFilePath)) { + console.error(`主模板文件 ${baseFileName} 不存在,请检查路径或文件名`) + return + } + + const baseContent = fs.readFileSync(baseFilePath, 'utf-8') + let baseJson: I18N = {} + try { + baseJson = JSON.parse(baseContent) + } catch (error) { + console.error(`解析 ${baseFileName} 出错。${error}`) + return + } + + // 检查主模板是否存在重复键 + const duplicateKeys = checkDuplicateKeys(baseJson) + if (duplicateKeys.length > 0) { + throw new Error(`主模板文件 ${baseFileName} 存在以下重复键:\n${duplicateKeys.join('\n')}`) + } + + // 为主模板排序 + const sortedJson = sortedObjectByKeys(baseJson) + if (JSON.stringify(baseJson) !== JSON.stringify(sortedJson)) { + try { + fs.writeFileSync(baseFilePath, JSON.stringify(sortedJson, null, 2) + '\n', 'utf-8') + console.log(`主模板已排序`) + } catch (error) { + console.error(`写入 ${baseFilePath} 出错。`, error) + return + } + } + + const files = fs.readdirSync(translationsDir).filter((file) => file.endsWith('.json') && file !== baseFileName) + + // 同步键 + for (const file of files) { + const filePath = path.join(translationsDir, file) + let targetJson: I18N = {} + try { + const fileContent = fs.readFileSync(filePath, 'utf-8') + targetJson = JSON.parse(fileContent) + } catch (error) { + console.error(`解析 ${file} 出错,跳过此文件。`, error) + continue + } + + syncRecursively(targetJson, baseJson) + + const sortedJson = sortedObjectByKeys(targetJson) + + try { + fs.writeFileSync(filePath, JSON.stringify(sortedJson, null, 2) + '\n', 'utf-8') + console.log(`文件 ${file} 已排序并同步更新为主模板的内容`) + } catch (error) { + console.error(`写入 ${file} 出错。${error}`) + } + } +} + +syncTranslations() diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 6f9861eb9..1f47f9172 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -204,6 +204,7 @@ "input.upload": "Upload image or document file", "input.upload.document": "Upload document file (model does not support images)", "input.upload.upload_from_local": "Upload local file...", + "input.url_context": "URL Context", "input.web_search": "Web Search", "input.web_search.builtin": "Model Built-in", "input.web_search.builtin.disabled_content": "The current model does not support web search", @@ -211,7 +212,6 @@ "input.web_search.button.ok": "Go to Settings", "input.web_search.enable": "Enable web search", "input.web_search.enable_content": "Need to check web search connectivity in settings first", - "input.url_context": "URL Context", "input.web_search.no_web_search": "Disable Web Search", "input.web_search.no_web_search.description": "Do not enable web search", "input.web_search.settings": "Web Search Settings", @@ -237,32 +237,32 @@ "save": "Save", "save.file.title": "Save to Local File", "save.knowledge": { - "title": "Save to Knowledge Base", - "content.maintext.title": "Main Text", - "content.maintext.description": "Includes primary text content", - "content.code.title": "Code Blocks", - "content.code.description": "Includes standalone code blocks", - "content.thinking.title": "Reasoning", - "content.thinking.description": "Includes model reasoning content", - "content.tool_use.title": "Tool Usage", - "content.tool_use.description": "Includes tool call parameters and execution results", - "content.citation.title": "Citations", "content.citation.description": "Includes web search and knowledge base reference information", - "content.translation.title": "Translations", - "content.translation.description": "Includes translation content", - "content.error.title": "Errors", + "content.citation.title": "Citations", + "content.code.description": "Includes standalone code blocks", + "content.code.title": "Code Blocks", "content.error.description": "Includes error messages during execution", - "content.file.title": "Files", + "content.error.title": "Errors", "content.file.description": "Includes attached files", + "content.file.title": "Files", + "content.maintext.description": "Includes primary text content", + "content.maintext.title": "Main Text", + "content.thinking.description": "Includes model reasoning content", + "content.thinking.title": "Reasoning", + "content.tool_use.description": "Includes tool call parameters and execution results", + "content.tool_use.title": "Tool Usage", + "content.translation.description": "Includes translation content", + "content.translation.title": "Translations", "empty.no_content": "This message has no saveable content", "empty.no_knowledge_base": "No knowledge bases available, please create one first", - "error.save_failed": "Save failed, please check knowledge base configuration", "error.invalid_base": "Selected knowledge base is not properly configured", "error.no_content_selected": "Please select at least one content type", - "select.base.title": "Select Knowledge Base", + "error.save_failed": "Save failed, please check knowledge base configuration", "select.base.placeholder": "Please select a knowledge base", + "select.base.title": "Select Knowledge Base", + "select.content.tip": "Selected {{count}} items, text types will be merged and saved as one note", "select.content.title": "Select content types to save", - "select.content.tip": "Selected {{count}} items, text types will be merged and saved as one note" + "title": "Save to Knowledge Base" }, "settings.code.title": "Code Block Settings", "settings.code_collapsible": "Code block collapsible", @@ -361,12 +361,6 @@ "topics.unpinned": "Unpinned Topics", "translate": "Translate" }, - "html_artifacts": { - "code": "Code", - "generating": "Generating", - "preview": "Preview", - "split": "Split" - }, "code_block": { "collapse": "Collapse", "copy": "Copy", @@ -428,6 +422,7 @@ "footnote": "Reference content", "footnotes": "References", "fullscreen": "Entered fullscreen mode. Press F11 to exit", + "i_know": "I know", "inspect": "Inspect", "knowledge_base": "Knowledge Base", "language": "Language", @@ -461,8 +456,7 @@ "swap": "Swap", "topics": "Topics", "warning": "Warning", - "you": "You", - "i_know": "I know" + "you": "You" }, "docs": { "title": "Docs" @@ -545,6 +539,12 @@ "search.topics.empty": "No topics found, press Enter to search all messages", "title": "Topics Search" }, + "html_artifacts": { + "code": "Code", + "generating": "Generating", + "preview": "Preview", + "split": "Split" + }, "knowledge": { "add": { "title": "Add Knowledge Base" @@ -661,6 +661,112 @@ "keep_alive_time.title": "Keep Alive Time", "title": "LM Studio" }, + "memory": { + "actions": "Actions", + "add_failed": "Failed to add memory", + "add_first_memory": "Add Your First Memory", + "add_memory": "Add Memory", + "add_new_user": "Add New User", + "add_success": "Memory added successfully", + "add_user": "Add User", + "add_user_failed": "Failed to add user", + "all_users": "All Users", + "cannot_delete_default_user": "Cannot delete the default user", + "configure_memory_first": "Please configure memory settings first", + "content": "Content", + "current_user": "Current User", + "custom": "Custom", + "default": "Default", + "default_user": "Default User", + "delete_confirm": "Are you sure you want to delete this memory?", + "delete_confirm_content": "Are you sure you want to delete {{count}} memories?", + "delete_confirm_single": "Are you sure you want to delete this memory?", + "delete_confirm_title": "Delete Memories", + "delete_failed": "Failed to delete memory", + "delete_selected": "Delete Selected", + "delete_success": "Memory deleted successfully", + "delete_user": "Delete User", + "delete_user_confirm_content": "Are you sure you want to delete user {{user}} and all their memories?", + "delete_user_confirm_title": "Delete User", + "delete_user_failed": "Failed to delete user", + "description": "Memory allows you to store and manage information about your interactions with the assistant. You can add, edit, and delete memories, as well as filter and search through them.", + "edit_memory": "Edit Memory", + "embedding_dimensions": "Embedding Dimensions", + "embedding_model": "Embedding Model", + "enable_global_memory_first": "Please enable global memory first", + "end_date": "End Date", + "global_memory": "Global Memory", + "global_memory_description": "To use memory features, please enable global memory in assistant settings.", + "global_memory_disabled_desc": "To use memory features, please enable global memory in assistant settings first.", + "global_memory_disabled_title": "Global Memory Disabled", + "global_memory_enabled": "Global memory enabled", + "go_to_memory_page": "Go to Memory Page", + "initial_memory_content": "Welcome! This is your first memory.", + "llm_model": "LLM Model", + "load_failed": "Failed to load memories", + "loading": "Loading memories...", + "loading_memories": "Loading memories...", + "memories_description": "Showing {{count}} of {{total}} memories", + "memories_reset_success": "All memories for {{user}} have been reset successfully", + "memory": "memory", + "memory_content": "Memory Content", + "memory_placeholder": "Enter memory content...", + "new_user_id": "New User ID", + "new_user_id_placeholder": "Enter a unique user ID", + "no_matching_memories": "No matching memories found", + "no_memories": "No memories yet", + "no_memories_description": "Start by adding your first memory to get started", + "not_configured_desc": "Please configure embedding and LLM models in memory settings to enable memory functionality.", + "not_configured_title": "Memory Not Configured", + "pagination_total": "{{start}}-{{end}} of {{total}} items", + "please_enter_memory": "Please enter memory content", + "please_select_embedding_model": "Please select an embedding model", + "please_select_llm_model": "Please select an LLM model", + "reset_filters": "Reset Filters", + "reset_memories": "Reset Memories", + "reset_memories_confirm_content": "Are you sure you want to permanently delete all memories for {{user}}? This action cannot be undone.", + "reset_memories_confirm_title": "Reset All Memories", + "reset_memories_failed": "Failed to reset memories", + "reset_user_memories": "Reset User Memories", + "reset_user_memories_confirm_content": "Are you sure you want to reset all memories for {{user}}?", + "reset_user_memories_confirm_title": "Reset User Memories", + "reset_user_memories_failed": "Failed to reset user memories", + "score": "Score", + "search": "Search", + "search_placeholder": "Search memories...", + "select_embedding_model_placeholder": "Select Embedding Model", + "select_llm_model_placeholder": "Select LLM Model", + "select_user": "Select User", + "settings": "Settings", + "settings_title": "Memory Settings", + "start_date": "Start Date", + "statistics": "Statistics", + "stored_memories": "Stored Memories", + "switch_user": "Switch User", + "switch_user_confirm": "Switch user context to {{user}}?", + "time": "Time", + "title": "Memories", + "total_memories": "total memories", + "try_different_filters": "Try adjusting your search criteria", + "update_failed": "Failed to update memory", + "update_success": "Memory updated successfully", + "user": "User", + "user_created": "User {{user}} created and switched successfully", + "user_deleted": "User {{user}} deleted successfully", + "user_id": "User ID", + "user_id_exists": "This user ID already exists", + "user_id_invalid_chars": "User ID can only contain letters, numbers, hyphens and underscores", + "user_id_placeholder": "Enter user ID (optional)", + "user_id_required": "User ID is required", + "user_id_reserved": "'default-user' is reserved, please use a different ID", + "user_id_rules": "User ID must be unique and contain only letters, numbers, hyphens (-) and underscores (_)", + "user_id_too_long": "User ID cannot exceed 50 characters", + "user_management": "User Management", + "user_memories_reset": "All memories for {{user}} have been reset", + "user_switch_failed": "Failed to switch user", + "user_switched": "User context switched to {{user}}", + "users": "users" + }, "message": { "agents": { "import.error": "Import failed", @@ -753,13 +859,13 @@ "tools": { "abort_failed": "Tool call abort failed", "aborted": "Tool call aborted", + "autoApproveEnabled": "Auto-approve enabled for this tool", "cancelled": "Cancelled", "completed": "Completed", "error": "Error occurred", "invoking": "Invoking", "pending": "Pending", "preview": "Preview", - "autoApproveEnabled": "Auto-approve enabled for this tool", "raw": "Raw" }, "topic.added": "New topic added", @@ -785,9 +891,9 @@ "goBack": "Go Back", "goForward": "Go Forward", "minimize": "Minimize MinApp", + "openExternal": "Open in Browser", "open_link_external_off": "Current: Open links in default window", "open_link_external_on": "Current: Open links in browser", - "openExternal": "Open in Browser", "refresh": "Refresh", "rightclick_copyurl": "Right-click to copy URL" }, @@ -1323,9 +1429,9 @@ }, "settings": { "about": "About & Feedback", - "about.checkingUpdate": "Checking for updates...", "about.checkUpdate": "Check Update", "about.checkUpdate.available": "Update", + "about.checkingUpdate": "Checking for updates...", "about.contact.button": "Email", "about.contact.title": "Contact", "about.debug.open": "Open", @@ -1653,6 +1759,10 @@ "backup.manager.title": "Backup Data Management", "backup.modal.filename.placeholder": "Please enter backup filename", "backup.modal.title": "Backup to WebDAV", + "disableStream": { + "help": "When enabled, loads the file into memory before uploading. This can solve incompatibility issues with some WebDAV servers that do not support chunked uploads, but it will increase memory usage.", + "title": "Disable Stream Upload" + }, "host": "WebDAV Host", "host.placeholder": "http://localhost:8080", "hour_interval_one": "{{count}} hour", @@ -1673,11 +1783,7 @@ "syncError": "Backup Error", "syncStatus": "Backup Status", "title": "WebDAV", - "user": "WebDAV User", - "disableStream": { - "title": "Disable Stream Upload", - "help": "When enabled, loads the file into memory before uploading. This can solve incompatibility issues with some WebDAV servers that do not support chunked uploads, but it will increase memory usage." - } + "user": "WebDAV User" }, "yuque": { "check": { @@ -1764,23 +1870,24 @@ "addServer.create": "Quick Create", "addServer.importFrom": "Import from JSON", "addServer.importFrom.connectionFailed": "Connection failed", - "addServer.importFrom.invalid": "Invalid input, please check JSON format", - "addServer.importFrom.nameExists": "Server already exists: {{name}}", - "addServer.importFrom.oneServer": "Only one MCP server configuration at a time", - "addServer.importFrom.method": "Import Method", + "addServer.importFrom.dxt": "Import DXT Package", "addServer.importFrom.dxtFile": "DXT Package File", "addServer.importFrom.dxtHelp": "Select a .dxt file containing an MCP server package", - "addServer.importFrom.selectDxtFile": "Select DXT File", - "addServer.importFrom.noDxtFile": "Please select a DXT file", "addServer.importFrom.dxtProcessFailed": "Failed to process DXT file", - "addServer.importFrom.dxt": "Import DXT Package", + "addServer.importFrom.invalid": "Invalid input, please check JSON format", + "addServer.importFrom.method": "Import Method", + "addServer.importFrom.nameExists": "Server already exists: {{name}}", + "addServer.importFrom.noDxtFile": "Please select a DXT file", + "addServer.importFrom.oneServer": "Only one MCP server configuration at a time", "addServer.importFrom.placeholder": "Paste MCP server JSON config", + "addServer.importFrom.selectDxtFile": "Select DXT File", "addServer.importFrom.tooltip": "Please copy the configuration JSON (prioritizing\n NPX or UVX configurations) from the MCP Servers introduction page and paste it into the input box.", "addSuccess": "Server added successfully", "advancedSettings": "Advanced Settings", "args": "Arguments", "argsTooltip": "Each argument on a new line", "baseUrlTooltip": "Remote server base URL", + "builtinServers": "Builtin Servers", "command": "Command", "config_description": "Configure Model Context Protocol servers", "customRegistryPlaceholder": "Enter private registry URL, e.g.: https://npm.company.com", @@ -1817,6 +1924,17 @@ "jsonSaveSuccess": "JSON configuration has been saved.", "logoUrl": "Logo URL", "missingDependencies": "is Missing, please install it to continue.", + "more": { + "awesome": "Curated MCP Server List", + "composio": "Composio MCP Development Tools", + "glama": "Glama MCP Server Directory", + "higress": "Higress MCP Server", + "mcpso": "MCP Server Discovery Platform", + "modelscope": "ModelScope Community MCP Server", + "official": "Official MCP Server Collection", + "pulsemcp": "Pulse MCP Server", + "smithery": "Smithery MCP Tools" + }, "name": "Name", "newServer": "MCP Server", "noDescriptionAvailable": "No description available", @@ -1849,6 +1967,7 @@ "registry": "Package Registry", "registryDefault": "Default", "registryTooltip": "Choose the registry for package installation to resolve network issues with the default registry.", + "requiresConfig": "Requires Configuration", "resources": { "availableResources": "Available Resources", "blob": "Blob", @@ -1896,17 +2015,17 @@ "timeoutTooltip": "Timeout in seconds for requests to this server, default is 60 seconds", "title": "MCP Settings", "tools": { + "autoApprove": "Auto Approve", + "autoApprove.tooltip.confirm": "Are you sure you want to run this MCP tool?", + "autoApprove.tooltip.disabled": "Tool will require manual approval before running", + "autoApprove.tooltip.enabled": "Tool will run automatically without confirmation", + "autoApprove.tooltip.howToEnable": "Enable the tool first to use auto-approve", "availableTools": "Available Tools", + "enable": "Enable Tool", "inputSchema": "Input Schema", "inputSchema.enum.allowedValues": "Allowed Values", "loadError": "Get tools Error", "noToolsAvailable": "No tools available", - "enable": "Enable Tool", - "autoApprove": "Auto Approve", - "autoApprove.tooltip.howToEnable": "Enable the tool first to use auto-approve", - "autoApprove.tooltip.enabled": "Tool will run automatically without confirmation", - "autoApprove.tooltip.disabled": "Tool will require manual approval before running", - "autoApprove.tooltip.confirm": "Are you sure you want to run this MCP tool?", "run": "Run" }, "type": "Type", @@ -1919,20 +2038,7 @@ "updateError": "Failed to update server", "updateSuccess": "Server updated successfully", "url": "URL", - "user": "User", - "requiresConfig": "Requires Configuration", - "builtinServers": "Builtin Servers", - "more": { - "modelscope": "ModelScope Community MCP Server", - "higress": "Higress MCP Server", - "mcpso": "MCP Server Discovery Platform", - "smithery": "Smithery MCP Tools", - "glama": "Glama MCP Server Directory", - "pulsemcp": "Pulse MCP Server", - "composio": "Composio MCP Development Tools", - "official": "Official MCP Server Collection", - "awesome": "Curated MCP Server List" - } + "user": "User" }, "messages.divider": "Show divider between messages", "messages.divider.tooltip": "Not applicable to bubble-style message", @@ -2226,13 +2332,13 @@ } }, "proxy": { + "address": "Proxy Address", "mode": { "custom": "Custom Proxy", "none": "No Proxy", "system": "System Proxy", "title": "Proxy Mode" - }, - "address": "Proxy Address" + } }, "quickAssistant": { "click_tray_to_show": "Click the tray icon to start", @@ -2455,115 +2561,9 @@ }, "words": { "knowledgeGraph": "Knowledge Graph", - "quit": "Quit", + "quit": "[to be translated]:退出", "show_window": "Show Window", "visualization": "Visualization" - }, - "memory": { - "title": "Memories", - "actions": "Actions", - "description": "Memory allows you to store and manage information about your interactions with the assistant. You can add, edit, and delete memories, as well as filter and search through them.", - "add_memory": "Add Memory", - "edit_memory": "Edit Memory", - "memory_content": "Memory Content", - "please_enter_memory": "Please enter memory content", - "memory_placeholder": "Enter memory content...", - "user_id": "User ID", - "user_id_placeholder": "Enter user ID (optional)", - "load_failed": "Failed to load memories", - "add_success": "Memory added successfully", - "add_failed": "Failed to add memory", - "update_success": "Memory updated successfully", - "update_failed": "Failed to update memory", - "delete_success": "Memory deleted successfully", - "delete_failed": "Failed to delete memory", - "delete_confirm_title": "Delete Memories", - "delete_confirm_content": "Are you sure you want to delete {{count}} memories?", - "delete_confirm": "Are you sure you want to delete this memory?", - "time": "Time", - "user": "User", - "content": "Content", - "score": "Score", - "memories_description": "Showing {{count}} of {{total}} memories", - "search_placeholder": "Search memories...", - "start_date": "Start Date", - "end_date": "End Date", - "all_users": "All Users", - "users": "users", - "delete_selected": "Delete Selected", - "reset_filters": "Reset Filters", - "pagination_total": "{{start}}-{{end}} of {{total}} items", - "current_user": "Current User", - "select_user": "Select User", - "default_user": "Default User", - "switch_user": "Switch User", - "user_switched": "User context switched to {{user}}", - "switch_user_confirm": "Switch user context to {{user}}?", - "add_user": "Add User", - "add_new_user": "Add New User", - "new_user_id": "New User ID", - "new_user_id_placeholder": "Enter a unique user ID", - "user_id_required": "User ID is required", - "user_id_reserved": "'default-user' is reserved, please use a different ID", - "user_id_exists": "This user ID already exists", - "user_id_too_long": "User ID cannot exceed 50 characters", - "user_id_invalid_chars": "User ID can only contain letters, numbers, hyphens and underscores", - "user_id_rules": "User ID must be unique and contain only letters, numbers, hyphens (-) and underscores (_)", - "user_created": "User {{user}} created and switched successfully", - "add_user_failed": "Failed to add user", - "memory": "memory", - "reset_user_memories": "Reset User Memories", - "reset_memories": "Reset Memories", - "delete_user": "Delete User", - "loading_memories": "Loading memories...", - "no_memories": "No memories yet", - "no_matching_memories": "No matching memories found", - "no_memories_description": "Start by adding your first memory to get started", - "try_different_filters": "Try adjusting your search criteria", - "add_first_memory": "Add Your First Memory", - "user_switch_failed": "Failed to switch user", - "cannot_delete_default_user": "Cannot delete the default user", - "delete_user_confirm_title": "Delete User", - "delete_user_confirm_content": "Are you sure you want to delete user {{user}} and all their memories?", - "user_deleted": "User {{user}} deleted successfully", - "delete_user_failed": "Failed to delete user", - "reset_user_memories_confirm_title": "Reset User Memories", - "reset_user_memories_confirm_content": "Are you sure you want to reset all memories for {{user}}?", - "user_memories_reset": "All memories for {{user}} have been reset", - "reset_user_memories_failed": "Failed to reset user memories", - "reset_memories_confirm_title": "Reset All Memories", - "reset_memories_confirm_content": "Are you sure you want to permanently delete all memories for {{user}}? This action cannot be undone.", - "memories_reset_success": "All memories for {{user}} have been reset successfully", - "reset_memories_failed": "Failed to reset memories", - "delete_confirm_single": "Are you sure you want to delete this memory?", - "total_memories": "total memories", - "default": "Default", - "custom": "Custom", - "global_memory_enabled": "Global memory enabled", - "global_memory": "Global Memory", - "enable_global_memory_first": "Please enable global memory first", - "configure_memory_first": "Please configure memory settings first", - "global_memory_disabled_title": "Global Memory Disabled", - "global_memory_disabled_desc": "To use memory features, please enable global memory in assistant settings first.", - "not_configured_title": "Memory Not Configured", - "not_configured_desc": "Please configure embedding and LLM models in memory settings to enable memory functionality.", - "go_to_memory_page": "Go to Memory Page", - "settings": "Settings", - "user_management": "User Management", - "statistics": "Statistics", - "search": "Search", - "initial_memory_content": "Welcome! This is your first memory.", - "loading": "Loading memories...", - "settings_title": "Memory Settings", - "llm_model": "LLM Model", - "please_select_llm_model": "Please select an LLM model", - "select_llm_model_placeholder": "Select LLM Model", - "embedding_model": "Embedding Model", - "please_select_embedding_model": "Please select an embedding model", - "select_embedding_model_placeholder": "Select Embedding Model", - "embedding_dimensions": "Embedding Dimensions", - "stored_memories": "Stored Memories", - "global_memory_description": "To use memory features, please enable global memory in assistant settings." } } } diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index bc7fda495..1486bd29e 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -204,6 +204,7 @@ "input.upload": "画像またはドキュメントをアップロード", "input.upload.document": "ドキュメントをアップロード(モデルは画像をサポートしません)", "input.upload.upload_from_local": "ローカルファイルをアップロード...", + "input.url_context": "URLコンテキスト", "input.web_search": "ウェブ検索", "input.web_search.builtin": "モデル内蔵", "input.web_search.builtin.disabled_content": "現在のモデルはウェブ検索をサポートしていません", @@ -214,7 +215,6 @@ "input.web_search.no_web_search": "ウェブ検索を無効にする", "input.web_search.no_web_search.description": "ウェブ検索を無効にする", "input.web_search.settings": "ウェブ検索設定", - "input.url_context": "URLコンテキスト", "message.new.branch": "新しいブランチ", "message.new.branch.created": "新しいブランチが作成されました", "message.new.context": "新しいコンテキスト", @@ -235,33 +235,34 @@ }, "resend": "再送信", "save": "保存", + "save.file.title": "ローカルファイルに保存", "save.knowledge": { - "title": "ナレッジベースに保存", - "content.maintext.title": "メインテキスト", - "content.maintext.description": "主要なテキストコンテンツを含む", - "content.code.title": "コードブロック", - "content.code.description": "独立したコードブロックを含む", - "content.thinking.title": "思考プロセス", - "content.thinking.description": "モデルの推論内容を含む", - "content.tool_use.title": "ツール使用", - "content.tool_use.description": "ツール呼び出しパラメーターと実行結果を含む", - "content.citation.title": "引用", "content.citation.description": "ウェブ検索とナレッジベース参照情報を含む", - "content.translation.title": "翻訳", - "content.translation.description": "翻訳コンテンツを含む", - "content.error.title": "エラー", + "content.citation.title": "引用", + "content.code.description": "独立したコードブロックを含む", + "content.code.title": "コードブロック", "content.error.description": "実行中のエラーメッセージを含む", - "content.file.title": "ファイル", + "content.error.title": "エラー", "content.file.description": "添付ファイルを含む", + "content.file.title": "ファイル", + "content.maintext.description": "主要なテキストコンテンツを含む", + "content.maintext.title": "メインテキスト", + "content.thinking.description": "モデルの推論内容を含む", + "content.thinking.title": "思考プロセス", + "content.tool_use.description": "ツール呼び出しパラメーターと実行結果を含む", + "content.tool_use.title": "ツール使用", + "content.translation.description": "翻訳コンテンツを含む", + "content.translation.title": "翻訳", "empty.no_content": "このメッセージには保存可能なコンテンツがありません", "empty.no_knowledge_base": "利用可能なナレッジベースがありません。まず作成してください", - "error.save_failed": "保存に失敗しました。ナレッジベースの設定を確認してください", "error.invalid_base": "選択されたナレッジベースが正しく設定されていません", "error.no_content_selected": "少なくとも1つのコンテンツタイプを選択してください", - "select.base.title": "ナレッジベースを選択", + "error.save_failed": "保存に失敗しました。ナレッジベースの設定を確認してください", "select.base.placeholder": "ナレッジベースを選択してください", + "select.base.title": "ナレッジベースを選択", + "select.content.tip": "{{count}}項目が選択されました。テキストタイプは統合されて1つのノートとして保存されます", "select.content.title": "保存するコンテンツタイプを選択", - "select.content.tip": "{{count}}項目が選択されました。テキストタイプは統合されて1つのノートとして保存されます" + "title": "ナレッジベースに保存" }, "settings.code.title": "コード設定", "settings.code_collapsible": "コードブロック折り畳み", @@ -358,14 +359,7 @@ "topics.prompt.tips": "トピック提示語:現在のトピックに対して追加の補足提示語を提供", "topics.title": "トピック", "topics.unpinned": "固定解除", - "translate": "翻訳", - "save.file.title": "ローカルファイルに保存" - }, - "html_artifacts": { - "code": "コード", - "generating": "生成中", - "preview": "プレビュー", - "split": "分割" + "translate": "翻訳" }, "code_block": { "collapse": "折りたたむ", @@ -428,6 +422,7 @@ "footnote": "引用内容", "footnotes": "脚注", "fullscreen": "全画面モードに入りました。F11キーで終了します", + "i_know": "わかりました", "inspect": "検査", "knowledge_base": "ナレッジベース", "language": "言語", @@ -461,8 +456,7 @@ "swap": "交換", "topics": "トピック", "warning": "警告", - "you": "あなた", - "i_know": "わかりました" + "you": "あなた" }, "docs": { "title": "ドキュメント" @@ -545,6 +539,12 @@ "search.topics.empty": "トピックが見つかりませんでした。Enterキーを押してすべてのメッセージを検索", "title": "トピック検索" }, + "html_artifacts": { + "code": "コード", + "generating": "生成中", + "preview": "プレビュー", + "split": "分割" + }, "knowledge": { "add": { "title": "ナレッジベースを追加" @@ -661,6 +661,112 @@ "keep_alive_time.title": "保持時間", "title": "LM Studio" }, + "memory": { + "actions": "アクション", + "add_failed": "メモリーの追加に失敗しました", + "add_first_memory": "最初のメモリを追加", + "add_memory": "メモリーを追加", + "add_new_user": "新しいユーザーを追加", + "add_success": "メモリーが正常に追加されました", + "add_user": "ユーザーを追加", + "add_user_failed": "ユーザーの追加に失敗しました", + "all_users": "すべてのユーザー", + "cannot_delete_default_user": "デフォルトユーザーは削除できません", + "configure_memory_first": "最初にメモリ設定を構成してください", + "content": "内容", + "current_user": "現在のユーザー", + "custom": "カスタム", + "default": "デフォルト", + "default_user": "デフォルトユーザー", + "delete_confirm": "このメモリーを削除してもよろしいですか?", + "delete_confirm_content": "{{count}}件のメモリーを削除してもよろしいですか?", + "delete_confirm_single": "このメモリを削除してもよろしいですか?", + "delete_confirm_title": "メモリーを削除", + "delete_failed": "メモリーの削除に失敗しました", + "delete_selected": "選択したものを削除", + "delete_success": "メモリーが正常に削除されました", + "delete_user": "ユーザーを削除", + "delete_user_confirm_content": "ユーザー{{user}}とそのすべてのメモリを削除してもよろしいですか?", + "delete_user_confirm_title": "ユーザーを削除", + "delete_user_failed": "ユーザーの削除に失敗しました", + "description": "メモリは、アシスタントとのやりとりに関する情報を保存・管理する機能です。メモリの追加、編集、削除のほか、フィルタリングや検索を行うことができます。", + "edit_memory": "メモリーを編集", + "embedding_dimensions": "埋め込み次元", + "embedding_model": "埋め込みモデル", + "enable_global_memory_first": "最初にグローバルメモリを有効にしてください", + "end_date": "終了日", + "global_memory": "グローバルメモリ", + "global_memory_description": "メモリ機能を使用するには、アシスタント設定でグローバルメモリを有効にしてください。", + "global_memory_disabled_desc": "メモリ機能を使用するには、まずアシスタント設定でグローバルメモリを有効にしてください。", + "global_memory_disabled_title": "グローバルメモリが無効です", + "global_memory_enabled": "グローバルメモリが有効化されました", + "go_to_memory_page": "メモリページに移動", + "initial_memory_content": "ようこそ!これはあなたの最初の記憶です。", + "llm_model": "LLMモデル", + "load_failed": "メモリーの読み込みに失敗しました", + "loading": "思い出を読み込み中...", + "loading_memories": "メモリを読み込み中...", + "memories_description": "{{total}}件中{{count}}件のメモリーを表示", + "memories_reset_success": "{{user}}のすべてのメモリが正常にリセットされました", + "memory": "個のメモリ", + "memory_content": "メモリー内容", + "memory_placeholder": "メモリー内容を入力...", + "new_user_id": "新しいユーザーID", + "new_user_id_placeholder": "一意のユーザーIDを入力", + "no_matching_memories": "一致するメモリが見つかりません", + "no_memories": "メモリがありません", + "no_memories_description": "最初のメモリを追加してください", + "not_configured_desc": "メモリ機能を有効にするには、メモリ設定で埋め込みとLLMモデルを設定してください。", + "not_configured_title": "メモリが設定されていません", + "pagination_total": "{{total}}件中{{start}}-{{end}}件", + "please_enter_memory": "メモリー内容を入力してください", + "please_select_embedding_model": "埋め込みモデルを選択してください", + "please_select_llm_model": "LLMモデルを選択してください", + "reset_filters": "フィルターをリセット", + "reset_memories": "メモリをリセット", + "reset_memories_confirm_content": "{{user}}のすべてのメモリを完全に削除してもよろしいですか?この操作は元に戻せません。", + "reset_memories_confirm_title": "すべてのメモリをリセット", + "reset_memories_failed": "メモリのリセットに失敗しました", + "reset_user_memories": "ユーザーメモリをリセット", + "reset_user_memories_confirm_content": "{{user}}のすべてのメモリをリセットしてもよろしいですか?", + "reset_user_memories_confirm_title": "ユーザーメモリをリセット", + "reset_user_memories_failed": "ユーザーメモリのリセットに失敗しました", + "score": "スコア", + "search": "検索", + "search_placeholder": "メモリーを検索...", + "select_embedding_model_placeholder": "埋め込みモデルを選択", + "select_llm_model_placeholder": "LLMモデルを選択", + "select_user": "ユーザーを選択", + "settings": "設定", + "settings_title": "メモリ設定", + "start_date": "開始日", + "statistics": "統計", + "stored_memories": "保存された記憶", + "switch_user": "ユーザーを切り替え", + "switch_user_confirm": "ユーザーコンテキストを{{user}}に切り替えますか?", + "time": "時間", + "title": "グローバルメモリ", + "total_memories": "個のメモリ", + "try_different_filters": "検索条件を調整してください", + "update_failed": "メモリーの更新に失敗しました", + "update_success": "メモリーが正常に更新されました", + "user": "ユーザー", + "user_created": "ユーザー{{user}}が作成され、切り替えが成功しました", + "user_deleted": "ユーザー{{user}}が正常に削除されました", + "user_id": "ユーザーID", + "user_id_exists": "このユーザーIDはすでに存在します", + "user_id_invalid_chars": "ユーザーIDには文字、数字、ハイフン、アンダースコアのみ使用できます", + "user_id_placeholder": "ユーザーIDを入力(オプション)", + "user_id_required": "ユーザーIDは必須です", + "user_id_reserved": "'default-user'は予約済みです。別のIDを使用してください", + "user_id_rules": "ユーザーIDは一意であり、文字、数字、ハイフン(-)、アンダースコア(_)のみ含む必要があります", + "user_id_too_long": "ユーザーIDは50文字を超えられません", + "user_management": "ユーザー管理", + "user_memories_reset": "{{user}}のすべてのメモリがリセットされました", + "user_switch_failed": "ユーザーの切り替えに失敗しました", + "user_switched": "ユーザーコンテキストが{{user}}に切り替わりました", + "users": "ユーザー" + }, "message": { "agents": { "import.error": "インポートに失敗しました", @@ -753,13 +859,13 @@ "tools": { "abort_failed": "ツール呼び出し中断失敗", "aborted": "ツール呼び出し中断", + "autoApproveEnabled": "このツールは自動承認が有効になっています", "cancelled": "キャンセル", "completed": "完了", "error": "エラーが発生しました", "invoking": "呼び出し中", "pending": "保留中", "preview": "プレビュー", - "autoApproveEnabled": "このツールは自動承認が有効になっています", "raw": "生データ" }, "topic.added": "新しいトピックが追加されました", @@ -785,9 +891,9 @@ "goBack": "戻る", "goForward": "進む", "minimize": "ミニアプリを最小化", + "openExternal": "ブラウザで開く", "open_link_external_off": "現在:デフォルトのウィンドウで開く", "open_link_external_on": "現在:ブラウザで開く", - "openExternal": "ブラウザで開く", "refresh": "更新", "rightclick_copyurl": "右クリックでURLをコピー" }, @@ -1323,9 +1429,9 @@ }, "settings": { "about": "について", - "about.checkingUpdate": "更新を確認中...", "about.checkUpdate": "更新を確認", "about.checkUpdate.available": "今すぐ更新", + "about.checkingUpdate": "更新を確認中...", "about.contact.button": "メール", "about.contact.title": "連絡先", "about.debug.open": "開く", @@ -1653,6 +1759,10 @@ "backup.manager.title": "バックアップデータ管理", "backup.modal.filename.placeholder": "バックアップファイル名を入力してください", "backup.modal.title": "WebDAV にバックアップ", + "disableStream": { + "help": "有効にすると、アップロード前にファイルがメモリに読み込まれます。これにより、チャンクアップロードをサポートしていない一部のWebDAVサーバーとの互換性の問題を解決できますが、メモリ使用量が増加します。", + "title": "ストリーミングアップロードを無効にする" + }, "host": "WebDAVホスト", "host.placeholder": "http://localhost:8080", "hour_interval_one": "{{count}} 時間", @@ -1673,11 +1783,7 @@ "syncError": "バックアップエラー", "syncStatus": "バックアップ状態", "title": "WebDAV", - "user": "WebDAVユーザー", - "disableStream": { - "title": "ストリーミングアップロードを無効にする", - "help": "有効にすると、アップロード前にファイルがメモリに読み込まれます。これにより、チャンクアップロードをサポートしていない一部のWebDAVサーバーとの互換性の問題を解決できますが、メモリ使用量が増加します。" - } + "user": "WebDAVユーザー" }, "yuque": { "check": { @@ -1764,23 +1870,24 @@ "addServer.create": "クイック作成", "addServer.importFrom": "JSONからインポート", "addServer.importFrom.connectionFailed": "接続に失敗しました", - "addServer.importFrom.invalid": "無効な入力です。JSON形式を確認してください。", - "addServer.importFrom.nameExists": "サーバーはすでに存在します: {{name}}", - "addServer.importFrom.oneServer": "一度に1つのMCPサーバー設定のみを保存できます", - "addServer.importFrom.method": "インポート方法", + "addServer.importFrom.dxt": "DXTパッケージをインポート", "addServer.importFrom.dxtFile": "DXTパッケージファイル", "addServer.importFrom.dxtHelp": "MCPサーバーパッケージを含む.dxtファイルを選択", - "addServer.importFrom.selectDxtFile": "DXTファイルを選択", - "addServer.importFrom.noDxtFile": "DXTファイルを選択してください", "addServer.importFrom.dxtProcessFailed": "DXTファイルの処理に失敗しました", - "addServer.importFrom.dxt": "DXTパッケージをインポート", + "addServer.importFrom.invalid": "無効な入力です。JSON形式を確認してください。", + "addServer.importFrom.method": "インポート方法", + "addServer.importFrom.nameExists": "サーバーはすでに存在します: {{name}}", + "addServer.importFrom.noDxtFile": "DXTファイルを選択してください", + "addServer.importFrom.oneServer": "一度に1つのMCPサーバー設定のみを保存できます", "addServer.importFrom.placeholder": "MCPサーバーJSON設定を貼り付け", + "addServer.importFrom.selectDxtFile": "[to be translated]:选择 DXT 文件", "addServer.importFrom.tooltip": "MCPサーバー紹介ページから設定JSON(NPXまたはUVX設定を優先)をコピーし、入力ボックスに貼り付けてください。", "addSuccess": "サーバーが正常に追加されました", "advancedSettings": "詳細設定", "args": "引数", "argsTooltip": "1行に1つの引数を入力してください", "baseUrlTooltip": "リモートURLアドレス", + "builtinServers": "組み込みサーバー", "command": "コマンド", "config_description": "モデルコンテキストプロトコルサーバーの設定", "customRegistryPlaceholder": "プライベート倉庫のアドレスを入力してください(例:https://npm.company.com)", @@ -1817,6 +1924,17 @@ "jsonSaveSuccess": "JSON設定が保存されました。", "logoUrl": "ロゴURL", "missingDependencies": "が不足しています。続行するにはインストールしてください。", + "more": { + "awesome": "厳選された MCP サーバーリスト", + "composio": "Composio MCP 開発ツール", + "glama": "Glama MCP サーバーディレクトリ", + "higress": "Higress MCP サーバー", + "mcpso": "MCP サーバー発見プラットフォーム", + "modelscope": "魔搭コミュニティ MCP サーバー", + "official": "公式 MCP サーバーコレクション", + "pulsemcp": "Pulse MCP サーバー", + "smithery": "Smithery MCP ツール" + }, "name": "名前", "newServer": "MCP サーバー", "noDescriptionAvailable": "説明がありません", @@ -1849,6 +1967,7 @@ "registry": "パッケージ管理レジストリ", "registryDefault": "デフォルト", "registryTooltip": "デフォルトのレジストリでネットワークの問題が発生した場合、パッケージインストールに使用するレジストリを選択してください。", + "requiresConfig": "設定が必要", "resources": { "availableResources": "利用可能なリソース", "blob": "バイナリデータ", @@ -1896,17 +2015,17 @@ "timeoutTooltip": "このサーバーへのリクエストのタイムアウト時間(秒)、デフォルトは60秒です", "title": "MCP 設定", "tools": { + "autoApprove": "自動承認", + "autoApprove.tooltip.confirm": "このMCPツールを実行してもよろしいですか?", + "autoApprove.tooltip.disabled": "ツールは実行前に手動承認が必要です", + "autoApprove.tooltip.enabled": "ツールは承認なしで自動実行されます", + "autoApprove.tooltip.howToEnable": "ツールを有効にしてから自動承認を使用できます", "availableTools": "利用可能なツール", + "enable": "ツールを有効にする", "inputSchema": "入力スキーマ", "inputSchema.enum.allowedValues": "許可された値", "loadError": "ツール取得エラー", "noToolsAvailable": "利用可能なツールなし", - "enable": "ツールを有効にする", - "autoApprove": "自動承認", - "autoApprove.tooltip.howToEnable": "ツールを有効にしてから自動承認を使用できます", - "autoApprove.tooltip.enabled": "ツールは承認なしで自動実行されます", - "autoApprove.tooltip.disabled": "ツールは実行前に手動承認が必要です", - "autoApprove.tooltip.confirm": "このMCPツールを実行してもよろしいですか?", "run": "実行" }, "type": "タイプ", @@ -1919,20 +2038,7 @@ "updateError": "サーバーの更新に失敗しました", "updateSuccess": "サーバーが正常に更新されました", "url": "URL", - "user": "ユーザー", - "requiresConfig": "設定が必要", - "builtinServers": "組み込みサーバー", - "more": { - "modelscope": "魔搭コミュニティ MCP サーバー", - "higress": "Higress MCP サーバー", - "mcpso": "MCP サーバー発見プラットフォーム", - "smithery": "Smithery MCP ツール", - "glama": "Glama MCP サーバーディレクトリ", - "pulsemcp": "Pulse MCP サーバー", - "composio": "Composio MCP 開発ツール", - "official": "公式 MCP サーバーコレクション", - "awesome": "厳選された MCP サーバーリスト" - } + "user": "ユーザー" }, "messages.divider": "メッセージ間に区切り線を表示", "messages.divider.tooltip": "バブルスタイルのメッセージには適用されません", @@ -2126,6 +2232,7 @@ "api_key": "APIキー", "api_key.tip": "複数のキーはカンマまたはスペースで区切ります", "api_version": "APIバージョン", + "azure.apiversion.tip": "Azure OpenAIのAPIバージョン。Response APIを使用する場合は、previewバージョンを入力してください", "basic_auth": "HTTP 認証", "basic_auth.password": "パスワード", "basic_auth.password.tip": "", @@ -2222,17 +2329,16 @@ "private_key_placeholder": "サービスアカウントの秘密鍵を入力してください", "title": "サービスアカウント設定" } - }, - "azure.apiversion.tip": "Azure OpenAIのAPIバージョン。Response APIを使用する場合は、previewバージョンを入力してください" + } }, "proxy": { + "address": "プロキシアドレス", "mode": { "custom": "カスタムプロキシ", "none": "プロキシを使用しない", "system": "システムプロキシ", "title": "プロキシモード" - }, - "address": "プロキシアドレス" + } }, "quickAssistant": { "click_tray_to_show": "トレイアイコンをクリックして起動", @@ -2455,115 +2561,9 @@ }, "words": { "knowledgeGraph": "ナレッジグラフ", - "quit": "終了", + "quit": "[to be translated]:退出", "show_window": "ウィンドウを表示", "visualization": "可視化" - }, - "memory": { - "title": "グローバルメモリ", - "add_memory": "メモリーを追加", - "edit_memory": "メモリーを編集", - "memory_content": "メモリー内容", - "please_enter_memory": "メモリー内容を入力してください", - "memory_placeholder": "メモリー内容を入力...", - "user_id": "ユーザーID", - "user_id_placeholder": "ユーザーIDを入力(オプション)", - "load_failed": "メモリーの読み込みに失敗しました", - "add_success": "メモリーが正常に追加されました", - "add_failed": "メモリーの追加に失敗しました", - "update_success": "メモリーが正常に更新されました", - "update_failed": "メモリーの更新に失敗しました", - "delete_success": "メモリーが正常に削除されました", - "delete_failed": "メモリーの削除に失敗しました", - "delete_confirm_title": "メモリーを削除", - "delete_confirm_content": "{{count}}件のメモリーを削除してもよろしいですか?", - "delete_confirm": "このメモリーを削除してもよろしいですか?", - "time": "時間", - "user": "ユーザー", - "content": "内容", - "score": "スコア", - "memories_description": "{{total}}件中{{count}}件のメモリーを表示", - "search_placeholder": "メモリーを検索...", - "start_date": "開始日", - "end_date": "終了日", - "all_users": "すべてのユーザー", - "users": "ユーザー", - "delete_selected": "選択したものを削除", - "reset_filters": "フィルターをリセット", - "pagination_total": "{{total}}件中{{start}}-{{end}}件", - "current_user": "現在のユーザー", - "select_user": "ユーザーを選択", - "default_user": "デフォルトユーザー", - "switch_user": "ユーザーを切り替え", - "user_switched": "ユーザーコンテキストが{{user}}に切り替わりました", - "switch_user_confirm": "ユーザーコンテキストを{{user}}に切り替えますか?", - "add_user": "ユーザーを追加", - "add_new_user": "新しいユーザーを追加", - "new_user_id": "新しいユーザーID", - "new_user_id_placeholder": "一意のユーザーIDを入力", - "user_id_required": "ユーザーIDは必須です", - "user_id_reserved": "'default-user'は予約済みです。別のIDを使用してください", - "user_id_exists": "このユーザーIDはすでに存在します", - "user_id_too_long": "ユーザーIDは50文字を超えられません", - "user_id_invalid_chars": "ユーザーIDには文字、数字、ハイフン、アンダースコアのみ使用できます", - "user_id_rules": "ユーザーIDは一意であり、文字、数字、ハイフン(-)、アンダースコア(_)のみ含む必要があります", - "user_created": "ユーザー{{user}}が作成され、切り替えが成功しました", - "add_user_failed": "ユーザーの追加に失敗しました", - "memory": "個のメモリ", - "reset_user_memories": "ユーザーメモリをリセット", - "reset_memories": "メモリをリセット", - "delete_user": "ユーザーを削除", - "loading_memories": "メモリを読み込み中...", - "no_memories": "メモリがありません", - "no_matching_memories": "一致するメモリが見つかりません", - "no_memories_description": "最初のメモリを追加してください", - "try_different_filters": "検索条件を調整してください", - "add_first_memory": "最初のメモリを追加", - "user_switch_failed": "ユーザーの切り替えに失敗しました", - "cannot_delete_default_user": "デフォルトユーザーは削除できません", - "delete_user_confirm_title": "ユーザーを削除", - "delete_user_confirm_content": "ユーザー{{user}}とそのすべてのメモリを削除してもよろしいですか?", - "user_deleted": "ユーザー{{user}}が正常に削除されました", - "delete_user_failed": "ユーザーの削除に失敗しました", - "reset_user_memories_confirm_title": "ユーザーメモリをリセット", - "reset_user_memories_confirm_content": "{{user}}のすべてのメモリをリセットしてもよろしいですか?", - "user_memories_reset": "{{user}}のすべてのメモリがリセットされました", - "reset_user_memories_failed": "ユーザーメモリのリセットに失敗しました", - "reset_memories_confirm_title": "すべてのメモリをリセット", - "reset_memories_confirm_content": "{{user}}のすべてのメモリを完全に削除してもよろしいですか?この操作は元に戻せません。", - "memories_reset_success": "{{user}}のすべてのメモリが正常にリセットされました", - "reset_memories_failed": "メモリのリセットに失敗しました", - "delete_confirm_single": "このメモリを削除してもよろしいですか?", - "total_memories": "個のメモリ", - "default": "デフォルト", - "custom": "カスタム", - "description": "メモリは、アシスタントとのやりとりに関する情報を保存・管理する機能です。メモリの追加、編集、削除のほか、フィルタリングや検索を行うことができます。", - "global_memory_enabled": "グローバルメモリが有効化されました", - "global_memory": "グローバルメモリ", - "enable_global_memory_first": "最初にグローバルメモリを有効にしてください", - "configure_memory_first": "最初にメモリ設定を構成してください", - "global_memory_disabled_title": "グローバルメモリが無効です", - "global_memory_disabled_desc": "メモリ機能を使用するには、まずアシスタント設定でグローバルメモリを有効にしてください。", - "not_configured_title": "メモリが設定されていません", - "not_configured_desc": "メモリ機能を有効にするには、メモリ設定で埋め込みとLLMモデルを設定してください。", - "go_to_memory_page": "メモリページに移動", - "settings": "設定", - "statistics": "統計", - "search": "検索", - "actions": "アクション", - "user_management": "ユーザー管理", - "initial_memory_content": "ようこそ!これはあなたの最初の記憶です。", - "loading": "思い出を読み込み中...", - "settings_title": "メモリ設定", - "llm_model": "LLMモデル", - "please_select_llm_model": "LLMモデルを選択してください", - "select_llm_model_placeholder": "LLMモデルを選択", - "embedding_model": "埋め込みモデル", - "please_select_embedding_model": "埋め込みモデルを選択してください", - "select_embedding_model_placeholder": "埋め込みモデルを選択", - "embedding_dimensions": "埋め込み次元", - "stored_memories": "保存された記憶", - "global_memory_description": "メモリ機能を使用するには、アシスタント設定でグローバルメモリを有効にしてください。" } } } diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 7bab45d02..a461a9357 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -204,6 +204,7 @@ "input.upload": "Загрузить изображение или документ", "input.upload.document": "Загрузить документ (модель не поддерживает изображения)", "input.upload.upload_from_local": "Загрузить локальный файл...", + "input.url_context": "Контекст страницы", "input.web_search": "Веб-поиск", "input.web_search.builtin": "Модель встроена", "input.web_search.builtin.disabled_content": "Текущая модель не поддерживает веб-поиск", @@ -214,7 +215,6 @@ "input.web_search.no_web_search": "Отключить веб-поиск", "input.web_search.no_web_search.description": "Отключить веб-поиск", "input.web_search.settings": "Настройки веб-поиска", - "input.url_context": "Контекст страницы", "message.new.branch": "Новая ветка", "message.new.branch.created": "Новая ветка создана", "message.new.context": "Новый контекст", @@ -235,33 +235,34 @@ }, "resend": "Переотправить", "save": "Сохранить", + "save.file.title": "Сохранить в локальный файл", "save.knowledge": { - "title": "Сохранить в базу знаний", - "content.maintext.title": "Основной текст", - "content.maintext.description": "Включает основное текстовое содержимое", - "content.code.title": "Блоки кода", - "content.code.description": "Включает отдельные блоки кода", - "content.thinking.title": "Размышления", - "content.thinking.description": "Включает содержимое рассуждений модели", - "content.tool_use.title": "Использование инструментов", - "content.tool_use.description": "Включает параметры вызова инструментов и результаты выполнения", - "content.citation.title": "Цитаты", "content.citation.description": "Включает информацию веб-поиска и ссылки на базу знаний", - "content.translation.title": "Переводы", - "content.translation.description": "Включает переводное содержимое", - "content.error.title": "Ошибки", + "content.citation.title": "Цитаты", + "content.code.description": "Включает отдельные блоки кода", + "content.code.title": "Блоки кода", "content.error.description": "Включает сообщения об ошибках во время выполнения", - "content.file.title": "Файлы", + "content.error.title": "Ошибки", "content.file.description": "Включает прикрепленные файлы", + "content.file.title": "Файлы", + "content.maintext.description": "Включает основное текстовое содержимое", + "content.maintext.title": "Основной текст", + "content.thinking.description": "Включает содержимое рассуждений модели", + "content.thinking.title": "Размышления", + "content.tool_use.description": "Включает параметры вызова инструментов и результаты выполнения", + "content.tool_use.title": "Использование инструментов", + "content.translation.description": "Включает переводное содержимое", + "content.translation.title": "Переводы", "empty.no_content": "Это сообщение не содержит сохраняемого контента", "empty.no_knowledge_base": "Нет доступных баз знаний, сначала создайте одну", - "error.save_failed": "Сохранение не удалось, проверьте конфигурацию базы знаний", "error.invalid_base": "Выбранная база знаний настроена неправильно", "error.no_content_selected": "Выберите хотя бы один тип контента", - "select.base.title": "Выберите базу знаний", + "error.save_failed": "Сохранение не удалось, проверьте конфигурацию базы знаний", "select.base.placeholder": "Пожалуйста, выберите базу знаний", + "select.base.title": "Выберите базу знаний", + "select.content.tip": "Выбрано {{count}} элементов, текстовые типы будут объединены и сохранены как одна заметка", "select.content.title": "Выберите типы контента для сохранения", - "select.content.tip": "Выбрано {{count}} элементов, текстовые типы будут объединены и сохранены как одна заметка" + "title": "Сохранить в базу знаний" }, "settings.code.title": "Настройки кода", "settings.code_collapsible": "Блок кода свернут", @@ -358,14 +359,7 @@ "topics.prompt.tips": "Тематические подсказки: Дополнительные подсказки, предоставленные для текущей темы", "topics.title": "Топики", "topics.unpinned": "Открепленные темы", - "translate": "Перевести", - "save.file.title": "Сохранить в локальный файл" - }, - "html_artifacts": { - "code": "Код", - "generating": "Генерация", - "preview": "Предпросмотр", - "split": "Разделить" + "translate": "Перевести" }, "code_block": { "collapse": "Свернуть", @@ -428,6 +422,7 @@ "footnote": "Цитируемый контент", "footnotes": "Сноски", "fullscreen": "Вы вошли в полноэкранный режим. Нажмите F11 для выхода", + "i_know": "Я понял", "inspect": "Осмотреть", "knowledge_base": "База знаний", "language": "Язык", @@ -461,8 +456,7 @@ "swap": "Поменять местами", "topics": "Топики", "warning": "Предупреждение", - "you": "Вы", - "i_know": "Я понял" + "you": "Вы" }, "docs": { "title": "Документация" @@ -545,6 +539,12 @@ "search.topics.empty": "Топики не найдены, нажмите Enter для поиска всех сообщений", "title": "Поиск топиков" }, + "html_artifacts": { + "code": "Код", + "generating": "Генерация", + "preview": "Предпросмотр", + "split": "Разделить" + }, "knowledge": { "add": { "title": "Добавить базу знаний" @@ -661,6 +661,112 @@ "keep_alive_time.title": "Время жизни модели", "title": "LM Studio" }, + "memory": { + "actions": "Действия", + "add_failed": "Не удалось добавить память", + "add_first_memory": "Добавить первое воспоминание", + "add_memory": "Добавить память", + "add_new_user": "Добавить нового пользователя", + "add_success": "Память успешно добавлена", + "add_user": "Добавить пользователя", + "add_user_failed": "Не удалось добавить пользователя", + "all_users": "Все пользователи", + "cannot_delete_default_user": "Нельзя удалить пользователя по умолчанию", + "configure_memory_first": "Сначала настройте параметры памяти", + "content": "Содержимое", + "current_user": "Текущий пользователь", + "custom": "Пользовательский", + "default": "По умолчанию", + "default_user": "Пользователь по умолчанию", + "delete_confirm": "Вы уверены, что хотите удалить эту запись памяти?", + "delete_confirm_content": "Вы уверены, что хотите удалить {{count}} записей памяти?", + "delete_confirm_single": "Вы уверены, что хотите удалить это воспоминание?", + "delete_confirm_title": "Удалить память", + "delete_failed": "Не удалось удалить память", + "delete_selected": "Удалить выбранные", + "delete_success": "Память успешно удалена", + "delete_user": "Удалить пользователя", + "delete_user_confirm_content": "Вы уверены, что хотите удалить пользователя {{user}} и все его воспоминания?", + "delete_user_confirm_title": "Удалить пользователя", + "delete_user_failed": "Не удалось удалить пользователя", + "description": "Память позволяет хранить и управлять информацией о ваших взаимодействиях с ассистентом. Вы можете добавлять, редактировать и удалять воспоминания, а также фильтровать и искать их.", + "edit_memory": "Редактировать память", + "embedding_dimensions": "Размерность вложения", + "embedding_model": "Модель встраивания", + "enable_global_memory_first": "Сначала включите глобальную память", + "end_date": "Дата окончания", + "global_memory": "Глобальная память", + "global_memory_description": "Для использования функций памяти необходимо включить глобальную память в настройках ассистента.", + "global_memory_disabled_desc": "Чтобы использовать функции памяти, сначала включите глобальную память в настройках ассистента.", + "global_memory_disabled_title": "Глобальная память отключена", + "global_memory_enabled": "Глобальная память включена", + "go_to_memory_page": "Перейти на страницу памяти", + "initial_memory_content": "Добро пожаловать! Это ваше первое воспоминание.", + "llm_model": "Модель LLM", + "load_failed": "Не удалось загрузить память", + "loading": "Загрузка воспоминаний...", + "loading_memories": "Загрузка воспоминаний...", + "memories_description": "Показано {{count}} из {{total}} записей памяти", + "memories_reset_success": "Все воспоминания пользователя {{user}} успешно сброшены", + "memory": "воспоминаний", + "memory_content": "Содержимое памяти", + "memory_placeholder": "Введите содержимое памяти...", + "new_user_id": "Новый ID пользователя", + "new_user_id_placeholder": "Введите уникальный ID пользователя", + "no_matching_memories": "Подходящие воспоминания не найдены", + "no_memories": "Нет воспоминаний", + "no_memories_description": "Начните с добавления вашего первого воспоминания", + "not_configured_desc": "Пожалуйста, настройте модели встраивания и LLM в настройках памяти, чтобы включить функциональность памяти.", + "not_configured_title": "Память не настроена", + "pagination_total": "{{start}}-{{end}} из {{total}} элементов", + "please_enter_memory": "Пожалуйста, введите содержимое памяти", + "please_select_embedding_model": "Пожалуйста, выберите модель для внедрения", + "please_select_llm_model": "Пожалуйста, выберите модель LLM", + "reset_filters": "Сбросить фильтры", + "reset_memories": "Сбросить воспоминания", + "reset_memories_confirm_content": "Вы уверены, что хотите навсегда удалить все воспоминания пользователя {{user}}? Это действие нельзя отменить.", + "reset_memories_confirm_title": "Сбросить все воспоминания", + "reset_memories_failed": "Не удалось сбросить воспоминания", + "reset_user_memories": "Сбросить воспоминания пользователя", + "reset_user_memories_confirm_content": "Вы уверены, что хотите сбросить все воспоминания пользователя {{user}}?", + "reset_user_memories_confirm_title": "Сбросить воспоминания пользователя", + "reset_user_memories_failed": "Не удалось сбросить воспоминания пользователя", + "score": "Оценка", + "search": "Поиск", + "search_placeholder": "Поиск памяти...", + "select_embedding_model_placeholder": "Выберите модель внедрения", + "select_llm_model_placeholder": "Выбор модели LLM", + "select_user": "Выбрать пользователя", + "settings": "Настройки", + "settings_title": "Настройки памяти", + "start_date": "Дата начала", + "statistics": "Статистика", + "stored_memories": "Запасённые воспоминания", + "switch_user": "Переключить пользователя", + "switch_user_confirm": "Переключить контекст пользователя на {{user}}?", + "time": "Время", + "title": "Глобальная память", + "total_memories": "всего воспоминаний", + "try_different_filters": "Попробуйте изменить критерии поиска", + "update_failed": "Не удалось обновить память", + "update_success": "Память успешно обновлена", + "user": "Пользователь", + "user_created": "Пользователь {{user}} создан и переключен успешно", + "user_deleted": "Пользователь {{user}} успешно удален", + "user_id": "ID пользователя", + "user_id_exists": "Этот ID пользователя уже существует", + "user_id_invalid_chars": "ID пользователя может содержать только буквы, цифры, дефисы и подчёркивания", + "user_id_placeholder": "Введите ID пользователя (необязательно)", + "user_id_required": "ID пользователя обязателен", + "user_id_reserved": "'default-user' зарезервирован, используйте другой ID", + "user_id_rules": "ID пользователя должен быть уникальным и содержать только буквы, цифры, дефисы (-) и подчёркивания (_)", + "user_id_too_long": "ID пользователя не может превышать 50 символов", + "user_management": "Управление пользователями", + "user_memories_reset": "Все воспоминания пользователя {{user}} сброшены", + "user_switch_failed": "Не удалось переключить пользователя", + "user_switched": "Контекст пользователя переключен на {{user}}", + "users": "пользователи" + }, "message": { "agents": { "import.error": "Импорт не выполнен", @@ -753,13 +859,13 @@ "tools": { "abort_failed": "Вызов инструмента прерван", "aborted": "Вызов инструмента прерван", + "autoApproveEnabled": "Для этого инструмента включен автоматический одобрен", "cancelled": "Отменено", "completed": "Завершено", "error": "Произошла ошибка", "invoking": "Вызов", "pending": "Ожидание", "preview": "Предпросмотр", - "autoApproveEnabled": "Для этого инструмента включен автоматический одобрен", "raw": "Исходный" }, "topic.added": "Новый топик добавлен", @@ -785,9 +891,9 @@ "goBack": "Назад", "goForward": "Вперед", "minimize": "Свернуть встроенное приложение", + "openExternal": "Открыть в браузере", "open_link_external_off": "Текущий: Открыть ссылки в окне по умолчанию", "open_link_external_on": "Текущий: Открыть ссылки в браузере", - "openExternal": "Открыть в браузере", "refresh": "Обновить", "rightclick_copyurl": "ПКМ → Копировать URL" }, @@ -1323,9 +1429,9 @@ }, "settings": { "about": "О программе и обратная связь", - "about.checkingUpdate": "Проверка обновлений...", "about.checkUpdate": "Проверить обновления", "about.checkUpdate.available": "Обновить", + "about.checkingUpdate": "Проверка обновлений...", "about.contact.button": "Электронная почта", "about.contact.title": "Контакты", "about.debug.open": "Открыть", @@ -1653,6 +1759,10 @@ "backup.manager.title": "Управление резервными копиями", "backup.modal.filename.placeholder": "Введите имя файла резервной копии", "backup.modal.title": "Резервное копирование на WebDAV", + "disableStream": { + "help": "При включении файл загружается в память перед отправкой. Это может решить проблемы совместимости с некоторыми серверами WebDAV, не поддерживающими фрагментированную (chunked) загрузку, но увеличит потребление памяти.", + "title": "Отключить потоковую загрузку" + }, "host": "Хост WebDAV", "host.placeholder": "http://localhost:8080", "hour_interval_one": "{{count}} час", @@ -1673,11 +1783,7 @@ "syncError": "Ошибка резервного копирования", "syncStatus": "Статус резервного копирования", "title": "WebDAV", - "user": "Пользователь WebDAV", - "disableStream": { - "title": "Отключить потоковую загрузку", - "help": "При включении файл загружается в память перед отправкой. Это может решить проблемы совместимости с некоторыми серверами WebDAV, не поддерживающими фрагментированную (chunked) загрузку, но увеличит потребление памяти." - } + "user": "Пользователь WebDAV" }, "yuque": { "check": { @@ -1764,23 +1870,24 @@ "addServer.create": "Быстрое создание", "addServer.importFrom": "Импорт из JSON", "addServer.importFrom.connectionFailed": "Сбой подключения", - "addServer.importFrom.invalid": "Неверный ввод, проверьте формат JSON", - "addServer.importFrom.nameExists": "Сервер уже существует: {{name}}", - "addServer.importFrom.oneServer": "Можно сохранить только один конфигурационный файл MCP", - "addServer.importFrom.method": "Метод импорта", + "addServer.importFrom.dxt": "Импорт DXT-пакета", "addServer.importFrom.dxtFile": "DXT-пакет", "addServer.importFrom.dxtHelp": "Выберите .dxt файл, содержащий MCP сервер", - "addServer.importFrom.selectDxtFile": "Выбрать DXT-файл", - "addServer.importFrom.noDxtFile": "Пожалуйста, выберите DXT-файл", "addServer.importFrom.dxtProcessFailed": "Не удалось обработать DXT-файл", - "addServer.importFrom.dxt": "Импорт DXT-пакета", + "addServer.importFrom.invalid": "Неверный ввод, проверьте формат JSON", + "addServer.importFrom.method": "Метод импорта", + "addServer.importFrom.nameExists": "Сервер уже существует: {{name}}", + "addServer.importFrom.noDxtFile": "Пожалуйста, выберите DXT-файл", + "addServer.importFrom.oneServer": "Можно сохранить только один конфигурационный файл MCP", "addServer.importFrom.placeholder": "Вставьте JSON-конфигурацию сервера MCP", + "addServer.importFrom.selectDxtFile": "[to be translated]:选择 DXT 文件", "addServer.importFrom.tooltip": "Скопируйте JSON-конфигурацию (приоритет NPX или UVX конфигураций) со страницы введения MCP Servers и вставьте ее в поле ввода.", "addSuccess": "Сервер успешно добавлен", "advancedSettings": "Расширенные настройки", "args": "Аргументы", "argsTooltip": "Каждый аргумент с новой строки", "baseUrlTooltip": "Адрес удаленного URL", + "builtinServers": "Встроенные серверы", "command": "Команда", "config_description": "Настройка серверов протокола контекста модели", "customRegistryPlaceholder": "Введите адрес частного склада, например: https://npm.company.com", @@ -1817,6 +1924,17 @@ "jsonSaveSuccess": "JSON конфигурация сохранена", "logoUrl": "URL логотипа", "missingDependencies": "отсутствует, пожалуйста, установите для продолжения.", + "more": { + "awesome": "Кураторский список серверов MCP", + "composio": "Инструменты разработки Composio MCP", + "glama": "Каталог серверов Glama MCP", + "higress": "Сервер Higress MCP", + "mcpso": "Платформа поиска серверов MCP", + "modelscope": "Сервер MCP сообщества ModelScope", + "official": "Официальная коллекция серверов MCP", + "pulsemcp": "Сервер Pulse MCP", + "smithery": "Инструменты Smithery MCP" + }, "name": "Имя", "newServer": "MCP сервер", "noDescriptionAvailable": "Описание отсутствует", @@ -1849,6 +1967,7 @@ "registry": "Реестр пакетов", "registryDefault": "По умолчанию", "registryTooltip": "Выберите реестр для установки пакетов, если возникают проблемы с сетью при использовании реестра по умолчанию.", + "requiresConfig": "Требуется настройка", "resources": { "availableResources": "Доступные ресурсы", "blob": "Двоичные данные", @@ -1896,17 +2015,17 @@ "timeoutTooltip": "Тайм-аут в секундах для запросов к этому серверу, по умолчанию 60 секунд", "title": "Настройки MCP", "tools": { + "autoApprove": "Автоматическое одобрение", + "autoApprove.tooltip.confirm": "Вы уверены, что хотите выполнить этот инструмент MCP?", + "autoApprove.tooltip.disabled": "Инструмент будет требовать ручное одобрение перед выполнением", + "autoApprove.tooltip.enabled": "Инструмент будет автоматически выполняться без подтверждения", + "autoApprove.tooltip.howToEnable": "Включите инструмент, чтобы использовать автоматическое одобрение", "availableTools": "Доступные инструменты", + "enable": "Включить инструмент", "inputSchema": "Схема ввода", "inputSchema.enum.allowedValues": "Допустимые значения", "loadError": "Ошибка получения инструментов", "noToolsAvailable": "Нет доступных инструментов", - "enable": "Включить инструмент", - "autoApprove": "Автоматическое одобрение", - "autoApprove.tooltip.howToEnable": "Включите инструмент, чтобы использовать автоматическое одобрение", - "autoApprove.tooltip.enabled": "Инструмент будет автоматически выполняться без подтверждения", - "autoApprove.tooltip.disabled": "Инструмент будет требовать ручное одобрение перед выполнением", - "autoApprove.tooltip.confirm": "Вы уверены, что хотите выполнить этот инструмент MCP?", "run": "Выполнить" }, "type": "Тип", @@ -1919,20 +2038,7 @@ "updateError": "Ошибка обновления сервера", "updateSuccess": "Сервер успешно обновлен", "url": "URL", - "user": "Пользователь", - "requiresConfig": "Требуется настройка", - "builtinServers": "Встроенные серверы", - "more": { - "modelscope": "Сервер MCP сообщества ModelScope", - "higress": "Сервер Higress MCP", - "mcpso": "Платформа поиска серверов MCP", - "smithery": "Инструменты Smithery MCP", - "glama": "Каталог серверов Glama MCP", - "pulsemcp": "Сервер Pulse MCP", - "composio": "Инструменты разработки Composio MCP", - "official": "Официальная коллекция серверов MCP", - "awesome": "Кураторский список серверов MCP" - } + "user": "Пользователь" }, "messages.divider": "Показывать разделитель между сообщениями", "messages.divider.tooltip": "Не применимо к сообщениям в стиле пузырей", @@ -2126,6 +2232,7 @@ "api_key": "Ключ API", "api_key.tip": "Несколько ключей, разделенных запятыми или пробелами", "api_version": "Версия API", + "azure.apiversion.tip": "Версия API Azure OpenAI. Если вы хотите использовать Response API, введите версию preview", "basic_auth": "HTTP аутентификация", "basic_auth.password": "Пароль", "basic_auth.password.tip": "", @@ -2222,17 +2329,16 @@ "private_key_placeholder": "Введите приватный ключ Service Account", "title": "Конфигурация Service Account" } - }, - "azure.apiversion.tip": "Версия API Azure OpenAI. Если вы хотите использовать Response API, введите версию preview" + } }, "proxy": { + "address": "Адрес прокси", "mode": { "custom": "Пользовательский прокси", "none": "Не использовать прокси", "system": "Системный прокси", "title": "Режим прокси" - }, - "address": "Адрес прокси" + } }, "quickAssistant": { "click_tray_to_show": "Нажмите на иконку трея для запуска", @@ -2455,115 +2561,9 @@ }, "words": { "knowledgeGraph": "Граф знаний", - "quit": "Выйти", + "quit": "[to be translated]:退出", "show_window": "Показать окно", "visualization": "Визуализация" - }, - "memory": { - "title": "Глобальная память", - "add_memory": "Добавить память", - "edit_memory": "Редактировать память", - "memory_content": "Содержимое памяти", - "please_enter_memory": "Пожалуйста, введите содержимое памяти", - "memory_placeholder": "Введите содержимое памяти...", - "user_id": "ID пользователя", - "user_id_placeholder": "Введите ID пользователя (необязательно)", - "load_failed": "Не удалось загрузить память", - "add_success": "Память успешно добавлена", - "add_failed": "Не удалось добавить память", - "update_success": "Память успешно обновлена", - "update_failed": "Не удалось обновить память", - "delete_success": "Память успешно удалена", - "delete_failed": "Не удалось удалить память", - "delete_confirm_title": "Удалить память", - "delete_confirm_content": "Вы уверены, что хотите удалить {{count}} записей памяти?", - "delete_confirm": "Вы уверены, что хотите удалить эту запись памяти?", - "time": "Время", - "user": "Пользователь", - "content": "Содержимое", - "score": "Оценка", - "memories_description": "Показано {{count}} из {{total}} записей памяти", - "search_placeholder": "Поиск памяти...", - "start_date": "Дата начала", - "end_date": "Дата окончания", - "all_users": "Все пользователи", - "users": "пользователи", - "delete_selected": "Удалить выбранные", - "reset_filters": "Сбросить фильтры", - "pagination_total": "{{start}}-{{end}} из {{total}} элементов", - "current_user": "Текущий пользователь", - "select_user": "Выбрать пользователя", - "default_user": "Пользователь по умолчанию", - "switch_user": "Переключить пользователя", - "user_switched": "Контекст пользователя переключен на {{user}}", - "switch_user_confirm": "Переключить контекст пользователя на {{user}}?", - "add_user": "Добавить пользователя", - "add_new_user": "Добавить нового пользователя", - "new_user_id": "Новый ID пользователя", - "new_user_id_placeholder": "Введите уникальный ID пользователя", - "user_id_required": "ID пользователя обязателен", - "user_id_reserved": "'default-user' зарезервирован, используйте другой ID", - "user_id_exists": "Этот ID пользователя уже существует", - "user_id_too_long": "ID пользователя не может превышать 50 символов", - "user_id_invalid_chars": "ID пользователя может содержать только буквы, цифры, дефисы и подчёркивания", - "user_id_rules": "ID пользователя должен быть уникальным и содержать только буквы, цифры, дефисы (-) и подчёркивания (_)", - "user_created": "Пользователь {{user}} создан и переключен успешно", - "add_user_failed": "Не удалось добавить пользователя", - "memory": "воспоминаний", - "reset_user_memories": "Сбросить воспоминания пользователя", - "reset_memories": "Сбросить воспоминания", - "delete_user": "Удалить пользователя", - "loading_memories": "Загрузка воспоминаний...", - "no_memories": "Нет воспоминаний", - "no_matching_memories": "Подходящие воспоминания не найдены", - "no_memories_description": "Начните с добавления вашего первого воспоминания", - "try_different_filters": "Попробуйте изменить критерии поиска", - "add_first_memory": "Добавить первое воспоминание", - "user_switch_failed": "Не удалось переключить пользователя", - "cannot_delete_default_user": "Нельзя удалить пользователя по умолчанию", - "delete_user_confirm_title": "Удалить пользователя", - "delete_user_confirm_content": "Вы уверены, что хотите удалить пользователя {{user}} и все его воспоминания?", - "user_deleted": "Пользователь {{user}} успешно удален", - "delete_user_failed": "Не удалось удалить пользователя", - "reset_user_memories_confirm_title": "Сбросить воспоминания пользователя", - "reset_user_memories_confirm_content": "Вы уверены, что хотите сбросить все воспоминания пользователя {{user}}?", - "user_memories_reset": "Все воспоминания пользователя {{user}} сброшены", - "reset_user_memories_failed": "Не удалось сбросить воспоминания пользователя", - "reset_memories_confirm_title": "Сбросить все воспоминания", - "reset_memories_confirm_content": "Вы уверены, что хотите навсегда удалить все воспоминания пользователя {{user}}? Это действие нельзя отменить.", - "memories_reset_success": "Все воспоминания пользователя {{user}} успешно сброшены", - "reset_memories_failed": "Не удалось сбросить воспоминания", - "delete_confirm_single": "Вы уверены, что хотите удалить это воспоминание?", - "total_memories": "всего воспоминаний", - "default": "По умолчанию", - "custom": "Пользовательский", - "description": "Память позволяет хранить и управлять информацией о ваших взаимодействиях с ассистентом. Вы можете добавлять, редактировать и удалять воспоминания, а также фильтровать и искать их.", - "global_memory_enabled": "Глобальная память включена", - "global_memory": "Глобальная память", - "enable_global_memory_first": "Сначала включите глобальную память", - "configure_memory_first": "Сначала настройте параметры памяти", - "global_memory_disabled_title": "Глобальная память отключена", - "global_memory_disabled_desc": "Чтобы использовать функции памяти, сначала включите глобальную память в настройках ассистента.", - "not_configured_title": "Память не настроена", - "not_configured_desc": "Пожалуйста, настройте модели встраивания и LLM в настройках памяти, чтобы включить функциональность памяти.", - "go_to_memory_page": "Перейти на страницу памяти", - "settings": "Настройки", - "statistics": "Статистика", - "search": "Поиск", - "actions": "Действия", - "user_management": "Управление пользователями", - "initial_memory_content": "Добро пожаловать! Это ваше первое воспоминание.", - "loading": "Загрузка воспоминаний...", - "settings_title": "Настройки памяти", - "llm_model": "Модель LLM", - "please_select_llm_model": "Пожалуйста, выберите модель LLM", - "select_llm_model_placeholder": "Выбор модели LLM", - "embedding_model": "Модель встраивания", - "please_select_embedding_model": "Пожалуйста, выберите модель для внедрения", - "select_embedding_model_placeholder": "Выберите модель внедрения", - "embedding_dimensions": "Размерность вложения", - "stored_memories": "Запасённые воспоминания", - "global_memory_description": "Для использования функций памяти необходимо включить глобальную память в настройках ассистента." } } } diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 6a5ef80ef..ceaebd274 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -204,6 +204,7 @@ "input.upload": "上传图片或文档", "input.upload.document": "上传文档(模型不支持图片)", "input.upload.upload_from_local": "上传本地文件...", + "input.url_context": "网页上下文", "input.web_search": "网络搜索", "input.web_search.builtin": "模型内置", "input.web_search.builtin.disabled_content": "当前模型不支持网络搜索功能", @@ -214,7 +215,6 @@ "input.web_search.no_web_search": "不使用网络", "input.web_search.no_web_search.description": "不启用网络搜索功能", "input.web_search.settings": "网络搜索设置", - "input.url_context": "网页上下文", "message.new.branch": "分支", "message.new.branch.created": "新分支已创建", "message.new.context": "清除上下文", @@ -237,32 +237,32 @@ "save": "保存", "save.file.title": "保存到本地文件", "save.knowledge": { - "title": "保存到知识库", - "content.maintext.title": "主文本", - "content.maintext.description": "包括主要的文本内容", - "content.code.title": "代码块", - "content.code.description": "包括独立的代码块", - "content.thinking.title": "思考", - "content.thinking.description": "包括模型思考内容", - "content.tool_use.title": "工具调用", - "content.tool_use.description": "包括工具调用参数和执行结果", - "content.citation.title": "引用", "content.citation.description": "包括网络搜索和知识库引用信息", - "content.translation.title": "翻译", - "content.translation.description": "包括翻译内容", - "content.error.title": "错误", + "content.citation.title": "引用", + "content.code.description": "包括独立的代码块", + "content.code.title": "代码块", "content.error.description": "包括执行过程中的错误信息", - "content.file.title": "文件", + "content.error.title": "错误", "content.file.description": "包括作为附件的文件", + "content.file.title": "文件", + "content.maintext.description": "包括主要的文本内容", + "content.maintext.title": "主文本", + "content.thinking.description": "包括模型思考内容", + "content.thinking.title": "思考", + "content.tool_use.description": "包括工具调用参数和执行结果", + "content.tool_use.title": "工具调用", + "content.translation.description": "包括翻译内容", + "content.translation.title": "翻译", "empty.no_content": "此消息没有可保存的内容", "empty.no_knowledge_base": "暂无可用知识库,请先创建知识库", - "error.save_failed": "保存失败,请检查知识库配置", "error.invalid_base": "所选知识库未正确配置", "error.no_content_selected": "请至少选择一种内容", - "select.base.title": "选择知识库", + "error.save_failed": "保存失败,请检查知识库配置", "select.base.placeholder": "请选择知识库", + "select.base.title": "选择知识库", + "select.content.tip": "已选择 {{count}} 项内容,文本类型将合并保存为一个笔记", "select.content.title": "选择要保存的内容类型", - "select.content.tip": "已选择 {{count}} 项内容,文本类型将合并保存为一个笔记" + "title": "保存到知识库" }, "settings.code.title": "代码块设置", "settings.code_collapsible": "代码块可折叠", @@ -361,12 +361,6 @@ "topics.unpinned": "取消固定", "translate": "翻译" }, - "html_artifacts": { - "code": "代码", - "generating": "生成中", - "preview": "预览", - "split": "分屏" - }, "code_block": { "collapse": "收起", "copy": "复制", @@ -428,6 +422,7 @@ "footnote": "引用内容", "footnotes": "引用内容", "fullscreen": "已进入全屏模式,按 F11 退出", + "i_know": "我知道了", "inspect": "检查", "knowledge_base": "知识库", "language": "语言", @@ -461,8 +456,7 @@ "swap": "交换", "topics": "话题", "warning": "警告", - "you": "用户", - "i_know": "我知道了" + "you": "用户" }, "docs": { "title": "帮助文档" @@ -545,6 +539,12 @@ "search.topics.empty": "没有找到相关话题,点击回车键搜索所有消息", "title": "话题搜索" }, + "html_artifacts": { + "code": "代码", + "generating": "生成中", + "preview": "预览", + "split": "分屏" + }, "knowledge": { "add": { "title": "添加知识库" @@ -661,6 +661,112 @@ "keep_alive_time.title": "保持活跃时间", "title": "LM Studio" }, + "memory": { + "actions": "操作", + "add_failed": "添加记忆失败", + "add_first_memory": "添加您的第一条记忆", + "add_memory": "添加记忆", + "add_new_user": "添加新用户", + "add_success": "记忆添加成功", + "add_user": "添加用户", + "add_user_failed": "添加用户失败", + "all_users": "所有用户", + "cannot_delete_default_user": "不能删除默认用户", + "configure_memory_first": "请先配置记忆设置", + "content": "内容", + "current_user": "当前用户", + "custom": "自定义", + "default": "默认", + "default_user": "默认用户", + "delete_confirm": "确定要删除这条记忆吗?", + "delete_confirm_content": "确定要删除 {{count}} 条记忆吗?", + "delete_confirm_single": "确定要删除这条记忆吗?", + "delete_confirm_title": "删除记忆", + "delete_failed": "删除记忆失败", + "delete_selected": "删除选中", + "delete_success": "记忆删除成功", + "delete_user": "删除用户", + "delete_user_confirm_content": "确定要删除用户 {{user}} 及其所有记忆吗?", + "delete_user_confirm_title": "删除用户", + "delete_user_failed": "删除用户失败", + "description": "记忆功能允许您存储和管理与助手交互的信息。您可以添加、编辑和删除记忆,也可以对它们进行过滤和搜索。", + "edit_memory": "编辑记忆", + "embedding_dimensions": "嵌入维度", + "embedding_model": "嵌入模型", + "enable_global_memory_first": "请先启用全局记忆", + "end_date": "结束日期", + "global_memory": "全局记忆", + "global_memory_description": "需要开启助手设置中的全局记忆才能使用", + "global_memory_disabled_desc": "要使用记忆功能,请先在助手设置中启用全局记忆。", + "global_memory_disabled_title": "全局记忆已禁用", + "global_memory_enabled": "全局记忆已启用", + "go_to_memory_page": "前往记忆页面", + "initial_memory_content": "欢迎!这是您的第一条记忆。", + "llm_model": "LLM 模型", + "load_failed": "加载记忆失败", + "loading": "正在加载记忆...", + "loading_memories": "正在加载记忆...", + "memories_description": "显示 {{count}} / {{total}} 条记忆", + "memories_reset_success": "{{user}} 的所有记忆已成功重置", + "memory": "条记忆", + "memory_content": "记忆内容", + "memory_placeholder": "输入记忆内容...", + "new_user_id": "新用户ID", + "new_user_id_placeholder": "输入唯一的用户ID", + "no_matching_memories": "未找到匹配的记忆", + "no_memories": "暂无记忆", + "no_memories_description": "开始添加您的第一条记忆吧", + "not_configured_desc": "请在记忆设置中配置嵌入和LLM模型以启用记忆功能。", + "not_configured_title": "记忆未配置", + "pagination_total": "第 {{start}}-{{end}} 项,共 {{total}} 项", + "please_enter_memory": "请输入记忆内容", + "please_select_embedding_model": "请选择嵌入模型", + "please_select_llm_model": "请选择 LLM 模型", + "reset_filters": "重置筛选", + "reset_memories": "重置记忆", + "reset_memories_confirm_content": "确定要永久删除 {{user}} 的所有记忆吗?此操作无法撤销。", + "reset_memories_confirm_title": "重置所有记忆", + "reset_memories_failed": "重置记忆失败", + "reset_user_memories": "重置用户记忆", + "reset_user_memories_confirm_content": "确定要重置 {{user}} 的所有记忆吗?", + "reset_user_memories_confirm_title": "重置用户记忆", + "reset_user_memories_failed": "重置用户记忆失败", + "score": "分数", + "search": "搜索", + "search_placeholder": "搜索记忆...", + "select_embedding_model_placeholder": "选择嵌入模型", + "select_llm_model_placeholder": "选择 LLM 模型", + "select_user": "选择用户", + "settings": "设置", + "settings_title": "记忆设置", + "start_date": "开始日期", + "statistics": "统计", + "stored_memories": "已存储记忆", + "switch_user": "切换用户", + "switch_user_confirm": "将用户上下文切换到 {{user}}?", + "time": "时间", + "title": "全局记忆", + "total_memories": "条记忆", + "try_different_filters": "尝试调整搜索条件", + "update_failed": "更新记忆失败", + "update_success": "记忆更新成功", + "user": "用户", + "user_created": "用户 {{user}} 创建并切换成功", + "user_deleted": "用户 {{user}} 删除成功", + "user_id": "用户 ID", + "user_id_exists": "该用户ID已存在", + "user_id_invalid_chars": "用户ID只能包含字母、数字、连字符和下划线", + "user_id_placeholder": "输入用户 ID(可选)", + "user_id_required": "用户ID为必填项", + "user_id_reserved": "'default-user' 为保留字,请使用其他ID", + "user_id_rules": "用户ID必须唯一,只能包含字母、数字、连字符(-)和下划线(_)", + "user_id_too_long": "用户ID不能超过50个字符", + "user_management": "用户管理", + "user_memories_reset": "{{user}} 的所有记忆已重置", + "user_switch_failed": "切换用户失败", + "user_switched": "用户上下文已切换到 {{user}}", + "users": "用户" + }, "message": { "agents": { "import.error": "导入失败", @@ -753,13 +859,13 @@ "tools": { "abort_failed": "工具调用中断失败", "aborted": "工具调用已中断", + "autoApproveEnabled": "此工具已启用自动批准", "cancelled": "已取消", "completed": "已完成", "error": "发生错误", "invoking": "调用中", "pending": "等待中", "preview": "预览", - "autoApproveEnabled": "此工具已启用自动批准", "raw": "原始" }, "topic.added": "话题添加成功", @@ -785,9 +891,9 @@ "goBack": "后退", "goForward": "前进", "minimize": "最小化小程序", + "openExternal": "在浏览器中打开", "open_link_external_off": "当前:使用默认窗口打开链接", "open_link_external_on": "当前:在浏览器中打开链接", - "openExternal": "在浏览器中打开", "refresh": "刷新", "rightclick_copyurl": "右键复制 URL" }, @@ -1323,9 +1429,9 @@ }, "settings": { "about": "关于我们", - "about.checkingUpdate": "正在检查更新...", "about.checkUpdate": "检查更新", "about.checkUpdate.available": "立即更新", + "about.checkingUpdate": "正在检查更新...", "about.contact.button": "邮件", "about.contact.title": "邮件联系", "about.debug.open": "打开", @@ -1653,6 +1759,10 @@ "backup.manager.title": "备份数据管理", "backup.modal.filename.placeholder": "请输入备份文件名", "backup.modal.title": "备份到 WebDAV", + "disableStream": { + "help": "开启后,将文件加载到内存中再上传,可解决部分WebDAV服务不兼容chunked上传的问题,但会增加内存占用。", + "title": "禁用流式上传" + }, "host": "WebDAV 地址", "host.placeholder": "http://localhost:8080", "hour_interval_one": "{{count}} 小时", @@ -1673,11 +1783,7 @@ "syncError": "备份错误", "syncStatus": "备份状态", "title": "WebDAV", - "user": "WebDAV 用户名", - "disableStream": { - "title": "禁用流式上传", - "help": "开启后,将文件加载到内存中再上传,可解决部分WebDAV服务不兼容chunked上传的问题,但会增加内存占用。" - } + "user": "WebDAV 用户名" }, "yuque": { "check": { @@ -1764,23 +1870,24 @@ "addServer.create": "快速创建", "addServer.importFrom": "从 JSON 导入", "addServer.importFrom.connectionFailed": "連接失敗", - "addServer.importFrom.invalid": "无效输入,请检查 JSON 格式", - "addServer.importFrom.nameExists": "服务器已存在:{{name}}", - "addServer.importFrom.oneServer": "每次只能保存一個 MCP 伺服器配置", - "addServer.importFrom.method": "导入方式", + "addServer.importFrom.dxt": "导入 DXT 包", "addServer.importFrom.dxtFile": "DXT 包文件", "addServer.importFrom.dxtHelp": "选择包含 MCP 服务器的 .dxt 文件", - "addServer.importFrom.selectDxtFile": "选择 DXT 文件", - "addServer.importFrom.noDxtFile": "请选择一个 DXT 文件", "addServer.importFrom.dxtProcessFailed": "处理 DXT 文件失败", - "addServer.importFrom.dxt": "导入 DXT 包", + "addServer.importFrom.invalid": "无效输入,请检查 JSON 格式", + "addServer.importFrom.method": "导入方式", + "addServer.importFrom.nameExists": "服务器已存在:{{name}}", + "addServer.importFrom.noDxtFile": "请选择一个 DXT 文件", + "addServer.importFrom.oneServer": "每次只能保存一個 MCP 伺服器配置", "addServer.importFrom.placeholder": "粘贴 MCP 服务器 JSON 配置", + "addServer.importFrom.selectDxtFile": "选择 DXT 文件", "addServer.importFrom.tooltip": "请从 MCP Servers 的介绍页面复制配置 JSON(优先使用\n NPX 或 UVX 配置),并粘贴到输入框中", "addSuccess": "服务器添加成功", "advancedSettings": "高级设置", "args": "参数", "argsTooltip": "每个参数占一行", "baseUrlTooltip": "远程 URL 地址", + "builtinServers": "内置服务器", "command": "命令", "config_description": "配置模型上下文协议服务器", "customRegistryPlaceholder": "请输入私有仓库地址,如: https://npm.company.com", @@ -1817,6 +1924,17 @@ "jsonSaveSuccess": "JSON 配置已保存", "logoUrl": "标志网址", "missingDependencies": "缺失,请安装它以继续", + "more": { + "awesome": "精选的 MCP 服务器列表", + "composio": "Composio MCP 开发工具", + "glama": "Glama MCP 服务器目录", + "higress": "Higress MCP 服务器", + "mcpso": "MCP 服务器发现平台", + "modelscope": "魔搭社区 MCP 服务器", + "official": "官方 MCP 服务器集合", + "pulsemcp": "Pulse MCP 服务器", + "smithery": "Smithery MCP 工具" + }, "name": "名称", "newServer": "MCP 服务器", "noDescriptionAvailable": "暂无描述", @@ -1849,6 +1967,7 @@ "registry": "包管理源", "registryDefault": "默认", "registryTooltip": "选择用于安装包的源,以解决默认源的网络问题", + "requiresConfig": "需要配置", "resources": { "availableResources": "可用资源", "blob": "二进制数据", @@ -1896,17 +2015,17 @@ "timeoutTooltip": "对该服务器请求的超时时间(秒),默认为 60 秒", "title": "MCP 设置", "tools": { + "autoApprove": "自动批准", + "autoApprove.tooltip.confirm": "是否运行该MCP工具?", + "autoApprove.tooltip.disabled": "工具运行前需要手动批准", + "autoApprove.tooltip.enabled": "工具将自动运行而无需批准", + "autoApprove.tooltip.howToEnable": "启用工具后才能使用自动批准", "availableTools": "可用工具", + "enable": "启用工具", "inputSchema": "输入模式", "inputSchema.enum.allowedValues": "允许的值", "loadError": "获取工具失败", "noToolsAvailable": "无可用工具", - "enable": "启用工具", - "autoApprove": "自动批准", - "autoApprove.tooltip.howToEnable": "启用工具后才能使用自动批准", - "autoApprove.tooltip.enabled": "工具将自动运行而无需批准", - "autoApprove.tooltip.disabled": "工具运行前需要手动批准", - "autoApprove.tooltip.confirm": "是否运行该MCP工具?", "run": "运行" }, "type": "类型", @@ -1919,20 +2038,7 @@ "updateError": "更新服务器失败", "updateSuccess": "服务器更新成功", "url": "URL", - "user": "用户", - "requiresConfig": "需要配置", - "builtinServers": "内置服务器", - "more": { - "modelscope": "魔搭社区 MCP 服务器", - "higress": "Higress MCP 服务器", - "mcpso": "MCP 服务器发现平台", - "smithery": "Smithery MCP 工具", - "glama": "Glama MCP 服务器目录", - "pulsemcp": "Pulse MCP 服务器", - "composio": "Composio MCP 开发工具", - "official": "官方 MCP 服务器集合", - "awesome": "精选的 MCP 服务器列表" - } + "user": "用户" }, "messages.divider": "消息分割线", "messages.divider.tooltip": "不适用于气泡样式消息", @@ -2226,13 +2332,13 @@ } }, "proxy": { + "address": "代理地址", "mode": { "custom": "自定义代理", "none": "不使用代理", "system": "系统代理", "title": "代理模式" - }, - "address": "代理地址" + } }, "quickAssistant": { "click_tray_to_show": "点击托盘图标启动", @@ -2458,112 +2564,6 @@ "quit": "退出", "show_window": "显示窗口", "visualization": "可视化" - }, - "memory": { - "title": "全局记忆", - "settings": "设置", - "statistics": "统计", - "search": "搜索", - "actions": "操作", - "add_memory": "添加记忆", - "edit_memory": "编辑记忆", - "memory_content": "记忆内容", - "please_enter_memory": "请输入记忆内容", - "memory_placeholder": "输入记忆内容...", - "user_id": "用户 ID", - "user_id_placeholder": "输入用户 ID(可选)", - "load_failed": "加载记忆失败", - "add_success": "记忆添加成功", - "add_failed": "添加记忆失败", - "update_success": "记忆更新成功", - "update_failed": "更新记忆失败", - "delete_success": "记忆删除成功", - "delete_failed": "删除记忆失败", - "delete_confirm_title": "删除记忆", - "delete_confirm_content": "确定要删除 {{count}} 条记忆吗?", - "delete_confirm": "确定要删除这条记忆吗?", - "time": "时间", - "user": "用户", - "content": "内容", - "score": "分数", - "memories_description": "显示 {{count}} / {{total}} 条记忆", - "search_placeholder": "搜索记忆...", - "start_date": "开始日期", - "end_date": "结束日期", - "all_users": "所有用户", - "users": "用户", - "delete_selected": "删除选中", - "reset_filters": "重置筛选", - "pagination_total": "第 {{start}}-{{end}} 项,共 {{total}} 项", - "current_user": "当前用户", - "select_user": "选择用户", - "default_user": "默认用户", - "switch_user": "切换用户", - "user_switched": "用户上下文已切换到 {{user}}", - "switch_user_confirm": "将用户上下文切换到 {{user}}?", - "add_user": "添加用户", - "add_new_user": "添加新用户", - "new_user_id": "新用户ID", - "new_user_id_placeholder": "输入唯一的用户ID", - "user_management": "用户管理", - "user_id_required": "用户ID为必填项", - "user_id_reserved": "'default-user' 为保留字,请使用其他ID", - "user_id_exists": "该用户ID已存在", - "user_id_too_long": "用户ID不能超过50个字符", - "user_id_invalid_chars": "用户ID只能包含字母、数字、连字符和下划线", - "user_id_rules": "用户ID必须唯一,只能包含字母、数字、连字符(-)和下划线(_)", - "user_created": "用户 {{user}} 创建并切换成功", - "add_user_failed": "添加用户失败", - "memory": "条记忆", - "reset_user_memories": "重置用户记忆", - "reset_memories": "重置记忆", - "delete_user": "删除用户", - "loading_memories": "正在加载记忆...", - "no_memories": "暂无记忆", - "no_matching_memories": "未找到匹配的记忆", - "no_memories_description": "开始添加您的第一条记忆吧", - "try_different_filters": "尝试调整搜索条件", - "add_first_memory": "添加您的第一条记忆", - "user_switch_failed": "切换用户失败", - "cannot_delete_default_user": "不能删除默认用户", - "delete_user_confirm_title": "删除用户", - "delete_user_confirm_content": "确定要删除用户 {{user}} 及其所有记忆吗?", - "user_deleted": "用户 {{user}} 删除成功", - "delete_user_failed": "删除用户失败", - "reset_user_memories_confirm_title": "重置用户记忆", - "reset_user_memories_confirm_content": "确定要重置 {{user}} 的所有记忆吗?", - "user_memories_reset": "{{user}} 的所有记忆已重置", - "reset_user_memories_failed": "重置用户记忆失败", - "reset_memories_confirm_title": "重置所有记忆", - "reset_memories_confirm_content": "确定要永久删除 {{user}} 的所有记忆吗?此操作无法撤销。", - "memories_reset_success": "{{user}} 的所有记忆已成功重置", - "reset_memories_failed": "重置记忆失败", - "delete_confirm_single": "确定要删除这条记忆吗?", - "total_memories": "条记忆", - "default": "默认", - "custom": "自定义", - "description": "记忆功能允许您存储和管理与助手交互的信息。您可以添加、编辑和删除记忆,也可以对它们进行过滤和搜索。", - "global_memory_enabled": "全局记忆已启用", - "global_memory": "全局记忆", - "enable_global_memory_first": "请先启用全局记忆", - "configure_memory_first": "请先配置记忆设置", - "global_memory_disabled_title": "全局记忆已禁用", - "global_memory_disabled_desc": "要使用记忆功能,请先在助手设置中启用全局记忆。", - "not_configured_title": "记忆未配置", - "not_configured_desc": "请在记忆设置中配置嵌入和LLM模型以启用记忆功能。", - "go_to_memory_page": "前往记忆页面", - "initial_memory_content": "欢迎!这是您的第一条记忆。", - "loading": "正在加载记忆...", - "settings_title": "记忆设置", - "llm_model": "LLM 模型", - "please_select_llm_model": "请选择 LLM 模型", - "select_llm_model_placeholder": "选择 LLM 模型", - "embedding_model": "嵌入模型", - "please_select_embedding_model": "请选择嵌入模型", - "select_embedding_model_placeholder": "选择嵌入模型", - "embedding_dimensions": "嵌入维度", - "stored_memories": "已存储记忆", - "global_memory_description": "需要开启助手设置中的全局记忆才能使用" } } } diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 6201d1104..0a5b5936b 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -204,6 +204,7 @@ "input.upload": "上傳圖片或文件", "input.upload.document": "上傳文件(模型不支援圖片)", "input.upload.upload_from_local": "上傳本地文件...", + "input.url_context": "網頁上下文", "input.web_search": "網路搜尋", "input.web_search.builtin": "模型內置", "input.web_search.builtin.disabled_content": "當前模型不支持網路搜尋功能", @@ -214,7 +215,6 @@ "input.web_search.no_web_search": "關閉網路搜尋", "input.web_search.no_web_search.description": "關閉網路搜尋", "input.web_search.settings": "網路搜尋設定", - "input.url_context": "網頁上下文", "message.new.branch": "分支", "message.new.branch.created": "新分支已建立", "message.new.context": "新上下文", @@ -235,33 +235,34 @@ }, "resend": "重新傳送", "save": "儲存", + "save.file.title": "[to be translated]:Save to Local File", "save.knowledge": { - "title": "儲存到知識庫", - "content.maintext.title": "主文本", - "content.maintext.description": "包括主要的文本內容", - "content.code.title": "程式碼區塊", - "content.code.description": "包括獨立的程式碼區塊", - "content.thinking.title": "思考過程", - "content.thinking.description": "包括模型思考內容", - "content.tool_use.title": "工具使用", - "content.tool_use.description": "包括工具呼叫參數和執行結果", - "content.citation.title": "引用", "content.citation.description": "包括網路搜尋和知識庫引用資訊", - "content.translation.title": "翻譯", - "content.translation.description": "包括翻譯內容", - "content.error.title": "錯誤", + "content.citation.title": "引用", + "content.code.description": "包括獨立的程式碼區塊", + "content.code.title": "程式碼區塊", "content.error.description": "包括執行過程中的錯誤資訊", - "content.file.title": "檔案", + "content.error.title": "錯誤", "content.file.description": "包括作為附件的檔案", + "content.file.title": "檔案", + "content.maintext.description": "包括主要的文本內容", + "content.maintext.title": "主文本", + "content.thinking.description": "包括模型思考內容", + "content.thinking.title": "思考過程", + "content.tool_use.description": "包括工具呼叫參數和執行結果", + "content.tool_use.title": "工具使用", + "content.translation.description": "包括翻譯內容", + "content.translation.title": "翻譯", "empty.no_content": "此訊息沒有可儲存的內容", "empty.no_knowledge_base": "暫無可用知識庫,請先建立知識庫", - "error.save_failed": "儲存失敗,請檢查知識庫設定", "error.invalid_base": "所選知識庫未正確設定", "error.no_content_selected": "請至少選擇一種內容類型", - "select.base.title": "選擇知識庫", + "error.save_failed": "儲存失敗,請檢查知識庫設定", "select.base.placeholder": "請選擇知識庫", + "select.base.title": "選擇知識庫", + "select.content.tip": "已選擇 {{count}} 項內容,文本類型將合併儲存為一個筆記", "select.content.title": "選擇要儲存的內容類型", - "select.content.tip": "已選擇 {{count}} 項內容,文本類型將合併儲存為一個筆記" + "title": "儲存到知識庫" }, "settings.code.title": "程式碼區塊", "settings.code_collapsible": "程式碼區塊可折疊", @@ -358,14 +359,7 @@ "topics.prompt.tips": "話題提示詞:針對目前話題提供額外的補充提示詞", "topics.title": "話題", "topics.unpinned": "取消固定", - "translate": "翻譯", - "save.file.title": "[to be translated]:Save to Local File" - }, - "html_artifacts": { - "code": "程式碼", - "generating": "生成中", - "preview": "預覽", - "split": "分屏" + "translate": "翻譯" }, "code_block": { "collapse": "折疊", @@ -428,6 +422,7 @@ "footnote": "引用內容", "footnotes": "引用", "fullscreen": "已進入全螢幕模式,按 F11 結束", + "i_know": "我知道了", "inspect": "檢查", "knowledge_base": "知識庫", "language": "語言", @@ -461,8 +456,7 @@ "swap": "交換", "topics": "話題", "warning": "警告", - "you": "您", - "i_know": "我知道了" + "you": "您" }, "docs": { "title": "說明文件" @@ -545,6 +539,12 @@ "search.topics.empty": "沒有找到相關話題,按 Enter 鍵搜尋所有訊息", "title": "搜尋話題" }, + "html_artifacts": { + "code": "程式碼", + "generating": "生成中", + "preview": "預覽", + "split": "分屏" + }, "knowledge": { "add": { "title": "新增知識庫" @@ -661,6 +661,112 @@ "keep_alive_time.title": "保持活躍時間", "title": "LM Studio" }, + "memory": { + "actions": "操作", + "add_failed": "新增記憶失敗", + "add_first_memory": "新增您的第一個記憶", + "add_memory": "新增記憶", + "add_new_user": "新增新使用者", + "add_success": "記憶新增成功", + "add_user": "新增使用者", + "add_user_failed": "新增使用者失敗", + "all_users": "所有使用者", + "cannot_delete_default_user": "不能刪除預設使用者", + "configure_memory_first": "請先配置記憶設定", + "content": "內容", + "current_user": "目前使用者", + "custom": "自定義", + "default": "預設", + "default_user": "預設使用者", + "delete_confirm": "確定要刪除這條記憶嗎?", + "delete_confirm_content": "確定要刪除 {{count}} 條記憶嗎?", + "delete_confirm_single": "確定要刪除這個記憶嗎?", + "delete_confirm_title": "刪除記憶", + "delete_failed": "刪除記憶失敗", + "delete_selected": "刪除選取", + "delete_success": "記憶刪除成功", + "delete_user": "刪除使用者", + "delete_user_confirm_content": "確定要刪除使用者 {{user}} 及其所有記憶嗎?", + "delete_user_confirm_title": "刪除使用者", + "delete_user_failed": "刪除使用者失敗", + "description": "記憶功能讓您儲存和管理與助手互動的資訊。您可以新增、編輯和刪除記憶,也可以對它們進行篩選和搜尋。", + "edit_memory": "編輯記憶", + "embedding_dimensions": "嵌入維度", + "embedding_model": "嵌入模型", + "enable_global_memory_first": "請先啟用全域記憶", + "end_date": "結束日期", + "global_memory": "全域記憶", + "global_memory_description": "需要開啟助手設定中的全域記憶才能使用", + "global_memory_disabled_desc": "要使用記憶功能,請先在助手設定中啟用全域記憶。", + "global_memory_disabled_title": "全域記憶已停用", + "global_memory_enabled": "全域記憶已啟用", + "go_to_memory_page": "前往記憶頁面", + "initial_memory_content": "歡迎!這是你的第一個記憶。", + "llm_model": "LLM 模型", + "load_failed": "載入記憶失敗", + "loading": "載入記憶中...", + "loading_memories": "正在載入記憶...", + "memories_description": "顯示 {{count}} / {{total}} 條記憶", + "memories_reset_success": "{{user}} 的所有記憶已成功重置", + "memory": "個記憶", + "memory_content": "記憶內容", + "memory_placeholder": "輸入記憶內容...", + "new_user_id": "新使用者ID", + "new_user_id_placeholder": "輸入唯一的使用者ID", + "no_matching_memories": "未找到符合的記憶", + "no_memories": "暫無記憶", + "no_memories_description": "開始新增您的第一個記憶吧", + "not_configured_desc": "請在記憶設定中配置嵌入和LLM模型以啟用記憶功能。", + "not_configured_title": "記憶未配置", + "pagination_total": "第 {{start}}-{{end}} 項,共 {{total}} 項", + "please_enter_memory": "請輸入記憶內容", + "please_select_embedding_model": "請選擇一個嵌入模型", + "please_select_llm_model": "請選擇一個LLM模型", + "reset_filters": "重設篩選", + "reset_memories": "重置記憶", + "reset_memories_confirm_content": "確定要永久刪除 {{user}} 的所有記憶嗎?此操作無法復原。", + "reset_memories_confirm_title": "重置所有記憶", + "reset_memories_failed": "重置記憶失敗", + "reset_user_memories": "重置使用者記憶", + "reset_user_memories_confirm_content": "確定要重置 {{user}} 的所有記憶嗎?", + "reset_user_memories_confirm_title": "重置使用者記憶", + "reset_user_memories_failed": "重置使用者記憶失敗", + "score": "分數", + "search": "搜尋", + "search_placeholder": "搜尋記憶...", + "select_embedding_model_placeholder": "選擇嵌入模型", + "select_llm_model_placeholder": "選擇LLM模型", + "select_user": "選擇使用者", + "settings": "設定", + "settings_title": "記憶體設定", + "start_date": "開始日期", + "statistics": "統計", + "stored_memories": "儲存的記憶", + "switch_user": "切換使用者", + "switch_user_confirm": "將使用者內容切換至 {{user}}?", + "time": "時間", + "title": "全域記憶", + "total_memories": "個記憶", + "try_different_filters": "嘗試調整搜尋條件", + "update_failed": "更新記憶失敗", + "update_success": "記憶更新成功", + "user": "使用者", + "user_created": "使用者 {{user}} 建立並切換成功", + "user_deleted": "使用者 {{user}} 刪除成功", + "user_id": "使用者ID", + "user_id_exists": "此使用者ID已存在", + "user_id_invalid_chars": "使用者ID只能包含字母、數字、連字符和底線", + "user_id_placeholder": "輸入使用者ID(可選)", + "user_id_required": "使用者ID為必填欄位", + "user_id_reserved": "'default-user' 為保留字,請使用其他ID", + "user_id_rules": "使用者ID必须唯一,只能包含字母、數字、連字符(-)和底線(_)", + "user_id_too_long": "使用者ID不能超過50個字元", + "user_management": "使用者管理", + "user_memories_reset": "{{user}} 的所有記憶已重置", + "user_switch_failed": "切換使用者失敗", + "user_switched": "使用者內容已切換至 {{user}}", + "users": "使用者" + }, "message": { "agents": { "import.error": "匯入失敗", @@ -753,13 +859,13 @@ "tools": { "abort_failed": "工具調用中斷失敗", "aborted": "工具調用已中斷", + "autoApproveEnabled": "此工具已啟用自動批准", "cancelled": "已取消", "completed": "已完成", "error": "發生錯誤", "invoking": "調用中", "pending": "等待中", "preview": "預覽", - "autoApproveEnabled": "此工具已啟用自動批准", "raw": "原始碼" }, "topic.added": "新話題已新增", @@ -785,9 +891,9 @@ "goBack": "上一頁", "goForward": "下一頁", "minimize": "最小化小工具", + "openExternal": "在瀏覽器中開啟", "open_link_external_off": "当前:使用預設視窗開啟連結", "open_link_external_on": "当前:在瀏覽器中開啟連結", - "openExternal": "在瀏覽器中開啟", "refresh": "重新整理", "rightclick_copyurl": "右鍵複製 URL" }, @@ -1323,9 +1429,9 @@ }, "settings": { "about": "關於與回饋", - "about.checkingUpdate": "正在檢查更新...", "about.checkUpdate": "檢查更新", "about.checkUpdate.available": "立即更新", + "about.checkingUpdate": "正在檢查更新...", "about.contact.button": "電子郵件", "about.contact.title": "聯絡方式", "about.debug.open": "開啟", @@ -1653,6 +1759,10 @@ "backup.manager.title": "備份數據管理", "backup.modal.filename.placeholder": "請輸入備份文件名", "backup.modal.title": "備份到 WebDAV", + "disableStream": { + "help": "開啟後,將檔案載入到記憶體中再上傳,可解決部分 WebDAV 服務不相容 chunked 上傳的問題,但會增加記憶體佔用。", + "title": "禁用串流上傳" + }, "host": "WebDAV 主機位址", "host.placeholder": "http://localhost:8080", "hour_interval_one": "{{count}} 小時", @@ -1673,11 +1783,7 @@ "syncError": "備份錯誤", "syncStatus": "備份狀態", "title": "WebDAV", - "user": "WebDAV 使用者名稱", - "disableStream": { - "title": "禁用串流上傳", - "help": "開啟後,將檔案載入到記憶體中再上傳,可解決部分 WebDAV 服務不相容 chunked 上傳的問題,但會增加記憶體佔用。" - } + "user": "WebDAV 使用者名稱" }, "yuque": { "check": { @@ -1764,23 +1870,24 @@ "addServer.create": "快速創建", "addServer.importFrom": "從 JSON 導入", "addServer.importFrom.connectionFailed": "連線失敗", - "addServer.importFrom.invalid": "無效的輸入,請檢查 JSON 格式", - "addServer.importFrom.nameExists": "伺服器已存在:{{name}}", - "addServer.importFrom.oneServer": "每次只能保存一個 MCP 伺服器配置", - "addServer.importFrom.method": "導入方式", + "addServer.importFrom.dxt": "導入 DXT 包", "addServer.importFrom.dxtFile": "DXT 包文件", "addServer.importFrom.dxtHelp": "選擇包含 MCP 服務器的 .dxt 文件", - "addServer.importFrom.selectDxtFile": "選擇 DXT 文件", - "addServer.importFrom.noDxtFile": "請選擇一個 DXT 文件", "addServer.importFrom.dxtProcessFailed": "處理 DXT 文件失敗", - "addServer.importFrom.dxt": "導入 DXT 包", + "addServer.importFrom.invalid": "無效的輸入,請檢查 JSON 格式", + "addServer.importFrom.method": "導入方式", + "addServer.importFrom.nameExists": "伺服器已存在:{{name}}", + "addServer.importFrom.noDxtFile": "請選擇一個 DXT 文件", + "addServer.importFrom.oneServer": "每次只能保存一個 MCP 伺服器配置", "addServer.importFrom.placeholder": "貼上 MCP 伺服器 JSON 設定", + "addServer.importFrom.selectDxtFile": "[to be translated]:选择 DXT 文件", "addServer.importFrom.tooltip": "請從 MCP Servers 的介紹頁面複製配置 JSON(優先使用\n NPX 或 UVX 配置),並粘貼到輸入框中", "addSuccess": "伺服器新增成功", "advancedSettings": "高級設定", "args": "參數", "argsTooltip": "每個參數佔一行", "baseUrlTooltip": "遠端 URL 地址", + "builtinServers": "內置伺服器", "command": "指令", "config_description": "設定模型上下文協議伺服器", "customRegistryPlaceholder": "請輸入私有倉庫位址,如: https://npm.company.com", @@ -1817,6 +1924,17 @@ "jsonSaveSuccess": "JSON 配置已儲存", "logoUrl": "標誌網址", "missingDependencies": "缺失,請安裝它以繼續", + "more": { + "awesome": "精選的 MCP 伺服器清單", + "composio": "Composio MCP 開發工具", + "glama": "Glama MCP 伺服器目錄", + "higress": "Higress MCP 伺服器", + "mcpso": "MCP 伺服器發現平台", + "modelscope": "魔搭社區 MCP 伺服器", + "official": "官方 MCP 伺服器集合", + "pulsemcp": "Pulse MCP 伺服器", + "smithery": "Smithery MCP 工具" + }, "name": "名稱", "newServer": "MCP 伺服器", "noDescriptionAvailable": "描述不存在", @@ -1849,6 +1967,7 @@ "registry": "套件管理源", "registryDefault": "預設", "registryTooltip": "選擇用於安裝套件的源,以解決預設源的網路問題", + "requiresConfig": "需要配置", "resources": { "availableResources": "可用資源", "blob": "二進位數據", @@ -1896,17 +2015,17 @@ "timeoutTooltip": "對該伺服器請求的超時時間(秒),預設為 60 秒", "title": "MCP 設定", "tools": { + "autoApprove": "自動批准", + "autoApprove.tooltip.confirm": "是否運行該MCP工具?", + "autoApprove.tooltip.disabled": "工具運行前需要手動批准", + "autoApprove.tooltip.enabled": "工具將自動運行而無需批准", + "autoApprove.tooltip.howToEnable": "啟用工具後才能使用自動批准", "availableTools": "可用工具", + "enable": "啟用工具", "inputSchema": "輸入模式", "inputSchema.enum.allowedValues": "允許的值", "loadError": "獲取工具失敗", "noToolsAvailable": "無可用工具", - "enable": "啟用工具", - "autoApprove": "自動批准", - "autoApprove.tooltip.howToEnable": "啟用工具後才能使用自動批准", - "autoApprove.tooltip.enabled": "工具將自動運行而無需批准", - "autoApprove.tooltip.disabled": "工具運行前需要手動批准", - "autoApprove.tooltip.confirm": "是否運行該MCP工具?", "run": "運行" }, "type": "類型", @@ -1919,20 +2038,7 @@ "updateError": "更新伺服器失敗", "updateSuccess": "伺服器更新成功", "url": "URL", - "user": "用戶", - "requiresConfig": "需要配置", - "builtinServers": "內置伺服器", - "more": { - "modelscope": "魔搭社區 MCP 伺服器", - "higress": "Higress MCP 伺服器", - "mcpso": "MCP 伺服器發現平台", - "smithery": "Smithery MCP 工具", - "glama": "Glama MCP 伺服器目錄", - "pulsemcp": "Pulse MCP 伺服器", - "composio": "Composio MCP 開發工具", - "official": "官方 MCP 伺服器集合", - "awesome": "精選的 MCP 伺服器清單" - } + "user": "用戶" }, "messages.divider": "訊息間顯示分隔線", "messages.divider.tooltip": "不適用於氣泡樣式消息", @@ -2126,6 +2232,7 @@ "api_key": "API 金鑰", "api_key.tip": "多個金鑰使用逗號或空格分隔", "api_version": "API 版本", + "azure.apiversion.tip": "Azure OpenAI 的 API 版本,如果想要使用 Response API,請輸入 preview 版本", "basic_auth": "HTTP 認證", "basic_auth.password": "密碼", "basic_auth.password.tip": "", @@ -2222,17 +2329,16 @@ "private_key_placeholder": "輸入服務帳戶私密金鑰", "title": "服務帳戶設定" } - }, - "azure.apiversion.tip": "Azure OpenAI 的 API 版本,如果想要使用 Response API,請輸入 preview 版本" + } }, "proxy": { + "address": "代理伺服器位址", "mode": { "custom": "自訂代理伺服器", "none": "不使用代理伺服器", "system": "系統代理伺服器", "title": "代理伺服器模式" - }, - "address": "代理伺服器位址" + } }, "quickAssistant": { "click_tray_to_show": "點選工具列圖示啟動", @@ -2455,115 +2561,9 @@ }, "words": { "knowledgeGraph": "知識圖譜", - "quit": "結束", + "quit": "[to be translated]:退出", "show_window": "顯示視窗", "visualization": "視覺化" - }, - "memory": { - "title": "全域記憶", - "add_memory": "新增記憶", - "edit_memory": "編輯記憶", - "memory_content": "記憶內容", - "please_enter_memory": "請輸入記憶內容", - "memory_placeholder": "輸入記憶內容...", - "user_id": "使用者ID", - "user_id_placeholder": "輸入使用者ID(可選)", - "load_failed": "載入記憶失敗", - "add_success": "記憶新增成功", - "add_failed": "新增記憶失敗", - "update_success": "記憶更新成功", - "update_failed": "更新記憶失敗", - "delete_success": "記憶刪除成功", - "delete_failed": "刪除記憶失敗", - "delete_confirm_title": "刪除記憶", - "delete_confirm_content": "確定要刪除 {{count}} 條記憶嗎?", - "delete_confirm": "確定要刪除這條記憶嗎?", - "time": "時間", - "user": "使用者", - "content": "內容", - "score": "分數", - "memories_description": "顯示 {{count}} / {{total}} 條記憶", - "search_placeholder": "搜尋記憶...", - "start_date": "開始日期", - "end_date": "結束日期", - "all_users": "所有使用者", - "users": "使用者", - "delete_selected": "刪除選取", - "reset_filters": "重設篩選", - "pagination_total": "第 {{start}}-{{end}} 項,共 {{total}} 項", - "current_user": "目前使用者", - "select_user": "選擇使用者", - "default_user": "預設使用者", - "switch_user": "切換使用者", - "user_switched": "使用者內容已切換至 {{user}}", - "switch_user_confirm": "將使用者內容切換至 {{user}}?", - "add_user": "新增使用者", - "add_new_user": "新增新使用者", - "new_user_id": "新使用者ID", - "new_user_id_placeholder": "輸入唯一的使用者ID", - "user_id_required": "使用者ID為必填欄位", - "user_id_reserved": "'default-user' 為保留字,請使用其他ID", - "user_id_exists": "此使用者ID已存在", - "user_id_too_long": "使用者ID不能超過50個字元", - "user_id_invalid_chars": "使用者ID只能包含字母、數字、連字符和底線", - "user_id_rules": "使用者ID必须唯一,只能包含字母、數字、連字符(-)和底線(_)", - "user_created": "使用者 {{user}} 建立並切換成功", - "add_user_failed": "新增使用者失敗", - "memory": "個記憶", - "reset_user_memories": "重置使用者記憶", - "reset_memories": "重置記憶", - "delete_user": "刪除使用者", - "loading_memories": "正在載入記憶...", - "no_memories": "暫無記憶", - "no_matching_memories": "未找到符合的記憶", - "no_memories_description": "開始新增您的第一個記憶吧", - "try_different_filters": "嘗試調整搜尋條件", - "add_first_memory": "新增您的第一個記憶", - "user_switch_failed": "切換使用者失敗", - "cannot_delete_default_user": "不能刪除預設使用者", - "delete_user_confirm_title": "刪除使用者", - "delete_user_confirm_content": "確定要刪除使用者 {{user}} 及其所有記憶嗎?", - "user_deleted": "使用者 {{user}} 刪除成功", - "delete_user_failed": "刪除使用者失敗", - "reset_user_memories_confirm_title": "重置使用者記憶", - "reset_user_memories_confirm_content": "確定要重置 {{user}} 的所有記憶嗎?", - "user_memories_reset": "{{user}} 的所有記憶已重置", - "reset_user_memories_failed": "重置使用者記憶失敗", - "reset_memories_confirm_title": "重置所有記憶", - "reset_memories_confirm_content": "確定要永久刪除 {{user}} 的所有記憶嗎?此操作無法復原。", - "memories_reset_success": "{{user}} 的所有記憶已成功重置", - "reset_memories_failed": "重置記憶失敗", - "delete_confirm_single": "確定要刪除這個記憶嗎?", - "total_memories": "個記憶", - "default": "預設", - "custom": "自定義", - "description": "記憶功能讓您儲存和管理與助手互動的資訊。您可以新增、編輯和刪除記憶,也可以對它們進行篩選和搜尋。", - "global_memory_enabled": "全域記憶已啟用", - "global_memory": "全域記憶", - "enable_global_memory_first": "請先啟用全域記憶", - "configure_memory_first": "請先配置記憶設定", - "global_memory_disabled_title": "全域記憶已停用", - "global_memory_disabled_desc": "要使用記憶功能,請先在助手設定中啟用全域記憶。", - "not_configured_title": "記憶未配置", - "not_configured_desc": "請在記憶設定中配置嵌入和LLM模型以啟用記憶功能。", - "go_to_memory_page": "前往記憶頁面", - "settings": "設定", - "statistics": "統計", - "search": "搜尋", - "actions": "操作", - "user_management": "使用者管理", - "initial_memory_content": "歡迎!這是你的第一個記憶。", - "loading": "載入記憶中...", - "settings_title": "記憶體設定", - "llm_model": "LLM 模型", - "please_select_llm_model": "請選擇一個LLM模型", - "select_llm_model_placeholder": "選擇LLM模型", - "embedding_model": "嵌入模型", - "please_select_embedding_model": "請選擇一個嵌入模型", - "select_embedding_model_placeholder": "選擇嵌入模型", - "embedding_dimensions": "嵌入維度", - "stored_memories": "儲存的記憶", - "global_memory_description": "需要開啟助手設定中的全域記憶才能使用" } } } diff --git a/tsconfig.node.json b/tsconfig.node.json index 50fe4405a..5ff3cbb7d 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -6,12 +6,14 @@ "src/preload/**/*", "src/main/env.d.ts", "src/renderer/src/types/*", - "packages/shared/**/*" + "packages/shared/**/*", + "scripts" ], "compilerOptions": { "composite": true, "types": [ - "electron-vite/node" + "electron-vite/node", + "vitest/globals" ], "baseUrl": ".", "paths": { diff --git a/vitest.config.ts b/vitest.config.ts index 9736d0ab5..bfb611ef2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -35,6 +35,15 @@ export default defineConfig({ setupFiles: ['@vitest/web-worker', 'tests/renderer.setup.ts'], include: ['src/renderer/**/*.{test,spec}.{ts,tsx}', 'src/renderer/**/__tests__/**/*.{test,spec}.{ts,tsx}'] } + }, + // 脚本单元测试配置 + { + extends: true, + test: { + name: 'scripts', + environment: 'node', + include: ['scripts/**/*.{test,spec}.{ts,tsx}', 'scripts/**/__tests__/**/*.{test,spec}.{ts,tsx}'] + } } ], // 全局共享配置 diff --git a/yarn.lock b/yarn.lock index 052b0aa5b..2c7a74225 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6977,6 +6977,7 @@ __metadata: pdfjs-dist: "npm:4.10.38" playwright: "npm:^1.52.0" prettier: "npm:^3.5.3" + prettier-plugin-sort-json: "npm:^4.1.1" proxy-agent: "npm:^6.5.0" rc-virtual-list: "npm:^3.18.6" react: "npm:^19.0.0" @@ -16305,6 +16306,15 @@ __metadata: languageName: node linkType: hard +"prettier-plugin-sort-json@npm:^4.1.1": + version: 4.1.1 + resolution: "prettier-plugin-sort-json@npm:4.1.1" + peerDependencies: + prettier: ^3.0.0 + checksum: 10c0/b3b86ea679e95d0329c367aa860af4033d8a3b83a0656d7393f2005b2df78e20d19fbe2c40fe7b531262210e40060318a4287459c2a4f61c6a6bd1c2757e2b7d + languageName: node + linkType: hard + "prettier@npm:^3.5.3": version: 3.5.3 resolution: "prettier@npm:3.5.3"