diff --git a/.i18nrc.js b/.i18nrc.js new file mode 100644 index 00000000..7bb8ff29 --- /dev/null +++ b/.i18nrc.js @@ -0,0 +1,47 @@ +const { defineConfig } = require('@lobehub/i18n-cli'); + +module.exports = defineConfig({ + entry: 'locales/zh-CN', + entryLocale: 'zh-CN', + output: 'locales', + outputLocales: [ + 'bg-BG', + 'zh-TW', + 'en-US', + 'ru-RU', + 'ja-JP', + 'ko-KR', + 'fr-FR', + 'tr-TR', + 'es-ES', + 'pt-BR', + 'de-DE', + 'it-IT', + 'nl-NL', + 'pl-PL', + 'vi-VN', + ], + temperature: 0, + modelName: 'gpt-3.5-turbo-0125', + splitToken: 2048, + experimental: { + jsonMode: true, + }, + // 后续说明文档、技术文档等所需的国际化配置(暂时不需要) + // markdown: { + // // reference: '你需要保持 mdx 的组件格式,输出文本不需要在最外层包裹任何代码块语法', + // entry: ['./README.zh-CN.md', './contributing/**/*.zh-CN.md', './docs/**/*.zh-CN.mdx'], + // entryLocale: 'zh-CN', + // outputLocales: ['en-US'], + // exclude: ['./contributing/_Sidebar.md', './contributing/_Footer.md', './contributing/Home.md'], + // outputExtensions: (locale, { filePath }) => { + // if (filePath.includes('.mdx')) { + // if (locale === 'en-US') return '.mdx'; + // return `.${locale}.mdx`; + // } else { + // if (locale === 'en-US') return '.md'; + // return `.${locale}.md`; + // } + // }, + // }, +}); diff --git a/locales/bg-BG/chat.json b/locales/bg-BG/chat.json new file mode 100644 index 00000000..6abb5f25 --- /dev/null +++ b/locales/bg-BG/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Чат", + "chatDialog": { + "close": "Затвори" + }, + "dance": "Танц", + "header": { + "role": "Роля", + "session": "Сесия" + }, + "helloChat": "Здравей, нека си поговорим", + "helloDance": "Здравей, нека танцуваме заедно", + "market": "Пазар" +} diff --git a/locales/bg-BG/common.json b/locales/bg-BG/common.json new file mode 100644 index 00000000..e60b5e95 --- /dev/null +++ b/locales/bg-BG/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Добавяне", + "clearAll": "Изчистване на всичко", + "clearContext": "Изчистване на контекст", + "clearHistoryTip": "Това действие не може да се отмени, моля, бъдете внимателни", + "clearHistoryTitle": "Сигурни ли сте, че искате да изтриете цялата история на сесията?", + "clearNow": "Изчистване сега", + "clearSuccess": "Изтриването е успешно", + "clearTip": "Това действие не може да се отмени, след изчистването данните няма да могат да бъдат възстановени.Моля, бъдете внимателни", + "clearTitle": "Потвърждение за изтриване на всички сесии?", + "confirmDel": "Сигурни ли сте, че искате да изтриете?", + "copy": "Копиране", + "copySuccess": "Копирането е успешно", + "del": "Изтриване", + "delAndRegenerate": "Изтриване и възстановяване", + "downloadAvatar": "Изтегляне на аватар", + "downloadCover": "Изтегляне на корица", + "downloadFailed": "Изтеглянето е неуспешно", + "downloadModel": "Изтегляне на модел", + "downloadSubscribe": "Изтеглянето на абонамент", + "downloadSuccess": "Изтеглянето е успешно", + "edit": "Редакция", + "goBottom": "Към долната част", + "market": "Пазар", + "pause": "Пауза", + "play": "Пусни", + "regenerate": "Възстановяване", + "removeInList": "Премахване от списъка", + "reset": "Нулиране", + "resetNow": "Нулиране сега", + "resetSuccess": "Нулирането е успешно", + "resetTip": "Това действие не може да се отмени, след нулирането данните няма да могат да бъдат възстановени.Моля, бъдете внимателни", + "resetTitle": "Потвърждение за нулиране на всички системни настройки?", + "save": "Запазване", + "send": "Изпращане", + "share": "Споделяне", + "subscribe": "Абониране", + "subscribeDance": "Абониране за танц", + "subscribeRole": "Абониране за роля", + "subscribed": "Абониран", + "unsubscribe": "Отписване", + "unsubscribeSuccess": "Отписването е успешно", + "warp": "Нов ред" + }, + "aiAlert": "Забележка: Всичко, което казва изкуственият интелект, е генерирано от AI", + "cancel": "Отказ", + "commonSetting": "Общи настройки", + "confirm": "Потвърждение", + "defaultAssistant": "По подразбиране асистент", + "delAlert": "Сигурни ли сте, че искате да изтриете ролята и свързаните с нея сесии? След изтриване те няма да бъдат възстановени, моля, действайте внимателно!", + "delRole": "Изтриване на роля", + "delSession": "Изтриване на сесия", + "delSessionAlert": "Сигурни ли сте, че искате да изтриете сесията? След изтриването, тя няма да бъде възстановена, моля, действайте внимателно!", + "inputStartChat": "Моля, въведете съдържание, за да започнете разговор", + "languageModel": "Езиков модел", + "loading": "Зареждане...", + "noData": "Няма налични данни", + "openai": { + "callError": "Грешка при извикване на интерфейса, моля, проверете дали API ключът и адресът на интерфейса са зададени правилно", + "check": "Проверка", + "checkAll": "Проверка на дали API ключа и адресът на интерфейса са зададени правилно", + "checkConnect": "Проверка на свързаността", + "checkOk": "Проверката е успешна", + "langModel": "OpenAI езиков модел", + "model": "Модел", + "proxyUrl": "Адрес на интерфейса", + "roleModel": "Role GPT модел", + "useOwnKey": "Моля, използвайте собствения си ключ за OpenAI" + }, + "playlist": "Плейлист", + "search": "Търсене", + "selectInDanceList": "Моля, изберете от списъка с танци", + "selectModel": "Изберете модел", + "setLocalStorage": "Задаване на локално съхранение", + "startChat": "Започни разговор", + "ttsCombine": "Синтез на глас", + "ttsTip": "Разпознаване на говор (пресичане на научни изследвания)", + "uploadTip": "Щракнете или пуснете файл тук, за да го качите", + "words": { + "DIYAvatar": "Персонализирани аватари", + "DIYBackgroundEffect": "Персонализирани ефекти на задния план", + "DIYColor": "Персонализирани цветови тенденции", + "DIYNickname": "Персонализирани прякори", + "DIYTopicColor": "Персонализирани цветове на теми", + "avatar": "Аватар", + "backgroundEffect": "Ефект на задния план", + "chatSetting": "Настройки за чат", + "clearAllSession": "Изчистване на всички сесии", + "clearAllSessionDesc": "Ще бъдат изчистени всички сесии и данни за ролите, включително списъкът със сесии, списъкът с роли, съобщенията на сесиите и т.н.", + "midColor": "Среден цвят", + "nickname": "Прякор", + "resetSystemSetting": "Нулиране на системните настройки", + "resetSystemSettingDesc": "Ще бъдат нулирани всички системни настройки, включително настройките за тема, настройките за чат, настройките на езиков модел и т.н.", + "systemSetting": "Системни настройки", + "languageSetting": "Настройки за език", + "topicColor": "Цвят на тема", + "topicSetting": "Настройки за тема" + } +} diff --git a/locales/bg-BG/constants.json b/locales/bg-BG/constants.json new file mode 100644 index 00000000..d4fb6c4e --- /dev/null +++ b/locales/bg-BG/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Жена", + "male": "Мъж", + "other": "Други" + }, + "meta": { + "description": "Това е персонализирана роля", + "name": "Персонализирана роля" + } + }, + "touch": { + "area": { + "arm": "Ръка", + "belly": "Стомах", + "chest": "Гърди", + "head": "Глава", + "leg": "Крак" + }, + "emotion": { + "angry": "Ядосан", + "blink": "Мигане", + "blinkLeft": "Мигане на ляво", + "blinkRight": "Мигане на дясно", + "happy": "Щастлив", + "natural": "Природен", + "relaxed": "Релаксиран", + "sad": "Тъжен", + "surprised": "Изненадан" + }, + "femaleAction": { + "armAction": { + "happyA": "Ох, как ми харесва~", + "happyB": "Хаха, държането на ръка ме прави щастлива~", + "relaxedA": "Ръката на стопанина е толкова топла~" + }, + "bellyAction": { + "angryA": "Защо ме докосваш, внимавай да не те ухапя!", + "relaxedA": "Събуди се, между нас няма бъдеще!", + "relaxedB": "Отвратително! Ще се ядосам!", + "surprisedA": "Сигурно беше случайно докосване..." + }, + "chestAction": { + "angryA": "Не можеш да ме обиждаш по този начин! Махни ръката си!", + "angryB": "Един-един-нула? Тук има един психопат, който постоянно ме гали!", + "angryC": "Ако ме галиш отново, ще трябва да се обадя на полицията", + "surprisedA": "Защо ме докосваш така? Не можем ли да се забавляваме с разговори!" + }, + "headAction": { + "angryA": "Чула съм, че ако те галят по главата, няма да пораснеш!", + "angryB": "Защо ме докосваш така?", + "happyA": "Уау! Обичам да ме галиш по главата!", + "happyB": "Почувствай се пълна с енергия отново!", + "happyC": "Уау, този усещане от галене по главата е толкова чудесно!", + "happyD": "Галенето по главата ме прави щастлива цял ден!" + }, + "legAction": { + "angryA": "Хей, ти ли се опитваш да си навлезен?", + "angryB": "Ръката на стопанина отново не слуша команди?", + "angryC": "Отвратително~ ще ме зачесе, знай!", + "surprisedA": "Защо не можем да запазим чисто приятелство?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Не ме питай дали днес ял пиле, първо погледни моите бицепси", + "neutralB": "Моята ръка не е за докосване от всеки, ти си изключение", + "neutralC": "Ти си много храбър, като се докосваш до легендарната ми ръка на кирин" + }, + "bellyAction": { + "happyA": "Не ме дразни, внимавай да не ме накараш да се смея с коремните ми мускули", + "neutralA": "Моите коремни мускули са скрити в дълбините на моето усърдие", + "neutralB": "Виждал ли си моите коремни мускули? Те просто са добре скрити" + }, + "chestAction": { + "blinkLeftA": "Елате, прилегни на моите гръдни мускули!", + "neutralA": "Това е само моят ежедневен тренировъчен успех на гръдните мускули, няма защо да се изненадваш." + }, + "headAction": { + "neutralA": "Разбира се, само ти имаш право да ме галиш по главата", + "neutralB": "Аз не съм обикновен човек, когото позволявам да ме докосва", + "neutralC": "Не се притеснявай, след като ме погалиш по главата, твоят късмет значително ще се подобри" + }, + "legAction": { + "angryA": "Дръж се далеч от мен, ти, кракофил", + "neutralA": "Не се страхувай, моето мощно желязно крако не удря глупаци", + "neutralB": "Като си докоснал моя крак, чувстваш ли, че животът ти стана по-пълен?" + } + } + } +} diff --git a/locales/bg-BG/error.json b/locales/bg-BG/error.json new file mode 100644 index 00000000..c85da1f0 --- /dev/null +++ b/locales/bg-BG/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "Липсва OpenAI API ключ, моля добавете персонален OpenAI API ключ", + "error": "Грешка", + "errorTip": { + "clearSession": "Изчисти сесията", + "description": "Проектът в момента е в процес на изграждане и не гарантира стабилност на данните. В случай на проблеми, опитайте", + "forgive": ", моля прошете ни за причиненото неудобство", + "or": "или", + "problem": "Страницата се е сблъскала с проблем...", + "resetSystem": "Нулиране на системните настройки" + }, + "goBack": "Назад към началната страница", + "openaiError": "Грешка в OpenAI API, моля проверете дали OpenAI API ключът и краен пункт са правилни", + "reload": "Презареди", + "s3envError": "Променливите на S3 средата не са напълно настроени, моля проверете вашите променливи на средата", + "serverError": "Грешка на сървъра, моля свържете се с администратора", + "triggerError": "Предизвикай грешка", + "unknownError": "Неизвестна грешка" +} diff --git a/locales/bg-BG/features.json b/locales/bg-BG/features.json new file mode 100644 index 00000000..43c13398 --- /dev/null +++ b/locales/bg-BG/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Превключване на видео режим" + }, + "agent": { + "female": "Женски", + "male": "Мъжки", + "other": "Други" + }, + "feature": { + "addProxy": "Добавяне на адрес на OpenAI прокси (по избор)", + "closeTip": "Затваряне на съвета", + "comfirmRetry": "Потвърждаване и опит за отново", + "startDesc": "Въведете вашия ключ за OpenAI API, за да започнете сесия. Приложението няма да запазва вашия ключ за API", + "startTitle": "Персонализиран ключ за API" + }, + "mode": { + "chat": "Чат", + "video": "Видео" + }, + "settings": { + "glow": "Сияние", + "nickName": "Моля, въведете прякор", + "none": "Без заден план" + }, + "share": { + "downloadScreenshot": "Изтегляне на снимка на екрана", + "imageType": "Тип на изображението", + "screenshot": "Снимка на екрана", + "share": "Споделяне", + "shareGPT": "Споделяне на GPT", + "shareToGPT": "Създаване на споделена връзка ShareGPT", + "shareToMarket": "Споделяне в помощния пазар", + "withBackground": "Със заден план", + "withFooter": "Със подвал", + "withSystemRole": "Със системна настройка на ролята" + }, + "submit": { + "assistantId": "Идентификатор на помощника", + "assistantIdTip": "Моля, въведете идентификатора на помощника, който трябва да бъде уникален, като например vidol-agent-klee", + "submitAssistant": "Изпращане на помощник", + "submitWarning": "Моля, попълнете информацията за помощника преди изпращане, трябва да включва име, описание, профилна снимка и корица" + }, + "support": "Общностна подкрепа", + "theme": { + "auto": "Следване на системата", + "dark": "Тъмен режим", + "light": "Светъл режим" + }, + "token": { + "overload": "Претоварване на токена", + "remained": "Оставащи токени", + "tokenCount": "Брой токени", + "useToken": "Използване на токени за изчисляване, включително съобщения, настройки на ролите и контекст: {{usedTokens}} / {{maxValue}}", + "used": "Използвани токени" + }, + "toolBar": { + "cameraControl": "Контрол на камерата", + "cameraHelper": "Помощник за камера", + "downloadModel": "Изтегляне на модела, моля изчакайте...", + "floor": "Превключване на пода", + "grid": "Мрежа", + "resetCamera": "Нулиране на камерата" + } +} diff --git a/locales/bg-BG/layout.json b/locales/bg-BG/layout.json new file mode 100644 index 00000000..22f7c8af --- /dev/null +++ b/locales/bg-BG/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialog Box", + "header": { + "chat": "Chat", + "market": "Discover", + "role": "Role", + "settings": "Settings", + "tips": "The project is currently under construction, and data stability is not guaranteed. If you encounter any problems, you can clear the session messages and reset the system settings in the system settings. We apologize for any inconvenience." + }, + "sessionList": "Session List", + "siderBar": "Sidebar" +} diff --git a/locales/bg-BG/my.json b/locales/bg-BG/my.json new file mode 100644 index 00000000..35553a11 --- /dev/null +++ b/locales/bg-BG/my.json @@ -0,0 +1,5 @@ +{ + "my": "Моя", + "myDance": "Моят танц", + "myRole": "Моята роля" +} diff --git a/locales/bg-BG/panel.json b/locales/bg-BG/panel.json new file mode 100644 index 00000000..3e825ad3 --- /dev/null +++ b/locales/bg-BG/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Добави към списъка", + "addPlaySuccess": "Добавено в списъка за възпроизвеждане", + "cancelAddPlay": "Сигурни ли сте, че искате да отмените абонамента за музиката {{musicName}}?", + "cancelSubscribed": "Отказ от абонамент", + "findDance": "Намери любимия ти танц", + "musicAndDance": "Музика и танци", + "play": "Възпроизвеждане" + }, + "info": { + "avatarDescription": "Персонализиране на аватара. Кликнете, за да качите собствен аватар", + "avatarLabel": "Аватар", + "coverDescription": "Използвана за представяне на страницата с открити персонажи. Препоръчителни размери {{width}} x {{height}} пиксела", + "coverLabel": "Обложка", + "descDescription": "Описание на персонажа, използвано за кратко представяне на персонажа", + "descLabel": "Описание", + "emotionDescription": "Избор на емоция при отговор, влияе на израза на персонажа", + "emotionLabel": "Емоция и израз", + "genderDescription": "Пол на персонажа, влияе на реакциите му при докосване", + "genderLabel": "Пол", + "greetDescription": "Поздрав при първото срещане с персонажа", + "greetLabel": "Поздрав", + "modelDescription": "Преглед на модела, можете да замените моделния файл с повлачване", + "modelLabel": "Преглед на модела", + "nameDescription": "Име на персонажа, с което да се обръщате към него по време на разговор", + "nameLabel": "Име", + "readmeDescription": "Файл с инструкции за персонажа, използван за детайлно представяне на страницата с открити персонажи", + "readmeLabel": "Инструкции за персонажа", + "textDescription": "Персонализиран отговорен текст", + "textLabel": "Текст", + "categoryLabel": "Категория", + "categoryDescription": "Категория на персонажа, използвана за класификация" + }, + "market": { + "findVidol": "Намерете своя любим идол" + }, + "nav": { + "info": "Основна информация", + "model": "3D модел", + "role": "Настройка на персонажа", + "voice": "Глас" + }, + "role": { + "greetTip": "Моля, въведете поздрава, който персонажът да използва при общуване с вас", + "inputRoleSetting": "Моля, въведете настройките на системата за персонажа", + "roleDescriptionTip": "Моля, въведете описание на персонажа", + "roleNameTip": "Моля, въведете име на персонажа", + "roleReadmeTip": "Моля, въведете инструкции за персонажа", + "roleSettingDescription": "Фоновите настройки на персонажа, които се изпращат на модела по време на разговор", + "roleSettingLabel": "Настройки на системата за персонажа", + "uploadSize": "Поддържа се качване на един файл, препоръчителни размери са {{width}} x {{height}} пиксела" + }, + "touch": { + "addAction": "Добавяне на реакция при докосване", + "editAction": "Редактиране на реакцията при докосване", + "inputActionEmotion": "Моля, въведете емоцията на персонажа при реакция", + "inputActionText": "Моля, въведете текст за реакция", + "inputDIYText": "Моля, въведете персонализиран текст", + "touchActionList": "Списък на реакциите при докосване в зоната {{touchArea}}", + "touchArea": "Зона за докосване" + }, + "tts": { + "audition": "Пробно слушане", + "auditionDescription": "Пробно слушане на текста според избрания език", + "engineDescription": "Гласов двигател за синтез на глас, препоръчва се използването на браузъра Edge", + "engineLabel": "Гласов двигател", + "localeDescription": "Език за синтез на глас, поддържат се най-често използваните езици", + "localeLabel": "Език", + "pitchDescription": "Контрол на тона на гласа, стойностите са от 0 до 2, по подразбиране е 1", + "pitchLabel": "Тон", + "selectLanguage": "Моля, първо изберете език", + "selectVoice": "Моля, първо изберете глас", + "speedDescription": "Контрол на скоростта на говора, стойностите са от 0 до 3, по подразбиране е 1", + "speedLabel": "Скорост на говора", + "transfromSuccess": "Преобразуването е успешно", + "voiceDescription": "Варира според гласовия двигател и езика", + "voiceLabel": "Глас" + }, + "upload": { + "support": "Поддържа се качване на един файл, в момента само във формат VRM" + } +} diff --git a/locales/bg-BG/role.json b/locales/bg-BG/role.json new file mode 100644 index 00000000..57ebb99e --- /dev/null +++ b/locales/bg-BG/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Изтриване на роля", + "delRoleDesc": "Наистина ли искате да изтриете ролята {{name}} и свързаните с нея сесии? Действието не може да бъде отменено, моля, бъдете внимателни!", + "header": { + "role": "Роля", + "session": "Сесия" + }, + "noRole": "Няма налични роли. Можете да добавите персонализирана роля чрез + или да добавите роли чрез страницата за откриване.", + "roleList": "Списък с роли", + "topBannerTitle": "Преглед и настройка на ролите" +} diff --git a/locales/bg-BG/welcome.json b/locales/bg-BG/welcome.json new file mode 100644 index 00000000..973c2143 --- /dev/null +++ b/locales/bg-BG/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} е стандартният герой на Видол, твоят личен асистент", + "greeting": "Здравей, скъпи господарю! Аз съм твоят личен асистент {{name}}, радост е да ти помагам! Има ли нещо с което да ти помогна?", + "hello": "Здравей!", + "meta": { + "description": "Това е персонализиран герой", + "name": "Персонализиран герой" + } + }, + "greet": "Здравей, аз съм {{name}}, има ли нещо с което да помогна?", + "loadingTitle": "Инициализиране на приложението, моля изчакайте...", + "waitting": "Подготвям целия ми свят за теб" +} diff --git a/locales/de-DE/chat.json b/locales/de-DE/chat.json new file mode 100644 index 00000000..11a736b8 --- /dev/null +++ b/locales/de-DE/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chat", + "chatDialog": { + "close": "Close" + }, + "dance": "Tanz", + "header": { + "role": "Rolle", + "session": "Sitzung" + }, + "helloChat": "Hallo, lass uns chatten", + "helloDance": "Hallo, lass uns tanzen", + "market": "Entdecken" +} diff --git a/locales/de-DE/common.json b/locales/de-DE/common.json new file mode 100644 index 00000000..dfaf1901 --- /dev/null +++ b/locales/de-DE/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Hinzufügen", + "clearAll": "Alles löschen", + "clearContext": "Kontext löschen", + "clearHistoryTip": "Diese Aktion ist nicht umkehrbar. Bitte seien Sie vorsichtig.", + "clearHistoryTitle": "Historische Nachrichten wirklich löschen?", + "clearNow": "Jetzt löschen", + "clearSuccess": "Löschen erfolgreich", + "clearTip": "Aktion kann nicht rückgängig gemacht werden. Daten können nach dem Löschen nicht wiederhergestellt werden. Bitte seien Sie vorsichtig.", + "clearTitle": "Alle Sitzungsnachrichten wirklich löschen?", + "confirmDel": "Sind Sie sicher, dass Sie löschen möchten?", + "copy": "Kopieren", + "copySuccess": "Erfolgreich kopiert", + "del": "Löschen", + "delAndRegenerate": "Löschen und neu generieren", + "downloadAvatar": "Avatar herunterladen", + "downloadCover": "Cover herunterladen", + "downloadFailed": "Download fehlgeschlagen", + "downloadModel": "Modell herunterladen", + "downloadSubscribe": "Abonnement herunterladen", + "downloadSuccess": "Download erfolgreich", + "edit": "Bearbeiten", + "goBottom": "Zurück zum Ende", + "market": "Entdecken", + "pause": "Pause", + "play": "Abspielen", + "regenerate": "Neu generieren", + "removeInList": "Aus Liste entfernen", + "reset": "Zurücksetzen", + "resetNow": "Jetzt zurücksetzen", + "resetSuccess": "Zurücksetzen erfolgreich", + "resetTip": "Aktion kann nicht rückgängig gemacht werden. Daten können nach dem Zurücksetzen nicht wiederhergestellt werden. Bitte seien Sie vorsichtig.", + "resetTitle": "Alle Systemeinstellungen wirklich zurücksetzen?", + "save": "Speichern", + "send": "Senden", + "share": "Teilen", + "subscribe": "Abonnieren", + "subscribeDance": "Tanz abonnieren", + "subscribeRole": "Rolle abonnieren", + "subscribed": "Abonniert", + "unsubscribe": "Abonnement kündigen", + "unsubscribeSuccess": "Abonnement erfolgreich gekündigt", + "warp": "Zeilenumbruch" + }, + "aiAlert": "Bitte beachten Sie: Alles, was der KI-Assistent sagt, wurde von KI generiert.", + "cancel": "Abbrechen", + "commonSetting": "Allgemeine Einstellungen", + "confirm": "Bestätigen", + "defaultAssistant": "Standardassistent", + "delAlert": "Sind Sie sicher, dass Sie die Rolle und die zugehörigen Sitzungsnachrichten löschen möchten? Dies kann nicht rückgängig gemacht werden. Bitte seien Sie vorsichtig!", + "delRole": "Rolle löschen", + "delSession": "Sitzung löschen", + "delSessionAlert": "Sind Sie sicher, dass Sie den Chat löschen möchten? Dies kann nicht rückgängig gemacht werden. Bitte seien Sie vorsichtig!", + "inputStartChat": "Geben Sie einen Text ein, um das Gespräch zu beginnen", + "languageModel": "Sprachmodell", + "loading": "Laden...", + "noData": "Keine Daten", + "openai": { + "callError": "API-Aufruf fehlgeschlagen. Bitte überprüfen Sie, ob der API-Schlüssel und die Proxy-URL korrekt eingestellt sind.", + "check": "Überprüfen", + "checkAll": "Überprüfen Sie, ob der API-Schlüssel und die Proxy-URL korrekt eingestellt sind", + "checkConnect": "Verbindungstest", + "checkOk": "Überprüfung erfolgreich", + "langModel": "OpenAI Sprachmodell", + "model": "Modell", + "proxyUrl": "Proxy-URL", + "roleModel": "Rollen-GPT-Modell", + "useOwnKey": "Bitte verwenden Sie Ihren eigenen OpenAI-Schlüssel" + }, + "playlist": "Wiedergabeliste", + "search": "Suche", + "selectInDanceList": "Bitte wählen Sie aus der Tanzliste aus", + "selectModel": "Modell auswählen", + "setLocalStorage": "Lokalen Speicher einstellen", + "startChat": "Chat starten", + "ttsCombine": "Sprachsynthese", + "ttsTip": "Spracherkennung (erfordert Zugang zum Internet)", + "uploadTip": "Klicken Sie hier oder ziehen Sie eine Datei in diesen Bereich, um sie hochzuladen", + "words": { + "DIYAvatar": "Eigenen Avatar erstellen", + "DIYBackgroundEffect": "Eigenen Hintergrundeffekt erstellen", + "DIYColor": "Graustufen mit verschiedenen Farbneigungen anpassen", + "DIYNickname": "Eigenen Spitznamen erstellen", + "DIYTopicColor": "Eigenen Themenfarbe erstellen", + "avatar": "Avatar", + "backgroundEffect": "Hintergrundeffekt", + "chatSetting": "Chat-Einstellungen", + "clearAllSession": "Alle Sitzungsnachrichten löschen", + "clearAllSessionDesc": "Alle Sitzungen und Rollendaten werden gelöscht, einschließlich Sitzungsliste, Rollenliste und Sitzungsnachrichten", + "midColor": "Mittlere Farbe", + "nickname": "Spitzname", + "resetSystemSetting": "Systemeinstellungen zurücksetzen", + "resetSystemSettingDesc": "Alle Systemeinstellungen werden zurückgesetzt, einschließlich Themen-, Chat- und Sprachmodell-Einstellungen", + "systemSetting": "Systemeinstellungen", + "languageSetting": "Spracheinstellungen", + "topicColor": "Themenfarbe", + "topicSetting": "Themen-Einstellungen" + } +} diff --git a/locales/de-DE/constants.json b/locales/de-DE/constants.json new file mode 100644 index 00000000..3ab8b74a --- /dev/null +++ b/locales/de-DE/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "女", + "male": "男", + "other": "其他" + }, + "meta": { + "description": "这是一个自定义角色", + "name": "自定义角色" + } + }, + "touch": { + "area": { + "arm": "手臂", + "belly": "腹部", + "chest": "胸部", + "head": "头部", + "leg": "腿部" + }, + "emotion": { + "angry": "生气", + "blink": "眨眼", + "blinkLeft": "眨左眼", + "blinkRight": "眨右眼", + "happy": "开心", + "natural": "自然", + "relaxed": "放松", + "sad": "伤心", + "surprised": "惊讶" + }, + "femaleAction": { + "armAction": { + "happyA": "啊,好喜欢呢~", + "happyB": "哈哈,牵手让我感到快乐~", + "relaxedA": "主人的手好温暖啊~" + }, + "bellyAction": { + "angryA": "干嘛动我呀,小心我咬你哦!", + "relaxedA": "醒醒,我们之间没有结果的!", + "relaxedB": "讨厌!我可要生气啦!", + "surprisedA": "是不小心碰到的吧..." + }, + "chestAction": { + "angryA": "不可以这样欺负我啦!快把手拿开!", + "angryB": "幺幺零吗?这里有个变态一直在摸我!", + "angryC": "再摸的话我可要报警了", + "surprisedA": "干嘛戳我呀!还能不能愉快地聊天了!" + }, + "headAction": { + "angryA": "听说被摸头是会长不高的呢!", + "angryB": "干嘛戳我呀?", + "happyA": "哇!最喜欢摸摸头!", + "happyB": "感觉又充满了力量呢!", + "happyC": "哇塞,这个摸摸头的感觉好神奇!", + "happyD": "摸摸头让我开心一整天!" + }, + "legAction": { + "angryA": "喂,你是要作死吗?", + "angryB": "主人的手又不听指挥了吗?", + "angryC": "讨厌~会痒的啦~!", + "surprisedA": "让我们保持纯洁的友谊不好吗?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "别问我今天吃没吃鸡,先看看我的肱二头肌", + "neutralB": "我的手臂可不是随便让人触碰的,你是个例外而已", + "neutralC": "你很勇敢,敢触碰到传说中的麒麟臂" + }, + "bellyAction": { + "happyA": "别挠痒痒,小心我笑出腹肌", + "neutralA": "我的腹肌只是再修炼深藏不露的内力", + "neutralB": "看到我这团腹肌了吗?它们只是藏得比较深罢了" + }, + "chestAction": { + "blinkLeftA": "来,哥的胸肌给你靠!", + "neutralA": "这不过时我日常修炼成就的胸肌,没什么好惊讶的。" + }, + "headAction": { + "neutralA": "当然了,只有你有资格摸我的头", + "neutralB": "我可不是什么普通人允许触碰的哦", + "neutralC": "别担心,摸过我的头后,你的运气会大幅提升的" + }, + "legAction": { + "angryA": "别靠近我,你这个腿控", + "neutralA": "别害怕,我的大力金刚腿不踢傻瓜", + "neutralB": "让你碰到我的腿,是不是觉得你的生活完整了许多?" + } + } + } +} diff --git a/locales/de-DE/error.json b/locales/de-DE/error.json new file mode 100644 index 00000000..6dfc701c --- /dev/null +++ b/locales/de-DE/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API-Schlüssel fehlt. Bitte fügen Sie Ihren benutzerdefinierten OpenAI API-Schlüssel hinzu.", + "error": "Fehler", + "errorTip": { + "clearSession": "Sitzung löschen", + "description": "Das Projekt befindet sich derzeit im Aufbau. Die Datenstabilität kann nicht garantiert werden. Wenn Probleme auftreten, können Sie es versuchen", + "forgive": ", wir bitten um Ihr Verständnis für eventuelle Unannehmlichkeiten", + "or": "oder", + "problem": "Es gab ein Problem mit der Seite...", + "resetSystem": "Systemeinstellungen zurücksetzen" + }, + "goBack": "Zurück zur Startseite", + "openaiError": "OpenAI API-Fehler. Bitte überprüfen Sie den OpenAI API-Schlüssel und den Endpunkt.", + "reload": "Neu laden", + "s3envError": "S3-Umgebungsvariablen sind nicht vollständig konfiguriert. Bitte überprüfen Sie Ihre Umgebungsvariablen.", + "serverError": "Serverfehler. Bitte kontaktieren Sie den Administrator.", + "triggerError": "Fehler auslösen", + "unknownError": "Unbekannter Fehler" +} diff --git a/locales/de-DE/features.json b/locales/de-DE/features.json new file mode 100644 index 00000000..0e96541b --- /dev/null +++ b/locales/de-DE/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Videomodus verwenden" + }, + "agent": { + "female": "Weiblich", + "male": "Männlich", + "other": "Andere" + }, + "feature": { + "addProxy": "OpenAI-Proxy hinzufügen (optional)", + "closeTip": "Tipp schließen", + "comfirmRetry": "Bestätigen und erneut versuchen", + "startDesc": "Geben Sie Ihren OpenAI-API-Schlüssel ein, um das Gespräch zu beginnen. Die App speichert Ihren API-Schlüssel nicht.", + "startTitle": "Benutzerdefinierter API-Schlüssel" + }, + "mode": { + "chat": "Chat", + "video": "Video" + }, + "settings": { + "glow": "Leuchten", + "nickName": "Geben Sie einen Spitznamen ein", + "none": "Kein Hintergrund" + }, + "share": { + "downloadScreenshot": "Screenshot herunterladen", + "imageType": "Bildformat", + "screenshot": "Screenshot", + "share": "Teilen", + "shareGPT": "GPT teilen", + "shareToGPT": "Erstellen Sie einen ShareGPT-Link zum Teilen", + "shareToMarket": "Auf dem Assistentenmarkt teilen", + "withBackground": "Mit Hintergrundbild", + "withFooter": "Mit Fußzeile", + "withSystemRole": "Mit Assistentenrolleneinstellung" + }, + "submit": { + "assistantId": "Assistenten-ID", + "assistantIdTip": "Geben Sie die ID des Assistenten ein. Sie muss eindeutig sein, z. B. vidol-agent-klee", + "submitAssistant": "Assistenten einreichen", + "submitWarning": "Bitte vervollständigen Sie die Assistenteninformationen, bevor Sie sie einreichen. Es müssen Name, Beschreibung, Avatar und Cover enthalten sein." + }, + "support": "Community-Support", + "theme": { + "auto": "System folgen", + "dark": "Dunkler Modus", + "light": "Heller Modus" + }, + "token": { + "overload": "Token-Überlastung", + "remained": "Verbleibende Token", + "tokenCount": "Token-Anzahl", + "useToken": "Verbrauchen Sie Token zur Berechnung, einschließlich Nachrichten, Rolleneinstellungen und Kontext: {{usedTokens}} / {{maxValue}}", + "used": "Verwendete Token" + }, + "toolBar": { + "cameraControl": "Kamerasteuerung", + "cameraHelper": "Kamerahilfe", + "downloadModel": "Modell wird heruntergeladen, bitte warten...", + "floor": "Boden wechseln", + "grid": "Raster", + "resetCamera": "Kamera zurücksetzen" + } +} diff --git a/locales/de-DE/layout.json b/locales/de-DE/layout.json new file mode 100644 index 00000000..d52b59c7 --- /dev/null +++ b/locales/de-DE/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialogfeld", + "header": { + "chat": "Chat", + "market": "Entdecken", + "role": "Rolle", + "settings": "Einstellungen", + "tips": "Das Projekt befindet sich derzeit im Bau. Die Datenstabilität kann nicht garantiert werden. Wenn Probleme auftreten, können Sie die Sitzungsnachrichten im System löschen und die Systemeinstellungen zurücksetzen. Wir entschuldigen uns für eventuelle Unannehmlichkeiten." + }, + "sessionList": "Sitzungsliste", + "siderBar": "Seitenleiste" +} diff --git a/locales/de-DE/my.json b/locales/de-DE/my.json new file mode 100644 index 00000000..60c0f712 --- /dev/null +++ b/locales/de-DE/my.json @@ -0,0 +1,5 @@ +{ + "my": "Mein", + "myDance": "Mein Tanz", + "myRole": "Meine Rolle" +} diff --git a/locales/de-DE/panel.json b/locales/de-DE/panel.json new file mode 100644 index 00000000..8d09d2a3 --- /dev/null +++ b/locales/de-DE/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Zur Wiedergabeliste hinzufügen", + "addPlaySuccess": "Zur Wiedergabeliste hinzugefügt", + "cancelAddPlay": "Möchten Sie das Abonnement für das Lied {{musicName}} wirklich abbrechen?", + "cancelSubscribed": "Abonnement kündigen", + "findDance": "Finde deinen Lieblingstanz", + "musicAndDance": "Musik und Tanz", + "play": "Abspielen" + }, + "info": { + "avatarDescription": "Benutzerdefiniertes Profilbild, klicken Sie auf das Bild, um es hochzuladen", + "avatarLabel": "Profilbild", + "coverDescription": "Zur Präsentation des Charakters auf der Entdeckungsseite, empfohlene Größe {{width}} x {{height}}", + "coverLabel": "Cover", + "descDescription": "Charakterbeschreibung, zur einfachen Vorstellung des Charakters", + "descLabel": "Beschreibung", + "emotionDescription": "Auswahl der Emotionen bei der Antwort, beeinflusst die Gesichtsausdrücke des Charakters", + "emotionLabel": "Gefühle und Emotionen", + "genderDescription": "Charaktergeschlecht, beeinflusst die Berührungsreaktion des Charakters", + "genderLabel": "Geschlecht", + "greetDescription": "Begrüßungsausdruck beim ersten Chat mit dem Charakter", + "greetLabel": "Begrüßung", + "modelDescription": "Modellvorschau, ziehen Sie Modelldateien hierher, um sie zu ersetzen", + "modelLabel": "Modellvorschau", + "nameDescription": "Charaktername, Anrede während des Chats mit dem Charakter", + "nameLabel": "Name", + "readmeDescription": "Anleitungsdatei des Charakters, zur detaillierten Vorstellung des Charakters auf der Entdeckungsseite", + "readmeLabel": "Charakteranleitung", + "textDescription": "Benutzerdefinierter Antworttext", + "textLabel": "Text", + "categoryLabel": "Kategorie", + "categoryDescription": "Charakterkategorie, zur Klassifizierung" + }, + "market": { + "findVidol": "Finde deinen Lieblingsidol" + }, + "nav": { + "info": "Grundinformationen", + "model": "3D-Modell", + "role": "Charaktereinstellungen", + "voice": "Stimme" + }, + "role": { + "greetTip": "Geben Sie den Begrüßungstext des Charakters ein", + "inputRoleSetting": "Geben Sie die Systemeinstellungen des Charakters ein", + "roleDescriptionTip": "Geben Sie die Charakterbeschreibung ein", + "roleNameTip": "Geben Sie den Charakternamen ein", + "roleReadmeTip": "Geben Sie die Charakteranleitung ein", + "roleSettingDescription": "Hintergrundinformationen des Charakters, die beim Chatten mit dem Charakter an das Modell gesendet werden", + "roleSettingLabel": "Systemeinstellungen des Charakters", + "uploadSize": "Unterstützt den Upload einer einzelnen Datei, empfohlene Größe ist ein Vielfaches von {{width}} x {{height}}" + }, + "touch": { + "addAction": "Reaktionsaktion hinzufügen", + "editAction": "Reaktionsaktion bearbeiten", + "inputActionEmotion": "Geben Sie die Emotion des Charakters bei der Antwort ein", + "inputActionText": "Geben Sie die Antwortnachricht ein", + "inputDIYText": "Geben Sie benutzerdefinierten Text ein", + "touchActionList": "Reaktionsliste beim Berühren von {{touchArea}}", + "touchArea": "Berührungszone" + }, + "tts": { + "audition": "Vorsprechen", + "auditionDescription": "Je nach Sprache unterschiedliche Vorsprechtexte", + "engineDescription": "Sprachsynthese-Engine, bevorzugen Sie die Verwendung des Edge-Browsers", + "engineLabel": "Sprachengine", + "localeDescription": "Sprachsynthese-Sprache, derzeit nur die gängigsten Sprachen werden unterstützt, bei Bedarf kontaktieren Sie uns bitte", + "localeLabel": "Sprache", + "pitchDescription": "Steuerung der Tonhöhe, Werte von 0 bis 2, Standardwert ist 1", + "pitchLabel": "Tonhöhe", + "selectLanguage": "Bitte wählen Sie zuerst die Sprache aus", + "selectVoice": "Bitte wählen Sie zuerst die Stimme aus", + "speedDescription": "Steuerung der Sprechgeschwindigkeit, Werte von 0 bis 3, Standardwert ist 1", + "speedLabel": "Geschwindigkeit", + "transfromSuccess": "Erfolgreich umgewandelt", + "voiceDescription": "Je nach Engine und Sprache unterschiedlich", + "voiceLabel": "Stimme" + }, + "upload": { + "support": "Unterstützt den Upload einer einzelnen Datei, derzeit nur Dateien im vrm-Format werden unterstützt" + } +} diff --git a/locales/de-DE/role.json b/locales/de-DE/role.json new file mode 100644 index 00000000..4b99ad84 --- /dev/null +++ b/locales/de-DE/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Rolle löschen", + "delRoleDesc": "Sind Sie sicher, dass Sie die Rolle {{name}} und die zugehörigen Sitzungsnachrichten löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. Bitte seien Sie vorsichtig!", + "header": { + "role": "Rolle", + "session": "Sitzung" + }, + "noRole": "Keine Rolle vorhanden. Sie können eine benutzerdefinierte Rolle erstellen, indem Sie auf + klicken, oder eine Rolle über die Entdeckungsseite hinzufügen.", + "roleList": "Rollenliste", + "topBannerTitle": "Rollenübersicht und Einstellungen" +} diff --git a/locales/de-DE/welcome.json b/locales/de-DE/welcome.json new file mode 100644 index 00000000..9af4503d --- /dev/null +++ b/locales/de-DE/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} ist die Standardrolle von Vidol und dein exklusiver persönlicher Assistent.", + "greeting": "Hallo, lieber Besitzer! Ich bin dein persönlicher Assistent {{name}}, und ich stehe dir gerne zur Verfügung! Kann ich dir helfen?", + "hello": "Hallo", + "meta": { + "description": "Dies ist eine benutzerdefinierte Rolle", + "name": "Benutzerdefinierte Rolle" + } + }, + "greet": "Hallo, ich bin {{name}}, wie kann ich dir helfen?", + "loadingTitle": "Anwendung wird initialisiert, bitte warten...", + "waitting": "Ich bereite gerade meine ganze Welt für dich vor" +} diff --git a/locales/en-US/chat.json b/locales/en-US/chat.json new file mode 100644 index 00000000..7a6f4ad7 --- /dev/null +++ b/locales/en-US/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chat", + "chatDialog": { + "close": "Close" + }, + "dance": "Dance", + "header": { + "role": "Role", + "session": "Session" + }, + "helloChat": "Hello, let's chat", + "helloDance": "Hi, let's dance together", + "market": "Discover" +} \ No newline at end of file diff --git a/locales/en-US/common.json b/locales/en-US/common.json new file mode 100644 index 00000000..b252b45a --- /dev/null +++ b/locales/en-US/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Add", + "clearAll": "Clear All", + "clearContext": "Clear Context", + "clearHistoryTip": "This action is irreversible. Please proceed with caution.", + "clearHistoryTitle": "Confirm Delete History Messages?", + "clearNow": "Clear Now", + "clearSuccess": "Clear Successful", + "clearTip": "This action cannot be undone. Data will be permanently deleted. Proceed with caution.", + "clearTitle": "Confirm Clear All Session Messages?", + "confirmDel": "Are you sure you want to delete?", + "copy": "Copy", + "copySuccess": "Copy Successful", + "del": "Delete", + "delAndRegenerate": "Delete and Regenerate", + "downloadAvatar": "Download Avatar", + "downloadCover": "Download Cover", + "downloadFailed": "Download Failed", + "downloadModel": "Download Model", + "downloadSubscribe": "Download Subscription", + "downloadSuccess": "Download Successful", + "edit": "Edit", + "goBottom": "Go to Bottom", + "market": "Discover", + "pause": "Pause", + "play": "Play", + "regenerate": "Regenerate", + "removeInList": "Remove from List", + "reset": "Reset", + "resetNow": "Reset Now", + "resetSuccess": "Reset Successful", + "resetTip": "This action cannot be undone. Data will be permanently reset. Proceed with caution.", + "resetTitle": "Confirm Reset All System Settings?", + "save": "Save", + "send": "Send", + "share": "Share", + "subscribe": "Subscribe", + "subscribeDance": "Subscribe to Dance", + "subscribeRole": "Subscribe to Role", + "subscribed": "Subscribed", + "unsubscribe": "Unsubscribe", + "unsubscribeSuccess": "Unsubscribed Successfully", + "warp": "Wrap" + }, + "aiAlert": "Please remember: everything the AI says is generated by AI.", + "cancel": "Cancel", + "commonSetting": "Common Settings", + "confirm": "Confirm", + "defaultAssistant": "Default Assistant", + "delAlert": "Are you sure you want to delete the role and its associated session messages? This action cannot be undone. Proceed with caution!", + "delRole": "Delete Role", + "delSession": "Delete Session", + "delSessionAlert": "Are you sure you want to delete the conversation? This action cannot be undone. Proceed with caution!", + "inputStartChat": "Please enter content to start chatting", + "languageModel": "Language Model", + "loading": "Loading...", + "noData": "No data", + "openai": { + "callError": "Failed to call the API. Please check if the API Key and proxy address are set correctly.", + "check": "Check", + "checkAll": "Check if the API Key and proxy address are set correctly", + "checkConnect": "Connectivity Check", + "checkOk": "Check passed", + "langModel": "OpenAI Language Model", + "model": "Model", + "proxyUrl": "Proxy Address", + "roleModel": "Role GPT Model", + "useOwnKey": "Please use your own OpenAI Key" + }, + "playlist": "Playlist", + "search": "Search", + "selectInDanceList": "Please select from the dance list", + "selectModel": "Please select a model", + "setLocalStorage": "Set Local Storage", + "startChat": "Start Chat", + "ttsCombine": "Text-to-Speech Combine", + "ttsTip": "Speech Recognition (requires VPN)", + "uploadTip": "Click or drag files here to upload", + "words": { + "DIYAvatar": "Customize Avatar", + "DIYBackgroundEffect": "Customize Background Effect", + "DIYColor": "Customize Grayscale with Different Color Preferences", + "DIYNickname": "Customize Nickname", + "DIYTopicColor": "Customize Theme Color", + "avatar": "Avatar", + "backgroundEffect": "Background Effect", + "chatSetting": "Chat Settings", + "clearAllSession": "Clear All Session Messages", + "clearAllSessionDesc": "This will clear all session and role data, including session list, role list, session messages, etc.", + "midColor": "Neutral Color", + "nickname": "Nickname", + "resetSystemSetting": "Reset System Settings", + "resetSystemSettingDesc": "This will reset all system settings, including theme settings, chat settings, language model settings, etc.", + "systemSetting": "System Settings", + "languageSetting": "Language Settings", + "topicColor": "Theme Color", + "topicSetting": "Topic Settings" + } +} diff --git a/locales/en-US/constants.json b/locales/en-US/constants.json new file mode 100644 index 00000000..96ab5e3a --- /dev/null +++ b/locales/en-US/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Female", + "male": "Male", + "other": "Other" + }, + "meta": { + "description": "This is a custom role", + "name": "Custom Role" + } + }, + "touch": { + "area": { + "arm": "Arm", + "belly": "Belly", + "chest": "Chest", + "head": "Head", + "leg": "Leg" + }, + "emotion": { + "angry": "Angry", + "blink": "Blink", + "blinkLeft": "Blink Left", + "blinkRight": "Blink Right", + "happy": "Happy", + "natural": "Natural", + "relaxed": "Relaxed", + "sad": "Sad", + "surprised": "Surprised" + }, + "femaleAction": { + "armAction": { + "happyA": "Ah, I love this~", + "happyB": "Haha, holding hands makes me happy~", + "relaxedA": "Master's hands are so warm~" + }, + "bellyAction": { + "angryA": "Why are you touching me? Be careful, I might bite you!", + "relaxedA": "Wake up, we're not meant to be!", + "relaxedB": "I hate it! I'm getting angry!", + "surprisedA": "It was an accident... right?" + }, + "chestAction": { + "angryA": "You can't bully me like this! Get your hands off!", + "angryB": "What's wrong? There's a pervert touching me!", + "angryC": "If you touch me again, I'll call the police!", + "surprisedA": "Why are you poking me? Can't we have a pleasant conversation anymore?" + }, + "headAction": { + "angryA": "I heard that being patted on the head stunts growth!", + "angryB": "Why are you poking me?", + "happyA": "Wow! I love head pats!", + "happyB": "I feel so energized!", + "happyC": "Wow, the feeling of a head pat is amazing!", + "happyD": "Head pats make me happy all day long!" + }, + "legAction": { + "angryA": "Hey, are you trying to pick a fight?", + "angryB": "Is Master's hand not following commands again?", + "angryC": "I hate it~ it's ticklish!", + "surprisedA": "Can't we maintain a pure friendship?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Don't ask if I had chicken today, first look at my biceps.", + "neutralB": "My arms are not for anyone to touch, you are an exception.", + "neutralC": "You are brave, daring to touch the legendary Kirin arm." + }, + "bellyAction": { + "happyA": "Stop tickling, be careful I might laugh out my abs.", + "neutralA": "My abs are just inner strength honed through training.", + "neutralB": "Have you seen my group of abs? They are just well-hidden." + }, + "chestAction": { + "blinkLeftA": "Come on, you can lean on my chest muscles!", + "neutralA": "This is just the chest muscle I have developed through daily training, nothing to be surprised about." + }, + "headAction": { + "neutralA": "Of course, only you have the privilege to touch my head.", + "neutralB": "I am not an ordinary person that anyone can touch.", + "neutralC": "Don't worry, after you touch my head, your luck will greatly improve." + }, + "legAction": { + "angryA": "Don't come near me, you leg enthusiast.", + "neutralA": "Don't be afraid, my powerful steel legs don't kick fools.", + "neutralB": "Do you feel like your life is much more complete after touching my leg?" + } + } + } +} \ No newline at end of file diff --git a/locales/en-US/error.json b/locales/en-US/error.json new file mode 100644 index 00000000..0a0fa5b2 --- /dev/null +++ b/locales/en-US/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key is missing, please add a custom OpenAI API Key", + "error": "Error", + "errorTip": { + "clearSession": "Clear Session Messages", + "description": "The project is currently under construction and data stability is not guaranteed. If you encounter any issues, please try", + "forgive": "", + "or": "or", + "problem": "Oops...something went wrong with the page.", + "resetSystem": "Reset System Settings" + }, + "goBack": "Go Back to Homepage", + "openaiError": "OpenAI API Error, please check if the OpenAI API Key and Endpoint are correct.", + "reload": "Reload", + "s3envError": "S3 environment variables are not fully set, please check your environment variables.", + "serverError": "Server Error, please contact the administrator.", + "triggerError": "Trigger Error", + "unknownError": "Unknown Error" +} \ No newline at end of file diff --git a/locales/en-US/features.json b/locales/en-US/features.json new file mode 100644 index 00000000..566e0893 --- /dev/null +++ b/locales/en-US/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Switch to video mode" + }, + "agent": { + "female": "Female", + "male": "Male", + "other": "Other" + }, + "feature": { + "addProxy": "Add OpenAI proxy address (optional)", + "closeTip": "Close tip", + "comfirmRetry": "Confirm and retry", + "startDesc": "Enter your OpenAI API Key to start the session. The application will not record your API Key.", + "startTitle": "Customize API Key" + }, + "mode": { + "chat": "Chat", + "video": "Video" + }, + "settings": { + "glow": "Glow", + "nickName": "Please enter a nickname", + "none": "None" + }, + "share": { + "downloadScreenshot": "Download screenshot", + "imageType": "Image format", + "screenshot": "Screenshot", + "share": "Share", + "shareGPT": "Share GPT", + "shareToGPT": "Generate ShareGPT sharing link", + "shareToMarket": "Share to Assistant Market", + "withBackground": "Include background image", + "withFooter": "Include footer", + "withSystemRole": "Include assistant role setting" + }, + "submit": { + "assistantId": "Assistant identifier", + "assistantIdTip": "Please enter a unique identifier for the assistant, e.g., vidol-agent-klee", + "submitAssistant": "Submit assistant", + "submitWarning": "Please complete assistant information before submitting. It should include name, description, avatar, and cover image." + }, + "support": "Community support", + "theme": { + "auto": "Follow system", + "dark": "Dark mode", + "light": "Light mode" + }, + "token": { + "overload": "Token overload", + "remained": "Tokens remaining", + "tokenCount": "Token count", + "useToken": "Token consumption calculation, including messages, role settings, and context: {{usedTokens}} / {{maxValue}}", + "used": "Tokens used" + }, + "toolBar": { + "cameraControl": "Camera control", + "cameraHelper": "Camera helper", + "downloadModel": "Model download in progress, please wait...", + "floor": "Switch floor", + "grid": "Grid", + "resetCamera": "Reset camera" + } +} \ No newline at end of file diff --git a/locales/en-US/layout.json b/locales/en-US/layout.json new file mode 100644 index 00000000..90d664ba --- /dev/null +++ b/locales/en-US/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialog", + "header": { + "chat": "Chat", + "market": "Discover", + "role": "Role", + "settings": "Settings", + "tips": "The project is currently under construction, and data stability is not guaranteed. If you encounter any issues, you can clear the session messages and reset the system settings in the system settings. We apologize for any inconvenience caused." + }, + "sessionList": "Session List", + "siderBar": "Sidebar" +} \ No newline at end of file diff --git a/locales/en-US/my.json b/locales/en-US/my.json new file mode 100644 index 00000000..d81cace0 --- /dev/null +++ b/locales/en-US/my.json @@ -0,0 +1,5 @@ +{ + "my": "My", + "myDance": "My dance", + "myRole": "My role" +} \ No newline at end of file diff --git a/locales/en-US/panel.json b/locales/en-US/panel.json new file mode 100644 index 00000000..ab172210 --- /dev/null +++ b/locales/en-US/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Add to playlist", + "addPlaySuccess": "Added to playlist", + "cancelAddPlay": "Are you sure you want to cancel subscribing to {{musicName}}?", + "cancelSubscribed": "Unsubscribe", + "findDance": "Find your favorite dance", + "musicAndDance": "Music and Dance", + "play": "Play" + }, + "info": { + "avatarDescription": "Customize your avatar. Click to upload", + "avatarLabel": "Avatar", + "coverDescription": "Used for displaying the character on the discovery page. Recommended size {{width}} x {{height}}", + "coverLabel": "Cover", + "descDescription": "Character description, used for a brief introduction", + "descLabel": "Description", + "emotionDescription": "Select the emotion when responding, which will affect the character's expression", + "emotionLabel": "Expression and Emotion", + "genderDescription": "Character gender, affects character's touch response", + "genderLabel": "Gender", + "greetDescription": "Greeting used when chatting with the character for the first time", + "greetLabel": "Greeting", + "modelDescription": "Model preview, drag and drop the model file to replace", + "modelLabel": "Model Preview", + "nameDescription": "Character name, used when chatting with the character", + "nameLabel": "Name", + "readmeDescription": "Character's description file, used for detailed introduction on the discovery page", + "readmeLabel": "Character Description", + "textDescription": "Custom response text", + "textLabel": "Text", + "categoryLabel": "Category", + "categoryDescription": "Character category, used for classification" + }, + "market": { + "findVidol": "Find your favorite idol" + }, + "nav": { + "info": "Basic Information", + "model": "3D Model", + "role": "Character Settings", + "voice": "Voice" + }, + "role": { + "greetTip": "Enter the greeting used by the character when greeting you", + "inputRoleSetting": "Enter the character's system settings", + "roleDescriptionTip": "Enter the character description", + "roleNameTip": "Enter the character name", + "roleReadmeTip": "Enter the character description", + "roleSettingDescription": "Character's background settings, will be sent to the model when chatting with the character", + "roleSettingLabel": "System Character Settings", + "uploadSize": "Supports uploading a single file, recommended size is a multiple of {{width}} x {{height}}" + }, + "touch": { + "addAction": "Add response action", + "editAction": "Edit response action", + "inputActionEmotion": "Enter the character's expression when responding", + "inputActionText": "Enter response text", + "inputDIYText": "Enter custom text", + "touchActionList": "Reaction list when touching {{touchArea}}", + "touchArea": "Touch area" + }, + "tts": { + "audition": "Audition", + "auditionDescription": "Audition text varies depending on the language", + "engineDescription": "Speech synthesis engine, it is recommended to choose Edge browser first", + "engineLabel": "Speech Engine", + "localeDescription": "Language used for speech synthesis, currently only supports several common languages. Please contact us if you need more", + "localeLabel": "Language", + "pitchDescription": "Control the pitch, range is 0 ~ 2, default is 1", + "pitchLabel": "Pitch", + "selectLanguage": "Please select a language first", + "selectVoice": "Please select a voice first", + "speedDescription": "Control the speed, range is 0 ~ 3, default is 1", + "speedLabel": "Speed", + "transfromSuccess": "Conversion successful", + "voiceDescription": "Different depending on the engine and language", + "voiceLabel": "Voice" + }, + "upload": { + "support": "Supports uploading a single file, currently only supports vrm format files" + } +} diff --git a/locales/en-US/role.json b/locales/en-US/role.json new file mode 100644 index 00000000..957a076e --- /dev/null +++ b/locales/en-US/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Delete Role", + "delRoleDesc": "Are you sure you want to delete role {{name}} and its associated session messages? This action cannot be undone, so please proceed with caution!", + "header": { + "role": "Role", + "session": "Session" + }, + "noRole": "No roles available. You can create custom roles by clicking on the '+' button, or add roles through the discovery page.", + "roleList": "Role List", + "topBannerTitle": "Role Preview and Settings" +} \ No newline at end of file diff --git a/locales/en-US/welcome.json b/locales/en-US/welcome.json new file mode 100644 index 00000000..ef5c7754 --- /dev/null +++ b/locales/en-US/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} is the default character of Vidol, your exclusive personal assistant", + "greeting": "Hello, dear master! I am your personal assistant {{name}}, delighted to serve you! How can I assist you?", + "hello": "Hello there", + "meta": { + "description": "This is a custom character", + "name": "Custom Character" + } + }, + "greet": "Hello, I'm {{name}}, how can I assist you?", + "loadingTitle": "Application initializing, please wait...", + "waitting": "Preparing my entire world for you" +} diff --git a/locales/es-ES/chat.json b/locales/es-ES/chat.json new file mode 100644 index 00000000..e5e80520 --- /dev/null +++ b/locales/es-ES/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chat", + "chatDialog": { + "close": "Close" + }, + "dance": "Dance", + "header": { + "role": "Role", + "session": "Session" + }, + "helloChat": "Hello, let's chat", + "helloDance": "Hi, let's dance together", + "market": "Discover" +} diff --git a/locales/es-ES/common.json b/locales/es-ES/common.json new file mode 100644 index 00000000..fa13f5b6 --- /dev/null +++ b/locales/es-ES/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Agregar", + "clearAll": "Limpiar todo", + "clearContext": "Limpiar contexto", + "clearHistoryTip": "Esta acción es irreversible. Por favor, proceda con precaución.", + "clearHistoryTitle": "¿Confirmar eliminar el historial de mensajes?", + "clearNow": "Limpiar ahora", + "clearSuccess": "¡Limpieza exitosa!", + "clearTip": "Esta acción no se puede deshacer. Los datos no se podrán recuperar después de limpiar. Por favor, proceda con precaución.", + "clearTitle": "¿Confirmar limpiar todos los mensajes de la sesión?", + "confirmDel": "¿Seguro que deseas eliminar?", + "copy": "Copiar", + "copySuccess": "¡Copiado exitosamente!", + "del": "Eliminar", + "delAndRegenerate": "Eliminar y regenerar", + "downloadAvatar": "Descargar avatar", + "downloadCover": "Descargar portada", + "downloadFailed": "Descarga fallida", + "downloadModel": "Descargar modelo", + "downloadSubscribe": "Descargar suscripción", + "downloadSuccess": "Descarga exitosa", + "edit": "Editar", + "goBottom": "Ir al fondo", + "market": "Descubrir", + "pause": "Pausa", + "play": "Reproducir", + "regenerate": "Regenerar", + "removeInList": "Eliminar de la lista", + "reset": "Restablecer", + "resetNow": "Restablecer ahora", + "resetSuccess": "¡Restablecimiento exitoso!", + "resetTip": "Esta acción no se puede deshacer. Los datos no se podrán recuperar después de restablecer. Por favor, proceda con precaución.", + "resetTitle": "¿Confirmar restablecer todas las configuraciones del sistema?", + "save": "Guardar", + "send": "Enviar", + "share": "Compartir", + "subscribe": "Suscribir", + "subscribeDance": "Suscribirse a la danza", + "subscribeRole": "Suscribirse al rol", + "subscribed": "Suscrito", + "unsubscribe": "Cancelar suscripción", + "unsubscribeSuccess": "Se ha cancelado la suscripción", + "warp": "Ajustar" + }, + "aiAlert": "Por favor, ten en cuenta: todo lo que diga el agente inteligente es generado por IA", + "cancel": "Cancelar", + "commonSetting": "Configuración común", + "confirm": "Confirmar", + "defaultAssistant": "Asistente predeterminado", + "delAlert": "¿Confirmar eliminar el rol y los mensajes de la sesión relacionados? ¡Esta acción no se puede deshacer, por favor, proceda con precaución!", + "delRole": "Eliminar rol", + "delSession": "Eliminar sesión", + "delSessionAlert": "¿Confirmar eliminar la conversación? ¡Esta acción no se puede deshacer, por favor, proceda con precaución!", + "inputStartChat": "Ingresa contenido para comenzar a chatear", + "languageModel": "Modelo de lenguaje", + "loading": "Cargando...", + "noData": "Sin datos", + "openai": { + "callError": "Error al llamar a la API, por favor verifica que la clave de API y la dirección del proxy estén configuradas correctamente", + "check": "Verificar", + "checkAll": "Verificar si la clave de API y la dirección del proxy están configuradas correctamente", + "checkConnect": "Verificar conectividad", + "checkOk": "Verificación exitosa", + "langModel": "Modelo de lenguaje OpenAI", + "model": "Modelo", + "proxyUrl": "Dirección del proxy de la API", + "roleModel": "Modelo GPT de rol", + "useOwnKey": "Utiliza tu propia clave de OpenAI" + }, + "playlist": "Lista de reproducción", + "search": "Buscar", + "selectInDanceList": "Selecciona de la lista de danzas", + "selectModel": "Selecciona un modelo", + "setLocalStorage": "Establecer almacenamiento local", + "startChat": "Comenzar a chatear", + "ttsCombine": "Síntesis de voz", + "ttsTip": "Reconocimiento de voz (requiere conexión a internet)", + "uploadTip": "Haz clic o arrastra un archivo a esta área para subirlo", + "words": { + "DIYAvatar": "Avatar personalizado", + "DIYBackgroundEffect": "Efecto de fondo personalizado", + "DIYColor": "Personalización de escala de grises con diferentes tendencias de color", + "DIYNickname": "Apodo personalizado", + "DIYTopicColor": "Color de tema personalizado", + "avatar": "Avatar", + "backgroundEffect": "Efecto de fondo", + "chatSetting": "Configuración de chat", + "clearAllSession": "Limpiar todas las conversaciones", + "clearAllSessionDesc": "Esto eliminará todas las conversaciones y datos de rol, incluidas las listas de conversaciones, roles y mensajes de conversación.", + "midColor": "Color neutro", + "nickname": "Apodo", + "resetSystemSetting": "Restablecer configuración del sistema", + "resetSystemSettingDesc": "Esto restablecerá todas las configuraciones del sistema, incluidas las de tema, chat, modelo de lenguaje, etc.", + "systemSetting": "Configuración del sistema", + "languageSetting": "Configuración de idioma", + "topicColor": "Color de tema", + "topicSetting": "Configuración de tema" + } +} diff --git a/locales/es-ES/constants.json b/locales/es-ES/constants.json new file mode 100644 index 00000000..e725a58b --- /dev/null +++ b/locales/es-ES/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Mujer", + "male": "Hombre", + "other": "Otro" + }, + "meta": { + "description": "Este es un rol personalizado", + "name": "Rol Personalizado" + } + }, + "touch": { + "area": { + "arm": "Brazo", + "belly": "Vientre", + "chest": "Pecho", + "head": "Cabeza", + "leg": "Pierna" + }, + "emotion": { + "angry": "Enojado", + "blink": "Parpadear", + "blinkLeft": "Parpadear Izquierda", + "blinkRight": "Parpadear Derecha", + "happy": "Feliz", + "natural": "Natural", + "relaxed": "Relajado", + "sad": "Triste", + "surprised": "Sorprendido" + }, + "femaleAction": { + "armAction": { + "happyA": "¡Ah, me encanta!", + "happyB": "¡Ja ja, tomar de la mano me hace feliz!", + "relaxedA": "¡Las manos de mi dueño son tan cálidas!" + }, + "bellyAction": { + "angryA": "¡No me toques, o te muerdo!", + "relaxedA": "¡Despierta, entre nosotros no hay futuro!", + "relaxedB": "¡Qué fastidio! ¡Me estás poniendo de mal humor!", + "surprisedA": "Seguro fue un accidente..." + }, + "chestAction": { + "angryA": "¡No puedes molestarme así! ¡Quita las manos de encima!", + "angryB": "¿Qué pasa? ¡Hay un pervertido tocándome todo el tiempo!", + "angryC": "Si me tocas de nuevo, voy a llamar a la policía", + "surprisedA": "¿Por qué me estás pinchando? ¡No podemos seguir charlando felizmente!" + }, + "headAction": { + "angryA": "¡Dicen que si te tocan la cabeza no creces!", + "angryB": "¡¿Por qué me estás pinchando?!", + "happyA": "¡Wow! ¡Me encanta que me toquen la cabeza!", + "happyB": "¡Me siento lleno de energía de nuevo!", + "happyC": "¡Guau, qué sensación tan mágica tocar la cabeza!", + "happyD": "¡Tocarme la cabeza me hace feliz todo el día!" + }, + "legAction": { + "angryA": "¡Oye, ¿quieres morir?", + "angryB": "¿Las manos de mi dueño ya no obedecen?", + "angryC": "¡Qué molesto, me va a dar comezón!", + "surprisedA": "¿Por qué no mantenemos una amistad pura?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "No me preguntes si he comido pollo hoy, primero mira mis bíceps", + "neutralB": "Mis brazos no son para que cualquiera los toque, tú eres una excepción", + "neutralC": "Eres valiente, atreverte a tocar el legendario brazo de unicornio" + }, + "bellyAction": { + "happyA": "No me hagas cosquillas, o reiré mostrando mis abdominales", + "neutralA": "Mis abdominales son solo el resultado de un entrenamiento oculto", + "neutralB": "¿Viste mis abdominales? Solo están escondidos profundamente" + }, + "chestAction": { + "blinkLeftA": "¡Ven, apóyate en mi pecho!", + "neutralA": "Esto es solo el resultado de mi entrenamiento diario, no hay nada sorprendente" + }, + "headAction": { + "neutralA": "Por supuesto, solo tú tienes el privilegio de tocarme la cabeza", + "neutralB": "No soy alguien a quien la gente común pueda tocar", + "neutralC": "No te preocupes, después de tocar mi cabeza, tu suerte mejorará considerablemente" + }, + "legAction": { + "angryA": "¡No te acerques, amante de las piernas!", + "neutralA": "No tengas miedo, mi pierna de acero no patea a tontos", + "neutralB": "¿Sentiste que tu vida se completó al tocar mi pierna?" + } + } + } +} diff --git a/locales/es-ES/error.json b/locales/es-ES/error.json new file mode 100644 index 00000000..02d5b63d --- /dev/null +++ b/locales/es-ES/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "La clave de API de OpenAI está vacía. Por favor, agregue su clave de API personalizada de OpenAI.", + "error": "Error", + "errorTip": { + "clearSession": "Limpiar mensajes de sesión", + "description": "El proyecto está actualmente en construcción y no se garantiza la estabilidad de los datos. Si encuentra algún problema, puede intentar", + "forgive": ", le pedimos disculpas por las molestias causadas", + "or": "o", + "problem": "Se ha producido un problema en la página...", + "resetSystem": "Restablecer la configuración del sistema" + }, + "goBack": "Volver a la página de inicio", + "openaiError": "Error de la API de OpenAI. Por favor, verifique que la clave de API de OpenAI y el punto final sean correctos.", + "reload": "Recargar", + "s3envError": "Error en la configuración de la variable de entorno S3. Por favor, verifique sus variables de entorno.", + "serverError": "Error del servidor. Por favor, contacte al administrador.", + "triggerError": "Error desencadenado", + "unknownError": "Error desconocido" +} diff --git a/locales/es-ES/features.json b/locales/es-ES/features.json new file mode 100644 index 00000000..6c97090a --- /dev/null +++ b/locales/es-ES/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Cambiar a modo vídeo" + }, + "agent": { + "female": "Mujer", + "male": "Hombre", + "other": "Otro" + }, + "feature": { + "addProxy": "Agregar dirección de proxy de OpenAI (opcional)", + "closeTip": "Cerrar consejo", + "comfirmRetry": "Confirmar y reintentar", + "startDesc": "Ingresa tu clave de API de OpenAI para comenzar la sesión. La aplicación no guardará tu clave de API.", + "startTitle": "Clave de API personalizada" + }, + "mode": { + "chat": "Chat", + "video": "Vídeo" + }, + "settings": { + "glow": "Brillo", + "nickName": "Ingresa un apodo", + "none": "Sin fondo" + }, + "share": { + "downloadScreenshot": "Descargar captura de pantalla", + "imageType": "Tipo de imagen", + "screenshot": "Captura de pantalla", + "share": "Compartir", + "shareGPT": "Compartir GPT", + "shareToGPT": "Generar enlace de compartir GPT", + "shareToMarket": "Compartir en el mercado de asistentes", + "withBackground": "Incluir imagen de fondo", + "withFooter": "Incluir pie de página", + "withSystemRole": "Incluir configuración de rol de asistente" + }, + "submit": { + "assistantId": "Identificador del asistente", + "assistantIdTip": "Ingresa el identificador único del asistente, por ejemplo vidol-agent-klee", + "submitAssistant": "Enviar asistente", + "submitWarning": "Por favor completa la información del asistente antes de enviar, debe incluir nombre, descripción, avatar y portada" + }, + "support": "Soporte comunitario", + "theme": { + "auto": "Seguir sistema", + "dark": "Modo oscuro", + "light": "Modo claro" + }, + "token": { + "overload": "Token excedido", + "remained": "Token restante", + "tokenCount": "Cantidad de tokens", + "useToken": "Cálculo de cantidad de tokens consumidos, incluyendo mensajes, configuraciones de rol y contexto: {{usedTokens}} / {{maxValue}}", + "used": "Token utilizado" + }, + "toolBar": { + "cameraControl": "Control de cámara", + "cameraHelper": "Asistente de cámara", + "downloadModel": "Descargando modelo, por favor espera...", + "floor": "Cambiar piso", + "grid": "Cuadrícula", + "resetCamera": "Restablecer cámara" + } +} diff --git a/locales/es-ES/layout.json b/locales/es-ES/layout.json new file mode 100644 index 00000000..ddc8dbed --- /dev/null +++ b/locales/es-ES/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Cuadro de diálogo", + "header": { + "chat": "Chat", + "market": "Descubrir", + "role": "Rol", + "settings": "Configuración", + "tips": "El proyecto está actualmente en construcción, no se garantiza la estabilidad de los datos. Si encuentra algún problema, puede borrar los mensajes de la sesión y restablecer la configuración del sistema en la configuración del sistema. Lamentamos las molestias ocasionadas." + }, + "sessionList": "Lista de sesiones", + "siderBar": "Barra lateral" +} diff --git a/locales/es-ES/my.json b/locales/es-ES/my.json new file mode 100644 index 00000000..4cebf9bd --- /dev/null +++ b/locales/es-ES/my.json @@ -0,0 +1,5 @@ +{ + "my": "Mi", + "myDance": "Mi baile", + "myRole": "Mi papel" +} diff --git a/locales/es-ES/panel.json b/locales/es-ES/panel.json new file mode 100644 index 00000000..510e4e8f --- /dev/null +++ b/locales/es-ES/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Agregar a la lista", + "addPlaySuccess": "Agregado a la lista de reproducción", + "cancelAddPlay": "¿Estás seguro de que quieres cancelar la suscripción a la música {{musicName}}?", + "cancelSubscribed": "Cancelar suscripción", + "findDance": "Encuentra tu baile favorito", + "musicAndDance": "Música y baile", + "play": "Reproducir" + }, + "info": { + "avatarDescription": "Avatar personalizado, haz clic en el avatar para cargar una imagen personalizada", + "avatarLabel": "Avatar", + "coverDescription": "Utilizado para mostrar al personaje en la página de descubrimiento, tamaño recomendado {{width}} x {{height}}", + "coverLabel": "Portada", + "descDescription": "Descripción del personaje, utilizada para una breve presentación del personaje", + "descLabel": "Descripción", + "emotionDescription": "Selecciona la emoción al responder, afectará los cambios de expresión del personaje", + "emotionLabel": "Expresión y emoción", + "genderDescription": "Género del personaje, afecta la respuesta táctil del personaje", + "genderLabel": "Género", + "greetDescription": "Saludo inicial al personaje al chatear por primera vez", + "greetLabel": "Saludo", + "modelDescription": "Vista previa del modelo, puedes arrastrar un archivo de modelo para reemplazarlo", + "modelLabel": "Vista previa del modelo", + "nameDescription": "Nombre del personaje, utilizado para dirigirse al personaje en el chat", + "nameLabel": "Nombre", + "readmeDescription": "Archivo de instrucciones del personaje, utilizado para mostrar una descripción detallada del personaje en la página de descubrimiento", + "readmeLabel": "Instrucciones del personaje", + "textDescription": "Texto de respuesta personalizado", + "textLabel": "Texto", + "categoryLabel": "Categoría", + "categoryDescription": "Categoría del personaje, utilizada para la clasificación" + }, + "market": { + "findVidol": "Encuentra tu ídolo favorito" + }, + "nav": { + "info": "Información básica", + "model": "Modelo 3D", + "role": "Configuración del personaje", + "voice": "Voz" + }, + "role": { + "greetTip": "Ingresa el saludo del personaje cuando te saluda", + "inputRoleSetting": "Ingresa la configuración del sistema del personaje", + "roleDescriptionTip": "Ingresa la descripción del personaje", + "roleNameTip": "Ingresa el nombre del personaje", + "roleReadmeTip": "Ingresa las instrucciones del personaje", + "roleSettingDescription": "Configuración de fondo del personaje, se enviará al modelo durante el chat con el personaje", + "roleSettingLabel": "Configuración del sistema del personaje", + "uploadSize": "Soporta la carga de un solo archivo, tamaño recomendado {{width}} x {{height}} o múltiplos de estos valores" + }, + "touch": { + "addAction": "Agregar acción de respuesta", + "editAction": "Editar acción de respuesta", + "inputActionEmotion": "Ingresa la emoción del personaje al responder", + "inputActionText": "Ingresa el texto de respuesta", + "inputDIYText": "Ingresa un texto personalizado", + "touchActionList": "Lista de reacciones al tocar {{touchArea}}", + "touchArea": "Área de contacto" + }, + "tts": { + "audition": "Audición", + "auditionDescription": "Texto de audición según el idioma", + "engineDescription": "Motor de síntesis de voz, se recomienda seleccionar primero el navegador Edge", + "engineLabel": "Motor de voz", + "localeDescription": "Idioma de síntesis de voz, actualmente solo se admiten los idiomas más comunes, para solicitudes adicionales, por favor contacta", + "localeLabel": "Idioma", + "pitchDescription": "Controla el tono de la voz, valores entre 0 y 2, por defecto es 1", + "pitchLabel": "Tono", + "selectLanguage": "Por favor, selecciona un idioma primero", + "selectVoice": "Por favor, selecciona una voz primero", + "speedDescription": "Controla la velocidad de la voz, valores entre 0 y 3, por defecto es 1", + "speedLabel": "Velocidad", + "transfromSuccess": "Transformación exitosa", + "voiceDescription": "Varía según el motor y el idioma", + "voiceLabel": "Voz" + }, + "upload": { + "support": "Soporta la carga de un solo archivo, actualmente solo se admite el formato de archivo vrm" + } +} diff --git a/locales/es-ES/role.json b/locales/es-ES/role.json new file mode 100644 index 00000000..5a89acbf --- /dev/null +++ b/locales/es-ES/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Eliminar rol", + "delRoleDesc": "¿Estás seguro de que deseas eliminar el rol {{name}} y los mensajes de sesión relacionados? Esta acción no se puede deshacer, ¡por favor, procede con precaución!", + "header": { + "role": "Rol", + "session": "Sesión" + }, + "noRole": "No hay roles por el momento. Puedes crear roles personalizados haciendo clic en +, o agregar roles desde la página de descubrimiento.", + "roleList": "Lista de roles", + "topBannerTitle": "Vista previa y configuración de roles" +} diff --git a/locales/es-ES/welcome.json b/locales/es-ES/welcome.json new file mode 100644 index 00000000..1902fc76 --- /dev/null +++ b/locales/es-ES/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} es el personaje predeterminado de Vidol, tu asistente personal exclusivo", + "greeting": "¡Hola, querido dueño! Soy tu asistente personal {{name}}, ¡encantado de servirte! ¿En qué puedo ayudarte?", + "hello": "¡Hola!", + "meta": { + "description": "Este es un personaje personalizado", + "name": "Personaje personalizado" + } + }, + "greet": "¡Hola, soy {{name}}, ¿en qué puedo ayudarte?", + "loadingTitle": "Inicializando la aplicación, por favor espera...", + "waitting": "Preparando todo mi mundo para ti" +} diff --git a/locales/fr-FR/chat.json b/locales/fr-FR/chat.json new file mode 100644 index 00000000..9b5bb014 --- /dev/null +++ b/locales/fr-FR/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chat", + "chatDialog": { + "close": "Fermer" + }, + "dance": "Danser", + "header": { + "role": "Rôle", + "session": "Session" + }, + "helloChat": "Bonjour, commençons à discuter", + "helloDance": "Salut, dansons ensemble", + "market": "Découvrir" +} diff --git a/locales/fr-FR/common.json b/locales/fr-FR/common.json new file mode 100644 index 00000000..79de0710 --- /dev/null +++ b/locales/fr-FR/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Ajouter", + "clearAll": "Tout effacer", + "clearContext": "Effacer le contexte", + "clearHistoryTip": "Cette action est irréversible. Veuillez procéder avec prudence.", + "clearHistoryTitle": "Confirmer la suppression de l'historique des messages ?", + "clearNow": "Effacer maintenant", + "clearSuccess": "Effacement réussi", + "clearTip": "Cette action est irréversible. Les données seront perdues définitivement. Veuillez procéder avec prudence.", + "clearTitle": "Confirmer la suppression de tous les messages de la session ?", + "confirmDel": "Confirmer la suppression ?", + "copy": "Copier", + "copySuccess": "Copie réussie", + "del": "Supprimer", + "delAndRegenerate": "Supprimer et régénérer", + "downloadAvatar": "Télécharger l'avatar", + "downloadCover": "Télécharger la couverture", + "downloadFailed": "Échec du téléchargement", + "downloadModel": "Télécharger le modèle", + "downloadSubscribe": "Télécharger l'abonnement", + "downloadSuccess": "Téléchargement réussi", + "edit": "Modifier", + "goBottom": "Aller en bas", + "market": "Découvrir", + "pause": "Pause", + "play": "Lire", + "regenerate": "Régénérer", + "removeInList": "Supprimer de la liste", + "reset": "Réinitialiser", + "resetNow": "Réinitialiser maintenant", + "resetSuccess": "Réinitialisation réussie", + "resetTip": "Cette action est irréversible. Les données seront perdues définitivement. Veuillez procéder avec prudence.", + "resetTitle": "Confirmer la réinitialisation de tous les paramètres système ?", + "save": "Enregistrer", + "send": "Envoyer", + "share": "Partager", + "subscribe": "S'abonner", + "subscribeDance": "S'abonner à la danse", + "subscribeRole": "S'abonner au rôle", + "subscribed": "Abonné", + "unsubscribe": "Se désabonner", + "unsubscribeSuccess": "Désabonnement réussi", + "warp": "Saut de ligne" + }, + "aiAlert": "Veuillez noter que tout ce que dit l'assistant est généré par l'IA.", + "cancel": "Annuler", + "commonSetting": "Paramètres communs", + "confirm": "Confirmer", + "defaultAssistant": "Assistant par défaut", + "delAlert": "Confirmer la suppression du rôle et des messages de session associés ? Cette action est irréversible. Veuillez procéder avec prudence !", + "delRole": "Supprimer le rôle", + "delSession": "Supprimer la session", + "delSessionAlert": "Confirmer la suppression de la conversation ? Cette action est irréversible. Veuillez procéder avec prudence !", + "inputStartChat": "Veuillez saisir du texte pour commencer la conversation", + "languageModel": "Modèle de langue", + "loading": "Chargement...", + "noData": "Aucune donnée", + "openai": { + "callError": "Échec de l'appel à l'API. Veuillez vérifier la clé API et l'adresse du proxy de l'API.", + "check": "Vérifier", + "checkAll": "Vérifier la clé API et l'adresse du proxy de l'API", + "checkConnect": "Vérifier la connectivité", + "checkOk": "Vérification réussie", + "langModel": "Modèle de langue OpenAI", + "model": "Modèle", + "proxyUrl": "Adresse du proxy de l'API", + "roleModel": "Modèle Role GPT", + "useOwnKey": "Veuillez utiliser votre propre clé OpenAI" + }, + "playlist": "Liste de lecture", + "search": "Rechercher", + "selectInDanceList": "Veuillez sélectionner dans la liste de danses", + "selectModel": "Veuillez sélectionner un modèle", + "setLocalStorage": "Définir le stockage local", + "startChat": "Commencer la conversation", + "ttsCombine": "Synthèse vocale", + "ttsTip": "Reconnaissance vocale (nécessite une connexion Internet)", + "uploadTip": "Cliquez ou faites glisser un fichier dans cette zone pour le télécharger", + "words": { + "DIYAvatar": "Avatar personnalisé", + "DIYBackgroundEffect": "Effet de fond personnalisé", + "DIYColor": "Personnalisation des nuances de gris selon les préférences de couleur", + "DIYNickname": "Pseudo personnalisé", + "DIYTopicColor": "Couleur de sujet personnalisée", + "avatar": "Avatar", + "backgroundEffect": "Effet de fond", + "chatSetting": "Paramètres de conversation", + "clearAllSession": "Effacer toutes les sessions", + "clearAllSessionDesc": "Cela effacera toutes les données de session et de rôle, y compris la liste des sessions, la liste des rôles, les messages de session, etc.", + "midColor": "Couleur neutre", + "nickname": "Pseudo", + "resetSystemSetting": "Réinitialiser les paramètres système", + "resetSystemSettingDesc": "Cela réinitialisera tous les paramètres système, y compris les paramètres de sujet, les paramètres de conversation, les paramètres du modèle de langue, etc.", + "systemSetting": "Paramètres système", + "languageSetting": "Paramètres de langue", + "topicColor": "Couleur de sujet", + "topicSetting": "Paramètres de sujet" + } +} diff --git a/locales/fr-FR/constants.json b/locales/fr-FR/constants.json new file mode 100644 index 00000000..a7249824 --- /dev/null +++ b/locales/fr-FR/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "femme", + "male": "homme", + "other": "autre" + }, + "meta": { + "description": "This is a custom role", + "name": "Custom Role" + } + }, + "touch": { + "area": { + "arm": "bras", + "belly": "ventre", + "chest": "poitrine", + "head": "tête", + "leg": "jambe" + }, + "emotion": { + "angry": "en colère", + "blink": "cligner des yeux", + "blinkLeft": "cligner de l'œil gauche", + "blinkRight": "cligner de l'œil droit", + "happy": "heureux", + "natural": "naturel", + "relaxed": "détendu", + "sad": "triste", + "surprised": "surpris" + }, + "femaleAction": { + "armAction": { + "happyA": "Ah, j'aime ça !", + "happyB": "Haha, tenir la main me rend heureuse !", + "relaxedA": "Les mains de mon propriétaire sont si chaudes !" + }, + "bellyAction": { + "angryA": "Pourquoi tu me touches ? Attention, je pourrais te mordre !", + "relaxedA": "Réveille-toi, il n'y a pas d'avenir entre nous !", + "relaxedB": "Je déteste ça ! Je vais me fâcher !", + "surprisedA": "C'était un accident, n'est-ce pas ?" + }, + "chestAction": { + "angryA": "Arrête de me taquiner ! Retire tes mains !", + "angryB": "Qu'est-ce que tu fais ? Il y a un pervers qui me touche tout le temps !", + "angryC": "Si tu continues, je vais appeler la police !", + "surprisedA": "Pourquoi tu me touches ? On ne peut plus discuter joyeusement ?" + }, + "headAction": { + "angryA": "On dit que se faire caresser la tête empêche de grandir !", + "angryB": "Pourquoi tu me touches ?", + "happyA": "Waouh ! J'adore quand on me caresse la tête !", + "happyB": "Je me sens plein d'énergie !", + "happyC": "Waouh, cette sensation de caresse sur la tête est incroyable !", + "happyD": "Me caresser la tête me rend heureuse toute la journée !" + }, + "legAction": { + "angryA": "Hé, tu veux mourir ?", + "angryB": "Les mains de mon propriétaire ne m'écoutent plus ?", + "angryC": "Je déteste ça, ça me chatouille !", + "surprisedA": "Pourquoi ne pas garder notre amitié pure ?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Ne me demande pas si j'ai mangé du poulet aujourd'hui, regarde plutôt mes biceps.", + "neutralB": "Mon bras n'est pas fait pour être touché par n'importe qui, tu es une exception.", + "neutralC": "Tu es courageux, oser toucher mon bras légendaire." + }, + "bellyAction": { + "happyA": "Ne me chatouille pas, tu risques de me faire rire et de voir mes abdominaux !", + "neutralA": "Mes abdominaux cachent simplement ma force intérieure que je continue de cultiver.", + "neutralB": "As-tu vu mes abdominaux ? Ils sont simplement bien cachés." + }, + "chestAction": { + "blinkLeftA": "Viens, tu peux te reposer sur mes pectoraux !", + "neutralA": "Ce sont juste mes pectoraux que j'ai développés grâce à mon entraînement quotidien, rien de surprenant." + }, + "headAction": { + "neutralA": "Bien sûr, tu es la seule personne autorisée à me caresser la tête.", + "neutralB": "Je ne suis pas quelqu'un que n'importe qui peut toucher.", + "neutralC": "Ne t'inquiète pas, après m'avoir caressé la tête, ta chance augmentera considérablement." + }, + "legAction": { + "angryA": "Ne t'approche pas de moi, fétichiste des jambes !", + "neutralA": "N'aie pas peur, ma jambe de fer ne frappe pas les idiots.", + "neutralB": "Maintenant que tu as touché ma jambe, ta vie est-elle plus complète ?" + } + } + } +} diff --git a/locales/fr-FR/error.json b/locales/fr-FR/error.json new file mode 100644 index 00000000..ce093a2d --- /dev/null +++ b/locales/fr-FR/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "La clé API OpenAI est manquante. Veuillez ajouter une clé API OpenAI personnalisée.", + "error": "Erreur", + "errorTip": { + "clearSession": "Effacer les messages de session", + "description": "Le projet est actuellement en cours de construction et la stabilité des données n'est pas garantie. Si vous rencontrez un problème, vous pouvez essayer", + "forgive": "", + "or": "ou", + "problem": "Le site a rencontré un problème...", + "resetSystem": "Réinitialiser les paramètres système" + }, + "goBack": "Retour à la page d'accueil", + "openaiError": "Erreur de l'API OpenAI. Veuillez vérifier votre clé API OpenAI et votre point de terminaison.", + "reload": "Recharger la page", + "s3envError": "Les variables d'environnement S3 ne sont pas entièrement configurées. Veuillez vérifier vos variables d'environnement.", + "serverError": "Erreur serveur. Veuillez contacter l'administrateur.", + "triggerError": "Erreur déclenchée", + "unknownError": "Erreur inconnue" +} diff --git a/locales/fr-FR/features.json b/locales/fr-FR/features.json new file mode 100644 index 00000000..dc52e6c8 --- /dev/null +++ b/locales/fr-FR/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Activer le mode vidéo" + }, + "agent": { + "female": "Femme", + "male": "Homme", + "other": "Autre" + }, + "feature": { + "addProxy": "Ajouter une adresse proxy OpenAI (facultatif)", + "closeTip": "Fermer l'astuce", + "comfirmRetry": "Confirmer et réessayer", + "startDesc": "Entrez votre clé d'API OpenAI pour commencer la session. L'application ne stockera pas votre clé d'API.", + "startTitle": "Personnaliser la clé d'API" + }, + "mode": { + "chat": "Discussion", + "video": "Vidéo" + }, + "settings": { + "glow": "Lueur", + "nickName": "Veuillez entrer un pseudonyme", + "none": "Aucun arrière-plan" + }, + "share": { + "downloadScreenshot": "Télécharger la capture d'écran", + "imageType": "Format de l'image", + "screenshot": "Capture d'écran", + "share": "Partager", + "shareGPT": "Partager GPT", + "shareToGPT": "Générer un lien de partage ShareGPT", + "shareToMarket": "Partager sur le marché des assistants", + "withBackground": "Inclure l'image d'arrière-plan", + "withFooter": "Inclure le pied de page", + "withSystemRole": "Inclure le rôle de l'assistant" + }, + "submit": { + "assistantId": "Identifiant de l'assistant", + "assistantIdTip": "Veuillez entrer l'identifiant de l'assistant. Il doit être unique, par exemple : vidol-agent-klee", + "submitAssistant": "Soumettre l'assistant", + "submitWarning": "Veuillez compléter les informations de l'assistant avant de soumettre. Cela doit inclure le nom, la description, l'avatar et la couverture." + }, + "support": "Support communautaire", + "theme": { + "auto": "Système par défaut", + "dark": "Mode sombre", + "light": "Mode clair" + }, + "token": { + "overload": "Dépassement de tokens", + "remained": "Tokens restants", + "tokenCount": "Nombre de tokens", + "useToken": "Calcul du nombre de tokens utilisés, y compris les messages, les rôles et le contexte : {{usedTokens}} / {{maxValue}}", + "used": "Tokens utilisés" + }, + "toolBar": { + "cameraControl": "Contrôle de la caméra", + "cameraHelper": "Assistant de caméra", + "downloadModel": "Téléchargement du modèle en cours, veuillez patienter...", + "floor": "Changer de sol", + "grid": "Grille", + "resetCamera": "Réinitialiser la caméra" + } +} diff --git a/locales/fr-FR/layout.json b/locales/fr-FR/layout.json new file mode 100644 index 00000000..e1303d52 --- /dev/null +++ b/locales/fr-FR/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialogue", + "header": { + "chat": "Chat", + "market": "Discover", + "role": "Role", + "settings": "Settings", + "tips": "The project is currently under construction, and data stability is not guaranteed. If you encounter any issues, you can clear the session messages and reset the system settings in the system settings. We apologize for any inconvenience caused." + }, + "sessionList": "Session List", + "siderBar": "Sidebar" +} diff --git a/locales/fr-FR/my.json b/locales/fr-FR/my.json new file mode 100644 index 00000000..a744bd34 --- /dev/null +++ b/locales/fr-FR/my.json @@ -0,0 +1,5 @@ +{ + "my": "mon", + "myDance": "ma danse", + "myRole": "mon rôle" +} diff --git a/locales/fr-FR/panel.json b/locales/fr-FR/panel.json new file mode 100644 index 00000000..73c021cd --- /dev/null +++ b/locales/fr-FR/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Ajouter à la liste", + "addPlaySuccess": "Ajouté à la liste de lecture", + "cancelAddPlay": "Voulez-vous vraiment annuler l'abonnement à la musique {{musicName}}?", + "cancelSubscribed": "Annuler l'abonnement", + "findDance": "Trouvez votre danse préférée", + "musicAndDance": "Musique et danse", + "play": "Jouer" + }, + "info": { + "avatarDescription": "Avatar personnalisé, cliquez sur l'avatar pour télécharger", + "avatarLabel": "Avatar", + "coverDescription": "Utilisé pour afficher le personnage sur la page de découverte, taille recommandée {{width}} x {{height}}", + "coverLabel": "Couverture", + "descDescription": "Description du personnage, utilisée pour une brève introduction", + "descLabel": "Description", + "emotionDescription": "Sélectionnez l'émotion lors de la réponse, affectera l'expression du personnage", + "emotionLabel": "Expression et émotion", + "genderDescription": "Genre du personnage, affecte la réponse au toucher", + "genderLabel": "Genre", + "greetDescription": "Phrase de salutation lors de la première conversation avec le personnage", + "greetLabel": "Salutation", + "modelDescription": "Aperçu du modèle, vous pouvez faire glisser le fichier du modèle pour le remplacer", + "modelLabel": "Aperçu du modèle", + "nameDescription": "Nom du personnage, utilisé pour l'appeler lors de la conversation", + "nameLabel": "Nom", + "readmeDescription": "Fichier de description du personnage, utilisé pour afficher une description détaillée sur la page de découverte", + "readmeLabel": "Description du personnage", + "textDescription": "Réponse personnalisée", + "textLabel": "Texte", + "categoryLabel": "Catégorie", + "categoryDescription": "Catégorie du personnage, utilisée pour la classification" + }, + "market": { + "findVidol": "Trouvez votre idole préférée" + }, + "nav": { + "info": "Informations de base", + "model": "Modèle 3D", + "role": "Paramètres du personnage", + "voice": "Voix" + }, + "role": { + "greetTip": "Entrez la phrase de salutation du personnage", + "inputRoleSetting": "Entrez les paramètres système du personnage", + "roleDescriptionTip": "Entrez la description du personnage", + "roleNameTip": "Entrez le nom du personnage", + "roleReadmeTip": "Entrez la description du personnage", + "roleSettingDescription": "Paramètres de fond du personnage, envoyés au modèle lors de la conversation avec le personnage", + "roleSettingLabel": "Paramètres système du personnage", + "uploadSize": "Prise en charge du téléchargement de fichiers uniques, taille recommandée multiple de {{width}} x {{height}}" + }, + "touch": { + "addAction": "Ajouter une action de réponse", + "editAction": "Modifier l'action de réponse", + "inputActionEmotion": "Entrez l'expression du personnage lors de la réponse", + "inputActionText": "Entrez le texte de réponse", + "inputDIYText": "Entrez le texte personnalisé", + "touchActionList": "Liste de réactions lors du toucher {{touchArea}}", + "touchArea": "Zone de toucher" + }, + "tts": { + "audition": "Audition", + "auditionDescription": "Texte d'audition en fonction de la langue", + "engineDescription": "Moteur de synthèse vocale, il est recommandé de choisir en priorité le navigateur Edge", + "engineLabel": "Moteur de synthèse vocale", + "localeDescription": "Langue de synthèse vocale, seules quelques langues courantes sont actuellement prises en charge, veuillez nous contacter si nécessaire", + "localeLabel": "Langue", + "pitchDescription": "Contrôle la tonalité de la voix, plage de valeurs 0 ~ 2, valeur par défaut 1", + "pitchLabel": "Tonalité", + "selectLanguage": "Veuillez sélectionner la langue", + "selectVoice": "Veuillez sélectionner la voix", + "speedDescription": "Contrôle la vitesse de synthèse vocale, plage de valeurs 0 ~ 3, valeur par défaut 1", + "speedLabel": "Vitesse", + "transfromSuccess": "Conversion réussie", + "voiceDescription": "Différentes voix sont disponibles en fonction du moteur et de la langue", + "voiceLabel": "Voix" + }, + "upload": { + "support": "Prise en charge du téléchargement de fichiers uniques, actuellement uniquement au format vrm" + } +} diff --git a/locales/fr-FR/role.json b/locales/fr-FR/role.json new file mode 100644 index 00000000..7e16e607 --- /dev/null +++ b/locales/fr-FR/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Supprimer le rôle", + "delRoleDesc": "Êtes-vous sûr de vouloir supprimer le rôle {{name}} ainsi que les messages de session associés ? Cette action est irréversible, veuillez procéder avec prudence !", + "header": { + "role": "Rôle", + "session": "Session" + }, + "noRole": "Aucun rôle disponible. Vous pouvez créer un rôle personnalisé en utilisant le symbole +, ou ajouter un rôle depuis la page de découverte.", + "roleList": "Liste des rôles", + "topBannerTitle": "Aperçu et configuration des rôles" +} diff --git a/locales/fr-FR/welcome.json b/locales/fr-FR/welcome.json new file mode 100644 index 00000000..e17b8df9 --- /dev/null +++ b/locales/fr-FR/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} est le personnage par défaut de Vidol, votre assistant personnel exclusif.", + "greeting": "Bonjour, cher maître ! Je suis votre assistant personnel {{name}}, ravi de vous aider ! Comment puis-je vous assister ?", + "hello": "Bonjour !", + "meta": { + "description": "Ceci est un personnage personnalisé.", + "name": "Personnage personnalisé" + } + }, + "greet": "Bonjour, je suis {{name}}, comment puis-je vous aider ?", + "loadingTitle": "Initialisation de l'application en cours, veuillez patienter...", + "waitting": "Je prépare tout mon monde pour toi" +} diff --git a/locales/it-IT/chat.json b/locales/it-IT/chat.json new file mode 100644 index 00000000..e5e80520 --- /dev/null +++ b/locales/it-IT/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chat", + "chatDialog": { + "close": "Close" + }, + "dance": "Dance", + "header": { + "role": "Role", + "session": "Session" + }, + "helloChat": "Hello, let's chat", + "helloDance": "Hi, let's dance together", + "market": "Discover" +} diff --git a/locales/it-IT/common.json b/locales/it-IT/common.json new file mode 100644 index 00000000..b615a204 --- /dev/null +++ b/locales/it-IT/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Aggiungi", + "clearAll": "Cancella tutto", + "clearContext": "Cancella contesto", + "clearHistoryTip": "Questa operazione è irreversibile. Procedere con cautela.", + "clearHistoryTitle": "Confermi di voler eliminare la cronologia dei messaggi?", + "clearNow": "Cancella ora", + "clearSuccess": "Cancellazione completata", + "clearTip": "L'operazione non può essere annullata. I dati non potranno essere ripristinati dopo la cancellazione. Procedere con cautela.", + "clearTitle": "Confermi di voler cancellare tutti i messaggi di sessione?", + "confirmDel": "Sei sicuro di voler eliminare?", + "copy": "Copia", + "copySuccess": "Copia riuscita", + "del": "Elimina", + "delAndRegenerate": "Elimina e rigenera", + "downloadAvatar": "Scarica avatar", + "downloadCover": "Scarica copertina", + "downloadFailed": "Download fallito", + "downloadModel": "Scarica modello", + "downloadSubscribe": "Scarica iscrizione", + "downloadSuccess": "Download completato", + "edit": "Modifica", + "goBottom": "Vai in fondo", + "market": "Scopri", + "pause": "Pausa", + "play": "Riproduci", + "regenerate": "Rigenera", + "removeInList": "Rimuovi dalla lista", + "reset": "Ripristina", + "resetNow": "Ripristina ora", + "resetSuccess": "Ripristino completato", + "resetTip": "L'operazione non può essere annullata. I dati non potranno essere ripristinati dopo il ripristino. Procedere con cautela.", + "resetTitle": "Confermi di voler ripristinare tutte le impostazioni di sistema?", + "save": "Salva", + "send": "Invia", + "share": "Condividi", + "subscribe": "Iscriviti", + "subscribeDance": "Iscriviti alla danza", + "subscribeRole": "Iscriviti al ruolo", + "subscribed": "Iscritto", + "unsubscribe": "Annulla iscrizione", + "unsubscribeSuccess": "Iscrizione annullata", + "warp": "A capo" + }, + "aiAlert": "Ricorda: tutto ciò che l'agente intelligente dice è generato dall'IA", + "cancel": "Annulla", + "commonSetting": "Impostazioni comuni", + "confirm": "Conferma", + "defaultAssistant": "Assistente predefinito", + "delAlert": "Confermi l'eliminazione del ruolo e dei messaggi di sessione correlati? L'operazione non può essere annullata, procedere con cautela!", + "delRole": "Elimina ruolo", + "delSession": "Elimina sessione", + "delSessionAlert": "Confermi l'eliminazione della conversazione? L'operazione non può essere annullata, procedere con cautela!", + "inputStartChat": "Inserisci il contenuto per iniziare la chat", + "languageModel": "Modello linguistico", + "loading": "Caricamento in corso...", + "noData": "Nessun dato", + "openai": { + "callError": "Errore di chiamata all'API, controlla che l'API Key e l'indirizzo del proxy siano corretti", + "check": "Controlla", + "checkAll": "Controlla che l'API Key e l'indirizzo del proxy siano corretti", + "checkConnect": "Controllo di connettività", + "checkOk": "Controllo riuscito", + "langModel": "Modello linguistico OpenAI", + "model": "Modello", + "proxyUrl": "Indirizzo del proxy", + "roleModel": "Modello GPT del ruolo", + "useOwnKey": "Utilizza la tua chiave OpenAI" + }, + "playlist": "Playlist", + "search": "Cerca", + "selectInDanceList": "Seleziona dalla lista delle danze", + "selectModel": "Seleziona modello", + "setLocalStorage": "Imposta la memoria locale", + "startChat": "Inizia la chat", + "ttsCombine": "Sintesi vocale", + "ttsTip": "Riconoscimento vocale (richiede una connessione Internet sicura)", + "uploadTip": "Fai clic o trascina il file in questa area per caricarlo", + "words": { + "DIYAvatar": "Avatar personalizzato", + "DIYBackgroundEffect": "Effetto di sfondo personalizzato", + "DIYColor": "Personalizzazione della scala di grigi con diverse tendenze di colore", + "DIYNickname": "Soprannome personalizzato", + "DIYTopicColor": "Colore dell'argomento personalizzato", + "avatar": "Avatar", + "backgroundEffect": "Effetto di sfondo", + "chatSetting": "Impostazioni chat", + "clearAllSession": "Cancella tutte le sessioni", + "clearAllSessionDesc": "Cancella tutti i dati delle sessioni e dei ruoli, inclusi elenchi di sessioni, elenchi di ruoli, messaggi di sessione, ecc.", + "midColor": "Colore neutro", + "nickname": "Soprannome", + "resetSystemSetting": "Ripristina impostazioni di sistema", + "resetSystemSettingDesc": "Ripristina tutte le impostazioni di sistema, inclusi le impostazioni dell'argomento, della chat, del modello linguistico, ecc.", + "systemSetting": "Impostazioni di sistema", + "languageSetting": "Impostazioni lingua", + "topicColor": "Colore dell'argomento", + "topicSetting": "Impostazioni argomento" + } +} diff --git a/locales/it-IT/constants.json b/locales/it-IT/constants.json new file mode 100644 index 00000000..643366a6 --- /dev/null +++ b/locales/it-IT/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Femmina", + "male": "Maschio", + "other": "Altro" + }, + "meta": { + "description": "Questo è un ruolo personalizzato", + "name": "Ruolo Personalizzato" + } + }, + "touch": { + "area": { + "arm": "Braccio", + "belly": "Pancia", + "chest": "Petto", + "head": "Testa", + "leg": "Gamba" + }, + "emotion": { + "angry": "Arrabbiato", + "blink": "Battere le palpebre", + "blinkLeft": "Battere la palpebra sinistra", + "blinkRight": "Battere la palpebra destra", + "happy": "Felice", + "natural": "Naturale", + "relaxed": "Rilassato", + "sad": "Triste", + "surprised": "Sorpreso" + }, + "femaleAction": { + "armAction": { + "happyA": "Oh, mi piace molto~", + "happyB": "Haha, tenere le mani mi rende felice~", + "relaxedA": "Le mani del padrone sono così calde~" + }, + "bellyAction": { + "angryA": "Perché mi tocchi, attento che ti mordo!", + "relaxedA": "Svegliati, non c'è futuro tra noi!", + "relaxedB": "No, mi sto arrabbiando!", + "surprisedA": "Sicuramente è stato un incidente..." + }, + "chestAction": { + "angryA": "Non puoi farmi questo! Togli subito le mani!", + "angryB": "Zero zero uno? C'è un pazzo che mi sta accarezzando!", + "angryC": "Se mi tocchi ancora, chiamo la polizia!", + "surprisedA": "Perché mi tocchi? Possiamo ancora parlare tranquillamente!" + }, + "headAction": { + "angryA": "Si dice che essere accarezzate in testa impedisca la crescita!", + "angryB": "Perché mi tocchi così?", + "happyA": "Wow! Adoro essere accarezzata in testa!", + "happyB": "Mi sento piena di energia!", + "happyC": "Wow, questa carezza in testa è così magica!", + "happyD": "Essere accarezzata in testa mi rende felice per tutta la giornata!" + }, + "legAction": { + "angryA": "Ehi, stai cercando guai?", + "angryB": "Le mani del padrone non obbediscono più?", + "angryC": "No, smettila, mi fa prudere!", + "surprisedA": "Possiamo mantenere una pura amicizia, giusto?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Non chiedermi se ho mangiato pollo oggi, guarda i miei bicipiti", + "neutralB": "Il mio braccio non è per essere toccato da tutti, tu sei un'eccezione", + "neutralC": "Sei coraggioso, hai toccato il mitico braccio di Kirin" + }, + "bellyAction": { + "happyA": "Non farmi solleticare, potrei scoppiare a ridere per i miei addominali", + "neutralA": "I miei addominali sono solo la forza nascosta che ho allenato", + "neutralB": "Hai visto i miei addominali? Sono solo ben nascosti" + }, + "chestAction": { + "blinkLeftA": "Vieni, appoggia al mio petto!", + "neutralA": "Questo è solo il petto che ho allenato quotidianamente, niente di sorprendente" + }, + "headAction": { + "neutralA": "Solo tu hai il permesso di toccarmi la testa", + "neutralB": "La mia testa non è per essere toccata da chiunque", + "neutralC": "Dopo avermi toccato la testa, avrai una grande fortuna" + }, + "legAction": { + "angryA": "Non avvicinarti, sei ossessionato dalle gambe", + "neutralA": "Non preoccuparti, la mia gamba di ferro non colpisce gli sciocchi", + "neutralB": "Sentire la mia gamba, ti fa sentire che la tua vita è più completa?" + } + } + } +} diff --git a/locales/it-IT/error.json b/locales/it-IT/error.json new file mode 100644 index 00000000..d5f0e84d --- /dev/null +++ b/locales/it-IT/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "La chiave API di OpenAI è vuota, si prega di aggiungere una chiave API personalizzata di OpenAI", + "error": "Errore", + "errorTip": { + "clearSession": "Cancella messaggio di sessione", + "description": "Il progetto è attualmente in fase di costruzione, non possiamo garantire la stabilità dei dati. Se riscontri problemi, puoi provare", + "forgive": ", ci scusiamo per l'inconveniente causato", + "or": "o", + "problem": "La pagina ha riscontrato un problema...", + "resetSystem": "Ripristina le impostazioni di sistema" + }, + "goBack": "Torna alla homepage", + "openaiError": "Errore nell'API di OpenAI, si prega di controllare che la chiave API di OpenAI e l'Endpoint siano corretti", + "reload": "Ricarica", + "s3envError": "Variabile di ambiente S3 non completamente impostata, si prega di controllare le variabili di ambiente", + "serverError": "Errore del server, si prega di contattare l'amministratore", + "triggerError": "Errore di attivazione", + "unknownError": "Errore sconosciuto" +} diff --git a/locales/it-IT/features.json b/locales/it-IT/features.json new file mode 100644 index 00000000..f4154d59 --- /dev/null +++ b/locales/it-IT/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Attiva modalità video" + }, + "agent": { + "female": "Femminile", + "male": "Maschile", + "other": "Altro" + }, + "feature": { + "addProxy": "Aggiungi indirizzo proxy OpenAI (opzionale)", + "closeTip": "Chiudi suggerimento", + "comfirmRetry": "Conferma e riprova", + "startDesc": "Inserisci la tua chiave API di OpenAI per iniziare la sessione. L'applicazione non memorizzerà la tua chiave API", + "startTitle": "Personalizza la chiave API" + }, + "mode": { + "chat": "Chat", + "video": "Video" + }, + "settings": { + "glow": "Bagliore", + "nickName": "Inserisci un nickname", + "none": "Nessuno sfondo" + }, + "share": { + "downloadScreenshot": "Scarica schermata", + "imageType": "Formato immagine", + "screenshot": "Cattura schermata", + "share": "Condividi", + "shareGPT": "Condividi GPT", + "shareToGPT": "Genera link condivisione ShareGPT", + "shareToMarket": "Condividi sul mercato assistenti", + "withBackground": "Includi immagine di sfondo", + "withFooter": "Includi piè di pagina", + "withSystemRole": "Includi impostazioni ruolo assistente" + }, + "submit": { + "assistantId": "ID assistente", + "assistantIdTip": "Inserisci l'identificatore dell'assistente, deve essere univoco, ad esempio vidol-agent-klee", + "submitAssistant": "Invia assistente", + "submitWarning": "Completa le informazioni dell'assistente prima di inviare, devono includere nome, descrizione, avatar e copertina" + }, + "support": "Supporto della community", + "theme": { + "auto": "Segui il sistema", + "dark": "Modalità scura", + "light": "Modalità chiara" + }, + "token": { + "overload": "Token esauriti", + "remained": "Token rimanenti", + "tokenCount": "Conteggio token", + "useToken": "Calcolo del numero di token consumati, inclusi messaggi, impostazioni ruolo e contesto: {{usedTokens}} / {{maxValue}}", + "used": "Token utilizzati" + }, + "toolBar": { + "cameraControl": "Controllo fotocamera", + "cameraHelper": "Assistente fotocamera", + "downloadModel": "Download del modello in corso, attendere...", + "floor": "Cambia pavimento", + "grid": "Griglia", + "resetCamera": "Reimposta fotocamera" + } +} diff --git a/locales/it-IT/layout.json b/locales/it-IT/layout.json new file mode 100644 index 00000000..abe918ec --- /dev/null +++ b/locales/it-IT/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialogo", + "header": { + "chat": "Chat", + "market": "Scopri", + "role": "Ruolo", + "settings": "Impostazioni", + "tips": "Il progetto è attualmente in fase di costruzione, non garantiamo la stabilità dei dati. In caso di problemi, è possibile cancellare i messaggi di sessione e ripristinare le impostazioni di sistema nelle impostazioni del sistema. Ci scusiamo per l'inconveniente." + }, + "sessionList": "Elenco sessioni", + "siderBar": "Barra laterale" +} diff --git a/locales/it-IT/my.json b/locales/it-IT/my.json new file mode 100644 index 00000000..a033e6f9 --- /dev/null +++ b/locales/it-IT/my.json @@ -0,0 +1,5 @@ +{ + "my": "Il mio", + "myDance": "La mia danza", + "myRole": "Il mio ruolo" +} diff --git a/locales/it-IT/panel.json b/locales/it-IT/panel.json new file mode 100644 index 00000000..9de556b9 --- /dev/null +++ b/locales/it-IT/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Aggiungi alla lista", + "addPlaySuccess": "Aggiunto alla lista di riproduzione", + "cancelAddPlay": "Sei sicuro di voler annullare l'iscrizione alla musica {{musicName}}?", + "cancelSubscribed": "Annulla iscrizione", + "findDance": "Trova la tua danza preferita", + "musicAndDance": "Musica e danza", + "play": "Riproduci" + }, + "info": { + "avatarDescription": "Personalizza l'avatar, fai clic sull'avatar per caricare personalizzazioni", + "avatarLabel": "Avatar", + "coverDescription": "Utilizzato per mostrare il personaggio nella pagina di scoperta, dimensioni consigliate {{width}} x {{height}}", + "coverLabel": "Copertina", + "descDescription": "Descrizione del personaggio, utilizzata per una breve presentazione del personaggio", + "descLabel": "Descrizione", + "emotionDescription": "Seleziona l'emozione durante la risposta, influenzerà i cambiamenti di espressione del personaggio", + "emotionLabel": "Espressione ed emozione", + "genderDescription": "Sesso del personaggio, influisce sulla risposta tattile del personaggio", + "genderLabel": "Sesso", + "greetDescription": "Saluto iniziale al personaggio durante la chat", + "greetLabel": "Saluto", + "modelDescription": "Anteprima del modello, trascina il file del modello per sostituirlo", + "modelLabel": "Anteprima del modello", + "nameDescription": "Nome del personaggio, utilizzato per chiamare il personaggio durante la chat", + "nameLabel": "Nome", + "readmeDescription": "File di istruzioni del personaggio, utilizzato per mostrare una descrizione dettagliata del personaggio nella pagina di scoperta", + "readmeLabel": "Istruzioni del personaggio", + "textDescription": "Testo di risposta personalizzato", + "textLabel": "Testo", + "categoryLabel": "Categoria", + "categoryDescription": "Categoria del personaggio, utilizzata per la classificazione" + }, + "market": { + "findVidol": "Trova il tuo idolo preferito" + }, + "nav": { + "info": "Informazioni di base", + "model": "Modello 3D", + "role": "Impostazioni del personaggio", + "voice": "Voce" + }, + "role": { + "greetTip": "Inserisci il saluto del personaggio quando ti saluta", + "inputRoleSetting": "Inserisci le impostazioni di sistema del personaggio", + "roleDescriptionTip": "Inserisci la descrizione del personaggio", + "roleNameTip": "Inserisci il nome del personaggio", + "roleReadmeTip": "Inserisci le istruzioni del personaggio", + "roleSettingDescription": "Impostazioni di background del personaggio, inviate al modello durante la chat con il personaggio", + "roleSettingLabel": "Impostazioni di sistema del personaggio", + "uploadSize": "Supporto per il caricamento di un singolo file, dimensioni consigliate {{width}} x {{height}} o multipli" + }, + "touch": { + "addAction": "Aggiungi azione di risposta", + "editAction": "Modifica azione di risposta", + "inputActionEmotion": "Inserisci l'emozione del personaggio durante la risposta", + "inputActionText": "Inserisci il testo di risposta", + "inputDIYText": "Inserisci il testo personalizzato", + "touchActionList": "Elenco di reazioni quando tocchi {{touchArea}}", + "touchArea": "Area di tocco" + }, + "tts": { + "audition": "Audizione", + "auditionDescription": "Il testo di audizione varia a seconda della lingua", + "engineDescription": "Motore di sintesi vocale, si consiglia di utilizzare il browser Edge", + "engineLabel": "Motore vocale", + "localeDescription": "Lingua di sintesi vocale supportata, contattare per richieste specifiche", + "localeLabel": "Lingua", + "pitchDescription": "Controlla il tono, compreso tra 0 e 2, predefinito 1", + "pitchLabel": "Tono", + "selectLanguage": "Seleziona prima la lingua", + "selectVoice": "Seleziona prima la voce", + "speedDescription": "Controlla la velocità, compresa tra 0 e 3, predefinito 1", + "speedLabel": "Velocità", + "transfromSuccess": "Trasformazione riuscita", + "voiceDescription": "Varia a seconda del motore e della lingua", + "voiceLabel": "Voce" + }, + "upload": { + "support": "Supporto per il caricamento di un singolo file, attualmente supporta solo file in formato vrm" + } +} diff --git a/locales/it-IT/role.json b/locales/it-IT/role.json new file mode 100644 index 00000000..594be8ea --- /dev/null +++ b/locales/it-IT/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Elimina ruolo", + "delRoleDesc": "Sei sicuro di voler eliminare il ruolo {{name}} e i messaggi di sessione correlati? L'eliminazione non può essere annullata, procedi con cautela!", + "header": { + "role": "Ruolo", + "session": "Sessione" + }, + "noRole": "Nessun ruolo al momento, puoi creare un ruolo personalizzato con +, oppure aggiungere un ruolo dalla pagina di scoperta", + "roleList": "Elenco ruoli", + "topBannerTitle": "Anteprima e impostazioni del ruolo" +} diff --git a/locales/it-IT/welcome.json b/locales/it-IT/welcome.json new file mode 100644 index 00000000..31a05cfb --- /dev/null +++ b/locales/it-IT/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} è il personaggio predefinito di Vidol, il tuo assistente personale esclusivo", + "greeting": "Ciao, caro padrone! Sono il tuo assistente personale {{name}}, felice di servirti! C'è qualcosa in cui posso aiutarti?", + "hello": "Ciao", + "meta": { + "description": "Questo è un ruolo personalizzato", + "name": "Ruolo personalizzato" + } + }, + "greet": "Ciao, sono {{name}}, in che modo posso aiutarti?", + "loadingTitle": "Inizializzazione dell'app in corso, attendere...", + "waitting": "Sto preparando il mio intero mondo per te" +} diff --git a/locales/ja-JP/chat.json b/locales/ja-JP/chat.json new file mode 100644 index 00000000..9478c352 --- /dev/null +++ b/locales/ja-JP/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "チャット", + "chatDialog": { + "close": "閉じる" + }, + "dance": "ダンス", + "header": { + "role": "役割", + "session": "セッション" + }, + "helloChat": "こんにちは、チャットしましょう", + "helloDance": "こんにちは、一緒にダンスしましょう", + "market": "マーケット" +} diff --git a/locales/ja-JP/common.json b/locales/ja-JP/common.json new file mode 100644 index 00000000..d6c371da --- /dev/null +++ b/locales/ja-JP/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "追加", + "clearAll": "すべてクリア", + "clearContext": "コンテキストをクリア", + "clearHistoryTip": "この操作は元に戻せません。慎重に操作してください", + "clearHistoryTitle": "履歴メッセージを削除しますか?", + "clearNow": "今すぐクリア", + "clearSuccess": "クリア成功", + "clearTip": "操作は取り消せません。データは戻せなくなりますので、慎重に操作してください", + "clearTitle": "すべてのセッションメッセージを削除しますか?", + "confirmDel": "削除してもよろしいですか?", + "copy": "コピー", + "copySuccess": "コピー成功", + "del": "削除", + "delAndRegenerate": "削除して再生成", + "downloadAvatar": "アバターをダウンロード", + "downloadCover": "カバーをダウンロード", + "downloadFailed": "ダウンロード失敗", + "downloadModel": "モデルをダウンロード", + "downloadSubscribe": "購読ダウンロード", + "downloadSuccess": "ダウンロード成功", + "edit": "編集", + "goBottom": "一番下に移動", + "market": "発見", + "pause": "一時停止", + "play": "再生", + "regenerate": "再生成", + "removeInList": "リストから削除", + "reset": "リセット", + "resetNow": "今すぐリセット", + "resetSuccess": "リセット成功", + "resetTip": "操作は取り消せません。データは戻せなくなりますので、慎重に操作してください", + "resetTitle": "すべてのシステム設定をリセットしますか?", + "save": "保存", + "send": "送信", + "share": "共有", + "subscribe": "購読", + "subscribeDance": "ダンスを購読", + "subscribeRole": "役割を購読", + "subscribed": "購読済み", + "unsubscribe": "購読解除", + "unsubscribeSuccess": "購読解除済み", + "warp": "改行" + }, + "aiAlert": "AIが生成したすべてはAIによって生成されたものです。ご注意ください。", + "cancel": "キャンセル", + "commonSetting": "一般設定", + "confirm": "確認", + "defaultAssistant": "デフォルトアシスタント", + "delAlert": "役割および関連するセッションメッセージを削除しますか?削除後は復元できませんので、慎重に操作してください。", + "delRole": "役割を削除", + "delSession": "セッションを削除", + "delSessionAlert": "対話を削除しますか?削除後は復元できませんので、慎重に操作してください。", + "inputStartChat": "チャットを開始するには内容を入力してください", + "languageModel": "言語モデル", + "loading": "読み込み中...", + "noData": "データなし", + "openai": { + "callError": "APIキーとプロキシアドレスが正しく設定されているかどうかを確認してください", + "check": "チェック", + "checkAll": "APIキーとプロキシアドレスが正しく設定されているかどうかを確認してください", + "checkConnect": "接続チェック", + "checkOk": "チェックOK", + "langModel": "OpenAI言語モデル", + "model": "モデル", + "proxyUrl": "プロキシアドレス", + "roleModel": "Role GPTモデル", + "useOwnKey": "独自のOpenAIキーを使用してください" + }, + "playlist": "再生リスト", + "search": "検索", + "selectInDanceList": "ダンスリストから選択してください", + "selectModel": "モデルを選択してください", + "setLocalStorage": "ローカルストレージを設定", + "startChat": "チャットを開始", + "ttsCombine": "音声合成", + "ttsTip": "音声認識(科学的インターネット接続が必要です)", + "uploadTip": "ここをクリックするかファイルをここにドラッグしてアップロードしてください", + "words": { + "DIYAvatar": "カスタムアバター", + "DIYBackgroundEffect": "カスタム背景エフェクト", + "DIYColor": "異なる色の階調のカスタム", + "DIYNickname": "カスタムニックネーム", + "DIYTopicColor": "カスタムトピックカラー", + "avatar": "アバター", + "backgroundEffect": "背景エフェクト", + "chatSetting": "チャット設定", + "clearAllSession": "すべてのセッションをクリア", + "clearAllSessionDesc": "会話リスト、役割リスト、セッションメッセージなどを含むすべてのセッションと役割データを削除します", + "midColor": "中間色", + "nickname": "ニックネーム", + "resetSystemSetting": "システム設定をリセット", + "resetSystemSettingDesc": "トピック設定、チャット設定、言語モデル設定などを含むすべてのシステム設定をリセットします", + "systemSetting": "システム設定", + "languageSetting": "言語設定", + "topicColor": "トピックカラー", + "topicSetting": "トピック設定" + } +} diff --git a/locales/ja-JP/constants.json b/locales/ja-JP/constants.json new file mode 100644 index 00000000..0ad371c7 --- /dev/null +++ b/locales/ja-JP/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "女性", + "male": "男性", + "other": "その他" + }, + "meta": { + "description": "これはカスタムキャラクターです", + "name": "カスタムキャラクター" + } + }, + "touch": { + "area": { + "arm": "腕", + "belly": "腹部", + "chest": "胸部", + "head": "頭部", + "leg": "脚" + }, + "emotion": { + "angry": "怒り", + "blink": "まばたき", + "blinkLeft": "左目をまばたき", + "blinkRight": "右目をまばたき", + "happy": "幸せ", + "natural": "自然", + "relaxed": "リラックス", + "sad": "悲しい", + "surprised": "驚いた" + }, + "femaleAction": { + "armAction": { + "happyA": "ああ、とっても好き!", + "happyB": "ハハ、手をつなぐと幸せを感じるよ!", + "relaxedA": "飼い主の手はとっても温かいなぁ" + }, + "bellyAction": { + "angryA": "なんで動かすの?噛むから気をつけてね!", + "relaxedA": "目を覚まして、私たちの間には未来はないんだよ!", + "relaxedB": "嫌だ!怒っちゃうよ!", + "surprisedA": "うっかりぶつけただけだよ..." + }, + "chestAction": { + "angryA": "そんな風にいじめられるのは嫌!手を離して!", + "angryB": "なんだよ、ここに変態がいつも触ってくるんだ!", + "angryC": "もう触ったら警察呼ぶからね", + "surprisedA": "なんでつつくの?楽しく話せなくなるじゃん!" + }, + "headAction": { + "angryA": "頭を撫でられると身長が伸びないって聞いたことある!", + "angryB": "なんでつつくの?", + "happyA": "わー!頭を撫でられるのが大好き!", + "happyB": "力がみなぎってきた感じがする!", + "happyC": "わあ、頭を撫でると不思議な感じがする!", + "happyD": "頭を撫でられると一日中幸せ!" + }, + "legAction": { + "angryA": "ちょっと、命知らず?", + "angryB": "飼い主の手が勝手に動いてるじゃないか!", + "angryC": "嫌だよ、かゆいんだから!", + "surprisedA": "純粋な友情を保つのはどう?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "私が今日鶏を食べたかどうか聞く前に、私の上腕二頭筋を見てみて", + "neutralB": "私の腕は誰にでも触らせるわけではない、君は例外だけどね", + "neutralC": "君は勇敢だね、伝説の麒麟腕に触れるなんて" + }, + "bellyAction": { + "happyA": "かゆいところをかくな、笑って腹筋が割れるから", + "neutralA": "私の腹筋は内力を秘めた修行の結果さ", + "neutralB": "私の腹筋の塊を見たか?ただ深く隠しているだけさ" + }, + "chestAction": { + "blinkLeftA": "さあ、胸筋に寄りかかってごらん!", + "neutralA": "これは日常の修行で鍛え上げた胸筋だ、驚くことはないさ" + }, + "headAction": { + "neutralA": "もちろん、君だけが私の頭を撫でる資格がある", + "neutralB": "私は普通の人に触れられるわけではないんだよ", + "neutralC": "心配しないで、私の頭を撫でた後は運気が大幅に上がるよ" + }, + "legAction": { + "angryA": "私に近づくな、お前は脚フェチだ", + "neutralA": "怖がらないで、私の強力な金剛脚はバカを蹴らないよ", + "neutralB": "私の脚に触れたことで、君の人生が充実した感じがするんじゃない?" + } + } + } +} diff --git a/locales/ja-JP/error.json b/locales/ja-JP/error.json new file mode 100644 index 00000000..6d2e752c --- /dev/null +++ b/locales/ja-JP/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI APIキーが空です。カスタムのOpenAI APIキーを追加してください。", + "error": "エラー", + "errorTip": { + "clearSession": "セッションメッセージをクリアする", + "description": "現在、プロジェクトは作業中です。データの安定性は保証されません。問題が発生した場合は、次のことを試してみてください", + "forgive": "ご不便をおかけして申し訳ありません", + "or": "または", + "problem": "ページに問題が発生しました...", + "resetSystem": "システム設定をリセットする" + }, + "goBack": "ホームに戻る", + "openaiError": "OpenAI APIエラーです。OpenAI APIキーとエンドポイントが正しいか確認してください。", + "reload": "再読み込み", + "s3envError": "S3環境変数が完全に設定されていません。環境変数を確認してください。", + "serverError": "サーバーエラーです。管理者に連絡してください。", + "triggerError": "エラーが発生しました", + "unknownError": "不明なエラーです" +} diff --git a/locales/ja-JP/features.json b/locales/ja-JP/features.json new file mode 100644 index 00000000..0f43aae2 --- /dev/null +++ b/locales/ja-JP/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "ビデオモードに切り替える" + }, + "agent": { + "female": "女性", + "male": "男性", + "other": "その他" + }, + "feature": { + "addProxy": "OpenAIプロキシアドレスを追加(オプション)", + "closeTip": "ヒントを閉じる", + "comfirmRetry": "確認して再試行する", + "startDesc": "OpenAI APIキーを入力して会話を開始できます。アプリはAPIキーを記録しません", + "startTitle": "APIキーをカスタマイズする" + }, + "mode": { + "chat": "チャット", + "video": "ビデオ" + }, + "settings": { + "glow": "グロー", + "nickName": "ニックネームを入力してください", + "none": "背景なし" + }, + "share": { + "downloadScreenshot": "スクリーンショットをダウンロードする", + "imageType": "画像形式", + "screenshot": "スクリーンショット", + "share": "共有する", + "shareGPT": "GPTを共有する", + "shareToGPT": "ShareGPT共有リンクを生成する", + "shareToMarket": "アシスタントマーケットに共有する", + "withBackground": "背景画像を含む", + "withFooter": "フッターを含む", + "withSystemRole": "アシスタントの役割設定を含む" + }, + "submit": { + "assistantId": "アシスタントID", + "assistantIdTip": "アシスタントのIDを入力してください。一意である必要があります。例:vidol-agent-klee", + "submitAssistant": "アシスタントを提出する", + "submitWarning": "名前、説明、アイコン、カバーを含めたアシスタント情報を入力してから提出してください" + }, + "support": "コミュニティサポート", + "theme": { + "auto": "システムに従う", + "dark": "ダークモード", + "light": "ライトモード" + }, + "token": { + "overload": "トークン超過", + "remained": "トークン残量", + "tokenCount": "トークン数", + "useToken": "メッセージ、ロール設定、およびコンテキストを含むトークン数の消費:{{usedTokens}} / {{maxValue}}", + "used": "使用済みトークン" + }, + "toolBar": { + "cameraControl": "カメラ制御", + "cameraHelper": "カメラアシスト", + "downloadModel": "モデルのダウンロード中、しばらくお待ちください...", + "floor": "床を切り替える", + "grid": "グリッド", + "resetCamera": "カメラをリセットする" + } +} diff --git a/locales/ja-JP/layout.json b/locales/ja-JP/layout.json new file mode 100644 index 00000000..23e531af --- /dev/null +++ b/locales/ja-JP/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "ダイアログ", + "header": { + "chat": "チャット", + "market": "マーケット", + "role": "役割", + "settings": "設定", + "tips": "プロジェクトは現在進行中です。データの安定性は保証されていません。問題が発生した場合は、セッションメッセージをクリアしシステム設定をリセットすることができます。ご不便をおかけして申し訳ございません。" + }, + "sessionList": "セッションリスト", + "siderBar": "[侧边栏]" +} diff --git a/locales/ja-JP/my.json b/locales/ja-JP/my.json new file mode 100644 index 00000000..206504ac --- /dev/null +++ b/locales/ja-JP/my.json @@ -0,0 +1,5 @@ +{ + "my": "私の", + "myDance": "私のダンス", + "myRole": "私の役割" +} diff --git a/locales/ja-JP/panel.json b/locales/ja-JP/panel.json new file mode 100644 index 00000000..86d3073f --- /dev/null +++ b/locales/ja-JP/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "リストに追加", + "addPlaySuccess": "再生リストに追加されました", + "cancelAddPlay": "音楽{{musicName}}の購読をキャンセルしますか?", + "cancelSubscribed": "購読をキャンセルする", + "findDance": "お気に入りのダンスを見つける", + "musicAndDance": "音楽とダンス", + "play": "再生する" + }, + "info": { + "avatarDescription": "カスタムアバター、アバターをクリックしてカスタムアップロード", + "avatarLabel": "アバター", + "coverDescription": "キャラクターを発見ページに表示するために使用される、推奨サイズ {{width}} x {{height}} ", + "coverLabel": "カバー", + "descDescription": "キャラクターの説明、キャラクターの簡単な紹介に使用される", + "descLabel": "説明", + "emotionDescription": "応答を選択するときの感情、キャラクターの表情変化に影響を与える", + "emotionLabel": "表情と感情", + "genderDescription": "キャラクターの性別、キャラクターのタッチ反応に影響を与える", + "genderLabel": "性別", + "greetDescription": "キャラクターと初めて話すときの挨拶の言葉", + "greetLabel": "挨拶", + "modelDescription": "モデルプレビュー、モデルファイルをドラッグして置き換えることができます", + "modelLabel": "モデルプレビュー", + "nameDescription": "キャラクター名、キャラクターとのチャット時の呼び名", + "nameLabel": "名前", + "readmeDescription": "キャラクターの説明ファイル、発見ページでキャラクターの詳細な説明を表示するために使用される", + "readmeLabel": "キャラクター説明", + "textDescription": "カスタム応答文案", + "textLabel": "文案", + "categoryLabel": "カテゴリ", + "categoryDescription": "キャラクターカテゴリ、分類に使用される" + }, + "market": { + "findVidol": "お気に入りのアイドルを見つける" + }, + "nav": { + "info": "基本情報", + "model": "3Dモデル", + "role": "キャラクター設定", + "voice": "音声" + }, + "role": { + "greetTip": "キャラクターがあなたに挨拶するときに使用する言葉を入力してください", + "inputRoleSetting": "キャラクターのシステム設定を入力してください", + "roleDescriptionTip": "キャラクターの説明を入力してください", + "roleNameTip": "キャラクター名を入力してください", + "roleReadmeTip": "キャラクターの説明を入力してください", + "roleSettingDescription": "キャラクターの背景設定、キャラクターとのチャット時にモデルに送信されます", + "roleSettingLabel": "システムキャラクター設定", + "uploadSize": "単一ファイルのアップロードがサポートされています、推奨サイズは {{width}} x {{height}} の倍数です" + }, + "touch": { + "addAction": "応答アクションを追加する", + "editAction": "応答アクションを編集する", + "inputActionEmotion": "キャラクターが応答するときの表情を入力してください", + "inputActionText": "応答文案を入力してください", + "inputDIYText": "カスタムテキストを入力してください", + "touchActionList": "{{touchArea}}をタッチしたときの反応リスト", + "touchArea": "タッチエリア" + }, + "tts": { + "audition": "オーディション", + "auditionDescription": "言語によって異なります", + "engineDescription": "音声合成エンジン、Edgeブラウザを優先的に選択することをお勧めします", + "engineLabel": "音声エンジン", + "localeDescription": "音声合成の言語、現在は最も一般的な言語のみサポートされています。必要に応じてお問い合わせください", + "localeLabel": "言語", + "pitchDescription": "音程を制御します、値の範囲は0〜2、デフォルトは1です", + "pitchLabel": "ピッチ", + "selectLanguage": "言語を選択してください", + "selectVoice": "音声を選択してください", + "speedDescription": "速度を制御します、値の範囲は0〜3、デフォルトは1です", + "speedLabel": "速度", + "transfromSuccess": "変換成功", + "voiceDescription": "エンジンと言語によって異なります", + "voiceLabel": "音声" + }, + "upload": { + "support": "単一ファイルのアップロードがサポートされています、現在はvrm形式のファイルのみサポートされています" + } +} diff --git a/locales/ja-JP/role.json b/locales/ja-JP/role.json new file mode 100644 index 00000000..c092cbb8 --- /dev/null +++ b/locales/ja-JP/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "ロールを削除", + "delRoleDesc": "{{name}} と関連するセッションメッセージを削除しますか?一度削除すると元に戻せませんので、慎重に操作してください。", + "header": { + "role": "ロール", + "session": "対話" + }, + "noRole": "現在、ロールはありません。+ を選択してカスタムロールを作成するか、発見ページでロールを追加できます。", + "roleList": "ロールリスト", + "topBannerTitle": "役割のプレビューおよび設定" +} diff --git a/locales/ja-JP/welcome.json b/locales/ja-JP/welcome.json new file mode 100644 index 00000000..e206bdbd --- /dev/null +++ b/locales/ja-JP/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}}はVidolのデフォルトキャラクターで、あなた専属の個人アシスタントです。", + "greeting": "こんにちは、大切なマスター!私はあなたの専属アシスタント{{name}}です。どうぞよろしくお願いします!何かお手伝いできることはありますか?", + "hello": "こんにちは", + "meta": { + "description": "これはカスタムキャラクターです", + "name": "カスタムキャラクター" + } + }, + "greet": "こんにちは、私は{{name}}です。何かお手伝いできることはありますか?", + "loadingTitle": "アプリを初期化しています...少々お待ちください。", + "waitting": "私の世界を準備しています" +} diff --git a/locales/ko-KR/chat.json b/locales/ko-KR/chat.json new file mode 100644 index 00000000..39fcc901 --- /dev/null +++ b/locales/ko-KR/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "대화", + "chatDialog": { + "close": "닫기" + }, + "dance": "춤을 추다", + "header": { + "role": "역할", + "session": "세션" + }, + "helloChat": "안녕하세요, 대화를 나눠보세요", + "helloDance": "'안녕, 함께 춤을 추자'", + "market": "시장" +} diff --git a/locales/ko-KR/common.json b/locales/ko-KR/common.json new file mode 100644 index 00000000..2caf3c24 --- /dev/null +++ b/locales/ko-KR/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "추가", + "clearAll": "모두 지우기", + "clearContext": "컨텍스트 지우기", + "clearHistoryTip": "이 작업은 되돌릴 수 없으므로 신중하게 작업하세요.", + "clearHistoryTitle": "기록된 메시지를 삭제하시겠습니까?", + "clearNow": "지금 지우기", + "clearSuccess": "지우기 성공", + "clearTip": "작업은 취소할 수 없으며, 데이터를 삭제하면 복구할 수 없습니다. 신중하게 작업하세요.", + "clearTitle": "모든 대화 메시지를 삭제하시겠습니까?", + "confirmDel": "삭제하시겠습니까?", + "copy": "복사", + "copySuccess": "복사 성공", + "del": "삭제", + "delAndRegenerate": "삭제하고 다시 생성", + "downloadAvatar": "아바타 다운로드", + "downloadCover": "커버 다운로드", + "downloadFailed": "다운로드 실패", + "downloadModel": "모델 다운로드", + "downloadSubscribe": "구독 다운로드", + "downloadSuccess": "다운로드 성공", + "edit": "편집", + "goBottom": "맨 아래로 이동", + "market": "발견", + "pause": "일시 정지", + "play": "재생", + "regenerate": "다시 생성", + "removeInList": "목록에서 제거", + "reset": "재설정", + "resetNow": "지금 재설정", + "resetSuccess": "재설정 성공", + "resetTip": "작업은 취소할 수 없으며, 데이터를 재설정하면 복구할 수 없습니다. 신중하게 작업하세요.", + "resetTitle": "모든 시스템 설정을 재설정하시겠습니까?", + "save": "저장", + "send": "보내기", + "share": "공유", + "subscribe": "구독", + "subscribeDance": "댄스 구독", + "subscribeRole": "역할 구독", + "subscribed": "구독됨", + "unsubscribe": "구독 취소", + "unsubscribeSuccess": "구독 취소됨", + "warp": "줄바꿈" + }, + "aiAlert": "기억하세요: AI가 생성한 모든 내용입니다.", + "cancel": "취소", + "commonSetting": "일반 설정", + "confirm": "확인", + "defaultAssistant": "기본 어시스턴트", + "delAlert": "역할과 관련된 모든 대화 메시지를 삭제하시겠습니까? 삭제 후에는 복구할 수 없습니다. 신중하게 작업하세요!", + "delRole": "역할 삭제", + "delSession": "대화 삭제", + "delSessionAlert": "대화를 삭제하시겠습니까? 삭제 후에는 복구할 수 없습니다. 신중하게 작업하세요!", + "inputStartChat": "채팅을 시작하려면 내용을 입력하세요", + "languageModel": "언어 모델", + "loading": "로딩 중...", + "noData": "데이터 없음", + "openai": { + "callError": "API 호출에 실패했습니다. API 키와 프록시 주소를 올바르게 설정했는지 확인하세요.", + "check": "확인", + "checkAll": "API 키와 프록시 주소를 확인하세요.", + "checkConnect": "연결 확인", + "checkOk": "확인 완료", + "langModel": "OpenAI 언어 모델", + "model": "모델", + "proxyUrl": "프록시 주소", + "roleModel": "Role GPT 모델", + "useOwnKey": "자체 OpenAI 키를 사용하세요." + }, + "playlist": "재생 목록", + "search": "검색", + "selectInDanceList": "댄스 목록에서 선택하세요", + "selectModel": "모델 선택", + "setLocalStorage": "로컬 저장소 설정", + "startChat": "채팅 시작", + "ttsCombine": "음성 합성", + "ttsTip": "음성 인식 (VPN 필요)", + "uploadTip": "여기를 클릭하거나 파일을 이곳으로 드래그하여 업로드하세요", + "words": { + "DIYAvatar": "사용자 정의 아바타", + "DIYBackgroundEffect": "사용자 정의 배경 효과", + "DIYColor": "다양한 색상 기호에 따른 사용자 정의 회색조", + "DIYNickname": "사용자 정의 닉네임", + "DIYTopicColor": "사용자 정의 주제 색상", + "avatar": "아바타", + "backgroundEffect": "배경 효과", + "chatSetting": "채팅 설정", + "clearAllSession": "모든 대화 메시지 지우기", + "clearAllSessionDesc": "대화 목록, 역할 목록, 대화 메시지 등 모든 대화와 역할 데이터를 지웁니다.", + "midColor": "중간 색상", + "nickname": "닉네임", + "resetSystemSetting": "시스템 설정 재설정", + "resetSystemSettingDesc": "주제 설정, 채팅 설정, 언어 모델 설정 등 모든 시스템 설정을 재설정합니다.", + "systemSetting": "시스템 설정", + "languageSetting": "언어 설정", + "topicColor": "주제 색상", + "topicSetting": "주제 설정" + } +} diff --git a/locales/ko-KR/constants.json b/locales/ko-KR/constants.json new file mode 100644 index 00000000..52d67b1f --- /dev/null +++ b/locales/ko-KR/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "여성", + "male": "남성", + "other": "기타" + }, + "meta": { + "description": "이것은 사용자 정의 캐릭터입니다.", + "name": "사용자 정의 캐릭터" + } + }, + "touch": { + "area": { + "arm": "팔", + "belly": "배", + "chest": "가슴", + "head": "머리", + "leg": "다리" + }, + "emotion": { + "angry": "화난", + "blink": "눈 깜박임", + "blinkLeft": "왼눈 깜박임", + "blinkRight": "오른눈 깜박임", + "happy": "행복한", + "natural": "자연스러운", + "relaxed": "편안한", + "sad": "슬픈", + "surprised": "놀라운" + }, + "femaleAction": { + "armAction": { + "happyA": "오, 정말 좋아~", + "happyB": "하하, 손 잡는 건 나를 행복하게 만들어!", + "relaxedA": "주인님의 손이 정말 따뜻해~" + }, + "bellyAction": { + "angryA": "나를 만지지마, 조심해 내가 물어", + "relaxedA": "깨어나, 우리 사이엔 미래가 없어!", + "relaxedB": "싫어! 화날 거야!", + "surprisedA": "실수로 건드렸나봐..." + }, + "chestAction": { + "angryA": "나를 이렇게 괴롭히면 안 돼! 손을 떼어!", + "angryB": "영영하묘? 여기 한 이상한 사람이 내게 계속 만지고 있어!", + "angryC": "만지려면 나는 경찰에 신고해야겠어", + "surprisedA": "왜 나를 콕 찌르는 거야! 더 이상 즐겁게 이야기 못 하겠어!" + }, + "headAction": { + "angryA": "머리를 쓰면 키가 작아진다는데!", + "angryB": "왜 나를 콕 찌르는 거야?", + "happyA": "와! 머리 쓸다니 내가 가장 좋아하는 것!", + "happyB": "이렇게 강해진 느낌이야!", + "happyC": "와, 머리 쓸면 뭔가 신기한 느낌이야!", + "happyD": "한 번 머리 쓰면 하루 종일 행복해!" + }, + "legAction": { + "angryA": "야, 너 정말 죽고 싶어?", + "angryB": "주인님의 손이 말 좀 안 듣는 거야?", + "angryC": "싫어~ 가려워요~!", + "surprisedA": "우리는 깨끗한 우정을 유지하는 게 어때?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "오늘 치킨 먹었는지 묻지 마, 먼저 내 이두근을 봐", + "neutralB": "내 팔은 아무나 만질 수 있는 게 아니야, 당신은 예외야", + "neutralC": "당신은 용감해, 전설적인 기린팔을 만졌어" + }, + "bellyAction": { + "happyA": "가려둬, 웃으면 복근이 나와", + "neutralA": "내 복근은 깊이 감춰진 내력일 뿐", + "neutralB": "내 복근을 보았나? 그냥 깊이 숨겨놓은 것 뿐이야" + }, + "chestAction": { + "blinkLeftA": "와, 내 가슴근육에 기대봐!", + "neutralA": "이건 내가 일상적인 수련으로 얻은 가슴근육일 뿐이야, 놀라울 게 없어" + }, + "headAction": { + "neutralA": "당연하지, 당신만이 내 머리를 만질 자격이 있어", + "neutralB": "내가 어쩌면 일반인이 만지지 않는 거야", + "neutralC": "걱정 마, 내 머리 만질 때 나의 운이 크게 향상될 거야" + }, + "legAction": { + "angryA": "내게 다가오지마, 넌 다리에 집중하는 놈이야", + "neutralA": "무서워하지마, 내 강력한 콩쿨 족은 바보한테 때릴 일 없어", + "neutralB": "내 다리를 만지면 당신의 삶이 훨씬 더 완전해진 것 같아?" + } + } + } +} diff --git a/locales/ko-KR/error.json b/locales/ko-KR/error.json new file mode 100644 index 00000000..49ee8117 --- /dev/null +++ b/locales/ko-KR/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API 키가 비어 있습니다. 사용자 지정 OpenAI API 키를 추가하세요.", + "error": "에러", + "errorTip": { + "clearSession": "세션 메시지 지우기", + "description": "프로젝트는 현재 작업 중이므로 데이터의 안정성을 보장할 수 없으며 문제가 발생하면 다음을 시도해 볼 수 있습니다.", + "forgive": ", 불편을 드려 죄송합니다.", + "or": "또는", + "problem": "페이지에 문제가 발생했습니다...", + "resetSystem": "시스템 설정 초기화" + }, + "goBack": "홈으로 돌아가기", + "openaiError": "OpenAI API 오류입니다. OpenAI API 키와 엔드포인트를 확인해주세요.", + "reload": "다시 불러오기", + "s3envError": "S3 환경 변수가 완전하게 설정되지 않았습니다. 환경 변수를 확인해주세요.", + "serverError": "서버 오류입니다. 관리자에게 문의하세요.", + "triggerError": "오류 생성", + "unknownError": "알 수 없는 오류" +} diff --git a/locales/ko-KR/features.json b/locales/ko-KR/features.json new file mode 100644 index 00000000..075a33bc --- /dev/null +++ b/locales/ko-KR/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "비디오 모드 전환" + }, + "agent": { + "female": "여성", + "male": "남성", + "other": "기타" + }, + "feature": { + "addProxy": "OpenAI 프록시 주소 추가 (선택 사항)", + "closeTip": "팁 닫기", + "comfirmRetry": "확인 및 다시 시도", + "startDesc": "OpenAI API 키를 입력하여 대화를 시작하세요. 애플리케이션은 API 키를 기록하지 않습니다.", + "startTitle": "사용자 정의 API 키" + }, + "mode": { + "chat": "채팅", + "video": "비디오" + }, + "settings": { + "glow": "광휘", + "nickName": "닉네임을 입력하세요", + "none": "배경 없음" + }, + "share": { + "downloadScreenshot": "스크린샷 다운로드", + "imageType": "이미지 형식", + "screenshot": "스크린샷", + "share": "공유", + "shareGPT": "GPT 공유", + "shareToGPT": "ShareGPT 공유 링크 생성", + "shareToMarket": "Assistant Market에 공유", + "withBackground": "배경 포함", + "withFooter": "푸터 포함", + "withSystemRole": "시스템 역할 포함" + }, + "submit": { + "assistantId": "Assistant 식별자", + "assistantIdTip": "Assistant의 고유 식별자를 입력하세요. 예를 들어, vidol-agent-klee와 같이 고유해야 합니다.", + "submitAssistant": "Assistant 제출", + "submitWarning": "Assistant 정보를 완성한 후 제출해주세요. 이름, 설명, 프로필 사진 및 커버가 포함되어야 합니다." + }, + "support": "커뮤니티 지원", + "theme": { + "auto": "시스템 따라가기", + "dark": "다크 모드", + "light": "라이트 모드" + }, + "token": { + "overload": "토큰 초과", + "remained": "남은 토큰", + "tokenCount": "토큰 수", + "useToken": "메시지, 역할 설정 및 컨텍스트를 포함한 토큰 소비: {{usedTokens}} / {{maxValue}}", + "used": "사용된 토큰" + }, + "toolBar": { + "cameraControl": "카메라 제어", + "cameraHelper": "카메라 도움말", + "downloadModel": "모델 다운로드 중입니다. 잠시만 기다려주세요...", + "floor": "바닥 전환", + "grid": "그리드", + "resetCamera": "카메라 재설정" + } +} diff --git a/locales/ko-KR/layout.json b/locales/ko-KR/layout.json new file mode 100644 index 00000000..2e74f81c --- /dev/null +++ b/locales/ko-KR/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "대화 상자", + "header": { + "chat": "채팅", + "market": "발견", + "role": "역할", + "settings": "설정", + "tips": "현재 프로젝트는 작업 중이며 데이터의 안정성을 보장하지 않습니다. 문제가 발생하면 시스템 설정에서 대화 메시지를 지우고 시스템 설정을 재설정할 수 있습니다. 불편을 드려 죄송합니다." + }, + "sessionList": "세션 목록", + "siderBar": "사이드바" +} diff --git a/locales/ko-KR/my.json b/locales/ko-KR/my.json new file mode 100644 index 00000000..922ccf06 --- /dev/null +++ b/locales/ko-KR/my.json @@ -0,0 +1,5 @@ +{ + "my": "나의", + "myDance": "내 춤", + "myRole": "내 역할" +} diff --git a/locales/ko-KR/panel.json b/locales/ko-KR/panel.json new file mode 100644 index 00000000..f3606247 --- /dev/null +++ b/locales/ko-KR/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "리스트에 추가", + "addPlaySuccess": "재생 목록에 추가되었습니다", + "cancelAddPlay": "{{musicName}} 음악 구독을 취소 하시겠습니까?", + "cancelSubscribed": "구독 취소", + "findDance": "좋아하는 춤을 찾아보세요", + "musicAndDance": "음악과 춤", + "play": "재생" + }, + "info": { + "avatarDescription": "사용자 정의 아바타, 클릭하여 업로드", + "avatarLabel": "아바타", + "coverDescription": "캐릭터를 발견 페이지에서 표시하는 데 사용되는 커버, 권장 크기 {{width}} x {{height}} ", + "coverLabel": "커버", + "descDescription": "캐릭터 설명, 캐릭터의 간단한 소개에 사용됩니다", + "descLabel": "설명", + "emotionDescription": "응답할 때 선택한 감정, 캐릭터의 표정 변화에 영향을 줍니다", + "emotionLabel": "표정과 감정", + "genderDescription": "캐릭터 성별, 캐릭터의 터치 응답에 영향을 줍니다", + "genderLabel": "성별", + "greetDescription": "캐릭터와 처음 대화할 때 사용되는 인사말", + "greetLabel": "인사", + "modelDescription": "모델 미리보기, 모델 파일을 드래그하여 교체할 수 있습니다", + "modelLabel": "모델 미리보기", + "nameDescription": "캐릭터 이름, 캐릭터와 대화할 때 사용되는 이름", + "nameLabel": "이름", + "readmeDescription": "캐릭터 설명서, 발견 페이지에서 캐릭터의 자세한 설명을 표시하는 데 사용됩니다", + "readmeLabel": "캐릭터 설명서", + "textDescription": "사용자 정의 응답 문구", + "textLabel": "문구", + "categoryLabel": "카테고리", + "categoryDescription": "캐릭터 카테고리, 분류에 사용됩니다" + }, + "market": { + "findVidol": "좋아하는 아이돌을 찾아보세요" + }, + "nav": { + "info": "기본 정보", + "model": "3D 모델", + "role": "캐릭터 설정", + "voice": "음성" + }, + "role": { + "greetTip": "캐릭터와 인사할 때 사용할 문구를 입력하세요", + "inputRoleSetting": "캐릭터 시스템 설정을 입력하세요", + "roleDescriptionTip": "캐릭터 설명을 입력하세요", + "roleNameTip": "캐릭터 이름을 입력하세요", + "roleReadmeTip": "캐릭터 설명을 입력하세요", + "roleSettingDescription": "캐릭터의 배경 설정, 캐릭터와 대화할 때 모델에게 전송됩니다", + "roleSettingLabel": "시스템 캐릭터 설정", + "uploadSize": "단일 파일 업로드가 지원되며, 권장 크기는 {{width}} x {{height}}의 배수입니다" + }, + "touch": { + "addAction": "응답 동작 추가", + "editAction": "응답 동작 편집", + "inputActionEmotion": "캐릭터 응답 시 사용할 표정을 입력하세요", + "inputActionText": "응답 문구를 입력하세요", + "inputDIYText": "사용자 정의 문구를 입력하세요", + "touchActionList": "{{touchArea}}을(를) 터치할 때의 반응 목록", + "touchArea": "터치 영역" + }, + "tts": { + "audition": "시험 듣기", + "auditionDescription": "언어에 따라 시험 듣기 문구가 다릅니다", + "engineDescription": "음성 합성 엔진, 우선적으로 Edge 브라우저를 선택하는 것이 좋습니다", + "engineLabel": "음성 엔진", + "localeDescription": "음성 합성 언어, 현재 가장 일반적인 몇 가지 언어만 지원됩니다. 필요한 경우 연락하세요", + "localeLabel": "언어", + "pitchDescription": "음높이를 제어하고 0 ~ 2의 값을 취합니다. 기본값은 1입니다", + "pitchLabel": "음높이", + "selectLanguage": "먼저 언어를 선택하세요", + "selectVoice": "먼저 음성을 선택하세요", + "speedDescription": "속도를 제어하고 0 ~ 3의 값을 취합니다. 기본값은 1입니다", + "speedLabel": "속도", + "transfromSuccess": "변환 성공", + "voiceDescription": "엔진 및 언어에 따라 다릅니다", + "voiceLabel": "음성" + }, + "upload": { + "support": "단일 파일 업로드가 지원되며, 현재 vrm 형식 파일만 지원됩니다" + } +} diff --git a/locales/ko-KR/role.json b/locales/ko-KR/role.json new file mode 100644 index 00000000..17a3ea53 --- /dev/null +++ b/locales/ko-KR/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "역할 삭제", + "delRoleDesc": "{{name}} 및 관련된 대화 메시지를 삭제하시겠습니까? 삭제 후에는 복구할 수 없으므로 신중하게 작업하십시오!", + "header": { + "role": "역할", + "session": "대화" + }, + "noRole": "현재 역할이 없습니다. +를 통해 사용자 정의 역할을 생성하거나 발견 페이지에서 역할을 추가할 수 있습니다.", + "roleList": "역할 목록", + "topBannerTitle": "역할 미리보기 및 설정" +} diff --git a/locales/ko-KR/welcome.json b/locales/ko-KR/welcome.json new file mode 100644 index 00000000..dd0f5da7 --- /dev/null +++ b/locales/ko-KR/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}}은(는) Vidol의 기본 캐릭터로, 당신만을 위한 개인 비서입니다.", + "greeting": "안녕하세요, 사랑하는 주인님! 저는 당신의 개인 비서, {{name}}입니다. 기쁜 마음으로 도와드리겠습니다! 어떤 것을 도와드릴까요?", + "hello": "안녕하세요", + "meta": { + "description": "이것은 사용자 정의 캐릭터입니다.", + "name": "사용자 정의 캐릭터" + } + }, + "greet": "안녕하세요, 저는 {{name}}입니다. 어떤 도움이 필요하신가요?", + "loadingTitle": "앱 초기화 중입니다. 잠시 기다려주세요...", + "waitting": "당신을 위한 모든 것을 준비하고 있습니다." +} diff --git a/locales/nl-NL/chat.json b/locales/nl-NL/chat.json new file mode 100644 index 00000000..d607c2ea --- /dev/null +++ b/locales/nl-NL/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chatten", + "chatDialog": { + "close": "Sluiten" + }, + "dance": "Dansen", + "header": { + "role": "Rol", + "session": "Sessie" + }, + "helloChat": "Hallo, laten we chatten", + "helloDance": "Hoi, laten we dansen", + "market": "Ontdek" +} diff --git a/locales/nl-NL/common.json b/locales/nl-NL/common.json new file mode 100644 index 00000000..2ceef760 --- /dev/null +++ b/locales/nl-NL/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Toevoegen", + "clearAll": "Alles wissen", + "clearContext": "Context wissen", + "clearHistoryTip": "Deze bewerking kan niet ongedaan worden gemaakt, wees voorzichtig met het uitvoeren", + "clearHistoryTitle": "Weet u zeker dat u de geschiedenis wilt wissen?", + "clearNow": "Nu wissen", + "clearSuccess": "Succesvol gewist", + "clearTip": "De bewerking kan niet ongedaan worden gemaakt, de gegevens kunnen na het wissen niet hersteld worden, wees voorzichtig met het uitvoeren", + "clearTitle": "Weet u zeker dat u alle gespreksberichten wilt wissen?", + "confirmDel": "Weet u zeker dat u wilt verwijderen?", + "copy": "Kopiëren", + "copySuccess": "Succesvol gekopieerd", + "del": "Verwijderen", + "delAndRegenerate": "Verwijderen en opnieuw genereren", + "downloadAvatar": "Avatar downloaden", + "downloadCover": "Omslag downloaden", + "downloadFailed": "Download mislukt", + "downloadModel": "Model downloaden", + "downloadSubscribe": "Abonnement downloaden", + "downloadSuccess": "Download succesvol", + "edit": "Bewerken", + "goBottom": "Naar onder gaan", + "market": "Ontdekken", + "pause": "Pauze", + "play": "Afspelen", + "regenerate": "Opnieuw genereren", + "removeInList": "Uit lijst verwijderen", + "reset": "Resetten", + "resetNow": "Nu resetten", + "resetSuccess": "Succesvol gereset", + "resetTip": "De bewerking kan niet ongedaan worden gemaakt, de gegevens kunnen na het resetten niet hersteld worden, wees voorzichtig met het uitvoeren", + "resetTitle": "Weet u zeker dat u alle systeeminstellingen wilt resetten?", + "save": "Opslaan", + "send": "Verzenden", + "share": "Delen", + "subscribe": "Abonneren", + "subscribeDance": "Dans abonneren", + "subscribeRole": "Rol abonneren", + "subscribed": "Geabonneerd", + "unsubscribe": "Afmelden", + "unsubscribeSuccess": "Aanmelding succesvol geannuleerd", + "warp": "Regelomkeren" + }, + "aiAlert": "Houd er rekening mee: alles wat de intelligente entiteit zegt, wordt gegenereerd door AI", + "cancel": "Annuleren", + "commonSetting": "Algemene instellingen", + "confirm": "Bevestigen", + "defaultAssistant": "Standaard assistent", + "delAlert": "Weet u zeker dat u de rol en de bijbehorende gespreksberichten wilt verwijderen? Na verwijdering kan dit niet hersteld worden, wees voorzichtig met het uitvoeren!", + "delRole": "Rol verwijderen", + "delSession": "Sessie verwijderen", + "delSessionAlert": "Weet u zeker dat u het gesprek wilt verwijderen? Na verwijdering kan dit niet hersteld worden, wees voorzichtig met het uitvoeren!", + "inputStartChat": "Voer inhoud in om het chatten te starten", + "languageModel": "Taalmodel", + "loading": "Bezig met laden...", + "noData": "Geen gegevens beschikbaar", + "openai": { + "callError": "Aanroep van de interface is mislukt, controleer of de APIKey en de interface proxy-adres correct zijn ingesteld", + "check": "Controleren", + "checkAll": "Controleer of de APIKey en de interface proxy-adres correct zijn ingesteld", + "checkConnect": "Connectiviteitscontrole", + "checkOk": "Controle geslaagd", + "langModel": "OpenAI taalmodel", + "model": "Model", + "proxyUrl": "Interface proxy-adres", + "roleModel": "Role GPT model", + "useOwnKey": "Gebruik uw eigen OpenAI Key" + }, + "playlist": "Afspeellijst", + "search": "Zoeken", + "selectInDanceList": "Selecteer alstublieft uit de danslijst", + "selectModel": "Selecteer een model", + "setLocalStorage": "Lokaal opslaan", + "startChat": "Start chatten", + "ttsCombine": "Tekst naar spraak", + "ttsTip": "Spraakherkenning (benodigd om te kunnen surfen)", + "uploadTip": "Klik of sleep het bestand naar deze regio om te uploaden", + "words": { + "DIYAvatar": "Aangepaste avatar", + "DIYBackgroundEffect": "Aangepaste achtergrondeffecten", + "DIYColor": "Aangepaste schaalgrijze met verschillende kleuren", + "DIYNickname": "Aangepast bijnaam", + "DIYTopicColor": "Aangepast thema-kleur", + "avatar": "Avatar", + "backgroundEffect": "Achtergrondeffect", + "chatSetting": "Chatinstellingen", + "clearAllSession": "Verwijder alle gespreksberichten", + "clearAllSessionDesc": "Zal alle gesprekken en rolgegevens wissen, inclusief gesprekslijst, rollijst, gespreksberichten, enz.", + "midColor": "Middenkleur", + "nickname": "Bijnaam", + "resetSystemSetting": "Reset systeeminstellingen", + "resetSystemSettingDesc": "Zal alle systeeminstellingen resetten, inclusief thema-instellingen, chatinstellingen, taalmodelinstellingen, enz.", + "systemSetting": "Systeeminstellingen", + "languageSetting": "Taalinstellingen", + "topicColor": "Themakleur", + "topicSetting": "Thema-instellingen" + } +} diff --git a/locales/nl-NL/constants.json b/locales/nl-NL/constants.json new file mode 100644 index 00000000..834b86ae --- /dev/null +++ b/locales/nl-NL/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Vrouw", + "male": "Man", + "other": "Anders" + }, + "meta": { + "description": "Dit is een aangepaste rol", + "name": "Aangepaste rol" + } + }, + "touch": { + "area": { + "arm": "Arm", + "belly": "Buik", + "chest": "Borst", + "head": "Hoofd", + "leg": "Been" + }, + "emotion": { + "angry": "Boos", + "blink": "Knipperen", + "blinkLeft": "Linker oog knipperen", + "blinkRight": "Rechter oog knipperen", + "happy": "Blij", + "natural": "Natuurlijk", + "relaxed": "Ontspannen", + "sad": "Triest", + "surprised": "Verbaasd" + }, + "femaleAction": { + "armAction": { + "happyA": "Ah, ik hou ervan~", + "happyB": "Haha, het vasthouden geeft me plezier~", + "relaxedA": "De hand van de meester is zo warm~" + }, + "bellyAction": { + "angryA": "Waarom beweeg je me? Wees voorzichtig, ik bijt je!", + "relaxedA": "Wakker worden, er is geen resultaat tussen ons!", + "relaxedB": "Ik word boos!", + "surprisedA": "Gestoord per ongeluk, toch..." + }, + "chestAction": { + "angryA": "Je mag me niet zo behandelen! Haal je hand weg!", + "angryB": "Heleen? Hier is iemand die blijft touchen!", + "angryC": "Als je blijft touchen, roep ik de politie", + "surprisedA": "Waarom prik je me! Kan we niet plezierig chatten!" + }, + "headAction": { + "angryA": "Ik hoorde dat als je op het hoofd wordt aangeraakt, je niet meer groeit!", + "angryB": "Waarom prik je me?", + "happyA": "Wauw! Ik hou ervan als je op mijn hoofd aait!", + "happyB": "Ik voel me weer vol kracht!", + "happyC": "Wauw, deze gevoel van het aaien van het hoofd is zo magisch!", + "happyD": "Het aaien van het hoofd laat me de hele dag blij zijn!" + }, + "legAction": { + "angryA": "Hé, wil je sterven?", + "angryB": "Is de hand van de meester weer niet onder controle?", + "angryC": "Ik vind het eng~ het prikken!", + "surprisedA": "Kunnen we niet een puur vriendschap houden?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Vraag me niet of ik vandaag kip heb gegeten, kijk eerst naar mijn biceps", + "neutralB": "Mijn armen zijn niet voor iedereen om te touchen, je bent een uitzondering", + "neutralC": "Je bent moedig om te komen in aanraking met de legendarische Qilin-arme" + }, + "bellyAction": { + "happyA": "Schaam me niet, anders lach ik zo hard dat ik ab's krijg", + "neutralA": "Mijn ab's zijn gewoon verborgen door het oefenen van de inwendige kracht", + "neutralB": "Zie je deze ab's? Ze zijn gewoon diep verborgen" + }, + "chestAction": { + "blinkLeftA": "Kom, je kunt op de borstspier van je broer leunen!", + "neutralA": "Dit is slechts de borstspier die ik dagelijks oefen, er is niets om van te verbazen." + }, + "headAction": { + "neutralA": "Natuurlijk, alleen jij hebt het recht om op mijn hoofd te touchen", + "neutralB": "Ik ben niet iemand die laat dat iedereen me raakt", + "neutralC": "Maak je geen zorgen, na het touchen van mijn hoofd zal je geluk enorm stijgen" + }, + "legAction": { + "angryA": "Blijf van me af, jij been-fan", + "neutralA": "Wees niet bang, mijn krachtige koppelbeen schiet geen dwazen", + "neutralB": "Laat je mijn been touchen, voel je niet dat je leven veel compleeter is?" + } + } + } +} diff --git a/locales/nl-NL/error.json b/locales/nl-NL/error.json new file mode 100644 index 00000000..6842488a --- /dev/null +++ b/locales/nl-NL/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key ontbreekt, voeg alstublieft uw aangepaste OpenAI API Key toe", + "error": "Fout", + "errorTip": { + "clearSession": "Sessieberichten wissen", + "description": "Het project is momenteel in aanbouw en de gegevensstabiliteit kan niet worden gegarandeerd. Als u problemen ondervindt, kunt u proberen", + "forgive": ", excuses voor het ongemak", + "or": "of", + "problem": "Er is een probleem opgetreden op de pagina...", + "resetSystem": "Systeeminstellingen resetten" + }, + "goBack": "Terug naar startpagina", + "openaiError": "OpenAI API-fout, controleer of de OpenAI API Key en Endpoint correct zijn", + "reload": "Herladen", + "s3envError": "S3-omgevingsvariabelen zijn niet volledig ingesteld, controleer uw omgevingsvariabelen", + "serverError": "Serverfout, neem contact op met de beheerder", + "triggerError": "Fout activeren", + "unknownError": "Onbekende fout" +} diff --git a/locales/nl-NL/features.json b/locales/nl-NL/features.json new file mode 100644 index 00000000..12987a12 --- /dev/null +++ b/locales/nl-NL/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Overschakelen naar videomodus" + }, + "agent": { + "female": "Vrouw", + "male": "Man", + "other": "Anders" + }, + "feature": { + "addProxy": "Voeg OpenAI proxy-adres toe (optioneel)", + "closeTip": "Tip sluiten", + "comfirmRetry": "Bevestig en opnieuw proberen", + "startDesc": "Voer je OpenAI API Key in om de sessie te starten. De applicatie zal je API Key niet opslaan", + "startTitle": "Aangepaste API Key" + }, + "mode": { + "chat": "Chat", + "video": "Video" + }, + "settings": { + "glow": "Gloed", + "nickName": "Voer een bijnaam in", + "none": "Geen achtergrond" + }, + "share": { + "downloadScreenshot": "Download screenshot", + "imageType": "Afbeeldingsformaat", + "screenshot": "Screenshot", + "share": "Delen", + "shareGPT": "Deel GPT", + "shareToGPT": "Genereer een ShareGPT deellink", + "shareToMarket": "Deel op de markt van assistenten", + "withBackground": "Met achtergrondafbeelding", + "withFooter": "Met voettekst", + "withSystemRole": "Met assistent rolinstellingen" + }, + "submit": { + "assistantId": "Assistent identificatie", + "assistantIdTip": "Voer de identificatie van de assistent in, moet uniek zijn, bijvoorbeeld vidol-agent-klee", + "submitAssistant": "Assistent indienen", + "submitWarning": "Vul alstublieft alle informatie van de assistent in voordat je indient, moet naam, beschrijving, avatar en omslag bevatten" + }, + "support": "Communityondersteuning", + "theme": { + "auto": "Volgens systeem", + "dark": "Donkere modus", + "light": "Lichte modus" + }, + "token": { + "overload": "Token overschreden", + "remained": "Token resterend", + "tokenCount": "Token aantal", + "useToken": "Token verbruikberekening, inclusief berichten, rolinstellingen en context: {{usedTokens}} / {{maxValue}}", + "used": "Token gebruikt" + }, + "toolBar": { + "cameraControl": "Camerabediening", + "cameraHelper": "Camerahulp", + "downloadModel": "Model downloaden, even geduld aub...", + "floor": "Verander vloer", + "grid": "Raster", + "resetCamera": "Camera resetten" + } +} diff --git a/locales/nl-NL/layout.json b/locales/nl-NL/layout.json new file mode 100644 index 00000000..a24eaf36 --- /dev/null +++ b/locales/nl-NL/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialoogvenster", + "header": { + "chat": "Chat", + "market": "Ontdekken", + "role": "Rol", + "settings": "Instellingen", + "tips": "Het project is momenteel in ontwikkeling en we kunnen de stabiliteit van de gegevens niet garanderen. Als u problemen ondervindt, kunt u dialoogberichten wissen en systeeminstellingen resetten in de systeeminstellingen. Excuses voor het ongemak." + }, + "sessionList": "Sessielijst", + "siderBar": "Zijbalk" +} diff --git a/locales/nl-NL/my.json b/locales/nl-NL/my.json new file mode 100644 index 00000000..5f5b19d2 --- /dev/null +++ b/locales/nl-NL/my.json @@ -0,0 +1,5 @@ +{ + "my": "mijn", + "myDance": "mijn dans", + "myRole": "mijn rol" +} diff --git a/locales/nl-NL/panel.json b/locales/nl-NL/panel.json new file mode 100644 index 00000000..0b97eb1f --- /dev/null +++ b/locales/nl-NL/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Aan lijst toevoegen", + "addPlaySuccess": "Is toegevoegd aan de afspeellijst", + "cancelAddPlay": "Weet u zeker dat u wilt afmelden voor muziek {{musicName}}?", + "cancelSubscribed": "Afmelden", + "findDance": "Vind je favoriete dans", + "musicAndDance": "Muziek en Dans", + "play": "Afspelen" + }, + "info": { + "avatarDescription": "Aangepast avatar, klik op het avatar om een aangepaste upload te selecteren", + "avatarLabel": "Avatar", + "coverDescription": "Wordt gebruikt voor het presenteren van de rol op de ontdek-pagina, aanbevolen formaat {{width}} x {{height}}", + "coverLabel": "Omslag", + "descDescription": "Rolbeschrijving, voor een eenvoudige inleiding van de rol", + "descLabel": "Beschrijving", + "emotionDescription": "Selecteer de emotie bij het reageren, beïnvloedt de expressie van de rol", + "emotionLabel": "Uitdrukking en emotie", + "genderDescription": "Geslacht van de rol, beïnvloedt de touch-respons van de rol", + "genderLabel": "Geslacht", + "greetDescription": "Groet bij de eerste keer praten met de rol", + "greetLabel": "Groet", + "modelDescription": "Modelvoorbeeld, sleep het modelbestand om te vervangen", + "modelLabel": "Modelvoorbeeld", + "nameDescription": "Rolnaam, hoe de rol wordt aangesproken tijdens het chatten", + "nameLabel": "Naam", + "readmeDescription": "De handleiding van de rol, voor het presenteren van de rol op de ontdek-pagina", + "readmeLabel": "Rolhandleiding", + "textDescription": "Aangepaste responstekst", + "textLabel": "Tekst", + "categoryLabel": "Categorie", + "categoryDescription": "Rolcategorie, voor classificatie" + }, + "market": { + "findVidol": "Vind je favoriete idool" + }, + "nav": { + "info": "Basisinformatie", + "model": "3D Model", + "role": "Rolinstelling", + "voice": "Stem" + }, + "role": { + "greetTip": "Voer de groet in die de rol gebruikt wanneer hij met je praat", + "inputRoleSetting": "Voer de systeeminstellingen van de rol in", + "roleDescriptionTip": "Voer de beschrijving van de rol in", + "roleNameTip": "Voer de naam van de rol in", + "roleReadmeTip": "Voer de handleiding van de rol in", + "roleSettingDescription": "De achtergrondinstelling van de rol, zal worden verzonden naar het model tijdens het chatten met de rol", + "roleSettingLabel": "Systeemrolinstelling", + "uploadSize": "Ondersteuning voor individuele bestandsuploads, aanbevolen formaat is een veelvoud van {{width}} x {{height}}" + }, + "touch": { + "addAction": "Voeg reagerend gebaar toe", + "editAction": "Bewerk reagerend gebaar", + "inputActionEmotion": "Voer de uitdrukking in die de rol moet tonen bij reageren", + "inputActionText": "Voer de responstekst in", + "inputDIYText": "Voer aangepaste tekst in", + "touchActionList": "Reactielijst bij het aanraken van {{touchArea}}", + "touchArea": "Aanraakgebied" + }, + "tts": { + "audition": "Afspeellijst", + "auditionDescription": "Afspeellijst kan verschillen per taal", + "engineDescription": "Stemsynthesizengine, het is aanbevolen om de Edge-browser te gebruiken", + "engineLabel": "Stemengine", + "localeDescription": "Taal voor stemsynthese, momenteel alleen de meest voorkomende talen ondersteund, neem contact op indien nodig", + "localeLabel": "Taal", + "pitchDescription": "Bewaar toonhoogte, waardebereik 0 ~ 2, standaard is 1", + "pitchLabel": "Toonhoogte", + "selectLanguage": "Selecteer eerst de taal", + "selectVoice": "Selecteer eerst de stem", + "speedDescription": "Bewaar spraaksnelheid, waardebereik 0 ~ 3, standaard is 1", + "speedLabel": "Spraaksnelheid", + "transfromSuccess": "Converteren succesvol", + "voiceDescription": "Kan verschillen afhankelijk van de engine en taal", + "voiceLabel": "Stem" + }, + "upload": { + "support": "Ondersteuning voor individuele bestandsuploads, momenteel alleen vrm-formaat bestanden ondersteund" + } +} diff --git a/locales/nl-NL/role.json b/locales/nl-NL/role.json new file mode 100644 index 00000000..c6546c87 --- /dev/null +++ b/locales/nl-NL/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Verwijder rol", + "delRoleDesc": "Weet je zeker dat je de rol {{name}} en gerelateerde sessieberichten wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt, wees voorzichtig!", + "header": { + "role": "Rol", + "session": "Sessie" + }, + "noRole": "Er zijn momenteel geen rollen. Je kunt een aangepaste rol maken door op + te klikken, of rollen toevoegen via de ontdekkingspagina.", + "roleList": "Rollenlijst", + "topBannerTitle": "Rolvoorbeeld en instellingen" +} diff --git a/locales/nl-NL/welcome.json b/locales/nl-NL/welcome.json new file mode 100644 index 00000000..ef39f26f --- /dev/null +++ b/locales/nl-NL/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} is de standaardrol van Vidol, en je persoonlijke assistent", + "greeting": "Hallo, lieve meester! Ik ben je persoonlijke assistent {{name}}, ik ben blij je te kunnen bedienen! Is er iets waar ik je bij kan helpen?", + "hello": "Hallo", + "meta": { + "description": "Dit is een aangepaste rol", + "name": "Aangepaste rol" + } + }, + "greet": "Hallo, ik ben {{name}}, is er iets waarmee ik je kan helpen?", + "loadingTitle": "Applicatie initialisatie, even geduld aub...", + "waitting": "Ik ben bezig om je mijn hele wereld voor te bereiden" +} diff --git a/locales/pl-PL/chat.json b/locales/pl-PL/chat.json new file mode 100644 index 00000000..7385d83e --- /dev/null +++ b/locales/pl-PL/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Rozmowa", + "chatDialog": { + "close": "Zamknij" + }, + "dance": "Taniec", + "header": { + "role": "Rola", + "session": "Sesja" + }, + "helloChat": "Cześć, porozmawiajmy", + "helloDance": "Cześć, zatańczmy razem", + "market": "Odkrywaj" +} diff --git a/locales/pl-PL/common.json b/locales/pl-PL/common.json new file mode 100644 index 00000000..44ac3511 --- /dev/null +++ b/locales/pl-PL/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Dodaj", + "clearAll": "Wyczyść wszystko", + "clearContext": "Wyczyść kontekst", + "clearHistoryTip": "Ta operacja jest nieodwracalna, proszę zachować ostrożność", + "clearHistoryTitle": "Czy na pewno chcesz usunąć historię wiadomości?", + "clearNow": "Wyczyść teraz", + "clearSuccess": "Pomyślnie wyczyszczono", + "clearTip": "Operacja nie może zostać cofnięta, po wyczyszczeniu danych nie będzie można odzyskać, proszę zachować ostrożność", + "clearTitle": "Czy na pewno chcesz usunąć wszystkie wiadomości sesji?", + "confirmDel": "Czy na pewno chcesz usunąć?", + "copy": "Kopiuj", + "copySuccess": "Pomyślnie skopiowano", + "del": "Usuń", + "delAndRegenerate": "Usuń i wygeneruj ponownie", + "downloadAvatar": "Pobierz awatar", + "downloadCover": "Pobierz okładkę", + "downloadFailed": "Pobieranie nie powiodło się", + "downloadModel": "Pobierz model", + "downloadSubscribe": "Pobierz subskrypcję", + "downloadSuccess": "Pobieranie powiodło się", + "edit": "Edytuj", + "goBottom": "Powrót do dołu", + "market": "Odkryj", + "pause": "Pauza", + "play": "Odtwarzaj", + "regenerate": "Wygeneruj ponownie", + "removeInList": "Usuń z listy", + "reset": "Resetuj", + "resetNow": "Zresetuj teraz", + "resetSuccess": "Pomyślnie zresetowano", + "resetTip": "Operacja nie może zostać cofnięta, po resetowaniu danych nie będzie można odzyskać, proszę zachować ostrożność", + "resetTitle": "Czy na pewno chcesz zresetować wszystkie ustawienia systemowe?", + "save": "Zapisz", + "send": "Wyślij", + "share": "Udostępnij", + "subscribe": "Subskrybuj", + "subscribeDance": "Subskrybuj taniec", + "subscribeRole": "Subskrybuj rolę", + "subscribed": "Subskrybowane", + "unsubscribe": "Anuluj subskrypcję", + "unsubscribeSuccess": "Pomyślnie anulowano subskrypcję", + "warp": "Zmień linię" + }, + "aiAlert": "Pamiętaj: wszystko, co mówi inteligentny agent, jest generowane przez AI", + "cancel": "Anuluj", + "commonSetting": "Ustawienia ogólne", + "confirm": "Potwierdź", + "defaultAssistant": "Domyślny asystent", + "delAlert": "Czy na pewno chcesz usunąć postać i powiązane z nią wiadomości? Po usunięciu nie będzie można odzyskać, proszę zachować ostrożność!", + "delRole": "Usuń rolę", + "delSession": "Usuń sesję", + "delSessionAlert": "Czy na pewno chcesz usunąć rozmowę? Po usunięciu nie będzie można odzyskać, proszę zachować ostrożność!", + "inputStartChat": "Wprowadź treść, aby rozpocząć rozmowę", + "languageModel": "Model językowy", + "loading": "Ładowanie...", + "noData": "Brak danych", + "openai": { + "callError": "Nie udało się wywołać interfejsu, proszę sprawdzić czy APIKey i adres serwera proxy są poprawnie skonfigurowane", + "check": "Sprawdź", + "checkAll": "Sprawdź czy APIKey i adres serwera proxy są poprawnie skonfigurowane", + "checkConnect": "Sprawdź łączność", + "checkOk": "Sprawdzenie zakończone powodzeniem", + "langModel": "Model językowy OpenAI", + "model": "Model", + "proxyUrl": "Adres serwera proxy", + "roleModel": "Model Role GPT", + "useOwnKey": "Proszę użyć własnego klucza OpenAI" + }, + "playlist": "Playlista", + "search": "Szukaj", + "selectInDanceList": "Proszę wybrać z listy tańców", + "selectModel": "Proszę wybrać model", + "setLocalStorage": "Ustaw lokal", + "startChat": "Rozpocznij rozmowę", + "ttsCombine": "Sinteza mowy", + "ttsTip": "Rozpoznawanie mowy (wymaga dostępu do internetu)", + "uploadTip": "Kliknij lub przeciągnij plik do tego obszaru, aby przesłać", + "words": { + "DIYAvatar": "Niestandardowy awatar", + "DIYBackgroundEffect": "Niestandardowy efekt tła", + "DIYColor": "Niestandardowy ton szarości o różnych kolorowych tendencjach", + "DIYNickname": "Niestandardowa nazwa użytkownika", + "DIYTopicColor": "Niestandardowy kolor tematu", + "avatar": "Awatar", + "backgroundEffect": "Efekt tła", + "chatSetting": "Ustawienia czatu", + "clearAllSession": "Wyczyść wszystkie wiadomości sesji", + "clearAllSessionDesc": "Spowoduje usunięcie wszystkich danych sesji i postaci, w tym listy rozmów, listy postaci, wiadomości sesji itp.", + "midColor": "Kolor średni", + "nickname": "Nazwa użytkownika", + "resetSystemSetting": "Resetuj ustawienia systemowe", + "resetSystemSettingDesc": "Spowoduje zresetowanie wszystkich ustawień systemowych, w tym ustawień motywów, czat, modeli językowych itp.", + "systemSetting": "Ustawienia systemowe", + "languageSetting": "Ustawienia języka", + "topicColor": "Kolor tematu", + "topicSetting": "Ustawienia tematu" + } +} diff --git a/locales/pl-PL/constants.json b/locales/pl-PL/constants.json new file mode 100644 index 00000000..9a2ca84a --- /dev/null +++ b/locales/pl-PL/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Kobieta", + "male": "Mężczyzna", + "other": "Inne" + }, + "meta": { + "description": "To jest niestandardowa postać", + "name": "Niestandardowa postać" + } + }, + "touch": { + "area": { + "arm": "Ramiona", + "belly": "Brzuch", + "chest": "Część piersiowa", + "head": "Głowa", + "leg": "Nogi" + }, + "emotion": { + "angry": "Zły", + "blink": "Mrugnięcie", + "blinkLeft": "Mrugnięcie lewym okiem", + "blinkRight": "Mrugnięcie prawym okiem", + "happy": "Szczęśliwy", + "natural": "Naturalny", + "relaxed": "Spokojny", + "sad": "Smutny", + "surprised": "Zaskoczony" + }, + "femaleAction": { + "armAction": { + "happyA": "Ah, bardzo mi się to podoba~", + "happyB": "Ha ha, trzymanie dłoni sprawia mi przyjemność~", + "relaxedA": "Ręce Pana są tak ciepłe~" + }, + "bellyAction": { + "angryA": "Co się śmiejesz, trzymając mnie? Uważaj, żebym cię nie ugryzła!", + "relaxedA": "Budź się, między nami nie będzie wyniku!", + "relaxedB": "Niesłuchanie! W końcu się rozgniewam!", + "surprisedA": "To bynajmniej nie było celowe... " + }, + "chestAction": { + "angryA": "Nie można tak mnie traktować! Usuń ręce!", + "angryB": "Jest tu policyjny numer 110? Tutaj jest someone, który ciągle mnie dotyka!", + "angryC": "Kontynuuj dotykanie, a wywołam policyjną pomoc", + "surprisedA": "Co to za picie? Czy możemy rozmawiać spokojnie?" + }, + "headAction": { + "angryA": "Słyszałam, że głowę trzymać może przestać rosnąć!", + "angryB": "Co to za picie?", + "happyA": "Wau! Najbardziej lubię, gdy ktoś mnie głowę trzymać!", + "happyB": "Czuję, że znów jestem pełen sił!", + "happyC": "Wow, to trzymanie głowy jest cudowne!", + "happyD": "Tym trzymaniem głowy, mogę być szczęśliwa przez cały dzień!" + }, + "legAction": { + "angryA": "Hej, czy chcesz umrzeć?", + "angryB": "Czy ręce Pana nie słuchają?", + "angryC": "Niesłuchanie~ To jest denerwujące!", + "surprisedA": "Nie mogłabyś zachować naszej niewinnej przyjaźni?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Nie pytaj mnie, czy jadłem kurczaka dzisiaj, spójrz najpierw na mój biceps", + "neutralB": "Moje ramiona nie są dla każdego do dotknięcia, jesteś wyjątkiem", + "neutralC": "Jesteś odważny, dotknąłeś się legendarnego ramienia Kirin" + }, + "bellyAction": { + "happyA": "Nie hałasuj, uważa, żebym nie wylał sił", + "neutralA": "To są tylko moje brzuchowe mięśnie, które ukrywają swoją siłę", + "neutralB": "Zobaczyłeś te brzuchowe mięśnie? Po prostu są głęboko ukryte" + }, + "chestAction": { + "blinkLeftA": "No, bierz na ramiona, moje piersiowe mięśnie są dla ciebie!", + "neutralA": "To tylko jest osiągnięcie z codziennych treningów, nic się nie dziwnego." + }, + "headAction": { + "neutralA": "Oczywiście, tylko ty masz kwalifikacje, aby trzymać głowę", + "neutralB": "Nie jestem tak samo, jak zwykła osoba, którą można dotknąć", + "neutralC": "Nie martw się, po tym, jak dotkniesz się mojej głowy, twoja szczęśliwa rzeka będzie znacznie większa" + }, + "legAction": { + "angryA": "Nie przystąp do mnie, ty fanatyczny miłośnik nóg", + "neutralA": "Nie obawiaj się, moje potężne nogi nie biją głupców", + "neutralB": "Pozwól mi dotknąć twoich nóg, czy nie czujesz, że twoje życie jest teraz pełne?" + } + } + } +} diff --git a/locales/pl-PL/error.json b/locales/pl-PL/error.json new file mode 100644 index 00000000..368d00f9 --- /dev/null +++ b/locales/pl-PL/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key jest pusty. Proszę dodać niestandardowy klucz API OpenAI.", + "error": "Błąd", + "errorTip": { + "clearSession": "Wyczyść sesję", + "description": "Projekt jest obecnie w trakcie budowy, nie gwarantuje stabilności danych. W razie problemów można spróbować", + "forgive": ", przepraszamy za wszelkie niedogodności", + "or": "lub", + "problem": "Strona napotkała pewien problem...", + "resetSystem": "Zresetuj ustawienia systemu" + }, + "goBack": "Powrót do strony głównej", + "openaiError": "Błąd OpenAI API. Proszę sprawdź, czy klucz API OpenAI i Endpoint są poprawne.", + "reload": "Przeładuj", + "s3envError": "Błąd środowiska S3. Sprawdź, czy Twoje zmienne środowiskowe są ustawione poprawnie.", + "serverError": "Błąd serwera. Skontaktuj się z administratorem.", + "triggerError": "Wystąpił błąd", + "unknownError": "Nieznany błąd" +} diff --git a/locales/pl-PL/features.json b/locales/pl-PL/features.json new file mode 100644 index 00000000..900a12b6 --- /dev/null +++ b/locales/pl-PL/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Przełącz na tryb wideo" + }, + "agent": { + "female": "Kobieta", + "male": "Mężczyzna", + "other": "Inne" + }, + "feature": { + "addProxy": "Dodaj adres proxy OpenAI (opcjonalnie)", + "closeTip": "Zamknij wskazówkę", + "comfirmRetry": "Potwierdź i spróbuj ponownie", + "startDesc": "Wprowadź swój klucz API OpenAI, aby rozpocząć rozmowę. Aplikacja nie będzie rejestrować Twojego klucza API", + "startTitle": "Niestandardowy klucz API" + }, + "mode": { + "chat": "Czat", + "video": "Wideo" + }, + "settings": { + "glow": "Płomien", + "nickName": "Wprowadź pseudonim", + "none": "Brak tła" + }, + "share": { + "downloadScreenshot": "Pobierz zrzut ekranu", + "imageType": "Typ obrazu", + "screenshot": "Zrzut ekranu", + "share": "Udostępnij", + "shareGPT": "Udostępnij GPT", + "shareToGPT": "Utwórz link udostępniania ShareGPT", + "shareToMarket": "Udostępnij na rynku asystentów", + "withBackground": "Z obrazem tła", + "withFooter": "Z stopką", + "withSystemRole": "Z ustawieniami roli asystenta" + }, + "submit": { + "assistantId": "Identyfikator asystenta", + "assistantIdTip": "Wprowadź identyfikator asystenta, musi być unikalny, np. vidol-agent-klee", + "submitAssistant": "Prześlij asystenta", + "submitWarning": "Proszę uzupełnić informacje o asystencie przed przesłaniem, w tym nazwę, opis, awatar i okładkę" + }, + "support": "Wsparcie społeczności", + "theme": { + "auto": "Śledzenie systemu", + "dark": "Ciemny motyw", + "light": "Jasny motyw" + }, + "token": { + "overload": "Przekroczenie tokenów", + "remained": "Pozostało tokenów", + "tokenCount": "Liczba tokenów", + "useToken": "Obliczanie zużycia tokenów, w tym wiadomości, ustawienia roli i kontekstu: {{usedTokens}} / {{maxValue}}", + "used": "Tokenów użytych" + }, + "toolBar": { + "cameraControl": "Kontrola kamery", + "cameraHelper": "Asystent kamery", + "downloadModel": "Pobieranie modelu, proszę czekać...", + "floor": "Przełącz podłogę", + "grid": "Siatka", + "resetCamera": "Zresetuj kamerę" + } +} diff --git a/locales/pl-PL/layout.json b/locales/pl-PL/layout.json new file mode 100644 index 00000000..a89825df --- /dev/null +++ b/locales/pl-PL/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Okno dialogowe", + "header": { + "chat": "Czat", + "market": "Odkrywanie", + "role": "Rola", + "settings": "Ustawienia", + "tips": "Projekt jest obecnie w trakcie budowy, nie gwarantuje stabilności danych. W przypadku problemów można wyczyścić wiadomości sesji i zresetować ustawienia systemu w ustawieniach systemowych. Przepraszamy za wszelkie niedogodności." + }, + "sessionList": "Lista sesji", + "siderBar": "Pasek boczny" +} diff --git a/locales/pl-PL/my.json b/locales/pl-PL/my.json new file mode 100644 index 00000000..27efa2c9 --- /dev/null +++ b/locales/pl-PL/my.json @@ -0,0 +1,5 @@ +{ + "my": "moje", + "myDance": "moje tańce", + "myRole": "moja rola" +} diff --git a/locales/pl-PL/panel.json b/locales/pl-PL/panel.json new file mode 100644 index 00000000..2c049c70 --- /dev/null +++ b/locales/pl-PL/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Dodaj do listy", + "addPlaySuccess": "Zostało dodane do listy odtwarzania", + "cancelAddPlay": "Czy na pewno chcesz anulować subskrypcję muzyki {{musicName}}?", + "cancelSubscribed": "Anuluj subskrypcję", + "findDance": "Znajdź swój ulubiony taniec", + "musicAndDance": "Muzyka i taniec", + "play": "Odtwórz" + }, + "info": { + "avatarDescription": "Niestandardowe zdjęcie profilowe, kliknij zdjęcie profilowe, aby przesłać własne", + "avatarLabel": "Zdjęcie profilowe", + "coverDescription": "Używane do prezentacji postaci na stronie odkrywania, zalecany rozmiar {{width}} x {{height}}", + "coverLabel": "Okładka", + "descDescription": "Opis postaci, używany do prostego przedstawienia postaci", + "descLabel": "Opis", + "emotionDescription": "Wybierz emocje reakcji, które będą wpływać na wyraz twarzy postaci", + "emotionLabel": "Wyraz twarzy i emocje", + "genderDescription": "Płeć postaci, wpływa na reakcje na dotknięcie", + "genderLabel": "Płeć", + "greetDescription": "Forma przywitania postaci podczas pierwszego rozmowy", + "greetLabel": "Przywitanie", + "modelDescription": "Podgląd modelu, możesz przeciągnąć plik modelu, aby zastąpić", + "modelLabel": "Podgląd modelu", + "nameDescription": "Nazwa postaci, nazwa używana podczas rozmowy z postacią", + "nameLabel": "Nazwa", + "readmeDescription": "Plik z opisem postaci, używany do prezentacji szczegółowego opisu postaci na stronie odkrywania", + "readmeLabel": "Opis postaci", + "textDescription": "Niestandardowe tło odpowiedzi", + "textLabel": "Treść", + "categoryLabel": "Kategoria", + "categoryDescription": "Kategoria postaci, używana do klasyfikacji" + }, + "market": { + "findVidol": "Znajdź swojego ulubionego idola" + }, + "nav": { + "info": "Podstawowe informacje", + "model": "Model 3D", + "role": "Ustawienia postaci", + "voice": "Głos" + }, + "role": { + "greetTip": "Wprowadź formę przywitania postaci podczas pierwszego kontaktu", + "inputRoleSetting": "Wprowadź ustawienia systemu postaci", + "roleDescriptionTip": "Wprowadź opis postaci", + "roleNameTip": "Wprowadź nazwę postaci", + "roleReadmeTip": "Wprowadź opis postaci", + "roleSettingDescription": "Ustawienia tła postaci, będą wysyłane do modelu podczas rozmowy z postacią", + "roleSettingLabel": "Ustawienia systemu postaci", + "uploadSize": "Obsługiwany jest pojedynczy plik, zalecany rozmiar w wielokrotnością {{width}} x {{height}}" + }, + "touch": { + "addAction": "Dodaj reakcję", + "editAction": "Edytuj reakcję", + "inputActionEmotion": "Proszę wprowadzić wyraz twarzy postaci podczas reakcji", + "inputActionText": "Proszę wprowadzić treść odpowiedzi", + "inputDIYText": "Wprowadź niestandardową treść", + "touchActionList": "Lista reakcji na dotknięcie {{touchArea}}", + "touchArea": "Obszar dotknięcia" + }, + "tts": { + "audition": "Przetestuj", + "auditionDescription": "Przetestuj treść w zależności od języka", + "engineDescription": "Silnik syntezowania mowy, zaleca się wykorzystanie przeglądarki Edge", + "engineLabel": "Silnik mowy", + "localeDescription": "Język syntezowania mowy, obecnie obsługiwane są tylko najpopularniejsze języki, w razie potrzeby skontaktuj się z", + "localeLabel": "Język", + "pitchDescription": "Kontrola wysokości dźwięku, zakres 0 ~ 2, domyślnie 1", + "pitchLabel": "Wysokość dźwięku", + "selectLanguage": "Najpierw wybierz język", + "selectVoice": "Najpierw wybierz głos", + "speedDescription": "Kontrola szybkości mówienia, zakres 0 ~ 3, domyślnie 1", + "speedLabel": "Prędkość mówienia", + "transfromSuccess": "Konwersja powiodła się", + "voiceDescription": "Zależy od silnika i języka", + "voiceLabel": "Głos" + }, + "upload": { + "support": "Obsługiwany jest pojedynczy plik, obecnie obsługiwany jest tylko format vrm" + } +} diff --git a/locales/pl-PL/role.json b/locales/pl-PL/role.json new file mode 100644 index 00000000..5f365028 --- /dev/null +++ b/locales/pl-PL/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Usuń rolę", + "delRoleDesc": "Czy na pewno chcesz usunąć rolę {{name}} wraz z powiązanymi wiadomościami sesji? Po usunięciu nie będzie możliwe przywrócenie, dlatego działaj ostrożnie!", + "header": { + "role": "Rola", + "session": "Sesja" + }, + "noRole": "Brak ról, możesz utworzyć niestandardową rolę za pomocą + lub dodać rolę ze strony odkrywania", + "roleList": "Lista ról", + "topBannerTitle": "Podgląd i ustawienia roli" +} diff --git a/locales/pl-PL/welcome.json b/locales/pl-PL/welcome.json new file mode 100644 index 00000000..25df7f17 --- /dev/null +++ b/locales/pl-PL/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} jest domyślną postacią Vidola, twoim osobistym asystentem", + "greeting": "Cześć, drogi Panie/Pani! Jestem {{name}}, twoim prywatnym asystentem, chętnie służę Tobie! Czy mogę Ci w czymś pomóc?", + "hello": "Witaj", + "meta": { + "description": "To jest niestandardowa postać", + "name": "Niestandardowa postać" + } + }, + "greet": "Witaj, jestem {{name}}, jak mogę Ci pomóc?", + "loadingTitle": "Inicjalizacja aplikacji, proszę czekać...", + "waitting": "Trwa przygotowywanie całego mojego świata dla Ciebie" +} diff --git a/locales/pt-BR/chat.json b/locales/pt-BR/chat.json new file mode 100644 index 00000000..e5e80520 --- /dev/null +++ b/locales/pt-BR/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "Chat", + "chatDialog": { + "close": "Close" + }, + "dance": "Dance", + "header": { + "role": "Role", + "session": "Session" + }, + "helloChat": "Hello, let's chat", + "helloDance": "Hi, let's dance together", + "market": "Discover" +} diff --git a/locales/pt-BR/common.json b/locales/pt-BR/common.json new file mode 100644 index 00000000..daf525c9 --- /dev/null +++ b/locales/pt-BR/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Adicionar", + "clearAll": "Limpar tudo", + "clearContext": "Limpar contexto", + "clearHistoryTip": "Esta ação é irreversível. Por favor, proceda com cuidado.", + "clearHistoryTitle": "Confirmar exclusão do histórico de mensagens?", + "clearNow": "Limpar Agora", + "clearSuccess": "Limpeza bem-sucedida", + "clearTip": "A ação não pode ser desfeita. Os dados serão perdidos permanentemente. Por favor, proceda com cuidado.", + "clearTitle": "Confirmar limpar todas as mensagens da sessão?", + "confirmDel": "Tem certeza de que deseja excluir?", + "copy": "Copiar", + "copySuccess": "Cópia bem-sucedida", + "del": "Excluir", + "delAndRegenerate": "Excluir e Regenerar", + "downloadAvatar": "Baixar avatar", + "downloadCover": "Baixar capa", + "downloadFailed": "Falha no download", + "downloadModel": "Baixar modelo", + "downloadSubscribe": "Download de inscrição", + "downloadSuccess": "Download bem-sucedido", + "edit": "Editar", + "goBottom": "Ir para o final", + "market": "Descobrir", + "pause": "Pausar", + "play": "Reproduzir", + "regenerate": "Regenerar", + "removeInList": "Remover da lista", + "reset": "Redefinir", + "resetNow": "Redefinir Agora", + "resetSuccess": "Redefinição bem-sucedida", + "resetTip": "Esta ação não pode ser desfeita. Os dados serão perdidos permanentemente. Por favor, proceda com cuidado.", + "resetTitle": "Confirmar redefinir todas as configurações do sistema?", + "save": "Salvar", + "send": "Enviar", + "share": "Compartilhar", + "subscribe": "Inscrever-se", + "subscribeDance": "Inscrever-se na dança", + "subscribeRole": "Inscrever-se no papel", + "subscribed": "Inscrito", + "unsubscribe": "Cancelar inscrição", + "unsubscribeSuccess": "Inscrição cancelada com sucesso", + "warp": "Quebrar linha" + }, + "aiAlert": "Por favor, lembre-se: tudo o que o agente inteligente diz é gerado por IA", + "cancel": "Cancelar", + "commonSetting": "Configuração comum", + "confirm": "Confirmar", + "defaultAssistant": "Assistente padrão", + "delAlert": "Tem certeza de que deseja excluir o papel e as mensagens da sessão relacionadas? Esta ação não pode ser desfeita. Por favor, proceda com cuidado!", + "delRole": "Excluir papel", + "delSession": "Excluir sessão", + "delSessionAlert": "Tem certeza de que deseja excluir a conversa? Esta ação não pode ser desfeita. Por favor, proceda com cuidado!", + "inputStartChat": "Digite algo para começar a conversar", + "languageModel": "Modelo de idioma", + "loading": "Carregando...", + "noData": "Sem dados", + "openai": { + "callError": "Falha ao chamar a API. Por favor, verifique se a chave da API e o endereço do proxy estão configurados corretamente", + "check": "Verificar", + "checkAll": "Verificar se a chave da API e o endereço do proxy estão configurados corretamente", + "checkConnect": "Verificar conectividade", + "checkOk": "Verificação bem-sucedida", + "langModel": "Modelo de idioma OpenAI", + "model": "Modelo", + "proxyUrl": "Endereço do proxy da API", + "roleModel": "Modelo GPT de papel", + "useOwnKey": "Use sua própria chave OpenAI" + }, + "playlist": "Lista de reprodução", + "search": "Pesquisar", + "selectInDanceList": "Por favor, selecione na lista de danças", + "selectModel": "Selecione um modelo", + "setLocalStorage": "Definir armazenamento local", + "startChat": "Iniciar conversa", + "ttsCombine": "Síntese de voz", + "ttsTip": "Reconhecimento de voz (requer conexão à internet)", + "uploadTip": "Clique ou arraste arquivos para esta área para fazer upload", + "words": { + "DIYAvatar": "Avatar personalizado", + "DIYBackgroundEffect": "Efeito de fundo personalizado", + "DIYColor": "Personalização de tons de cinza com diferentes tendências de cores", + "DIYNickname": "Apelido personalizado", + "DIYTopicColor": "Cor do tópico personalizada", + "avatar": "Avatar", + "backgroundEffect": "Efeito de fundo", + "chatSetting": "Configuração de chat", + "clearAllSession": "Limpar todas as mensagens da sessão", + "clearAllSessionDesc": "Isso limpará todas as conversas e dados de papel, incluindo listas de conversas, listas de papéis, mensagens de conversa, etc.", + "midColor": "Cor neutra", + "nickname": "Apelido", + "resetSystemSetting": "Redefinir configurações do sistema", + "resetSystemSettingDesc": "Isso redefinirá todas as configurações do sistema, incluindo configurações de tópicos, chat, modelos de idioma, etc.", + "systemSetting": "Configuração do sistema", + "languageSetting": "Configuração de idioma", + "topicColor": "Cor do tópico", + "topicSetting": "Configuração de tópico" + } +} diff --git a/locales/pt-BR/constants.json b/locales/pt-BR/constants.json new file mode 100644 index 00000000..0cb560e3 --- /dev/null +++ b/locales/pt-BR/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Feminino", + "male": "Masculino", + "other": "Outro" + }, + "meta": { + "description": "Este é um papel personalizado", + "name": "Custom Role" + } + }, + "touch": { + "area": { + "arm": "Braço", + "belly": "Barriga", + "chest": "Peito", + "head": "Cabeça", + "leg": "Perna" + }, + "emotion": { + "angry": "Com raiva", + "blink": "Piscar", + "blinkLeft": "Piscar olho esquerdo", + "blinkRight": "Piscar olho direito", + "happy": "Feliz", + "natural": "Natural", + "relaxed": "Relaxado", + "sad": "Triste", + "surprised": "Surpreso" + }, + "femaleAction": { + "armAction": { + "happyA": "Ah, adoro isso~", + "happyB": "Haha, dar as mãos me faz feliz~", + "relaxedA": "As mãos do dono são tão quentes~" + }, + "bellyAction": { + "angryA": "Por que está mexendo em mim? Cuidado para não ser mordido!", + "relaxedA": "Acorda, não há futuro entre nós!", + "relaxedB": "Não gosto disso! Vou ficar bravo!", + "surprisedA": "Foi sem querer, certo..." + }, + "chestAction": { + "angryA": "Não me toque assim! Tire as mãos!", + "angryB": "O que está fazendo? Pare de me tocar!", + "angryC": "Se me tocar de novo, vou chamar a polícia!", + "surprisedA": "Por que está cutucando? Não podemos apenas conversar?" + }, + "headAction": { + "angryA": "Dizem que mexer no cabelo faz parar de crescer!", + "angryB": "Por que está cutucando minha cabeça?", + "happyA": "Wow! Adoro quando mexem no meu cabelo!", + "happyB": "Sinto-me cheia de energia!", + "happyC": "Uau, que sensação mágica de mexer no cabelo!", + "happyD": "Mexer no cabelo me deixa feliz o dia todo!" + }, + "legAction": { + "angryA": "Ei, você quer morrer?", + "angryB": "As mãos do dono não estão obedecendo?", + "angryC": "Não gosto disso, vai coçar!", + "surprisedA": "Vamos manter nossa amizade pura, ok?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Não me pergunte se comi frango hoje, olhe para o meu bíceps", + "neutralB": "Meus braços não são para qualquer um tocar, você é uma exceção", + "neutralC": "Você é corajoso, ousando tocar no lendário braço de unicórnio" + }, + "bellyAction": { + "happyA": "Não faça cócegas, cuidado para não rir dos meus abdominais", + "neutralA": "Meus abdominais são apenas o resultado do meu treinamento oculto", + "neutralB": "Vi meus abdominais? Eles estão apenas escondidos profundamente" + }, + "chestAction": { + "blinkLeftA": "Venha, encoste no meu peito!", + "neutralA": "Isso é apenas o resultado do meu treinamento diário, nada surpreendente" + }, + "headAction": { + "neutralA": "Claro, só você tem permissão para mexer no meu cabelo", + "neutralB": "Não sou uma pessoa comum que permite toques", + "neutralC": "Não se preocupe, depois de mexer no meu cabelo, sua sorte vai melhorar muito" + }, + "legAction": { + "angryA": "Não se aproxime, você tem fetiche por pernas", + "neutralA": "Não tenha medo, minha perna de aço não chuta tolos", + "neutralB": "Acha que sua vida está mais completa por tocar na minha perna?" + } + } + } +} diff --git a/locales/pt-BR/error.json b/locales/pt-BR/error.json new file mode 100644 index 00000000..88a282a8 --- /dev/null +++ b/locales/pt-BR/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key está vazio, por favor adicione sua chave de API personalizada OpenAI", + "error": "Erro", + "errorTip": { + "clearSession": "Limpar mensagens da sessão", + "description": "O projeto está em andamento e a estabilidade dos dados não é garantida. Se encontrar problemas, pode tentar", + "forgive": ", pedimos desculpas pelo inconveniente causado", + "or": "ou", + "problem": "A página encontrou um problema...", + "resetSystem": "Redefinir configurações do sistema" + }, + "goBack": "Voltar", + "openaiError": "Erro na API OpenAI, por favor verifique se a chave da API OpenAI e o Endpoint estão corretos", + "reload": "Recarregar", + "s3envError": "Variáveis de ambiente S3 não estão totalmente configuradas, por favor verifique suas variáveis de ambiente", + "serverError": "Erro do servidor, por favor entre em contato com o administrador", + "triggerError": "Erro acionado", + "unknownError": "Erro desconhecido" +} diff --git a/locales/pt-BR/features.json b/locales/pt-BR/features.json new file mode 100644 index 00000000..f9b59196 --- /dev/null +++ b/locales/pt-BR/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Alternar para modo de vídeo" + }, + "agent": { + "female": "Feminino", + "male": "Masculino", + "other": "Outro" + }, + "feature": { + "addProxy": "Adicionar endereço de proxy OpenAI (opcional)", + "closeTip": "Fechar dica", + "comfirmRetry": "Confirmar e tentar novamente", + "startDesc": "Digite sua chave de API OpenAI para iniciar a sessão. O aplicativo não irá armazenar sua chave de API", + "startTitle": "Chave de API personalizada" + }, + "mode": { + "chat": "Chat", + "video": "Vídeo" + }, + "settings": { + "glow": "Brilho", + "nickName": "Digite um apelido", + "none": "Sem fundo" + }, + "share": { + "downloadScreenshot": "Baixar captura de tela", + "imageType": "Tipo de imagem", + "screenshot": "Captura de tela", + "share": "Compartilhar", + "shareGPT": "Compartilhar GPT", + "shareToGPT": "Gerar link de compartilhamento ShareGPT", + "shareToMarket": "Compartilhar no mercado de assistentes", + "withBackground": "Incluir imagem de fundo", + "withFooter": "Incluir rodapé", + "withSystemRole": "Incluir configuração de papel de assistente" + }, + "submit": { + "assistantId": "Identificador do assistente", + "assistantIdTip": "Digite o identificador único do assistente, como vidol-agent-klee", + "submitAssistant": "Enviar assistente", + "submitWarning": "Por favor, complete as informações do assistente antes de enviar, incluindo nome, descrição, avatar e capa" + }, + "support": "Suporte da comunidade", + "theme": { + "auto": "Seguir sistema", + "dark": "Modo escuro", + "light": "Modo claro" + }, + "token": { + "overload": "Token excedido", + "remained": "Token restante", + "tokenCount": "Quantidade de token", + "useToken": "Cálculo de quantidade de token consumido, incluindo mensagens, configurações de papel e contexto: {{usedTokens}} / {{maxValue}}", + "used": "Token usado" + }, + "toolBar": { + "cameraControl": "Controle de câmera", + "cameraHelper": "Assistente de câmera", + "downloadModel": "Modelo sendo baixado, por favor, aguarde...", + "floor": "Alternar piso", + "grid": "Grade", + "resetCamera": "Redefinir câmera" + } +} diff --git a/locales/pt-BR/layout.json b/locales/pt-BR/layout.json new file mode 100644 index 00000000..86a18d12 --- /dev/null +++ b/locales/pt-BR/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Caixa de diálogo", + "header": { + "chat": "Chat", + "market": "Descobrir", + "role": "Função", + "settings": "Configurações", + "tips": "O projeto está em andamento, não garantimos a estabilidade dos dados. Se encontrar problemas, pode limpar as mensagens da sessão e redefinir as configurações do sistema nas configurações do sistema. Pedimos desculpas pelo inconveniente." + }, + "sessionList": "Lista de sessões", + "siderBar": "Barra lateral" +} diff --git a/locales/pt-BR/my.json b/locales/pt-BR/my.json new file mode 100644 index 00000000..da180e3d --- /dev/null +++ b/locales/pt-BR/my.json @@ -0,0 +1,5 @@ +{ + "my": "meu", + "myDance": "minha dança", + "myRole": "meu papel" +} diff --git a/locales/pt-BR/panel.json b/locales/pt-BR/panel.json new file mode 100644 index 00000000..8e0412de --- /dev/null +++ b/locales/pt-BR/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Adicionar à lista", + "addPlaySuccess": "Adicionado à lista de reprodução", + "cancelAddPlay": "Tem certeza de que deseja cancelar a inscrição na música {{musicName}}?", + "cancelSubscribed": "Cancelar inscrição", + "findDance": "Encontre sua dança favorita", + "musicAndDance": "Música e Dança", + "play": "Reproduzir" + }, + "info": { + "avatarDescription": "Avatar personalizado, clique no avatar para fazer upload personalizado", + "avatarLabel": "Avatar", + "coverDescription": "Usado para mostrar o personagem na página de descoberta, tamanho recomendado {{width}} x {{height}}", + "coverLabel": "Capa", + "descDescription": "Descrição do personagem, usada para uma breve introdução do personagem", + "descLabel": "Descrição", + "emotionDescription": "Escolha a emoção ao responder, afetará a mudança de expressão do personagem", + "emotionLabel": "Expressão e Emoção", + "genderDescription": "Gênero do personagem, afeta a resposta ao toque do personagem", + "genderLabel": "Gênero", + "greetDescription": "Saudação inicial ao conversar com o personagem", + "greetLabel": "Saudação", + "modelDescription": "Visualização do modelo, arraste o arquivo do modelo para substituir", + "modelLabel": "Visualização do Modelo", + "nameDescription": "Nome do personagem, usado para se referir ao personagem durante o chat", + "nameLabel": "Nome", + "readmeDescription": "Arquivo de instruções do personagem, usado para mostrar uma descrição detalhada do personagem na página de descoberta", + "readmeLabel": "Instruções do personagem", + "textDescription": "Texto de resposta personalizado", + "textLabel": "Texto", + "categoryLabel": "Categoria", + "categoryDescription": "Categoria do personagem, usada para classificação" + }, + "market": { + "findVidol": "Encontre seu ídolo favorito" + }, + "nav": { + "info": "Informações Básicas", + "model": "Modelo 3D", + "role": "Configuração do Personagem", + "voice": "Voz" + }, + "role": { + "greetTip": "Digite a saudação do personagem para você", + "inputRoleSetting": "Digite as configurações do sistema do personagem", + "roleDescriptionTip": "Digite a descrição do personagem", + "roleNameTip": "Digite o nome do personagem", + "roleReadmeTip": "Digite as instruções do personagem", + "roleSettingDescription": "Configurações de fundo do personagem, serão enviadas ao modelo durante o chat com o personagem", + "roleSettingLabel": "Configurações do Sistema do Personagem", + "uploadSize": "Suporta upload de um único arquivo, tamanho recomendado é múltiplo de {{width}} x {{height}}" + }, + "touch": { + "addAction": "Adicionar ação de resposta", + "editAction": "Editar ação de resposta", + "inputActionEmotion": "Digite a emoção do personagem ao responder", + "inputActionText": "Digite o texto de resposta", + "inputDIYText": "Digite o texto personalizado", + "touchActionList": "Lista de reações ao tocar {{touchArea}}", + "touchArea": "Área de toque" + }, + "tts": { + "audition": "Audição", + "auditionDescription": "Texto de audição varia de acordo com o idioma", + "engineDescription": "Motor de síntese de voz, é recomendado priorizar o navegador Edge", + "engineLabel": "Motor de Voz", + "localeDescription": "Idioma da síntese de voz, atualmente suporta apenas os idiomas mais comuns, entre em contato se precisar de mais", + "localeLabel": "Idioma", + "pitchDescription": "Controla o tom, varia de 0 a 2, padrão é 1", + "pitchLabel": "Tom", + "selectLanguage": "Por favor, selecione o idioma primeiro", + "selectVoice": "Por favor, selecione a voz primeiro", + "speedDescription": "Controla a velocidade, varia de 0 a 3, padrão é 1", + "speedLabel": "Velocidade", + "transfromSuccess": "Transformação bem-sucedida", + "voiceDescription": "Varia de acordo com o motor e idioma", + "voiceLabel": "Voz" + }, + "upload": { + "support": "Suporta upload de um único arquivo, atualmente suporta arquivos no formato vrm" + } +} diff --git a/locales/pt-BR/role.json b/locales/pt-BR/role.json new file mode 100644 index 00000000..e31a3e9c --- /dev/null +++ b/locales/pt-BR/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Excluir função", + "delRoleDesc": "Tem certeza de que deseja excluir a função {{name}} e as mensagens de sessão relacionadas? Esta ação não pode ser desfeita, por favor, proceda com cautela!", + "header": { + "role": "Função", + "session": "Sessão" + }, + "noRole": "Nenhuma função encontrada. Você pode criar uma função personalizada usando o botão +, ou adicionar funções na página de descoberta.", + "roleList": "Lista de funções", + "topBannerTitle": "Visualização e configuração de funções" +} diff --git a/locales/pt-BR/welcome.json b/locales/pt-BR/welcome.json new file mode 100644 index 00000000..1ea8f8f5 --- /dev/null +++ b/locales/pt-BR/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} é o personagem padrão da Vidol, sendo sua assistente pessoal exclusiva.", + "greeting": "Olá, querido mestre! Eu sou sua assistente pessoal {{name}}, pronta para te ajudar! Em que posso ajudar?", + "hello": "Olá!", + "meta": { + "description": "Este é um personagem personalizado", + "name": "Personagem Personalizado" + } + }, + "greet": "Olá, eu sou {{name}}, como posso te ajudar?", + "loadingTitle": "Inicializando o aplicativo, por favor aguarde...", + "waitting": "Preparando todo o meu mundo para você" +} diff --git a/locales/ru-RU/chat.json b/locales/ru-RU/chat.json new file mode 100644 index 00000000..7e5cbe24 --- /dev/null +++ b/locales/ru-RU/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "чат", + "chatDialog": { + "close": "закрыть" + }, + "dance": "танцевать", + "header": { + "role": "роль", + "session": "сессия" + }, + "helloChat": "Привет, давай поболтаем", + "helloDance": "Привет, давай потанцуем вместе", + "market": "рынок" +} diff --git a/locales/ru-RU/common.json b/locales/ru-RU/common.json new file mode 100644 index 00000000..bc1afde9 --- /dev/null +++ b/locales/ru-RU/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Добавить", + "clearAll": "Очистить все", + "clearContext": "Очистить контекст", + "clearHistoryTip": "Данное действие нельзя отменить. Пожалуйста, будьте осторожны.", + "clearHistoryTitle": "Вы уверены, что хотите удалить историю сообщений?", + "clearNow": "Очистить сейчас", + "clearSuccess": "Успешно очищено", + "clearTip": "Данное действие нельзя отменить. После очистки данные будут недоступны. Пожалуйста, будьте осторожны.", + "clearTitle": "Вы уверены, что хотите удалить все сообщения сессии?", + "confirmDel": "Вы уверены, что хотите удалить?", + "copy": "Копировать", + "copySuccess": "Успешно скопировано", + "del": "Удалить", + "delAndRegenerate": "Удалить и сгенерировать заново", + "downloadAvatar": "Загрузить аватар", + "downloadCover": "Загрузить обложку", + "downloadFailed": "Ошибка загрузки", + "downloadModel": "Загрузить модель", + "downloadSubscribe": "Загрузить подписку", + "downloadSuccess": "Успешно загружено", + "edit": "Редактировать", + "goBottom": "Перейти вниз", + "market": "Маркет", + "pause": "Пауза", + "play": "Воспроизвести", + "regenerate": "Сгенерировать заново", + "removeInList": "Удалить из списка", + "reset": "Сбросить", + "resetNow": "Сбросить сейчас", + "resetSuccess": "Успешно сброшено", + "resetTip": "Данное действие нельзя отменить. После сброса данные будут недоступны. Пожалуйста, будьте осторожны.", + "resetTitle": "Вы уверены, что хотите сбросить все системные настройки?", + "save": "Сохранить", + "send": "Отправить", + "share": "Поделиться", + "subscribe": "Подписаться", + "subscribeDance": "Подписаться на танец", + "subscribeRole": "Подписаться на роль", + "subscribed": "Подписан", + "unsubscribe": "Отписаться", + "unsubscribeSuccess": "Успешно отписан", + "warp": "Перенос строки" + }, + "aiAlert": "Пожалуйста, помните: все, что говорит ассистент, создано искусственным интеллектом.", + "cancel": "Отмена", + "commonSetting": "Общие настройки", + "confirm": "Подтвердить", + "defaultAssistant": "По умолчанию", + "delAlert": "Вы уверены, что хотите удалить роль и связанные с ней сообщения? После удаления восстановление будет невозможно. Пожалуйста, будьте осторожны!", + "delRole": "Удалить роль", + "delSession": "Удалить сессию", + "delSessionAlert": "Вы уверены, что хотите удалить диалог? После удаления восстановление будет невозможно. Пожалуйста, будьте осторожны!", + "inputStartChat": "Введите текст для начала чата", + "languageModel": "Языковая модель", + "loading": "Загрузка...", + "noData": "Нет данных", + "openai": { + "callError": "Ошибка вызова API. Пожалуйста, проверьте правильность API-ключа и адреса прокси.", + "check": "Проверить", + "checkAll": "Проверить правильность API-ключа и адреса прокси", + "checkConnect": "Проверить подключение", + "checkOk": "Проверка пройдена", + "langModel": "Языковая модель OpenAI", + "model": "Модель", + "proxyUrl": "Адрес прокси", + "roleModel": "Модель Role GPT", + "useOwnKey": "Используйте свой ключ OpenAI" + }, + "playlist": "Плейлист", + "search": "Поиск", + "selectInDanceList": "Выберите из списка танцев", + "selectModel": "Выберите модель", + "setLocalStorage": "Установить локальное хранилище", + "startChat": "Начать чат", + "ttsCombine": "Синтез речи", + "ttsTip": "Распознавание речи (требуется доступ к интернету)", + "uploadTip": "Нажмите или перетащите файл в эту область для загрузки", + "words": { + "DIYAvatar": "Настроить аватар", + "DIYBackgroundEffect": "Настроить эффект фона", + "DIYColor": "Настроить цветовую гамму", + "DIYNickname": "Настроить никнейм", + "DIYTopicColor": "строить цвет темы", + "avatar": "Аватар", + "backgroundEffect": "Эффект фона", + "chatSetting": "Настройки чата", + "clearAllSession": "Очистить все сессии", + "clearAllSessionDesc": "Это очистит все данные сессий и ролей, включая список сессий, список ролей и сообщения сессий.", + "midColor": "Средний цвет", + "nickname": "Никнейм", + "resetSystemSetting": "Сбросить системные настройки", + "resetSystemSettingDesc": "Это сбросит все системные настройки, включая настройки темы, настройки чата, настройки языковой модели и т. д.", + "systemSetting": "Системные настройки", + "languageSetting": "Настройки языка", + "topicColor": "Цвет темы", + "topicSetting": "Настройки темы" + } +} diff --git a/locales/ru-RU/constants.json b/locales/ru-RU/constants.json new file mode 100644 index 00000000..756d1ffc --- /dev/null +++ b/locales/ru-RU/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Женщина", + "male": "Мужчина", + "other": "Другой" + }, + "meta": { + "description": "Это пользовательский персонаж", + "name": "Пользовательский персонаж" + } + }, + "touch": { + "area": { + "arm": "Рука", + "belly": "Живот", + "chest": "Грудь", + "head": "Голова", + "leg": "Нога" + }, + "emotion": { + "angry": "Злой", + "blink": "Моргание", + "blinkLeft": "Моргание (левый глаз)", + "blinkRight": "Моргание (правый глаз)", + "happy": "Счастливая", + "natural": "Естественная", + "relaxed": "Расслабленный", + "sad": "Грустный", + "surprised": "Удивлённый" + }, + "femaleAction": { + "armAction": { + "happyA": "О, как мне это нравится~", + "happyB": "Ха-ха, держать за руку делает меня счастливой~", + "relaxedA": "Руки хозяина такие теплые~" + }, + "bellyAction": { + "angryA": "Чего ты дергаешь, берегись, что я не укушу!", + "relaxedA": "Просыпайся, у нас нет будущего!", + "relaxedB": "Прекрати! Я могу рассердиться!", + "surprisedA": "Это случайное прикосновение, верно..." + }, + "chestAction": { + "angryA": "Нельзя меня так дразнить! Убери руку!", + "angryB": "Что тут у тебя? Тут какой-то извращенец постоянно меня трогает!", + "angryC": "Если ты меня тронешь, я позвоню в полицию", + "surprisedA": "Зачем ты меня тыкаешь? Мы ещё не успели хорошо поболтать!" + }, + "headAction": { + "angryA": "Говорят, что ласкание по голове мешает росту!", + "angryB": "Зачем ты меня тыкаешь?", + "happyA": "Ух ты! Обожаю ласкать по голове!", + "happyB": "Чувствую, как вновь наполняюсь силой!", + "happyC": "Ого, это прикосновение к голове такое удивительное!", + "happyD": "Ласкание по голове делает меня счастливой целый день!" + }, + "legAction": { + "angryA": "Эй, ты что, собираешься погибнуть?", + "angryB": "Рука хозяина снова не подчиняется командам?", + "angryC": "Прекрати! Это будет воспринято как зуд!", + "surprisedA": "Давай оставим наше дружбу чистой, хорошо?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Не спрашивай, я сегодня ел курицу или нет, сначала посмотри на мои бицепсы", + "neutralB": "Мою руку не трогают просто так, ты исключение", + "neutralC": "Ты очень смелый, ведь затронул легендарное бицепс" + }, + "bellyAction": { + "happyA": "Не щекочи меня, остерегайся, что я не расхохочусь", + "neutralA": "Мои мышцы живота - это сила, скрытая во время тренировки", + "neutralB": "Ты видел мои мышцы живота? Они просто скрыты глубоко" + }, + "chestAction": { + "blinkLeftA": "Подойди, мой грудной мускул для тебя!", + "neutralA": "Это результат моей ежедневной тренировки. Нет ничего удивительного." + }, + "headAction": { + "neutralA": "Конечно, только ты имеешь право трогать мою голову", + "neutralB": "Я не тот, кого можно трогать обычным людям", + "neutralC": "Не волнуйся, после того, как ты погладишь мою голову, твоя удача значительно увеличится" + }, + "legAction": { + "angryA": "Не подходи ко мне, ты, фетишист ног!", + "neutralA": "Не бойся, моя сильная нога не будет пинать дурака", + "neutralB": "Посмотрел на мою ногу, и ты чувствуешь, что твоя жизнь стала лучше?" + } + } + } +} diff --git a/locales/ru-RU/error.json b/locales/ru-RU/error.json new file mode 100644 index 00000000..69b0e0ad --- /dev/null +++ b/locales/ru-RU/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "Отсутствует ключ OpenAI API. Пожалуйста, добавьте ваш собственный ключ OpenAI API.", + "error": "Ошибка", + "errorTip": { + "clearSession": "", + "description": "Проект в настоящее время находится в стадии разработки и не гарантируется стабильность данных. Если возникли проблемы, попробуйте", + "forgive": "", + "or": "или", + "problem": "Страница столкнулась с некоторой проблемой...", + "resetSystem": "" + }, + "goBack": "Вернуться на главную страницу", + "openaiError": "Ошибка OpenAI API. Проверьте правильность вашего ключа OpenAI API и конечной точки.", + "reload": "Перезагрузить", + "s3envError": "", + "serverError": "Серверная ошибка. Свяжитесь с администратором.", + "triggerError": "", + "unknownError": "" +} diff --git a/locales/ru-RU/features.json b/locales/ru-RU/features.json new file mode 100644 index 00000000..d5709414 --- /dev/null +++ b/locales/ru-RU/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Изменить режим видео" + }, + "agent": { + "female": "Женщина", + "male": "Мужчина", + "other": "Другое" + }, + "feature": { + "addProxy": "Добавить адрес прокси OpenAI (необязательно)", + "closeTip": "Закрыть подсказку", + "comfirmRetry": "Подтвердить и повторить", + "startDesc": "Введите свой ключ API OpenAI, чтобы начать сеанс. Приложение не будет сохранять ваш ключ API", + "startTitle": "Настроить ключ API" + }, + "mode": { + "chat": "Чат", + "video": "Видео" + }, + "settings": { + "glow": "Сияние", + "nickName": "Введите никнейм", + "none": "Без фона" + }, + "share": { + "downloadScreenshot": "Скачать скриншот", + "imageType": "Тип изображения", + "screenshot": "Скриншот", + "share": "Поделиться", + "shareGPT": "Поделиться GPT", + "shareToGPT": "Создать ссылку для поделиться ShareGPT", + "shareToMarket": "Поделиться в маркетплейсе ассистентов", + "withBackground": "Включить фоновое изображение", + "withFooter": "Включить нижний колонтитул", + "withSystemRole": "Включить роль ассистента" + }, + "submit": { + "assistantId": "Идентификатор ассистента", + "assistantIdTip": "Введите уникальный идентификатор ассистента, например, vidol-agent-klee", + "submitAssistant": "Отправить ассистента", + "submitWarning": "Пожалуйста, заполните информацию об ассистенте перед отправкой. Необходимо указать имя, описание, аватар и обложку" + }, + "support": "Поддержка сообщества", + "theme": { + "auto": "Следовать системе", + "dark": "Темная тема", + "light": "Светлая тема" + }, + "token": { + "overload": "Превышение лимита токенов", + "remained": "Осталось токенов", + "tokenCount": "Количество токенов", + "useToken": "Расчет количества использованных токенов, включая сообщения, настройки ролей и контекст: {{usedTokens}} / {{maxValue}}", + "used": "Использовано токенов" + }, + "toolBar": { + "cameraControl": "Управление камерой", + "cameraHelper": "Помощник камеры", + "downloadModel": "Загрузка модели, пожалуйста, подождите...", + "floor": "Переключить пол", + "grid": "Сетка", + "resetCamera": "Сбросить камеру" + } +} diff --git a/locales/ru-RU/layout.json b/locales/ru-RU/layout.json new file mode 100644 index 00000000..ac099303 --- /dev/null +++ b/locales/ru-RU/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Диалог", + "header": { + "chat": "Чат", + "market": "Открыть", + "role": "Роль", + "settings": "Настройки", + "tips": "В настоящее время проект находится в процессе строительства, стабильность данных не гарантируется. Если возникнут проблемы, вы можете очистить сообщения сеанса и сбросить настройки системы в разделе «Настройки системы». Приносим извинения за неудобства." + }, + "sessionList": "Список сессий", + "siderBar": "Боковая панель" +} diff --git a/locales/ru-RU/my.json b/locales/ru-RU/my.json new file mode 100644 index 00000000..9416f710 --- /dev/null +++ b/locales/ru-RU/my.json @@ -0,0 +1,5 @@ +{ + "my": "мой", + "myDance": "мой танец", + "myRole": "моя роль" +} diff --git a/locales/ru-RU/panel.json b/locales/ru-RU/panel.json new file mode 100644 index 00000000..4c62ddb2 --- /dev/null +++ b/locales/ru-RU/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "добавить в список", + "addPlaySuccess": "добавлено в список воспроизведения", + "cancelAddPlay": "Вы уверены, что хотите отменить подписку на музыку {{musicName}}?", + "cancelSubscribed": "отменить подписку", + "findDance": "найдите свой любимый танец", + "musicAndDance": "музыка и танец", + "play": "воспроизвести" + }, + "info": { + "avatarDescription": "настройте свой аватар, нажмите на аватар, чтобы загрузить свой собственный", + "avatarLabel": "аватар", + "coverDescription": "используется для отображения персонажа на странице обнаружения, рекомендуемый размер {{width}} x {{height}} ", + "coverLabel": "обложка", + "descDescription": "описание персонажа, используется для краткого описания персонажа", + "descLabel": "описание", + "emotionDescription": "выберите эмоцию, которая будет отображаться при ответе персонажа", + "emotionLabel": "эмоции", + "genderDescription": "пол персонажа, влияет на его реакцию на касание", + "genderLabel": "пол", + "greetDescription": "приветствие при первом общении с персонажем", + "greetLabel": "приветствие", + "modelDescription": "предварительный просмотр модели, вы можете перетаскивать файл модели, чтобы заменить его", + "modelLabel": "предварительный просмотр модели", + "nameDescription": "имя персонажа, которое будет использоваться при общении с персонажем", + "nameLabel": "имя", + "readmeDescription": "инструкция по персонажу, используется для подробного описания персонажа на странице обнаружения", + "readmeLabel": "инструкция по персонажу", + "textDescription": "настройте ответный текст", + "textLabel": "текст", + "categoryLabel": "категория", + "categoryDescription": "категория персонажа, используется для классификации" + }, + "market": { + "findVidol": "найдите своего любимого идола" + }, + "nav": { + "info": "основная информация", + "model": "3D-модель", + "role": "настройка персонажа", + "voice": "голос" + }, + "role": { + "greetTip": "введите приветствие персонажа", + "inputRoleSetting": "введите системные настройки персонажа", + "roleDescriptionTip": "введите описание персонажа", + "roleNameTip": "введите имя персонажа", + "roleReadmeTip": "введите инструкцию по персонажу", + "roleSettingDescription": "фоновые настройки персонажа, которые будут отправлены модели при общении с персонажем", + "roleSettingLabel": "системные настройки персонажа", + "uploadSize": "поддерживается загрузка одного файла, рекомендуемый размер {{width}} x {{height}} " + }, + "touch": { + "addAction": "добавить действие", + "editAction": "редактировать действие", + "inputActionEmotion": "введите эмоцию персонажа при ответе", + "inputActionText": "введите текст ответа", + "inputDIYText": "введите свой текст", + "touchActionList": "список реакций на касание {{touchArea}}", + "touchArea": "область касания" + }, + "tts": { + "audition": "прослушать", + "auditionDescription": "прослушайте текст, в зависимости от языка", + "engineDescription": "система синтеза речи, рекомендуется использовать браузер Edge", + "engineLabel": "голосовой движок", + "localeDescription": "язык синтеза речи, поддерживаются только несколько наиболее распространенных языков, свяжитесь с нами, если вам нужен другой язык", + "localeLabel": "язык", + "pitchDescription": "контролирует высоту тона, диапазон значений 0 ~ 2, по умолчанию 1", + "pitchLabel": "высота тона", + "selectLanguage": "выберите язык", + "selectVoice": "выберите голос", + "speedDescription": "контролирует скорость речи, диапазон значений 0 ~ 3, по умолчанию 1", + "speedLabel": "скорость речи", + "transfromSuccess": "преобразование успешно", + "voiceDescription": "выберите голос в зависимости от движка и языка", + "voiceLabel": "голос" + }, + "upload": { + "support": "поддерживается загрузка одного файла, текущий формат файла - vrm" + } +} diff --git a/locales/ru-RU/role.json b/locales/ru-RU/role.json new file mode 100644 index 00000000..38f786f4 --- /dev/null +++ b/locales/ru-RU/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Удалить роль", + "delRoleDesc": "Вы уверены, что хотите удалить роль {{name}} и связанные с ней сообщения в сеансе? После удаления восстановление будет невозможно, поэтому будьте осторожны!", + "header": { + "role": "Роль", + "session": "Сеанс" + }, + "noRole": "Нет доступных ролей. Вы можете создать пользовательскую роль, используя символ '+', или добавить роль через страницу обнаружения.", + "roleList": "Список ролей", + "topBannerTitle": "Просмотр и настройка ролей" +} diff --git a/locales/ru-RU/welcome.json b/locales/ru-RU/welcome.json new file mode 100644 index 00000000..2d46222e --- /dev/null +++ b/locales/ru-RU/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} - это стандартный персонаж Vidol, твой личный помощник", + "greeting": "Привет, дорогой пользователь! Я твой персональный помощник {{name}} и с удовольствием готов тебе помочь! Чем я могу быть полезен?", + "hello": "Привет", + "meta": { + "description": "Это пользовательский персонаж", + "name": "Пользовательский персонаж" + } + }, + "greet": "Привет, я {{name}}, чем могу тебе помочь?", + "loadingTitle": "Подождите, идёт инициализация приложения...", + "waitting": "Я готовлю свой весь мир для вас" +} diff --git a/locales/tr-TR/chat.json b/locales/tr-TR/chat.json new file mode 100644 index 00000000..6b7d58ac --- /dev/null +++ b/locales/tr-TR/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "sohbet", + "chatDialog": { + "close": "kapat" + }, + "dance": "dans", + "header": { + "role": "rol", + "session": "oturum" + }, + "helloChat": "Merhaba, sohbet edelim", + "helloDance": "Merhaba, birlikte dans edelim", + "market": "keşfet" +} diff --git a/locales/tr-TR/common.json b/locales/tr-TR/common.json new file mode 100644 index 00000000..aeedf526 --- /dev/null +++ b/locales/tr-TR/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Ekle", + "clearAll": "Hepsini Temizle", + "clearContext": "Bağlamı Temizle", + "clearHistoryTip": "Bu işlem geri alınamaz, lütfen dikkatli olun", + "clearHistoryTitle": "Geçmiş mesajları silmek istediğinize emin misiniz?", + "clearNow": "Hemen Temizle", + "clearSuccess": "Temizleme başarılı", + "clearTip": "İşlem geri alınamaz, veriler temizlendikten sonra geri getirilemez, lütfen dikkatli olun", + "clearTitle": "Tüm oturum mesajlarını silmek istediğinize emin misiniz?", + "confirmDel": "Silmek istediğinize emin misiniz?", + "copy": "Kopyala", + "copySuccess": "Kopyalama başarılı", + "del": "Sil", + "delAndRegenerate": "Sil ve Yeniden Oluştur", + "downloadAvatar": "Avatar İndir", + "downloadCover": "Kapak İndir", + "downloadFailed": "İndirme başarısız", + "downloadModel": "Model İndir", + "downloadSubscribe": "Abonelik İndir", + "downloadSuccess": "İndirme başarılı", + "edit": "Düzenle", + "goBottom": "Alt kısma git", + "market": "Keşfet", + "pause": "Duraklat", + "play": "Oynat", + "regenerate": "Yeniden Oluştur", + "removeInList": "Listeden Kaldır", + "reset": "Sıfırla", + "resetNow": "Hemen Sıfırla", + "resetSuccess": "Sıfırlama başarılı", + "resetTip": "İşlem geri alınamaz, veriler sıfırlandıktan sonra geri getirilemez, lütfen dikkatli olun", + "resetTitle": "Tüm sistem ayarlarını sıfırlamak istediğinize emin misiniz?", + "save": "Kaydet", + "send": "Gönder", + "share": "Paylaş", + "subscribe": "Abone Ol", + "subscribeDance": "Dansı Abone Ol", + "subscribeRole": "Rolü Abone Ol", + "subscribed": "Abone", + "unsubscribe": "Aboneliği İptal Et", + "unsubscribeSuccess": "Abonelik başarıyla iptal edildi", + "warp": "Satır atla" + }, + "aiAlert": "Lütfen unutmayın: Yapay Zeka tarafından üretilen her şey AI tarafından üretilmiştir", + "cancel": "İptal", + "commonSetting": "Genel Ayarlar", + "confirm": "Onayla", + "defaultAssistant": "Varsayılan Asistan", + "delAlert": "Rolü ve ilgili oturum mesajlarını silmeyi onaylıyor musunuz? Silindikten sonra geri alınamaz, lütfen dikkatli olun!", + "delRole": "Rolü Sil", + "delSession": "Oturumu Sil", + "delSessionAlert": "Sohbeti silmeyi onaylıyor musunuz? Silindikten sonra geri alınamaz, lütfen dikkatli olun!", + "inputStartChat": "Sohbete başlamak için içerik girin", + "languageModel": "Dil Modeli", + "loading": "Yükleniyor...", + "noData": "Veri bulunamadı", + "openai": { + "callError": "API Anahtarınızı ve arayüz proxy adresinizi doğru şekilde ayarladığınızdan emin olun", + "check": "Kontrol Et", + "checkAll": "API Anahtarınızı ve arayüz proxy adresinizi kontrol edin", + "checkConnect": "Bağlantıyı Kontrol Et", + "checkOk": "Kontrol başarılı", + "langModel": "OpenAI Dil Modeli", + "model": "Model", + "proxyUrl": "Arayüz Proxy Adresi", + "roleModel": "Rol GPT Modeli", + "useOwnKey": "Kendi OpenAI Anahtarınızı kullanın" + }, + "playlist": "Oynatma Listesi", + "search": "Ara", + "selectInDanceList": "Dans listesinden seçiniz", + "selectModel": "Model seçin", + "setLocalStorage": "Yerel Depolamayı Ayarla", + "startChat": "Sohbete Başla", + "ttsCombine": "Konuşma Sentezi", + "ttsTip": "Konuşma Tanıma (VPN gerektirir)", + "uploadTip": "Dosyayı buraya yüklemek için tıklayın veya sürükleyin", + "words": { + "DIYAvatar": "Özel Avatar", + "DIYBackgroundEffect": "Özel Arka Plan Efekti", + "DIYColor": "Farklı renk tonlarına eğilimli gri tonları özelleştirme", + "DIYNickname": "Özel Takma Ad", + "DIYTopicColor": "Özel Konu Rengi", + "avatar": "Avatar", + "backgroundEffect": "Arka Plan Efekti", + "chatSetting": "Sohbet Ayarları", + "clearAllSession": "Tüm Oturumları Temizle", + "clearAllSessionDesc": "Tüm oturumları ve rol verilerini, oturum listelerini, rol listelerini, oturum mesajlarını vb. temizleyecektir", + "midColor": "Orta Renk", + "nickname": "Takma Ad", + "resetSystemSetting": "Sistem Ayarlarını Sıfırla", + "resetSystemSettingDesc": "Tüm sistem ayarlarını, konu ayarlarını, sohbet ayarlarını, dil modeli ayarlarını vb. sıfırlayacaktır", + "systemSetting": "Sistem Ayarları", + "languageSetting": "Dil Ayarları", + "topicColor": "Konu Rengi", + "topicSetting": "Konu Ayarları" + } +} diff --git a/locales/tr-TR/constants.json b/locales/tr-TR/constants.json new file mode 100644 index 00000000..a3b9c1a5 --- /dev/null +++ b/locales/tr-TR/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Kadın", + "male": "Erkek", + "other": "Diğer" + }, + "meta": { + "description": "Bu bir özel rol.", + "name": "Özel Rol" + } + }, + "touch": { + "area": { + "arm": "Kol", + "belly": "Karın", + "chest": "Göğüs", + "head": "Baş", + "leg": "Bacak" + }, + "emotion": { + "angry": "Kızgın", + "blink": "Göz kırpması", + "blinkLeft": "Sol göz kırpması", + "blinkRight": "Sağ göz kırpması", + "happy": "Mutlu", + "natural": "Doğal", + "relaxed": "Rahat", + "sad": "Üzgün", + "surprised": "Şaşırmış" + }, + "femaleAction": { + "armAction": { + "happyA": "Ah, bunu gerçekten seviyorum~", + "happyB": "Haha, el ele tutuşmak beni mutlu ediyor~", + "relaxedA": "Sahibimin elleri çok sıcak~" + }, + "bellyAction": { + "angryA": "Niye beni rahatsız ediyorsun, seni ısırırım!", + "relaxedA": "Uyan, aramızda bir şey olmayacak!", + "relaxedB": "Nefret ediyorum! Sinirleniyorum!", + "surprisedA": "Kazara dokundun değil mi..." + }, + "chestAction": { + "angryA": "Beni böyle taciz etme! Hemen elini çek!", + "angryB": "911 mi? Burada bir sapık sürekli beni okşuyor!", + "angryC": "Bir daha dokunursan polisi arayacağım!", + "surprisedA": "Niye beni dürtüyorsun? Hala keyifli bir şekilde sohbet edebilecek miyiz?" + }, + "headAction": { + "angryA": "Başını okşamanın boyunu uzatmayacağını duydum!", + "angryB": "Niye beni dürtüyorsun?", + "happyA": "Vay! Başımı okşamayı en çok seviyorum!", + "happyB": "Güç dolu hissettiriyor!", + "happyC": "Vay be, başımı okşamanın hissi çok garip!", + "happyD": "Başımı okşamak beni bütün gün mutlu ediyor!" + }, + "legAction": { + "angryA": "Hey, intihar mı etmek istiyorsun?", + "angryB": "Sahibimin elleri artık komutları dinlemiyor mu?", + "angryC": "İğnelenecek, kaşınacak!", + "surprisedA": "Neden saf dostluğumuzu koruyamıyoruz?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Bugün tavuk yedin mi diye sorma, önce bicepsime bak.", + "neutralB": "Kolumu herkesin dokunmasına izin vermiyorum, sen istisnasın.", + "neutralC": "Çok cesursun, efsanevi kollarıma dokunmaya cesaret ediyorsun." + }, + "bellyAction": { + "happyA": "Kaşınmamaya çalış, gülerken karın kaslarımı ortaya çıkarabilirsin.", + "neutralA": "Karın kaslarım sadece gizli iç gücümü geliştirmek için antrenman yapıyor.", + "neutralB": "Bu yumru karın kaslarımı gördün mü? Sadece derinlerde saklanıyorlar." + }, + "chestAction": { + "blinkLeftA": "Gel, abinin göğüs kaslarına dayan!", + "neutralA": "Bu sadece günlük egzersizlerimle geliştirdiğim göğüs kaslarım, şaşılacak bir şey yok." + }, + "headAction": { + "neutralA": "Tabii ki, sadece senin başımı okşama yetkisi var.", + "neutralB": "Ben sıradan insanların dokunmasına izin veren biri değilim.", + "neutralC": "Endişelenme, başımı okşadıktan sonra şansın büyük ölçüde artacak." + }, + "legAction": { + "angryA": "Bana yaklaşma, bacak sapığı.", + "neutralA": "Korkma, güçlü bacaklarım aptallara tekme atmaz.", + "neutralB": "Bacaklarıma dokunmak senin hayatını daha mı anlamlı hale getirdi?" + } + } + } +} diff --git a/locales/tr-TR/error.json b/locales/tr-TR/error.json new file mode 100644 index 00000000..ab4a0add --- /dev/null +++ b/locales/tr-TR/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key boş, lütfen özel OpenAI API Key ekleyin", + "error": "Hata", + "errorTip": { + "clearSession": "Oturum mesajlarını temizle", + "description": "Proje şu anda yapım aşamasında olduğundan veri stabilitesi garanti edilemez, sorun yaşarsanız deneyebilirsiniz", + "forgive": "rağmen rahatsızlık için özür dileriz", + "or": "veya", + "problem": "Sayfa bir sorunla karşılaştı...", + "resetSystem": "Sistemi sıfırla" + }, + "goBack": "Ana sayfaya dön", + "openaiError": "OpenAI API hatası, lütfen OpenAI API Key ve Endpoint'i doğru şekilde kontrol edin", + "reload": "Yeniden yükle", + "s3envError": "S3 ortam değişkeni tam olarak ayarlanmadı, lütfen ortam değişkenlerinizi kontrol edin", + "serverError": "Sunucu hatası, lütfen yöneticiyle iletişime geçin", + "triggerError": "Hata tetiklendi", + "unknownError": "Bilinmeyen hata" +} diff --git a/locales/tr-TR/features.json b/locales/tr-TR/features.json new file mode 100644 index 00000000..7074cf59 --- /dev/null +++ b/locales/tr-TR/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Video Modunu Değiştir" + }, + "agent": { + "female": "Kadın", + "male": "Erkek", + "other": "Diğer" + }, + "feature": { + "addProxy": "OpenAI Proxy Adresi Ekle (isteğe bağlı)", + "closeTip": "İpucunu Kapat", + "comfirmRetry": "Onayla ve Yeniden Dene", + "startDesc": "Sohbete başlamak için OpenAI API Anahtarınızı girin. Uygulama API Anahtarınızı kaydetmez.", + "startTitle": "Özel API Anahtarı" + }, + "mode": { + "chat": "Sohbet", + "video": "Video" + }, + "settings": { + "glow": "Parıltı", + "nickName": "Lütfen Takma Adınızı Girin", + "none": "Arka Plan Yok" + }, + "share": { + "downloadScreenshot": "Ekran Görüntüsünü İndir", + "imageType": "Resim Formatı", + "screenshot": "Ekran Görüntüsü", + "share": "Paylaş", + "shareGPT": "GPT'yi Paylaş", + "shareToGPT": "Paylaşım Bağlantısı Oluştur", + "shareToMarket": "Asistan Pazarına Paylaş", + "withBackground": "Arka Plan Resmi İçerir", + "withFooter": "Altbilgi İçerir", + "withSystemRole": "Sistem Rolünü İçerir" + }, + "submit": { + "assistantId": "Asistan Kimliği", + "assistantIdTip": "Lütfen asistanın kimliğini girin. Benzersiz olmalıdır, örneğin vidol-agent-klee.", + "submitAssistant": "Asistanı Gönder", + "submitWarning": "Lütfen asistan bilgilerini tamamlayın. İsim, açıklama, avatar ve kapak resmi gereklidir." + }, + "support": "Topluluk Destek", + "theme": { + "auto": "Sistemle Eşle", + "dark": "Karanlık Mod", + "light": "Açık Mod" + }, + "token": { + "overload": "Token Aşımı", + "remained": "Kalan Token", + "tokenCount": "Token Sayısı", + "useToken": "Token Sayısı Hesaplaması, Mesajlar, Rol Ayarları ve Bağlamı İçerir: {{usedTokens}} / {{maxValue}}", + "used": "Kullanılan Token" + }, + "toolBar": { + "cameraControl": "Kamera Kontrolü", + "cameraHelper": "Kamera Yardımcısı", + "downloadModel": "Model İndiriliyor, Lütfen Bekleyin...", + "floor": "Zemin Değiştir", + "grid": "Izgara", + "resetCamera": "Kamerayı Sıfırla" + } +} diff --git a/locales/tr-TR/layout.json b/locales/tr-TR/layout.json new file mode 100644 index 00000000..277e31cf --- /dev/null +++ b/locales/tr-TR/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Dialog kutusu", + "header": { + "chat": "Sohbet", + "market": "Keşfet", + "role": "Rol", + "settings": "Ayarlar", + "tips": "Proje şu anda inşa halinde, veri stabilitesi garanti edilmemektedir. Sorun yaşarsanız, oturum sohbetini temizleyebilir ve sistem ayarlarını sıfırlayabilirsiniz. Oluşabilecek rahatsızlıktan dolayı özür dileriz." + }, + "sessionList": "Oturum Listesi", + "siderBar": "İkincil Menü" +} diff --git a/locales/tr-TR/my.json b/locales/tr-TR/my.json new file mode 100644 index 00000000..daa802bc --- /dev/null +++ b/locales/tr-TR/my.json @@ -0,0 +1,5 @@ +{ + "my": "Benim", + "myDance": "Dansım", + "myRole": "Rolüm" +} diff --git a/locales/tr-TR/panel.json b/locales/tr-TR/panel.json new file mode 100644 index 00000000..15bafc0c --- /dev/null +++ b/locales/tr-TR/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Listeye Ekle", + "addPlaySuccess": "Oynatma listesine eklendi", + "cancelAddPlay": "{{musicName}} müziğini abonelikten çıkarmak istediğinize emin misiniz?", + "cancelSubscribed": "Aboneliği iptal et", + "findDance": "Favori dansını bul", + "musicAndDance": "Müzik ve Dans", + "play": "Oynat" + }, + "info": { + "avatarDescription": "Özel avatar, avatar'a tıklayarak özelleştirme yapın", + "avatarLabel": "Avatar", + "coverDescription": "Keşfetme sayfasında karakterin gösterilmesi için önerilen boyut {{width}} x {{height}} ", + "coverLabel": "Kapak", + "descDescription": "Karakter açıklaması, karakterin basit tanıtımı için kullanılır", + "descLabel": "Açıklama", + "emotionDescription": "Tepki verirken kullanılan duygu, karakterin ifadesini etkiler", + "emotionLabel": "Duygu ve Hareket", + "genderDescription": "Karakter cinsiyeti, karakterin dokunmatik tepkisini etkiler", + "genderLabel": "Cinsiyet", + "greetDescription": "Karakterle ilk konuşma sırasında kullanılan bir selam", + "greetLabel": "Merhaba", + "modelDescription": "Model önizleme, model dosyasını sürükleyerek değiştirin", + "modelLabel": "Model Önizleme", + "nameDescription": "Karakter adı, karakterle konuşurken kullanılan hitap", + "nameLabel": "İsim", + "readmeDescription": "Karakterin ayrıntılı açıklamasını keşfetme sayfasında göster", + "readmeLabel": "Karakter Açıklaması", + "textDescription": "Özel yanıt metni", + "textLabel": "Metin", + "categoryLabel": "Kategori", + "categoryDescription": "Karakter kategorisi, sınıflandırmada kullanılır" + }, + "market": { + "findVidol": "Favori idolünü bul" + }, + "nav": { + "info": "Temel Bilgiler", + "model": "3D Model", + "role": "Karakter Ayarları", + "voice": "Ses" + }, + "role": { + "greetTip": "Karakterle iletişim kurarken kullanılan selamı girin", + "inputRoleSetting": "Karakterin sistem ayarlarını girin", + "roleDescriptionTip": "Karakter açıklamasını girin", + "roleNameTip": "Karakter adını girin", + "roleReadmeTip": "Karakter açıklamasını girin", + "roleSettingDescription": "Karakterin arka plan ayarları, karakterle konuşurken modelle paylaşılır", + "roleSettingLabel": "Karakter Sistem Ayarları", + "uploadSize": "Tek dosya yükleme desteği, önerilen boyut {{width}} x {{height}} 'in katları" + }, + "touch": { + "addAction": "Tepki eylemi ekle", + "editAction": "Tepki eylemini düzenle", + "inputActionEmotion": "Karakter tepki verirken kullanılan duygu", + "inputActionText": "Tepki metnini girin", + "inputDIYText": "Özel metin girin", + "touchActionList": "{{touchArea}} dokunduğunda tepki listesi", + "touchArea": "Dokunma Alanı" + }, + "tts": { + "audition": "Audiyon", + "auditionDescription": "Dil farklı olduğunda audiyo", + "engineDescription": "Konuşma sentezi motoru, öncelikle Edge tarayıcısını seçmeniz önerilir", + "engineLabel": "Ses Motoru", + "localeDescription": "Konuşma sentezi dil seçeneği, şu anda yalnızca yaygın bazı diller desteklenmektedir, ihtiyacınız varsa lütfen bize ulaşın", + "localeLabel": "Dil", + "pitchDescription": "Tonu kontrol eder, değer aralığı 0 ~ 2, varsayılan 1", + "pitchLabel": "Ton", + "selectLanguage": "Lütfen önce dil seçin", + "selectVoice": "Lütfen önce ses seçin", + "speedDescription": "Hızı kontrol eder, değer aralığı 0 ~ 3, varsayılan 1", + "speedLabel": "Hız", + "transfromSuccess": "Dönüşüm başarılı", + "voiceDescription": "Motor ve dilin birleşimine göre değişir", + "voiceLabel": "Ses" + }, + "upload": { + "support": "Tek dosya yükleme desteği, şu anda yalnızca vrm formatı desteklenmektedir" + } +} diff --git a/locales/tr-TR/role.json b/locales/tr-TR/role.json new file mode 100644 index 00000000..e409521d --- /dev/null +++ b/locales/tr-TR/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Rolü Sil", + "delRoleDesc": " {{name}} adlı rolü ve ilgili oturum mesajlarını silmek istediğinizden emin misiniz? Silindikten sonra geri alınamaz, lütfen dikkatli olun!", + "header": { + "role": "Rol", + "session": "Oturum" + }, + "noRole": "Şu anda hiçbir rol yok, özel rol oluşturabilirsiniz veya keşfetme sayfasından rol ekleyebilirsiniz", + "roleList": "Rol Listesi", + "topBannerTitle": "{{name}} Önizleme ve Ayarları" +} diff --git a/locales/tr-TR/welcome.json b/locales/tr-TR/welcome.json new file mode 100644 index 00000000..b42e1109 --- /dev/null +++ b/locales/tr-TR/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} Vidol'un varsayılan karakteridir ve size özel bir kişisel asistandır", + "greeting": "Merhaba, sevgili sahibim! Ben senin kişisel asistanın {{name}} ve hizmet için buradayım! Size nasıl yardımcı olabilirim?", + "hello": "Merhaba", + "meta": { + "description": "Bu bir özel karakterdir", + "name": "Özel karakter" + } + }, + "greet": "Merhaba, ben {{name}}. Size nasıl yardımcı olabilirim?", + "loadingTitle": "Uygulama başlatılıyor, lütfen bekleyin...", + "waitting": "Benim dünyamı hazırlamak için çalışıyor" +} diff --git a/locales/vi-VN/chat.json b/locales/vi-VN/chat.json new file mode 100644 index 00000000..f37db67e --- /dev/null +++ b/locales/vi-VN/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "聊天", + "chatDialog": { + "close": "关闭" + }, + "dance": "跳舞", + "header": { + "role": "角色", + "session": "对话" + }, + "helloChat": "你好,让我们来聊天吧", + "helloDance": "嗨,让我们一起跳舞吧", + "market": "发现" +} diff --git a/locales/vi-VN/common.json b/locales/vi-VN/common.json new file mode 100644 index 00000000..a61a4c0d --- /dev/null +++ b/locales/vi-VN/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "Thêm", + "clearAll": "Xóa tất cả", + "clearContext": "Xóa ngữ cảnh", + "clearHistoryTip": "Hành động này không thể hoàn tác, vui lòng cân nhắc", + "clearHistoryTitle": "Xác nhận xóa lịch sử tin nhắn?", + "clearNow": "Xóa ngay", + "clearSuccess": "Xóa thành công", + "clearTip": "Hành động không thể hoàn tác, dữ liệu sẽ không thể khôi phục sau khi xóa, vui lòng cân nhắc", + "clearTitle": "Xác nhận xóa tất cả tin nhắn phiên?", + "confirmDel": "Xác nhận xóa?", + "copy": "Sao chép", + "copySuccess": "Sao chép thành công", + "del": "Xóa", + "delAndRegenerate": "Xóa và tạo lại", + "downloadAvatar": "Tải xuống hình đại diện", + "downloadCover": "Tải xuống bìa", + "downloadFailed": "Tải xuống thất bại", + "downloadModel": "Tải xuống mô hình", + "downloadSubscribe": "Tải xuống đăng ký", + "downloadSuccess": "Tải xuống thành công", + "edit": "Chỉnh sửa", + "goBottom": "Quay về dưới cùng", + "market": "Khám phá", + "pause": "Tạm dừng", + "play": "Phát", + "regenerate": "Tạo lại", + "removeInList": "Xóa khỏi danh sách", + "reset": "Đặt lại", + "resetNow": "Đặt lại ngay", + "resetSuccess": "Đặt lại thành công", + "resetTip": "Hành động không thể hoàn tác, dữ liệu sẽ không thể khôi phục sau khi đặt lại, vui lòng cân nhắc", + "resetTitle": "Xác nhận đặt lại tất cả cài đặt hệ thống?", + "save": "Lưu", + "send": "Gửi", + "share": "Chia sẻ", + "subscribe": "Đăng ký", + "subscribeDance": "Đăng ký nhảy múa", + "subscribeRole": "Đăng ký vai trò", + "subscribed": "Đã đăng ký", + "unsubscribe": "Hủy đăng ký", + "unsubscribeSuccess": "Đã hủy đăng ký", + "warp": "Xuống dòng" + }, + "aiAlert": "Vui lòng nhớ: Tất cả những gì trí tuệ nhân tạo nói đều được tạo ra bởi AI", + "cancel": "Hủy", + "commonSetting": "Cài đặt chung", + "confirm": "Xác nhận", + "defaultAssistant": "Trợ lý mặc định", + "delAlert": "Xác nhận xóa vai trò và tin nhắn liên quan? Hành động này không thể hoàn tác, vui lòng cân nhắc!", + "delRole": "Xóa vai trò", + "delSession": "Xóa phiên", + "delSessionAlert": "Xác nhận xóa cuộc trò chuyện? Hành động này không thể hoàn tác, vui lòng cân nhắc!", + "inputStartChat": "Nhập nội dung để bắt đầu trò chuyện", + "languageModel": "Mô hình ngôn ngữ", + "loading": "Đang tải...", + "noData": "Không có dữ liệu", + "openai": { + "callError": "Gọi API thất bại, vui lòng kiểm tra API Key và địa chỉ proxy API đã được thiết lập đúng chưa", + "check": "Kiểm tra", + "checkAll": "Kiểm tra xem API Key và địa chỉ proxy API đã được thiết lập đúng chưa", + "checkConnect": "Kiểm tra kết nối", + "checkOk": "Kiểm tra qua", + "langModel": "Mô hình ngôn ngữ OpenAI", + "model": "Mô hình", + "proxyUrl": "Địa chỉ proxy API", + "roleModel": "Mô hình Role GPT", + "useOwnKey": "Vui lòng sử dụng API Key của riêng bạn" + }, + "playlist": "Danh sách phát", + "search": "Tìm kiếm", + "selectInDanceList": "Vui lòng chọn từ danh sách nhảy múa", + "selectModel": "Chọn mô hình", + "setLocalStorage": "Lưu cài đặt vào bộ nhớ cục bộ", + "startChat": "Bắt đầu trò chuyện", + "ttsCombine": "Tổng hợp giọng nói", + "ttsTip": "Nhận dạng giọng nói (cần kết nối internet)", + "uploadTip": "Nhấp hoặc kéo tệp vào khu vực này để tải lên", + "words": { + "DIYAvatar": "Tùy chỉnh hình đại diện", + "DIYBackgroundEffect": "Tùy chỉnh hiệu ứng nền", + "DIYColor": "Tùy chỉnh màu xám với xu hướng màu khác nhau", + "DIYNickname": "Tùy chỉnh biệt danh", + "DIYTopicColor": "Tùy chỉnh màu chủ đề", + "avatar": "Hình đại diện", + "backgroundEffect": "Hiệu ứng nền", + "chatSetting": "Cài đặt trò chuyện", + "clearAllSession": "Xóa tất cả phiên trò chuyện", + "clearAllSessionDesc": "Sẽ xóa tất cả dữ liệu phiên và vai trò, bao gồm danh sách phiên, danh sách vai trò, tin nhắn phiên, v.v.", + "midColor": "Màu trung tính", + "nickname": "Biệt danh", + "resetSystemSetting": "Đặt lại cài đặt hệ thống", + "resetSystemSettingDesc": "Sẽ đặt lại tất cả cài đặt hệ thống, bao gồm cài đặt chủ đề, cài đặt trò chuyện, cài đặt mô hình ngôn ngữ, v.v.", + "systemSetting": "Cài đặt hệ thống", + "languageSetting": "Cài đặt ngôn ngữ", + "topicColor": "Màu chủ đề", + "topicSetting": "Cài đặt chủ đề" + } +} diff --git a/locales/vi-VN/constants.json b/locales/vi-VN/constants.json new file mode 100644 index 00000000..82c33c58 --- /dev/null +++ b/locales/vi-VN/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "Nữ", + "male": "Nam", + "other": "Khác" + }, + "meta": { + "description": "Đây là một Vai trò Tùy chỉnh", + "name": "Tùy chỉnh Vai trò" + } + }, + "touch": { + "area": { + "arm": "Cánh tay", + "belly": "Bụng", + "chest": "Ngực", + "head": "Đầu", + "leg": "Chân" + }, + "emotion": { + "angry": "Tức giận", + "blink": "Nháy mắt", + "blinkLeft": "Nháy mắt trái", + "blinkRight": "Nháy mắt phải", + "happy": "Vui vẻ", + "natural": "Tự nhiên", + "relaxed": "Thư giãn", + "sad": "Buồn", + "surprised": "Ngạc nhiên" + }, + "femaleAction": { + "armAction": { + "happyA": "Ôi, thích quá~", + "happyB": "Ha ha, nắm tay khiến tôi cảm thấy vui vẻ~", + "relaxedA": "Bàn tay của chủ nhân ấm áp quá~" + }, + "bellyAction": { + "angryA": "Tại sao lại đụng vào tôi, cẩn thận tôi cắn đấy!", + "relaxedA": "Tỉnh ngộ đi, giữa chúng ta không có kết quả gì đâu!", + "relaxedB": "Không thích! Tôi sẽ tức giận đấy!", + "surprisedA": "Chắc là va phải tình cờ thôi..." + }, + "chestAction": { + "angryA": "Không được đụng vào tôi như vậy! Hãy rút tay ra!", + "angryB": "Một một không hai à? Có một kẻ kỳ quặc luôn vuốt tôi!", + "angryC": "Nếu còn vuốt nữa tôi sẽ báo công an đấy", + "surprisedA": "Tại sao lại chọc tôi vậy! Không thể tiếp tục trò chuyện vui vẻ à!" + }, + "headAction": { + "angryA": "Nghe nói bị vuốt đầu sẽ không cao lên được đâu!", + "angryB": "Tại sao lại chọc tôi vậy?", + "happyA": "Wow! Thích nhất là vuốt đầu!", + "happyB": "Cảm thấy mạnh mẽ hơn nữa!", + "happyC": "Wow, cảm giác vuốt đầu này thật kỳ diệu!", + "happyD": "Vuốt đầu khiến tôi vui suốt cả ngày!" + }, + "legAction": { + "angryA": "Này, cậu có định tự sát à?", + "angryB": "Tay của chủ nhân lại không nghe lời rồi à?", + "angryC": "Không thích~ sẽ ngứa đấy~!", + "surprisedA": "Hãy giữ cho mối quan hệ của chúng ta trong sạch sẽ, được không?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "Đừng hỏi tôi hôm nay đã ăn gà chưa, hãy nhìn vào cơ bắp cánh tay của tôi trước đã", + "neutralB": "Cánh tay của tôi không phải ai cũng được chạm vào, bạn là ngoại lệ", + "neutralC": "Bạn rất dũng cảm, dám chạm vào cánh tay huyền thoại của tôi" + }, + "bellyAction": { + "happyA": "Đừng gãi gãi, cẩn thận tôi sẽ cười vì cơ bụng", + "neutralA": "Cơ bụng của tôi chỉ là sức mạnh ẩn giấu sau quá trình rèn luyện", + "neutralB": "Bạn đã thấy cụm cơ bụng của tôi chưa? Chúng chỉ là ẩn sâu thôi" + }, + "chestAction": { + "blinkLeftA": "Đến đây, cơ ngực của anh để cho em dựa vào!", + "neutralA": "Đây chỉ là cơ ngực tôi rèn luyện hàng ngày, không có gì đáng ngạc nhiên cả." + }, + "headAction": { + "neutralA": "Tất nhiên rồi, chỉ có bạn mới có thể vuốt đầu tôi", + "neutralB": "Tôi không phải là người bình thường cho phép ai chạm vào đâu", + "neutralC": "Đừng lo, sau khi vuốt đầu tôi, may mắn của bạn sẽ tăng đáng kể" + }, + "legAction": { + "angryA": "Đừng lại gần tôi, cậu thích chân lắm à", + "neutralA": "Đừng sợ, chân sắt đá của tôi không đá người ngốc", + "neutralB": "Khiến bạn chạm vào chân tôi, có phải bạn cảm thấy cuộc sống của bạn trọn vẹn hơn không?" + } + } + } +} diff --git a/locales/vi-VN/error.json b/locales/vi-VN/error.json new file mode 100644 index 00000000..44d1e022 --- /dev/null +++ b/locales/vi-VN/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "Khóa API OpenAI trống, vui lòng thêm Khóa API OpenAI tùy chỉnh", + "error": "Lỗi", + "errorTip": { + "clearSession": "Xóa thông báo phiên", + "description": "Dự án hiện đang trong quá trình xây dựng, không đảm bảo tính ổn định của dữ liệu, nếu gặp vấn đề bạn có thể thử", + "forgive": ", xin lỗi vì sự bất tiện", + "or": "hoặc", + "problem": "Trang gặp một chút vấn đề...", + "resetSystem": "Đặt lại cài đặt hệ thống" + }, + "goBack": "Quay lại trang chủ", + "openaiError": "Lỗi API OpenAI, vui lòng kiểm tra Khóa API OpenAI và Điểm cuối có đúng không", + "reload": "Tải lại", + "s3envError": "Biến môi trường S3 chưa được thiết lập đầy đủ, vui lòng kiểm tra biến môi trường của bạn", + "serverError": "Lỗi máy chủ, vui lòng liên hệ quản trị viên", + "triggerError": "Kích hoạt lỗi", + "unknownError": "Lỗi không xác định" +} diff --git a/locales/vi-VN/features.json b/locales/vi-VN/features.json new file mode 100644 index 00000000..fede1e3d --- /dev/null +++ b/locales/vi-VN/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "Chuyển sang chế độ video" + }, + "agent": { + "female": "Nữ", + "male": "Nam", + "other": "Khác" + }, + "feature": { + "addProxy": "Thêm địa chỉ proxy OpenAI (tùy chọn)", + "closeTip": "Đóng gợi ý", + "comfirmRetry": "Xác nhận và thử lại", + "startDesc": "Nhập OpenAI API Key của bạn để bắt đầu cuộc trò chuyện. Ứng dụng sẽ không ghi lại API Key của bạn", + "startTitle": "Tùy chỉnh API Key" + }, + "mode": { + "chat": "Trò chuyện", + "video": "Video" + }, + "settings": { + "glow": "Ánh sáng", + "nickName": "Nhập biệt danh của bạn", + "none": "Không có nền" + }, + "share": { + "downloadScreenshot": "Tải xuống ảnh chụp màn hình", + "imageType": "Định dạng hình ảnh", + "screenshot": "Ảnh chụp màn hình", + "share": "Chia sẻ", + "shareGPT": "Chia sẻ GPT", + "shareToGPT": "Tạo liên kết chia sẻ GPT", + "shareToMarket": "Chia sẻ đến thị trường trợ lý", + "withBackground": "Bao gồm hình nền", + "withFooter": "Bao gồm chân trang", + "withSystemRole": "Bao gồm thiết lập vai trò trợ lý" + }, + "submit": { + "assistantId": "ID trợ lý", + "assistantIdTip": "Vui lòng nhập ID của trợ lý, cần phải là duy nhất, ví dụ: vidol-agent-klee", + "submitAssistant": "Gửi trợ lý", + "submitWarning": "Vui lòng điền đầy đủ thông tin trợ lý trước khi gửi, bao gồm tên, mô tả, hình đại diện và bìa" + }, + "support": "Hỗ trợ cộng đồng", + "theme": { + "auto": "Theo hệ thống", + "dark": "Chế độ tối", + "light": "Chế độ sáng" + }, + "token": { + "overload": "Token vượt quá", + "remained": "Token còn lại", + "tokenCount": "Số lượng Token", + "useToken": "Số lượng Token đã sử dụng, bao gồm tin nhắn, thiết lập vai trò và ngữ cảnh: {{usedTokens}} / {{maxValue}}", + "used": "Token đã sử dụng" + }, + "toolBar": { + "cameraControl": "Điều khiển camera", + "cameraHelper": "Trợ lý camera", + "downloadModel": "Đang tải xuống mô hình, vui lòng đợi...", + "floor": "Chuyển đổi sàn", + "grid": "Lưới", + "resetCamera": "Đặt lại camera" + } +} diff --git a/locales/vi-VN/layout.json b/locales/vi-VN/layout.json new file mode 100644 index 00000000..ba25b0c8 --- /dev/null +++ b/locales/vi-VN/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "Hộp thoại", + "header": { + "chat": "Trò chuyện", + "market": "Khám phá", + "role": "Vai trò", + "settings": "Cài đặt", + "tips": "Dự án hiện đang trong quá trình xây dựng, không đảm bảo tính ổn định của dữ liệu. Nếu gặp vấn đề, bạn có thể xóa tin nhắn phiên và đặt lại cài đặt hệ thống trong cài đặt hệ thống. Xin lỗi vì sự bất tiện này." + }, + "sessionList": "Danh sách phiên", + "siderBar": "Thanh bên" +} diff --git a/locales/vi-VN/my.json b/locales/vi-VN/my.json new file mode 100644 index 00000000..76d864c1 --- /dev/null +++ b/locales/vi-VN/my.json @@ -0,0 +1,5 @@ +{ + "my": "Của tôi", + "myDance": "Vũ điệu của tôi", + "myRole": "Vai diễn của tôi" +} diff --git a/locales/vi-VN/panel.json b/locales/vi-VN/panel.json new file mode 100644 index 00000000..eed3e0f1 --- /dev/null +++ b/locales/vi-VN/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "Thêm vào danh sách", + "addPlaySuccess": "Đã thêm vào danh sách phát", + "cancelAddPlay": "Bạn có chắc muốn hủy đăng ký âm nhạc {{musicName}} không?", + "cancelSubscribed": "Hủy đăng ký", + "findDance": "Tìm kiếm những bước nhảy bạn yêu thích", + "musicAndDance": "Âm nhạc và nhảy múa", + "play": "Phát" + }, + "info": { + "avatarDescription": "Tùy chỉnh hình đại diện, nhấn vào hình đại diện để tải lên", + "avatarLabel": "Hình đại diện", + "coverDescription": "Dùng để hiển thị nhân vật trên trang khám phá, kích thước đề xuất {{width}} x {{height}}", + "coverLabel": "Bìa", + "descDescription": "Mô tả nhân vật, dùng để giới thiệu ngắn gọn về nhân vật", + "descLabel": "Mô tả", + "emotionDescription": "Chọn tâm trạng khi phản ứng, ảnh hưởng đến biểu cảm của nhân vật", + "emotionLabel": "Biểu cảm và tâm trạng", + "genderDescription": "Giới tính của nhân vật, ảnh hưởng đến phản ứng chạm của nhân vật", + "genderLabel": "Giới tính", + "greetDescription": "Lời chào khi trò chuyện lần đầu với nhân vật", + "greetLabel": "Chào hỏi", + "modelDescription": "Xem trước mô hình, kéo thả tệp mô hình để thay thế", + "modelLabel": "Xem trước mô hình", + "nameDescription": "Tên nhân vật, được gọi khi trò chuyện với nhân vật", + "nameLabel": "Tên", + "readmeDescription": "Tài liệu hướng dẫn về nhân vật, dùng để hiển thị thông tin chi tiết về nhân vật trên trang khám phá", + "readmeLabel": "Hướng dẫn nhân vật", + "textDescription": "Tùy chỉnh văn bản phản hồi", + "textLabel": "Văn bản", + "categoryLabel": "Danh mục", + "categoryDescription": "Danh mục nhân vật, dùng để phân loại" + }, + "market": { + "findVidol": "Tìm thấy ngôi sao mà bạn yêu thích nhất" + }, + "nav": { + "info": "Thông tin cơ bản", + "model": "Mô hình 3D", + "role": "Thiết lập nhân vật", + "voice": "Giọng nói" + }, + "role": { + "greetTip": "Nhập lời chào khi nhân vật chào bạn", + "inputRoleSetting": "Nhập cài đặt hệ thống cho nhân vật", + "roleDescriptionTip": "Nhập mô tả về nhân vật", + "roleNameTip": "Nhập tên nhân vật", + "roleReadmeTip": "Nhập hướng dẫn về nhân vật", + "roleSettingDescription": "Cài đặt nền cho nhân vật, sẽ gửi cho mô hình khi trò chuyện với nhân vật", + "roleSettingLabel": "Cài đặt hệ thống nhân vật", + "uploadSize": "Hỗ trợ tải lên một tệp, kích thước đề xuất là bội số của {{width}} x {{height}}" + }, + "touch": { + "addAction": "Thêm hành động phản ứng", + "editAction": "Chỉnh sửa hành động phản ứng", + "inputActionEmotion": "Nhập tâm trạng của nhân vật khi phản ứng", + "inputActionText": "Nhập văn bản phản ứng", + "inputDIYText": "Nhập văn bản tùy chỉnh", + "touchActionList": "Danh sách phản ứng khi chạm vào {{touchArea}}", + "touchArea": "Khu vực chạm" + }, + "tts": { + "audition": "Nghe thử", + "auditionDescription": "Văn bản nghe thử tùy theo ngôn ngữ", + "engineDescription": "Bộ công cụ tổng hợp giọng nói, nên ưu tiên chọn trình duyệt Edge", + "engineLabel": "Bộ công cụ giọng nói", + "localeDescription": "Ngôn ngữ tổng hợp giọng nói, hiện chỉ hỗ trợ một số ngôn ngữ phổ biến, nếu cần hỗ trợ thêm vui lòng liên hệ", + "localeLabel": "Ngôn ngữ", + "pitchDescription": "Điều chỉnh âm cao, giá trị từ 0 đến 2, mặc định là 1", + "pitchLabel": "Âm cao", + "selectLanguage": "Vui lòng chọn ngôn ngữ trước", + "selectVoice": "Vui lòng chọn giọng", + "speedDescription": "Điều chỉnh tốc độ, giá trị từ 0 đến 3, mặc định là 1", + "speedLabel": "Tốc độ", + "transfromSuccess": "Chuyển đổi thành công", + "voiceDescription": "Tùy theo bộ công cụ và ngôn ngữ", + "voiceLabel": "Giọng" + }, + "upload": { + "support": "Hỗ trợ tải lên một tệp, hiện chỉ hỗ trợ định dạng tệp vrm" + } +} diff --git a/locales/vi-VN/role.json b/locales/vi-VN/role.json new file mode 100644 index 00000000..2c83f9f3 --- /dev/null +++ b/locales/vi-VN/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "Xóa vai trò", + "delRoleDesc": "Bạn có chắc chắn muốn xóa vai trò {{name}} và các tin nhắn liên quan không? Hành động này không thể hoàn tác, hãy cẩn thận!", + "header": { + "role": "Vai trò", + "session": "Cuộc trò chuyện" + }, + "noRole": "Hiện chưa có vai trò nào, bạn có thể tạo vai trò tùy chỉnh bằng cách nhấn +, hoặc thêm vai trò từ trang khám phá", + "roleList": "Danh sách vai trò", + "topBannerTitle": "Xem trước và cài đặt vai trò" +} diff --git a/locales/vi-VN/welcome.json b/locales/vi-VN/welcome.json new file mode 100644 index 00000000..4c4aeaf1 --- /dev/null +++ b/locales/vi-VN/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}} là nhân vật mặc định của Vidol, là trợ lý riêng của bạn", + "greeting": "哈喽,亲爱的主人!我是你的私人助理 {{name}},愉快地为你服务!有什么我可以帮你的吗?", + "hello": "Xin chào", + "meta": { + "description": "Đây là một nhân vật tùy chỉnh", + "name": "Nhân vật tùy chỉnh" + } + }, + "greet": "Xin chào, tôi là {{name}}, có thứ gì tôi có thể giúp bạn không?", + "loadingTitle": "Ứng dụng đang khởi tạo, vui lòng đợi...", + "waitting": "Đang chuẩn bị thế giới của tôi cho bạn" +} diff --git a/locales/zh-CN/chat.json b/locales/zh-CN/chat.json new file mode 100644 index 00000000..a85eab08 --- /dev/null +++ b/locales/zh-CN/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "聊天", + "chatDialog": { + "close": "关闭" + }, + "dance": "跳舞", + "header": { + "session": "对话", + "role": "角色" + }, + "helloChat": "你好,让我们来聊天吧", + "helloDance": "嗨,让我们一起跳舞吧", + "market": "发现" +} diff --git a/locales/zh-CN/common.json b/locales/zh-CN/common.json new file mode 100644 index 00000000..87e38cd7 --- /dev/null +++ b/locales/zh-CN/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "copy": "复制", + "del": "删除", + "send": "发送", + "warp": "换行", + "confirmDel": "确定删除吗?", + "add": "添加", + "delAndRegenerate": "删除并重新生成", + "edit": "编辑", + "save": "保存", + "share": "分享", + "regenerate": "重新生成", + "reset": "重置", + "resetNow": "立即重置", + "play": "播放", + "pause": "暂停", + "copySuccess": "复制成功", + "removeInList": "从列表中移除", + "downloadSuccess": "下载成功", + "downloadFailed": "下载失败", + "subscribeRole": "订阅角色", + "subscribeDance": "订阅舞蹈", + "subscribe": "订阅", + "subscribed": "已订阅", + "unsubscribe": "取消订阅", + "unsubscribeSuccess": "已取消订阅", + "downloadSubscribe": "下载订阅", + "market": "发现", + "clearAll": "清空", + "clearNow": "立即清除", + "clearContext": "清除上下文", + "clearTip": "操作无法撤销,清除后数据将无法恢复,请慎重操作", + "clearHistoryTip": "该操作不可逆,请谨慎操作", + "clearSuccess": "清除成功", + "clearTitle": "确认清除所有会话消息?", + "clearHistoryTitle": "确定删除历史消息?", + "resetTip": "操作无法撤销,重置后数据将无法恢复,请慎重操作", + "resetSuccess": "重置成功", + "resetTitle": "确认重置所有系统设置?", + "goBottom": "返回底部", + "downloadCover": "下载封面", + "downloadAvatar": "下载头像", + "downloadModel": "下载模型" + }, + "aiAlert": "请谨记:智能体所说的一切都是由 AI 生成的", + "cancel": "取消", + "commonSetting": "通用设置", + "confirm": "确定", + "defaultAssistant": "默认助手", + "delAlert": "确认删除角色以及相关联的会话消息吗?删除后无法恢复, 请谨慎操作!", + "delRole": "删除角色", + "delSession": "删除会话", + "delSessionAlert": "确认删除对话吗?删除后无法恢复,请谨慎操作!", + "inputStartChat": "请输入内容开始聊天", + "languageModel": "语言模型", + "loading": "加载中...", + "noData": "暂无数据", + "openai": { + "callError": "调用接口失败,请检查 APIKey 和接口代理地址是否设置正确", + "checkOk": "检查通过", + "langModel": "OpenAI 语言模型", + "roleModel": "Role GPT 模型", + "model": "模型", + "useOwnKey": "请使用自己的 OpenAI Key", + "proxyUrl": "接口代理地址", + "checkAll": "检查 APIKey 和接口代理地址是否设置正确", + "checkConnect": "连通性检查", + "check": "检查" + }, + "playlist": "播放列表", + "search": "搜索", + "selectInDanceList": "请从舞蹈列表中选取", + "selectModel": "请选择模型", + "setLocalStorage": "设置本地存储", + "startChat": "开始聊天", + "ttsCombine": "语音合成", + "ttsTip": "语音识别(需科学上网)", + "uploadTip": "点击或拖拽文件到此区域上传", + "words": { + "chatSetting": "聊天设置", + "topicSetting": "主题设置", + "systemSetting": "系统设置", + "languageSetting": "语言设置", + "resetSystemSetting": "重置系统设置", + "resetSystemSettingDesc": "将会重置所有系统设置,包括主题设置、聊天设置、语言模型设置等", + "clearAllSession": "清除所有会话消息", + "clearAllSessionDesc": "将会清除所有会话与角色数据,包括会话列表,角色列表、会话消息等", + "DIYAvatar": "自定义头像", + "avatar": "头像", + "DIYNickname": "自定义昵称", + "nickname": "昵称", + "DIYTopicColor": "自定义主题色", + "topicColor": "主题色", + "midColor": "中性色", + "DIYColor": "不同色彩倾向的灰阶自定义", + "DIYBackgroundEffect": "自定义背景效果", + "backgroundEffect": "背景效果" + } +} diff --git a/locales/zh-CN/constants.json b/locales/zh-CN/constants.json new file mode 100644 index 00000000..ee78506b --- /dev/null +++ b/locales/zh-CN/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "meta": { + "name": "自定义角色", + "description": "这是一个自定义角色" + }, + "gender": { + "male": "男", + "female": "女", + "other": "其他" + } + }, + "touch": { + "area": { + "head": "头部", + "arm": "手臂", + "leg": "腿部", + "chest": "胸部", + "belly": "腹部" + }, + "emotion": { + "natural": "自然", + "happy": "开心", + "angry": "生气", + "sad": "伤心", + "relaxed": "放松", + "surprised": "惊讶", + "blink": "眨眼", + "blinkLeft": "眨左眼", + "blinkRight": "眨右眼" + }, + "femaleAction": { + "headAction": { + "happyA": "哇!最喜欢摸摸头!", + "happyB": "感觉又充满了力量呢!", + "happyC": "哇塞,这个摸摸头的感觉好神奇!", + "happyD": "摸摸头让我开心一整天!", + "angryA": "听说被摸头是会长不高的呢!", + "angryB": "干嘛戳我呀?" + }, + "armAction": { + "happyA": "啊,好喜欢呢~", + "happyB": "哈哈,牵手让我感到快乐~", + "relaxedA": "主人的手好温暖啊~" + }, + "legAction": { + "surprisedA": "让我们保持纯洁的友谊不好吗?", + "angryA": "喂,你是要作死吗?", + "angryB": "主人的手又不听指挥了吗?", + "angryC": "讨厌~会痒的啦~!" + }, + "chestAction": { + "angryA": "不可以这样欺负我啦!快把手拿开!", + "angryB": "幺幺零吗?这里有个变态一直在摸我!", + "angryC": "再摸的话我可要报警了", + "surprisedA": "干嘛戳我呀!还能不能愉快地聊天了!" + }, + "bellyAction": { + "surprisedA": "是不小心碰到的吧...", + "angryA": "干嘛动我呀,小心我咬你哦!", + "relaxedA": "醒醒,我们之间没有结果的!", + "relaxedB": "讨厌!我可要生气啦!" + } + }, + "maleAction": { + "headAction": { + "neutralA": "当然了,只有你有资格摸我的头", + "neutralB": "我可不是什么普通人允许触碰的哦", + "neutralC": "别担心,摸过我的头后,你的运气会大幅提升的" + }, + "armAction": { + "neutralA": "别问我今天吃没吃鸡,先看看我的肱二头肌", + "neutralB": "我的手臂可不是随便让人触碰的,你是个例外而已", + "neutralC": "你很勇敢,敢触碰到传说中的麒麟臂" + }, + "legAction": { + "neutralA": "别害怕,我的大力金刚腿不踢傻瓜", + "neutralB": "让你碰到我的腿,是不是觉得你的生活完整了许多?", + "angryA": "别靠近我,你这个腿控" + }, + "chestAction": { + "neutralA": "这不过时我日常修炼成就的胸肌,没什么好惊讶的。", + "blinkLeftA": "来,哥的胸肌给你靠!" + }, + "bellyAction": { + "neutralA": "我的腹肌只是再修炼深藏不露的内力", + "happyA": "别挠痒痒,小心我笑出腹肌", + "neutralB": "看到我这团腹肌了吗?它们只是藏得比较深罢了" + } + } + } +} diff --git a/locales/zh-CN/error.json b/locales/zh-CN/error.json new file mode 100644 index 00000000..62f54c4a --- /dev/null +++ b/locales/zh-CN/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key 为空,请添加自定义 OpenAI API Key", + "error": "错误", + "errorTip": { + "problem": "页面遇到一点问题...", + "description": "项目当前正在施工中,不保证数据稳定性,如果遇到问题可以尝试", + "or": "或", + "forgive": ",造成不便敬请谅解", + "clearSession": "清除会话消息", + "resetSystem": "重置系统设置" + }, + "goBack": "返回首页", + "openaiError": "OpenAI API 错误,请检查 OpenAI API Key 和 Endpoint 是否正确", + "reload": "重新加载", + "s3envError": "S3 环境变量未完全设置,请检查您的环境变量", + "serverError": "服务器错误,请联系管理员", + "triggerError": "触发错误", + "unknownError": "未知错误" +} diff --git a/locales/zh-CN/features.json b/locales/zh-CN/features.json new file mode 100644 index 00000000..04b2d642 --- /dev/null +++ b/locales/zh-CN/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "切换视频模式" + }, + "agent": { + "female": "女性", + "male": "男性", + "other": "其他" + }, + "feature": { + "startDesc": "输入你的 OpenAI API Key 即可开始会话。应用不会记录你的 API Key", + "startTitle": "自定义 API Key", + "addProxy": "添加 OpenAI 代理地址(可选)", + "comfirmRetry": "确认并重试", + "closeTip": "关闭提示" + }, + "mode": { + "chat": "聊天", + "video": "视频" + }, + "settings": { + "glow": "光辉", + "none": "无背景", + "nickName": "请输入昵称" + }, + "share": { + "screenshot": "截图", + "shareGPT": "分享GPT", + "withSystemRole": "包含助手角色设定", + "withBackground": "包含背景图片", + "withFooter": "包含页脚", + "imageType": "图片格式", + "downloadScreenshot": "下载截图", + "shareToGPT": "生成 ShareGPT 分享链接", + "share": "分享", + "shareToMarket": "分享到助手市场" + }, + "submit": { + "submitAssistant": "提交助手", + "submitWarning": "请补全助手信息后提交,需要包含名称、描述、头像和封面", + "assistantId": "助手标识符", + "assistantIdTip": "请输入助手的标识符,需要是唯一的,比如 vidol-agent-klee" + }, + "support": "社区支持", + "theme": { + "auto": "跟随系统", + "light": "亮色模式", + "dark": "暗黑模式" + }, + "token": { + "overload": "Token 超出", + "remained": "Token 剩余", + "used": "Token 已使用", + "useToken": "消耗 Token 数量计算,包括消息,角色设定与上下文:{{usedTokens}} / {{maxValue}}", + "tokenCount": "Token 数量" + }, + "toolBar": { + "cameraHelper": "镜头辅助", + "cameraControl": "镜头控制", + "floor": "切换地板", + "resetCamera": "重置镜头", + "grid": "网格", + "downloadModel": "模型下载中,请稍后..." + } +} diff --git a/locales/zh-CN/layout.json b/locales/zh-CN/layout.json new file mode 100644 index 00000000..f529ac4e --- /dev/null +++ b/locales/zh-CN/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "对话框", + "header": { + "tips": "项目当前正在施工中,不保证数据稳定性,如果遇到问题可以在系统设置中清除会话消息与重置系统设置,造成不便敬请谅解", + "chat": "聊天", + "role": "角色", + "market": "发现", + "settings": "设置" + }, + "sessionList": "会话列表", + "siderBar": "侧边栏" +} diff --git a/locales/zh-CN/my.json b/locales/zh-CN/my.json new file mode 100644 index 00000000..7ad0831c --- /dev/null +++ b/locales/zh-CN/my.json @@ -0,0 +1,5 @@ +{ + "my": "我的", + "myDance": "我的舞蹈", + "myRole": "我的角色" +} diff --git a/locales/zh-CN/panel.json b/locales/zh-CN/panel.json new file mode 100644 index 00000000..30ebca5e --- /dev/null +++ b/locales/zh-CN/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "play": "播放", + "addPlay": "添加到列表", + "addPlaySuccess": "已添加到播放列表", + "cancelAddPlay": "确定取消订阅音乐{{musicName}}吗?", + "cancelSubscribed": "取消订阅", + "findDance": "找到你最喜欢的舞蹈", + "musicAndDance": "音乐与舞蹈" + }, + "info": { + "avatarLabel": "头像", + "avatarDescription": "自定义头像,点击头像自定义上传", + "nameLabel": "名称", + "nameDescription": "角色名称,与角色聊天时的称呼", + "genderLabel": "性别", + "genderDescription": "角色性别,影响角色的触摸响应", + "descLabel": "描述", + "descDescription": "角色描述,用于角色的简单介绍", + "greetLabel": "招呼", + "greetDescription": "与角色初次聊天时的招呼用语", + "readmeLabel": "角色说明", + "readmeDescription": "角色的说明文件,用于发现页展示角色的详细说明", + "coverLabel": "封面", + "coverDescription": "用于发现页展示角色,推荐尺寸 {{width}} x {{height}} ", + "textLabel": "文案", + "textDescription": "自定义响应文案", + "emotionLabel": "表情与情绪", + "emotionDescription": "选择响应时的情绪,会影响角色的表情变化", + "modelLabel": "模型预览", + "modelDescription": "模型预览,可拖动模型文件以替换", + "categoryLabel": "类别", + "categoryDescription": "角色类别,用于展示分类" + }, + "market": { + "findVidol": "找到你最爱的偶像" + }, + "nav": { + "info": "基本信息", + "role": "角色设定", + "voice": "语音", + "model": "3D模型" + }, + "role": { + "uploadSize": "支持单个文件上传,推荐尺寸为 {{width}} x {{height}} 的倍数", + "greetTip": "请输入角色与你打招呼时的用语", + "roleReadmeTip": "请输入角色说明", + "roleDescriptionTip": "请输入角色描述", + "roleNameTip": "请输入角色名称", + "inputRoleSetting": "请输入角色的系统设定", + "roleSettingLabel": "系统角色设定", + "roleSettingDescription": "角色的背景设定,在与角色聊天时会发送给模型" + }, + "touch": { + "editAction": "编辑响应动作", + "addAction": "添加响应动作", + "inputDIYText": "请输入自定义文案", + "inputActionText": "请输入响应文案", + "inputActionEmotion": "请输入角色响应时的表情", + "touchActionList": "触摸{{touchArea}}时的反应列表", + "touchArea": "触摸区域" + }, + "tts": { + "transfromSuccess": "转换成功", + "selectLanguage": "请先选择语言", + "selectVoice": "请先选择语音", + "audition": "试听", + "engineLabel": "语音引擎", + "engineDescription": "语音合成引擎,建议优先选择 Edge 浏览器", + "localeLabel": "语言", + "localeDescription": "语音合成的语种,当前仅支持最常见的几种语言,如有需要请联系", + "voiceLabel": "语音", + "voiceDescription": "根据引擎和语种不同", + "speedLabel": "语速", + "speedDescription": "控制语速,取值范围 0 ~ 3,默认为 1", + "pitchLabel": "音调", + "pitchDescription": "控制音调,取值范围 0 ~ 2,默认为 1", + "auditionDescription": "试听文案根据语言不同" + }, + "upload": { + "support": "支持单个文件上传,当前仅支持 vrm 格式文件" + } +} diff --git a/locales/zh-CN/role.json b/locales/zh-CN/role.json new file mode 100644 index 00000000..b20e0ae4 --- /dev/null +++ b/locales/zh-CN/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "删除角色", + "delRoleDesc": "确定删除角色 {{name}} 以及相关联的会话消息吗?删除后无法恢复, 请谨慎操作!", + "header": { + "session": "对话", + "role": "角色" + }, + "noRole": "暂无角色,可以通过 + 创建自定义角色,也可通过发现页添加角色", + "roleList": "角色列表", + "topBannerTitle": "角色预览和设置" +} diff --git a/locales/zh-CN/welcome.json b/locales/zh-CN/welcome.json new file mode 100644 index 00000000..faf5570b --- /dev/null +++ b/locales/zh-CN/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "greeting": "哈喽,亲爱的主人!我是你的私人助理 {{name}},愉快地为你服务!有什么我可以帮你的吗?", + "description": "{{name}}是 Vidol 的默认角色,是你的专属私人助理", + "hello": "你好呀", + "meta": { + "name": "自定义角色", + "description": "这是一个自定义角色" + } + }, + "greet": "你好,我是{{name}},有什么可以帮助你的吗?", + "loadingTitle": "应用初始化中,请稍后...", + "waitting": "正在为你准备我的整个世界" +} diff --git a/locales/zh-TW/chat.json b/locales/zh-TW/chat.json new file mode 100644 index 00000000..ee9013ee --- /dev/null +++ b/locales/zh-TW/chat.json @@ -0,0 +1,14 @@ +{ + "chat": "聊天", + "chatDialog": { + "close": "關閉" + }, + "dance": "跳舞", + "header": { + "role": "角色", + "session": "對話" + }, + "helloChat": "妳好,讓我們來聊天吧", + "helloDance": "哈囉,讓我們一起跳舞吧", + "market": "發現" +} diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json new file mode 100644 index 00000000..0e5ccbf0 --- /dev/null +++ b/locales/zh-TW/common.json @@ -0,0 +1,100 @@ +{ + "actions": { + "add": "添加", + "clearAll": "清空", + "clearContext": "清除上下文", + "clearHistoryTip": "該操作不可逆,請謹慎操作", + "clearHistoryTitle": "確定刪除歷史消息?", + "clearNow": "立即清除", + "clearSuccess": "清除成功", + "clearTip": "操作無法撤銷,清除後數據將無法恢復,請慎重操作", + "clearTitle": "確認清除所有會話消息?", + "confirmDel": "確定刪除嗎?", + "copy": "複製", + "copySuccess": "複製成功", + "del": "刪除", + "delAndRegenerate": "刪除並重新生成", + "downloadAvatar": "下載頭像", + "downloadCover": "下載封面", + "downloadFailed": "下載失敗", + "downloadModel": "下載模型", + "downloadSubscribe": "下載訂閱", + "downloadSuccess": "下載成功", + "edit": "編輯", + "goBottom": "返回底部", + "market": "發現", + "pause": "暫停", + "play": "播放", + "regenerate": "重新生成", + "removeInList": "從列表中移除", + "reset": "重置", + "resetNow": "立即重置", + "resetSuccess": "重置成功", + "resetTip": "操作無法撤銷,重置後數據將無法恢復,請慎重操作", + "resetTitle": "確認重置所有系統設置?", + "save": "保存", + "send": "發送", + "share": "分享", + "subscribe": "訂閱", + "subscribeDance": "訂閱舞蹈", + "subscribeRole": "訂閱角色", + "subscribed": "已訂閱", + "unsubscribe": "取消訂閱", + "unsubscribeSuccess": "已取消訂閱", + "warp": "換行" + }, + "aiAlert": "請謹記: 智能體所說的一切都是由 AI 生成的", + "cancel": "取消", + "commonSetting": "通用設置", + "confirm": "確定", + "defaultAssistant": "默認助手", + "delAlert": "確認刪除角色以及相關聯的會話消息嗎?刪除後無法恢復,請謹慎操作!", + "delRole": "刪除角色", + "delSession": "刪除會話", + "delSessionAlert": "確認刪除對話嗎?刪除後無法恢復,請謹慎操作!", + "inputStartChat": "請輸入內容開始聊天", + "languageModel": "語言模型", + "loading": "加載中...", + "noData": "暫無數據", + "openai": { + "callError": "調用接口失敗,請檢查 APIKey 和接口代理地址是否設置正確", + "check": "檢查", + "checkAll": "檢查 APIKey 和接口代理地址是否設置正確", + "checkConnect": "連通性檢查", + "checkOk": "檢查通過", + "langModel": "OpenAI 語言模型", + "model": "模型", + "proxyUrl": "接口代理地址", + "roleModel": "Role GPT 模型", + "useOwnKey": "請使用自己的 OpenAI Key" + }, + "playlist": "播放列表", + "search": "搜索", + "selectInDanceList": "請從舞蹈列表中選取", + "selectModel": "請選擇模型", + "setLocalStorage": "設置本地存儲", + "startChat": "開始聊天", + "ttsCombine": "語音合成", + "ttsTip": "語音識別(需科學上網)", + "uploadTip": "點擊或拖拽文件到此區域上傳", + "words": { + "DIYAvatar": "自定義頭像", + "DIYBackgroundEffect": "自定義背景效果", + "DIYColor": "不同色彩傾向的灰階自定義", + "DIYNickname": "自定義暱稱", + "DIYTopicColor": "自定義主題色", + "avatar": "頭像", + "backgroundEffect": "背景效果", + "chatSetting": "聊天設置", + "clearAllSession": "清除所有會話消息", + "clearAllSessionDesc": "將會清除所有會話與角色數據,包括會話列表,角色列表、會話消息等", + "midColor": "中性色", + "nickname": "暱稱", + "resetSystemSetting": "重置系統設置", + "resetSystemSettingDesc": "將會重置所有系統設置,包括主題設置、聊天設置、語言模型設置等", + "systemSetting": "系統設置", + "languageSetting": "語言設置", + "topicColor": "主題色", + "topicSetting": "主題設置" + } +} diff --git a/locales/zh-TW/constants.json b/locales/zh-TW/constants.json new file mode 100644 index 00000000..39f319db --- /dev/null +++ b/locales/zh-TW/constants.json @@ -0,0 +1,92 @@ +{ + "agent": { + "gender": { + "female": "女", + "male": "男", + "other": "其他" + }, + "meta": { + "description": "這是一個自訂角色", + "name": "自訂角色" + } + }, + "touch": { + "area": { + "arm": "手臂", + "belly": "腹部", + "chest": "胸部", + "head": "頭部", + "leg": "腿部" + }, + "emotion": { + "angry": "生氣", + "blink": "眨眼", + "blinkLeft": "眨左眼", + "blinkRight": "眨右眼", + "happy": "開心", + "natural": "自然", + "relaxed": "放鬆", + "sad": "傷心", + "surprised": "驚訝" + }, + "femaleAction": { + "armAction": { + "happyA": "啊,好喜歡呢~", + "happyB": "哈哈,牽手讓我感到快樂~", + "relaxedA": "主人的手好溫暖啊~" + }, + "bellyAction": { + "angryA": "幹嘛動我啊,小心我咬你哦!", + "relaxedA": "醒醒,我們之間沒有結果的!", + "relaxedB": "討厭!我可要生氣啦!", + "surprisedA": "是不小心碰到的吧..." + }, + "chestAction": { + "angryA": "不可以這樣欺負我啦!快把手拿開!", + "angryB": "幺幺零嗎?這裡有個變態一直在摸我!", + "angryC": "再摸的話我可要報警了", + "surprisedA": "幹嘛戳我啊!還能不能愉快地聊天了!" + }, + "headAction": { + "angryA": "聽說被摸頭是會長不高的呢!", + "angryB": "幹嘛戳我呀?", + "happyA": "哇!最喜歡摸摸頭!", + "happyB": "感覺又充滿了力量呢!", + "happyC": "哇塞,這個摸摸頭的感覺好神奇!", + "happyD": "摸摸頭讓我開心一整天!" + }, + "legAction": { + "angryA": "喂,你是要作死嗎?", + "angryB": "主人的手又不聽指揮了嗎?", + "angryC": "討厭~會癢的啦~!", + "surprisedA": "讓我們保持純潔的友誼不好嗎?" + } + }, + "maleAction": { + "armAction": { + "neutralA": "別問我今天吃沒吃雞,先看看我的肱二頭肌", + "neutralB": "我的手臂可不是隨便讓人觸碰的,你是個例外而已", + "neutralC": "你很勇敢,敢觸碰到傳說中的麒麟臂" + }, + "bellyAction": { + "happyA": "別挠痒痒,小心我笑出腹肌", + "neutralA": "我的腹肌只是再修煉深藏不露的內力", + "neutralB": "看到我這團腹肌了嗎?它們只是藏得比較深罷了" + }, + "chestAction": { + "blinkLeftA": "來,哥的胸肌給你靠!", + "neutralA": "這不過時我日常修煉成就的胸肌,沒什麼好驚訝的。" + }, + "headAction": { + "neutralA": "當然了,只有你有資格摸我的頭", + "neutralB": "我可不是什麼普通人允許觸碰的哦", + "neutralC": "別擔心,摸過我的頭後,你的運氣會大幅提升的" + }, + "legAction": { + "angryA": "別靠近我,你這個腿控", + "neutralA": "別害怕,我的大力金剛腿不踢傻瓜", + "neutralB": "讓你碰到我的腿,是不是覺得你的生活完整了許多?" + } + } + } +} diff --git a/locales/zh-TW/error.json b/locales/zh-TW/error.json new file mode 100644 index 00000000..1176b187 --- /dev/null +++ b/locales/zh-TW/error.json @@ -0,0 +1,19 @@ +{ + "apiKeyMiss": "OpenAI API Key 空缺,請添加自訂 OpenAI API Key", + "error": "錯誤", + "errorTip": { + "clearSession": "清除會話訊息", + "description": "項目目前正在施工中,不保證數據穩定性,如果遇到問題可以嘗試", + "forgive": ",造成不便敬請諒解", + "or": "或", + "problem": "頁面遇到一點問題...", + "resetSystem": "重置系統設定" + }, + "goBack": "返回首頁", + "openaiError": "OpenAI API 錯誤,请檢查 OpenAI API Key 和 Endpoint 是否正確", + "reload": "重新載入", + "s3envError": "S3 環境變數未完全設定,請檢查您的環境變數", + "serverError": "伺服器錯誤,請聯絡管理員", + "triggerError": "觸發錯誤", + "unknownError": "未知錯誤" +} diff --git a/locales/zh-TW/features.json b/locales/zh-TW/features.json new file mode 100644 index 00000000..18eb2493 --- /dev/null +++ b/locales/zh-TW/features.json @@ -0,0 +1,65 @@ +{ + "actions": { + "useVideo": "切換視訊模式" + }, + "agent": { + "female": "女性", + "male": "男性", + "other": "其他" + }, + "feature": { + "addProxy": "添加 OpenAI 代理地址(可選)", + "closeTip": "關閉提示", + "comfirmRetry": "確認並重試", + "startDesc": "輸入你的 OpenAI API Key 即可開始會話。應用不會記錄你的 API Key", + "startTitle": "自定義 API Key" + }, + "mode": { + "chat": "聊天", + "video": "視訊" + }, + "settings": { + "glow": "光輝", + "nickName": "請輸入暱稱", + "none": "無背景" + }, + "share": { + "downloadScreenshot": "下載螢幕截圖", + "imageType": "圖片格式", + "screenshot": "螢幕截圖", + "share": "分享", + "shareGPT": "分享 GPT", + "shareToGPT": "生成分享至 ShareGPT 的連結", + "shareToMarket": "分享至助手市場", + "withBackground": "包含背景圖片", + "withFooter": "包含頁腳", + "withSystemRole": "包含助手角色設定" + }, + "submit": { + "assistantId": "助手識別符", + "assistantIdTip": "請輸入助手的識別符,需要是唯一的,例如 vidol-agent-klee", + "submitAssistant": "提交助手", + "submitWarning": "請補全助手資訊後提交,需要包含名稱、描述、頭像和封面" + }, + "support": "社區支援", + "theme": { + "auto": "跟隨系統", + "dark": "暗黑模式", + "light": "亮色模式" + }, + "token": { + "overload": "令牌超出", + "remained": "令牌剩餘", + "tokenCount": "令牌數量", + "useToken": "消耗令牌數量計算,包括訊息、角色設定與上下文:{{usedTokens}} / {{maxValue}}", + "used": "令牌已使用" + }, + "toolBar": { + "cameraControl": "鏡頭控制", + "cameraHelper": "鏡頭輔助", + "downloadModel": "模型下載中,請稍後...", + "floor": "切換地板", + "grid": "網格", + "resetCamera": "重設鏡頭" + } +} diff --git a/locales/zh-TW/layout.json b/locales/zh-TW/layout.json new file mode 100644 index 00000000..1f649d47 --- /dev/null +++ b/locales/zh-TW/layout.json @@ -0,0 +1,12 @@ +{ + "dialog": "對話框", + "header": { + "chat": "聊天", + "market": "發現", + "role": "角色", + "settings": "設置", + "tips": "項目當前正在施工中,不保證數據穩定性,如果遇到問題可以在系統設置中清除會話訊息與重置系統設置,造成不便敬請諒解" + }, + "sessionList": "會話列表", + "siderBar": "側邊欄" +} diff --git a/locales/zh-TW/my.json b/locales/zh-TW/my.json new file mode 100644 index 00000000..7ad0831c --- /dev/null +++ b/locales/zh-TW/my.json @@ -0,0 +1,5 @@ +{ + "my": "我的", + "myDance": "我的舞蹈", + "myRole": "我的角色" +} diff --git a/locales/zh-TW/panel.json b/locales/zh-TW/panel.json new file mode 100644 index 00000000..e5fe5383 --- /dev/null +++ b/locales/zh-TW/panel.json @@ -0,0 +1,83 @@ +{ + "dance": { + "addPlay": "新增至清單", + "addPlaySuccess": "已新增至播放清單", + "cancelAddPlay": "確定要取消訂閱音樂{{musicName}}嗎?", + "cancelSubscribed": "取消訂閱", + "findDance": "尋找您最喜愛的舞蹈", + "musicAndDance": "音樂與舞蹈", + "play": "播放" + }, + "info": { + "avatarDescription": "自訂頭像,點擊頭像自訂上傳", + "avatarLabel": "頭像", + "coverDescription": "用於發現頁展示角色,推薦尺寸 {{width}} x {{height}} ", + "coverLabel": "封面", + "descDescription": "角色描述,用於角色的簡單介紹", + "descLabel": "描述", + "emotionDescription": "選擇回應時的情緒,會影響角色的表情變化", + "emotionLabel": "表情與情緒", + "genderDescription": "角色性別,影響角色的觸摸回應", + "genderLabel": "性別", + "greetDescription": "與角色初次聊天時的招呼用語", + "greetLabel": "招呼", + "modelDescription": "模型預覽,可拖動模型文件以替換", + "modelLabel": "模型預覽", + "nameDescription": "角色名稱,與角色聊天時的稱呼", + "nameLabel": "名稱", + "readmeDescription": "角色的說明文件,用於發現頁展示角色的詳細說明", + "readmeLabel": "角色說明", + "textDescription": "自定義回應文案", + "textLabel": "文案", + "categoryLabel": "類別", + "categoryDescription": "角色類別,用於展示分類" + }, + "market": { + "findVidol": "找到您最愛的偶像" + }, + "nav": { + "info": "基本資訊", + "model": "3D模型", + "role": "角色設定", + "voice": "語音" + }, + "role": { + "greetTip": "請輸入角色與您打招呼時的用語", + "inputRoleSetting": "請輸入角色的系統設定", + "roleDescriptionTip": "請輸入角色描述", + "roleNameTip": "請輸入角色名稱", + "roleReadmeTip": "請輸入角色說明", + "roleSettingDescription": "角色的背景設定,在與角色聊天時會發送給模型", + "roleSettingLabel": "系統角色設定", + "uploadSize": "支持單個文件上傳,推薦尺寸為 {{width}} x {{height}} 的倍數" + }, + "touch": { + "addAction": "新增回應動作", + "editAction": "編輯回應動作", + "inputActionEmotion": "請輸入角色回應時的表情", + "inputActionText": "請輸入回應文案", + "inputDIYText": "請輸入自定義文案", + "touchActionList": "觸摸{{touchArea}}時的反應列表", + "touchArea": "觸摸區域" + }, + "tts": { + "audition": "試聽", + "auditionDescription": "試聽文案根據語言不同", + "engineDescription": "語音合成引擎,建議優先選擇 Edge 瀏覽器", + "engineLabel": "語音引擎", + "localeDescription": "語音合成的語種,當前僅支持最常見的幾種語言,如有需要請聯繫", + "localeLabel": "語言", + "pitchDescription": "控制音調,取值範圍 0 ~ 2,默認為 1", + "pitchLabel": "音調", + "selectLanguage": "請先選擇語言", + "selectVoice": "請先選擇語音", + "speedDescription": "控制語速,取值範圍 0 ~ 3,默認為 1", + "speedLabel": "語速", + "transfromSuccess": "轉換成功", + "voiceDescription": "根據引擎和語種不同", + "voiceLabel": "語音" + }, + "upload": { + "support": "支持單個文件上傳,當前僅支持 vrm 格式文件" + } +} diff --git a/locales/zh-TW/role.json b/locales/zh-TW/role.json new file mode 100644 index 00000000..b3441941 --- /dev/null +++ b/locales/zh-TW/role.json @@ -0,0 +1,11 @@ +{ + "delRole": "刪除角色", + "delRoleDesc": "確定刪除角色 {{name}} 以及相關聯的對話消息嗎?刪除後無法復原,請慎重操作!", + "header": { + "role": "角色", + "session": "對話" + }, + "noRole": "暫無角色,可以通過 + 創建自定義角色,也可通過發現頁添加角色", + "roleList": "角色清單", + "topBannerTitle": "角色預覽和設定" +} diff --git a/locales/zh-TW/welcome.json b/locales/zh-TW/welcome.json new file mode 100644 index 00000000..790d80c7 --- /dev/null +++ b/locales/zh-TW/welcome.json @@ -0,0 +1,14 @@ +{ + "agent": { + "description": "{{name}}是 Vidol 的預設角色,是您的專屬私人助理", + "greeting": "哈囉,親愛的主人!我是您的私人助理{{name}},很高興為您服務!有什麼我可以幫到您的嗎?", + "hello": "你好呀", + "meta": { + "description": "這是一個自訂角色", + "name": "自定義角色" + } + }, + "greet": "你好,我是{{name}},有什麼可以幫助您的嗎?", + "loadingTitle": "應用程式初始化中,請稍候...", + "waitting": "正在為您準備我的整個世界" +} diff --git a/package.json b/package.json index f91d9237..5d5b2459 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "scripts": { "build": "next build", "dev": "next dev", + "docs:i18n": "lobe-i18n md && npm run lint:mdx", + "i18n": "npm run workflow:i18n && lobe-i18n", "lint": "npm run lint:ts && npm run lint:style && npm run type-check", "lint:circular": "dpdm src/**/*.ts --warning false --tree false --exit-code circular:1 -T true --skip-dynamic-imports circular", "lint:md": "remark . --quiet --frail --output", @@ -39,7 +41,8 @@ "test": "vitest", "test:coverage": "vitest run --coverage", "test:update": "vitest -u", - "type-check": "tsc --noEmit" + "type-check": "tsc --noEmit", + "workflow:i18n": "tsx scripts/i18nWorkflow/index.ts" }, "lint-staged": { "*.mdx": [ @@ -68,6 +71,7 @@ "@dnd-kit/utilities": "^3.2.2", "@gltf-transform/core": "^4.0.2", "@icons-pack/react-simple-icons": "^9.6.0", + "@lobehub/i18n-cli": "^1.18.1", "@lobehub/icons": "^1.24.0", "@lobehub/tts": "^1.24.2", "@lobehub/ui": "^1.145.5", @@ -88,6 +92,9 @@ "classnames": "^2.5.1", "dayjs": "^1.11.11", "fast-deep-equal": "^3.1.3", + "i18next": "^23.11.5", + "i18next-browser-languagedetector": "^7.2.1", + "i18next-resources-to-backend": "^1.2.1", "immer": "^10.1.1", "js-tiktoken": "^1.0.12", "localforage": "^1.10.0", @@ -106,6 +113,7 @@ "query-string": "^9.0.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-i18next": "14.0.2", "react-intersection-observer": "^9.10.3", "react-layout-kit": "^1.9.0", "react-lazy-load": "^4.0.1", @@ -113,6 +121,7 @@ "remark": "^15.0.1", "remark-gfm": "^3.0.1", "remark-html": "^16.0.1", + "resolve-accept-language": "^3.1.4", "superjson": "^2.2.1", "swr": "^2.2.5", "three": "^0.165.0", @@ -142,11 +151,13 @@ "@types/ua-parser-js": "^0.7.39", "@types/uuid": "^10.0.0", "commitlint": "^19.3.0", + "consola": "^3.2.3", "dpdm": "^3.14.0", "eslint": "^8.57.0", "glob": "^10.4.2", "husky": "^9.0.11", "jsdom": "^24.1.0", + "just-diff": "^6.0.2", "lint-staged": "^15.2.5", "prettier": "^3.2.5", "remark": "^15.0.0", diff --git a/scripts/i18nWorkflow/const.ts b/scripts/i18nWorkflow/const.ts new file mode 100644 index 00000000..4142fcf0 --- /dev/null +++ b/scripts/i18nWorkflow/const.ts @@ -0,0 +1,18 @@ +import { readdirSync } from 'node:fs'; +import { resolve } from 'node:path'; + +import i18nConfig from '../../.i18nrc'; + +export const root = resolve(__dirname, '../..'); +export const localesDir = resolve(root, i18nConfig.output); +export const localeDir = (locale: string) => resolve(localesDir, locale); +export const localeDirJsonList = (locale: string) => + readdirSync(localeDir(locale)).filter((name) => name.includes('.json')); +export const srcLocalesDir = resolve(root, './src/locales'); +export const entryLocaleJsonFilepath = (file: string) => + resolve(localesDir, i18nConfig.entryLocale, file); +export const outputLocaleJsonFilepath = (locale: string, file: string) => + resolve(localesDir, locale, file); +export const srcDefaultLocales = resolve(root, srcLocalesDir, 'default'); + +export { default as i18nConfig } from '../../.i18nrc'; diff --git a/scripts/i18nWorkflow/genDefaultLocale.ts b/scripts/i18nWorkflow/genDefaultLocale.ts new file mode 100644 index 00000000..2d672a59 --- /dev/null +++ b/scripts/i18nWorkflow/genDefaultLocale.ts @@ -0,0 +1,19 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; + +import { entryLocaleJsonFilepath, i18nConfig, srcDefaultLocales } from './const'; +import { tagWhite, writeJSON } from './utils'; + +export const genDefaultLocale = () => { + consola.info(`Default locale is ${i18nConfig.entryLocale}...`); + + const resources = require(srcDefaultLocales); + const data = Object.entries(resources.default); + consola.start(`Generate default locale json, found ${data.length} namespaces...`); + + for (const [ns, value] of data) { + const filepath = entryLocaleJsonFilepath(`${ns}.json`); + writeJSON(filepath, value); + consola.success(tagWhite(ns), colors.gray(filepath)); + } +}; diff --git a/scripts/i18nWorkflow/genDiff.ts b/scripts/i18nWorkflow/genDiff.ts new file mode 100644 index 00000000..46774e9e --- /dev/null +++ b/scripts/i18nWorkflow/genDiff.ts @@ -0,0 +1,50 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; +import { diff } from 'just-diff'; +import { unset } from 'lodash-es'; +import { existsSync } from 'node:fs'; + +import { + entryLocaleJsonFilepath, + i18nConfig, + outputLocaleJsonFilepath, + srcDefaultLocales, +} from './const'; +import { readJSON, tagWhite, writeJSON } from './utils'; + +export const genDiff = () => { + consola.start(`Diff between Dev/Prod local...`); + + const resources = require(srcDefaultLocales); + const data = Object.entries(resources.default); + + for (const [ns, devJSON] of data) { + const filepath = entryLocaleJsonFilepath(`${ns}.json`); + if (!existsSync(filepath)) continue; + const prodJSON = readJSON(filepath); + + const diffResult = diff(prodJSON, devJSON as any); + const remove = diffResult.filter((item) => item.op === 'remove'); + if (remove.length === 0) { + consola.success(tagWhite(ns), colors.gray(filepath)); + continue; + } + + const clearLocals = []; + + for (const locale of [i18nConfig.entryLocale, ...i18nConfig.outputLocales]) { + const localeFilepath = outputLocaleJsonFilepath(locale, `${ns}.json`); + if (!existsSync(localeFilepath)) continue; + const localeJSON = readJSON(localeFilepath); + + for (const item of remove) { + unset(localeJSON, item.path); + } + + writeJSON(localeFilepath, localeJSON); + clearLocals.push(locale); + } + consola.info('clear', clearLocals); + consola.success(tagWhite(ns), colors.gray(filepath)); + } +}; diff --git a/scripts/i18nWorkflow/index.ts b/scripts/i18nWorkflow/index.ts new file mode 100644 index 00000000..395750fb --- /dev/null +++ b/scripts/i18nWorkflow/index.ts @@ -0,0 +1,11 @@ +import { genDefaultLocale } from './genDefaultLocale'; +import { genDiff } from './genDiff'; +import { split } from './utils'; + +split('DIFF ANALYSIS'); +genDiff(); + +split('GENERATE DEFAULT LOCALE'); +genDefaultLocale(); + +split('GENERATE I18N FILES'); diff --git a/scripts/i18nWorkflow/utils.ts b/scripts/i18nWorkflow/utils.ts new file mode 100644 index 00000000..bf557181 --- /dev/null +++ b/scripts/i18nWorkflow/utils.ts @@ -0,0 +1,54 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +import i18nConfig from '../../.i18nrc'; + +export const readJSON = (filePath: string) => { + const data = readFileSync(filePath, 'utf8'); + return JSON.parse(data); +}; + +export const writeJSON = (filePath: string, data: any) => { + const jsonStr = JSON.stringify(data, null, 2); + writeFileSync(filePath, jsonStr, 'utf8'); +}; + +export const genResourcesContent = (locales: string[]) => { + let index = ''; + let indexObj = ''; + + for (const locale of locales) { + index += `import ${locale} from "./${locale}";\n`; + indexObj += ` "${locale.replace('_', '-')}": ${locale},\n`; + } + + return `${index} +const resources = { +${indexObj}} as const; +export default resources; +export const defaultResources = ${i18nConfig.entryLocale}; +export type Resources = typeof resources; +export type DefaultResources = typeof defaultResources; +export type Namespaces = keyof DefaultResources; +export type Locales = keyof Resources; +`; +}; + +export const genNamespaceList = (files: string[], locale: string) => { + return files.map((file) => ({ + name: file.replace('.json', ''), + path: resolve(i18nConfig.output, locale, file), + })); +}; + +export const tagBlue = (text: string) => colors.bgBlueBright(colors.black(` ${text} `)); +export const tagYellow = (text: string) => colors.bgYellowBright(colors.black(` ${text} `)); +export const tagGreen = (text: string) => colors.bgGreenBright(colors.black(` ${text} `)); +export const tagWhite = (text: string) => colors.bgWhiteBright(colors.black(` ${text} `)); + +export const split = (name: string) => { + consola.log(''); + consola.log(colors.gray(`========================== ${name} ==============================`)); +}; diff --git a/src/app/chat/Apps.tsx b/src/app/chat/Apps.tsx index dfee8570..ae1e2fcb 100644 --- a/src/app/chat/Apps.tsx +++ b/src/app/chat/Apps.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next'; + import { DancePanel, MarketPanel } from '@/panels'; import { useGlobalStore } from '@/store/global'; import { PanelKey } from '@/types/config'; @@ -6,12 +8,12 @@ export const apps = [ { component: , key: 'dance', - label: '跳舞', + label: t('dance', { ns: 'chat' }), }, { component: , key: 'market', - label: '发现', + label: t('market', { ns: 'chat' }), }, ]; diff --git a/src/app/chat/SideBar/Header/index.tsx b/src/app/chat/SideBar/Header/index.tsx index be21c914..372bb58d 100644 --- a/src/app/chat/SideBar/Header/index.tsx +++ b/src/app/chat/SideBar/Header/index.tsx @@ -1,5 +1,6 @@ import { TabsNav } from '@lobehub/ui'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import Market from '@/features/Actions/Market'; @@ -9,10 +10,11 @@ import { useStyles } from './style'; const Index = () => { const { styles } = useStyles(); const [tab, setTab] = useState('session'); + const { t } = useTranslation('chat'); const options = [ - { key: 'session', label: '对话' }, - { key: 'character', label: '角色' }, + { key: 'session', label: t('header.session') }, + { key: 'character', label: t('header.role') }, ]; return ( diff --git a/src/app/chat/ViewerMode/ChatDialog/index.tsx b/src/app/chat/ViewerMode/ChatDialog/index.tsx index 6df6e384..de7643d1 100644 --- a/src/app/chat/ViewerMode/ChatDialog/index.tsx +++ b/src/app/chat/ViewerMode/ChatDialog/index.tsx @@ -4,6 +4,7 @@ import { Tooltip } from 'antd'; import classNames from 'classnames'; import { XIcon } from 'lucide-react'; import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import ChatItem from '@/features/ChatItem'; @@ -25,6 +26,7 @@ const Dialog = (props: DialogProps) => { const lastAgentChatIndex = currentChats.findLastIndex((item) => item.role === 'assistant'); const ref = React.useRef(null); const isHovered = useHover(ref); + const { t } = useTranslation('chat'); const { styles } = useStyles(); const [showChatDialog, setChatDialog] = useState(true); @@ -41,7 +43,7 @@ const Dialog = (props: DialogProps) => { showTitle={false} type="pure" /> - + setChatDialog(false)} diff --git a/src/app/my/SideBar/MyList/index.tsx b/src/app/my/SideBar/MyList/index.tsx index a2ba36d1..2761da48 100644 --- a/src/app/my/SideBar/MyList/index.tsx +++ b/src/app/my/SideBar/MyList/index.tsx @@ -1,6 +1,7 @@ import { Bot, Mic2 } from 'lucide-react'; import Link from 'next/link'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { MyTabs } from '../type'; import Item from './Item'; @@ -9,11 +10,12 @@ export interface MyListProps { activeTab?: MyTabs; mobile?: boolean; } - const MyList = memo(({ activeTab, mobile }) => { + const { t } = useTranslation('my'); + const items = [ - { icon: Bot, label: '我的角色', value: MyTabs.Agent }, - { icon: Mic2, label: '我的舞蹈', value: MyTabs.Dance }, + { icon: Bot, label: t('myRole'), value: MyTabs.Agent }, + { icon: Mic2, label: t('myDance'), value: MyTabs.Dance }, ]; return items.map(({ value, icon, label }) => ( diff --git a/src/app/my/SideBar/index.tsx b/src/app/my/SideBar/index.tsx index 1308d4b5..e99ea625 100644 --- a/src/app/my/SideBar/index.tsx +++ b/src/app/my/SideBar/index.tsx @@ -2,6 +2,7 @@ import { createStyles, useResponsive } from 'antd-style'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import MyList, { MyListProps } from './MyList'; @@ -24,10 +25,12 @@ const SideBar = memo(({ activeTab }) => { const { mobile } = useResponsive(); + const { t } = useTranslation('my'); + return ( - 我的 + {t('my')} diff --git a/src/app/role/SideBar/Header/index.tsx b/src/app/role/SideBar/Header/index.tsx index 7bc5dc6a..c619c451 100644 --- a/src/app/role/SideBar/Header/index.tsx +++ b/src/app/role/SideBar/Header/index.tsx @@ -1,5 +1,6 @@ import { TabsNav } from '@lobehub/ui'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import Agent from '@/features/Actions/Agent'; @@ -9,10 +10,11 @@ import { useStyles } from './style'; const Index = () => { const { styles } = useStyles(); const [tab, setTab] = useState('session'); + const { t } = useTranslation('role'); const options = [ - { key: 'session', label: '对话' }, - { key: 'character', label: '角色' }, + { key: 'session', label: t('header.session') }, + { key: 'character', label: t('header.role') }, ]; return ( diff --git a/src/app/role/page.tsx b/src/app/role/page.tsx index c2d2bf0d..ce27ddb6 100644 --- a/src/app/role/page.tsx +++ b/src/app/role/page.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import TopBanner from '@/components/TopBanner'; @@ -11,12 +12,13 @@ import { useStyles } from './style'; const Role = () => { const { styles } = useStyles(); + const { t } = useTranslation('role'); return ( - + diff --git a/src/app/welcome/loading.tsx b/src/app/welcome/loading.tsx index 136fe6bb..12739aa7 100644 --- a/src/app/welcome/loading.tsx +++ b/src/app/welcome/loading.tsx @@ -1,6 +1,7 @@ 'use client'; import { createStyles } from 'antd-style'; +import { useTranslation } from 'react-i18next'; import PageLoading from '@/components/PageLoading'; @@ -15,9 +16,10 @@ const useStyles = createStyles(({ css }) => ({ const Loading = () => { const { styles } = useStyles(); + const { t } = useTranslation('welcome'); return (
- +
); }; diff --git a/src/components/EmptyGuide/index.tsx b/src/components/EmptyGuide/index.tsx index 9f59004c..88b41507 100644 --- a/src/components/EmptyGuide/index.tsx +++ b/src/components/EmptyGuide/index.tsx @@ -1,5 +1,6 @@ import { InboxOutlined } from '@ant-design/icons'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { useStyles } from './style'; @@ -12,6 +13,7 @@ interface EmptyGuideProps { const EmptyGuide = (props: EmptyGuideProps) => { const { styles } = useStyles(); const { size, extra } = props; + const { t } = useTranslation('common'); return ( { style={{ height: size.height, width: size.width }} > -

点击或拖拽文件到此区域上传

+

{t('uploadTip')}

{extra ?

{extra}

: null}
); diff --git a/src/components/Error/index.tsx b/src/components/Error/index.tsx index 9f557673..d2e633a2 100644 --- a/src/components/Error/index.tsx +++ b/src/components/Error/index.tsx @@ -4,6 +4,7 @@ import { FluentEmoji } from '@lobehub/ui'; import { Button } from 'antd'; import Link from 'next/link'; import { memo, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { MAX_WIDTH } from '@/constants/common'; @@ -21,6 +22,8 @@ const ErrorCapture = memo(({ reset, error }) => { console.error(error); }, [error]); + const { t } = useTranslation('error'); + return (

(({ reset, error }) => { zIndex: 0, }} > - ERROR + {t('error')}

- 页面遇到一点问题... + {t('errorTip.problem')}

- 项目当前正在施工中,不保证数据稳定性,如果遇到问题可以尝试 - - 或 - ,造成不便敬请谅解 + {t('errorTip.description')} + + {t('errorTip.or')} + {t('errorTip.forgive')}

- + - +
diff --git a/src/components/GridList/index.tsx b/src/components/GridList/index.tsx index c023a218..b77f109d 100644 --- a/src/components/GridList/index.tsx +++ b/src/components/GridList/index.tsx @@ -3,6 +3,7 @@ import { Empty, Space } from 'antd'; import classNames from 'classnames'; import { Loader2 } from 'lucide-react'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { Center } from 'react-layout-kit'; import ListItem from './ListItem'; @@ -39,11 +40,12 @@ const GridList = (props: GridListProps) => { empty, } = props; const { styles } = useStyles(); + const { t } = useTranslation('common'); const Loading = () => (
- 加载中... + {t('loading')}
); @@ -68,7 +70,7 @@ const GridList = (props: GridListProps) => { ); const EmptyList = () => ( - + {empty?.actions ? {empty.actions} : null} ); diff --git a/src/components/ModelTag/index.tsx b/src/components/ModelTag/index.tsx index e118c336..e718b276 100644 --- a/src/components/ModelTag/index.tsx +++ b/src/components/ModelTag/index.tsx @@ -1,5 +1,6 @@ import { Tag } from '@lobehub/ui'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { OPENAI_MODEL_LIST } from '@/constants/openai'; @@ -9,11 +10,12 @@ interface ModelTagProps { model?: string; } const ModelTag = memo(({ model }) => { + const { t } = useTranslation('common'); const selectedModel = OPENAI_MODEL_LIST.find(({ id }) => id === model); return ( }> - {selectedModel ? selectedModel?.displayName : '请选择模型'} + {selectedModel ? selectedModel?.displayName : t('selectModel')} ); }); diff --git a/src/components/Panel/Container.tsx b/src/components/Panel/Container.tsx index ed379f74..2e0700f4 100644 --- a/src/components/Panel/Container.tsx +++ b/src/components/Panel/Container.tsx @@ -4,6 +4,7 @@ import { Tooltip } from 'antd'; import classNames from 'classnames'; import { XIcon } from 'lucide-react'; import React, { PropsWithChildren, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { INITIAL_COORDINATES, INITIAL_Z_INDEX } from '@/constants/token'; @@ -41,6 +42,7 @@ const Container = (props: PropsWithChildren) => { footer, } = props; const { styles } = useStyles(); + const { t } = useTranslation('chat'); const { attributes, listeners, transform, setNodeRef, setActivatorNodeRef } = useDraggable({ id: 'draggable', @@ -77,7 +79,7 @@ const Container = (props: PropsWithChildren) => {
{extra ? extra : null}
{toolbar ? toolbar : null} - +
diff --git a/src/constants/agent.ts b/src/constants/agent.ts index 99dcfeb0..162e008e 100644 --- a/src/constants/agent.ts +++ b/src/constants/agent.ts @@ -1,3 +1,5 @@ +import { t } from 'i18next'; + import { DEFAULT_AGENT_AVATAR_URL } from '@/constants/common'; import { DEFAULT_TOUCH_ACTION_CONFIG_FEMALE } from '@/constants/touch'; import { DEFAULT_TTS_CONFIG_FEMALE } from '@/constants/tts'; @@ -13,7 +15,7 @@ export const DEFAULT_VIDOL_AGENT: Agent = { agentId: LOBE_VIDOL_DEFAULT_AGENT_ID, author: 'LobeVidol', createAt: '2023-10-30', - greeting: `哈喽,亲爱的主人!我是你的私人助理 ${OFFICIAL_ROLE_NAME},愉快地为你服务!有什么我可以帮你的吗?`, + greeting: t('agent.greeting', { name: OFFICIAL_ROLE_NAME, ns: 'welcome' }), homepage: 'https://github.com/lobehub/lobe-vidol', meta: { cover: @@ -21,7 +23,7 @@ export const DEFAULT_VIDOL_AGENT: Agent = { avatar: 'data:application/octet-stream;base64,UklGRhoiAABXRUJQVlA4IA4iAADQawCdASqWAJYAPjEUiEKiISEWG5bEIAMEoyAL9rhFf6m9wCr2cpqQf9bhDrcrzKXUvd+blyL2s/APGPFXWN5cvPH/Q+6X6A+iH+3f572Ef1h/Wj3L/6T/l/5H3efuj6g/1q/aP3av9N/3f877tv7v6gH9D/z/rW/9b2JP3c9gD9oPTK/bn4T/8N/yP3D94X/P/+32APQA4VXzUeFH3P8qvOP8e+a/uH9k/aP++e0vlL61tRH5B9m/wv9u/b/+0fu792/63/c/kZ5z/IX+p9QL8h/lf+B/uH7cf3392/dF/ru4ztV/tPyj+Aj2k+ef43+9fub/pPSg/w/yQ9y/zv+1f8D3AP5N/NP8j/WP3a/xv//+lf934ff27/Y+wF/Of7d/2P8X+X302/zf/U/y3+Y/8H/B9sv6L/hP+j/h/9B+zn2EfzL+s/7f/A/vZ/mv///7fvE///t9/cH/ze6r+z//jc6tugS2nX/5narJpJuSIiH6dVW3navnwQVtmouHbXzIJro6NKrujJCrk3/opHjvwpb8AF6ajClBbA980qBi9pAmeeUGYMEZFxI+F8T0np53vSQDq+LagRu9PYY9EouCDBG2vt14bCOrWJgL1n0VfxpfXv4dcKEn+7mNWb84Xoq+3g5ymobeTI/rS7kAJaM7ufL4Z5pQqvH52oTAnlqFADDuLrrfi47XOzI9cMeNoQjW/DK3lr8mL5hTra58vjVcUr6R3IBlAu4IJsutgY/0yD6J2pGeD9g/TIFyiSQ5q0qqs+EpYTnzAPsA9rhsu13cOlUa6eGBWbNotSiqn/8A/5ffeuXQiyN2vJirN2lQW/yamqc2vjZy67jZSJV99pMFiVo6wHoGyIyVb7PiMLb9a2Z+mO85RjpmVuHew600exUJvBt1zYi4KC1uK621pNHZ78NjbtUEE5BVXIblbyvBWQhzJfLcmjFrimD9XqiUpq5edFBcMQ1Rzfk1YiuVdCEYCne6EHjBM9POv7XCSo2dLpd6umGa1USzQY98jyuztW+DfnWge9J4fuWzYh4a9CbhXZPp11ME8U4ytr+mPzGWr7ai8FsSD5xJueqlw9pE3BlhhBLgxK0vDHbXVXLnJ9RjZr9FTONk4gGFwxd9/DfNIPr/XlJkQhezAiTim1tgcEGZuLrlYy3QAP7+JvRxSh0gOlG4SfDlhB2BYvnf/qx4Hdgyz7qVlGOSM64ROGmiNvLqQjjTnP/97FZPLFQpPU6kSg+8b/vtSwoG/Sobg6rRltioiBpfPDdE+d5zI6EIv1z/MUlDzgP9L1vUnkUdefVl/6RxzztjvRyt1T29qCHq8oFT0wAH/SKT2nYzMNjbfiK3DZ2M8pQZwtfqx3p+7rCqAw+Rkuop3jQ1vLwt60XpQb/0yfetkx77FrMivA3PmYBfrT/nCTjAWqZ+RbDxCNTjqEC8GhjKj+TSqmOhEBSWMrJ4OAh4Dqi4nGGl+8EaywI6+veZqoGg/Dkl35hvatwFU59qsrPoUryfylRxTyaivq01J8KLitF8gN+SxQR5T9Mw3rxKkFy5I5ssfHWyB5rIbDL2qRr/AOpX/rLcM1myXA9OhUPwBROO5enI208hdCbybIdSRd3o6hPJYXZG+jAaPX7kZhYww4G5slUxJy3u+rs/ya7Y0GE9jDAvVmkhvjJa+znjp0k7mVoYyyQ/dPoRK4uw9ZaJ5Ld1vGbBHRQdjHz5TZAVlZGyGkgP8sM76A0bzPdHo94qzHHodreJc0fUQZTsVLampJG1WqE9XH18JnYaP2NAkd1gjG2vtald8pJbNJoNa43rpq6qbCz5YDktYmu8wVT8dT9K4AI4Wlfr76/9I4SkmOpATfjOt9VccBWGKTi58N+SuiHJGS2bm7fkH1kuNDK/IoeM1mCc0mqAjN0APRchRjytmPcHIGFm5xHRGM4WdzYcfdj+l3D6mCJOWZ96SaEJjAUdtvFqy4aIgTzWVmS1FM4pH+FKgJ3oekygssZ5ZaATzPOclqogUowCli95NXe083AiiiZI/yfuOmGhTMttnsoQrzRB/0l45IvLmFccDieZaXCAveBCkFERlZPq8zYxCnbTZ8C3g06XnMA4mI1NYbs7LNa97DyF5AXhO820iMpuEaykMYluwQ3Pp4xaolO6s6lx755zHmYwvsHKRQbBoKInqPOfxieHp9fD5aPk+TCmPC9jEY9rTOO47xZSruy7hjJEYCsL8of2XsiibB83lV8CaVi8Q1f50yr0+40JgMa2dorXC09JgDPUe0fHWO5R7WHC5RrWmFm69viHFL8McSTzrtRT3OleORA2WuUxkY0vIHSmgnTcQlUk5cVyIJ7sgaVKK+1jf5JQ3kET/0rRItBN0xdkQruBhZJgpEspwwvuviQkZ0PYIZZiW2LcBSypRBBPQfWBBLgWxQCmospVsgB1KrQKcvd9QaecrEP49v/xw5v6xncJJO0rKx/6utzixjoCQgH4hZj9oMt8AW+k/bU62jvRoUIzT13kET/6Vc++4uUHTc4qb7g6qPKonJTcO9+iYnDIhUwtP2dFTV2wf5hfKowt3yx30yDc4hIxCdCamYbVKz7M7g/B4xbQtzktEDvwfmjFXS2YTYjbrz9/VNc82CM3EN/2MX8lCKgpF1EISZYgQupuEnoJuJKQGlCR2rvXpQruLezcCoRZe824LpAzBIOAx/JPlccutMCfVUrYJRaWnxxEh2LfFmPnbuei7G7/GH+ba0WXrZawc8T0vFFHpMLG3OQHw93kFfqq2/xQvGm+bxjL4YUJwQhoVouZ1/C0Qisjt455kNQZJcsdj4AZ3BzqHPJYjkRawo7pYfLNRE8iNkCqIXYBvzOJtiOgBumh51WNR5qmuUGhdYOT87vx37XmBuAD7OLCiuE1pNPg82flZ7/M7SgV/nk0MDDaTKEKUQihTjpThYk6FEou/mGGQF6cUOgVcnZNGwrbqiQdWSDQOkYukHcmAUrTFDDeiwKYbGx6U9JcGAzcPfs7+VySbRWmBFVL5Y/Z7lv38E0euEPL5qaAplNAr2+jf1O9KiMFj6B3g5ZukGg8UGFazrCgFyPcbJs4A2yfVw08CbJjuWAvWb1y6X1hN4K327T4N2cNSCoF9S3DqAG/qDQV0OySr3sQGaHad8VMQQhSCYfuqu9EcVjfPcyrH554CkWGBrdB+kLlmC2OIQuOjJZpq2IJliHzw4U87Y6L2WGVodUWNth3GR2jut2c3X/8KAT0STvdWraApCrni1W+ioWVY566pYwvCzvFLpo8Lppn5erhKoGA7Mt6MF0jZTNI2uBWYydGbun1U7HxIEACFutXunLO12JdBHqzbm1RTHudmaBwx/LPneH8EnmZBS8glMALNcAPKMxR4a4e/4ze5poslwRiF4ondJOmxfMlhh2hVTJg14TzcKRGunyLJoUAFfOifS4LpKtBjuQDLuuPN6ireIoM7LNtnd2zcxCBHzmLZPA/mQrAd2WP+ICrMIJ/Sm93a0W0woJCoJRJJf/hpU9Ec/rYXwi9OdFts2ZDbVIIglzdmBEGipwNIO35gQPluBaRN7Su/5havS2ttF5qI8mJUR5bA/DkXNbqRn9p6l+lOnZubr1OXWrhVMqF72D4nzTp3EGmWb2eSGvmxMvHgvocKu8KZtoz5IX8zU/a2BkOo9pXPh5TPrjDXJV9m1qPtZqAmgXAaLJUayW0KUf/5ZusCKPYU8XmOx+I7OHX1uwMO/S4+IGUFZ18ccy963q9/OyyuFOF6Qo97PUQTRupPamfIq8uMiUdVj/2F4CYcV+AbFvj5zIAz6IzSjRtN/KBL/KpiI6eeJyqHpyepyBbd3iV5CqWX55/d+yjP7y45KLf9qqmyfcFRJwfRansb8eMN3VegaXHwZ3yAdtFQoo/YJL69xsSnxAJJQW5I0/R0zGg4wnU691W2cgxXMNtoQXv07p+F1d/pEG/Bnwo6Px+2K27NqTVQ1/2s5TRoLJzATObEo0b7+lEa5sh+o3ryPtnMUCsx+DF1LKtwt1bSicnEvzjHQGd2d9wyT3LspKmMQieu+ASmeXeb3CLAvPgG9H+9hUJa5WFDezpPPFQAcjzP5OMVYRTqLFvYbKNFLkqb7J8FI3KYJVMf93z0c+jY3Y/vvbP2j6b9QqsEA556Yq7Oi2XggTu9ncAN+RuhaVwn0JhMpH13BHEgZqQRuz8LEz8CNkqUFTLM9weeq9gAtbm4g12cupkoxCPJWfnbFO1j2Prt6D2KpMBdVeUB72EBwxGkLYdDRC2pV9vxT0gJ64K9NPOvgk/OeiD0VLXC8Jpd+7ZqTCafDQPSPXA0DE70RuSdNGqgUP1M0hzvM8hFNgRI636aNqHK6mGeJcZqlz/ZjY1d/gotLNjmuBUaADfYXrvWyrgGLCHpfNEa4V5yhuHb/5aiO6gnnmuUIV34zwMEUX2TsmHtdwRa9BMMw3AMEx8oOSiKALylVSLvSa61RiUvH9ctxtzujQiNGA2c/3w3B/ugaBHVmqumwP/uxO9doAszjy34qZNMyrxL4a5/s2ru3NAa8NReZ+gEC8C1FDSOjmjxUSK5UlZUkLrO64RQ3+9hmBSip3nQIi5396DG5zN1IAo8OtQaBlwukW+FNSpNZ1MLlr66aWpiKoxowMXxVb+IjHNavS7CH4mpXqEaPUSwlO0wz4V+RbTeNnvl379xpPHK5gwfFlOch1e+g52idDXTwyGBHc3vQI3uX/4Fz7a0f4QbPKP8lWT0L34JBAJAmGAiLclkG1hyzGpagR2IaaMeooz6U8H0SdYl80DFQSVrqIZ29oFYuN9uEh3fZGU1HsUnhEzilBBKEeMcUO8qjZzA1fngncdAv97Yrgb+CN0SgUnLSbU9HBUh8QhilKAsiXNHcnbaPg+YnZn241zObW6e/UcT50ywdpajtNWTqD5GvpafUzNP03x/SV/1V99ZnKLPgCr3IqTqamdATFhknquj6BCjU+zUT2dwqCnhq4QCf/3L47pQoITWgCk7qiGbXeqsuOqqmkFdu6Hmv2oIXVKGW+tCOovrLSNtWu+vGHwpqVXZ8KCwf3gmpfiPjTDYgpPpFQHJdDV7WfPF7X51hJSMWcjctL+mFq39ukBrv/9mfTfVjf0BeMDhQq0g8lKjGhf+Tepbvj/ZtSeYbk4fCiNmcNzP/QMZVS1/bkTQpz2r0+Ha1BuprsXVs85o48K4E8CIWSlIPwmgmRWiMyCiOQJTJ3ND3uT062Su9Hy6ZTUZIhLRwejiJBooWBQ7iv1poLqFPYpB0DSwHwUqhRaIUK1YkaURJ8Nip1jQwyEHDi2f7YAznWnQkIuyvaRpZxk8rMHfyZcsxJWEnbIRqCZLLgs2pH+5//lIRXn/y6lCwxS5JtMTqIj+BgaJ6taxUA2byvLoqjl2+0V8+BFtmpLcue54+VJDI0xZp5g0FCm5XuQY3jAhRD8eX3JIx6+ylwMv+j5+dK2SsZFC0fPIjkzHnW+s35Maj8LmK4/m2G9qwYYxuMVdtzPW3cROeO8hTRHHIy+0dOR5irBXVb06imq5rM8jHm8XP1d7ihn7cnxk5L0LJTOjOOGAvfaA9EIfq1dPEqigyi4G+0lKlSZ7mTfLJfnPcRfRjxL5rM/V9Own2fZzFIfdpGHwP6edExhhITyNeHi5IBKzf8hfFIeC5O7RMXOWFCmouMHbIs9KGBF+h5RUnTuNtK/4Htb9oXtcB3GDtIAHvacX57Bf9/ESjMP34P4BcMtOnz502TojQC3CrreBh5gB7BhD1yPZliPJUc9qfDV6F1TGXYFGFp8Zy58R9mbMM3bO9E+/sKE51HGhM2hWbMZPHZhK5Tc1X7r9SGc7hGgpJAobguI1w0JJyZoGfeLCPfViSQ6pyR6VKPjovKLDkF3Hu2OT2WGJVJ1ZMQOJ2woRQ7OO63gJ9uRvkPGzZTiyYLNaPQayKnTwBYVzG7/mAO+6nQJSszmheVSBY8lwYJrunNpj562jJv+FkNPDCKMl7+LOc63MMnBwNPwU8J9C6oo37YD6ejJb+cbFYAxWQ4rEqlk++f9S4NyBJ4ep8Sj8gU1t3VCibYA9px6o/vEiJ06jBExJcsNgajsFTzl3EX0DpFlZcA87CNbi9lZetz4fgNOyLVuGbGgB+pdjWPmy8RYAGT7o8ZXlbNMf1lY828FtExLdUIvNSAVlTqiKnP3yzfOsQJYCxct/wM8+EsjSwDkNt37/BAosijw79ksysVOcA7Gy9DpNRrEURXH5XIZbQonjHE7PMRFnA1pYKF0N4LZMdrqnkis6EnqS/CTs5H3ptxiMjAUL4ZDSdwxar2hK7Q45sNqoJYHGqbpKnpCeUC1iHOUi3gxwUTsWv0WTVaw3xuoJpEou6bqYeTtLJgywHGK1f0oxtPK8J0HqUtrLfFti/AMxchzyzaQNkbBLGNVIH6aSro9qysR4Bj1QWkqViuZV8YKlY/g8zuQ1UGNb/Dtj6HBXxe5I6Jj0CetVocqeOc+nCsk5bLQTNjX/ByLDcfSVX8H0Rzt1lR7nuv3CSyp+0HaG0MfYHS5GpJM8yD5jHx1jtejlLIhkvXDMVR6MYT+wByoBo6DwK9jSTp1wLTD07fzvz+ORrmz3afNai7mkc/dkfHUehEkGAKYhyCAABTPC+iPLGrWuNByFGYJNliZUQ9i+dx1Z9gHPT85POWyLR1mQk4jKY8tAl6QoHs4MTaYVlJw1km9/612Lb9jmJ5xiDKaHJ+fPrFj8no6KL5SyNFo3jykeV7tzGRPz4WYozCzRoFBxsdopBYqkyRXCXTnU835f4cKsJBYKxFlnoHi9FZeWQwyZ0amarppnwLalV7/ySgGHd7IGVyyxVzex0tfQ27Ovd7MbeYi1qmnVQd9n+BB34TfZFz+m4nrbHV4RurHRvSWsY7fAiAfJRg5GmY4DeywkmzT+I5WRQNlN9tfUIVfi563mkuIJVpXjIbDH6UrrIvTWcSj6KqhAAktPrmWQQvXzDlnnuiGNq3P/CSMn4RJWwruXA+3fOEvJ1bT2JYfajxu/0c8IkPVDgiIm7MCfz+/93fM3YUbwlT070CnUqvO+1iwnfnmXO9pBzSQu3jizBkKNy+O/xPCbLD2BCFepDK0bE4cypu7KNUv3TPeKCkQT+vz1Xe/jhhMzE9xd4D0NHUBrsAMpC/KzQVl6XVgy29cITXTEbtrwAXMjf45CvoU+iN9d2dKb2VSzUmvuZubMpCRXeBq0AezI6ixWzKUO5rjrJ94QWQZ1Wfr87bX3uZAnROXoxy4rZwS58zrXWRp5wzIGnQQ2dK+ga41Y1Ss5MrpU4Sm672jD5NJAIVnrD2lgwnukVBub9UzCd0QRpCMj14SucPIul7Bd/EjCw86AhP48FyMfEmgOIlY0UNwKDSe1OIi+Imxh8fcUOrkFsDmqyNI5dD0saT8z/Il+fLBiEHYMnLEQOS6IKg1aYyweQ5CPiphhUlbh8B3neILIHjvcH1DOqO8m6wiqIozEl7+ENy/gyCVyiyE58H/CyPZGVpzhwchv4vpZN8mOMNVK5sseeQcVSxj445kQYnhEWflbuzHLnNud+khrzAjDsnq9wt94YCCMcru34oxd6nuwtREVoArA5KeCjtybaOX6OIgWwoawT+td8BlpOoZMkFakBVSvgK5Vmy4bWRPIfLGjqJzCEindAg30DfwwZ0TGhtJkhWfYXSx6lH+VLg4QsvUWFrUWDrT1T1gd3/uJgyvveHtIUPrYz9GcteVl6VvNNfnUspucyBB5iX4XOdUIjW8gFvA+/mf8fgD/DrE5fL7AuzcuvEy1rM1hy6591K+ux4qcoQMNQ8nzLhnWwCsrI+B5b7FmEV16ruG6m6HqgIWPhubii5F5QXQeoDRqviyZ7yYjhGSpJV4T4P/EyeMb15pjqjUSJEXUrvMCnryiC1sq3aQOvY32iwpA7F19FVqR25+tQLfhr6v1ua5ITiHbPYYOt6J3Ci0PfGgBcopZUNjRwRh1AdDyCfM8veETNNjzJB8hj9yH1f4AAF6NXP1MiwWwLOe44vW6qnXIaf6SYjLypxrsNCDHTdSBWe7+LnoGZ66nh5ImxaVusDtq/WeiKEiaq/wAp12J0zt5qS8X9QbkeiFtn9OuyntNoyt1zA+CdCRlq2o25Sd55EoqeTjwW9E06gr+CNotj51ZvJlwsAd1XTJvGA7e4gCYhboQBlMSRf+N4yvJNnSA4BZWhFYSP56HxmlNmTRuqrozVi7c6nWKbyRbDfDF2op3n7rYSFO+t2M5cF/8+S45h8BSdb/ZLkphnjyfzBtvbK9zYwSHUOxbBlCjeRR7zJEwOGt75rfGw8KHLnxVB/RJAEinJqv9Wc4nJhoYasGdkEY1tbi3A9awDEiC2PpGPPDkmiIdLcCeCXueBbv35MAac1dv3oo9CFge56useTRD32pptSIHUVmG8+Nqgm2W7+9cZIH+GdDAm513l61TgRFq4/n33ife44CjLqup/4IfKTB5efDKbtRxVrMd3xfXKGa5Wl/pgXxDH61S/z6Wv2K5q6S5EOM9q82Ro2/zL9DOEXHxabA+3GCzKMhkYbPdr+EJTc9NeT/cSn+FL4k4s6dcOlZ0VZirIfxm80lNEos1EnUfgVNt5u/uSPEwrXknSt0taF7/hwYEtRoHhcvPEzbJWRuYlz9rE3wa+fjk48B94z5ejWJcpJPiIWlSk9y9aAWeAhZw6wpC1mVrCQTgYIhkBxmwsZkfYJ1RtfTEQdG4vwagW+YRUxdJ2GiFUBDlRhGYDv+Qi/6u31hkgphOmTfEWUA618O0qhAU4lFckqYrDWMyCPM8cu3MNJkRJf8SnIhyKjb3IkOcnwMWbsEBTu8r+S6x+dZE45/LmD/0DE7qVgo1eSVtG6UYw3k96whr2vbRAwy0ScxaDuzcS/iXwszK1VBxXy/PUT69A2i86ZZTnk6yN+CNZ2+M5UGNlJyhhV2ZSvsVtcF50zSIWMBY5MmxlnPZgvc6Lqpl5M+kCRkY+Eyx+FD0Xsm/dyy5/9bdt9GKnM/sLf3y8164/qDqSaAzH7chxs7dMg2D5JbKBZZqWTGrsml98E7TvdlDTRM/xDs6L2afEJYOZbdEvwRQhT66xyHjXke+wlEhOa4ZMGaHqdWFKovfcudAJ8vSEl7Al6UdyU65xQ6aJCZkNICLVrb8PF6FSxi4nDEn4NuSDD8JDpMIRMf9juKiHynFti8FXCIq0ogWllW6BhBXjb2XRimfnWn02AIPaeC7KRcwoliTT3RoRMkcfpUq7Z08YEJvvfYkcYANraispm/2scCG8m5dNJJeRcsytTgZxIJTo1NuI4uI1WHrKyAhxmJEYG2hl6vFsHMp67sWjHnu6jo8FMqX4bXuR9ctvk0N5IxOqyg7waKudmvKP82wy3svLTCrCQ0ScHybmVCGK84i5MtvxdAh/wHlHEaP/w18E0A+lHbrBBFJy0vkW92hn4BUtIzNnphW+Ahr5JvoIlWu+nBiF5xZ/0C6FGeKQ0QIr5CdselLNXBKlF27VseK4EMWHTWYqnj4nYJiWrr6yBhOtKuygZlv6PuCC4T1FBLdw5kTsVUUtfiew1xMuYanqXJOY5iVcikQ1OTtY5iOi6maIvgrlqmdEDbtwP9lafU17cYihPdXGhqBVMjvy7afsE5tZvcZa4QsiWr+Pyr9jFYiRhFLOM6W7RXRcLQ6y/MXOBDjrgmTqqR6Fvr4UnHUKF7VfF8nZQXvHkQPgNnVLAkfYW3wXURMtddcGZU8Cs0dsreMBEUsJCImEZ/CedqgT+4y9+O/f2rTcafC8y+u6p07T3lzFCMs8uxvD9Fis+wxU5FLFJFnYGMRSdrESEyGFHzFf3rOO5Sae7BOKijEK3tjDxFJ0l35/m01mnnBfdKr6fq7xyQUCZ1pneHvvNfBmbBdiPjf38zAB4X0y1gOUOKsUjHFkQaBNoy6/ur3ZvHyLG+xA4pp5HX75lmdkT9a08YTOOwdIo4jV2PhkYp4r3A+YRUOrSTAS6ombwQkGHWlv/jnfNiXq8GbJ+RVMA10H3xbY5INyaMcjRMnpoG5G3DFjOEt5teML6TY1MA3s9qtEWyrNuMNL6HANQNFUtgGPKYfIUTiDJv5jz0eujOjk+rVCTtMKG+C3f8VqWbeWtRDVCH9mgn0PDuLNLu/ZPqyEfWF47OI/q5kPFc5T1wPzQE9ufRYUUwnBs2zl9RAAe3bgrPyfEHIqFfxlctVxisBT/WGxXouOOGJzoE4dRb4jLVt+8KCmvvclw0MDSEixc4TBaTK6LpEiSb93h4nkaC24vTvusRGexAQaLsxZyLkmbURochKa7Z/Dkt+pF0+YwdZrGXYU6KMb4bVRgMJOprKMAvAbABNB7DpN1bIKImGAPRb4/Ozx+dYwCusJdHCmFHLzDK8OoxwmE3jqoo2gl4PHjWxCsT+o6Xug4P9X45ch0+AiQgV5yD+g87MOKcpjZzXSJj6U1ffZXwdv8f+p5dA67tVISg9IcQg3yDo+mzIiAdSbWCaKx6Hv+2NT/qk76RrZDJs9MVmb9n2of9H/EOriWpRlQbD3M8N//pdo53lhw36IB4SBxxUY/vvXhJK/87hY/40/My+RyGfu8JxZbnfZzAY3ap8SFMwWLJpX0pXzgjYWYAJV+dhuHmfJ8tqgaYFyCYi8hRUyDRULQMuuiegCeKwnL64K9+/mMyDXjPgkTp8dkpPYaAvlgS6BU/QwC69cO33OVjGLFlVF2HbK6djAYWQuaLlzq3tzQg5OtVOZV/uybrR7LqUFiY4sWLRUtuM3Qz/BE4IQ2loxBfBgXbbvgJdVcESOsfYGFKp5WfjxkewRj20EuDPYq4P0KvJqO3gxURJQvtG1rm8iWfjlEh4CcmGtOjhdLuclgX4RZpNT0Q4hTaP5SEVTgwouEHMkWMfkJ41281iH159UQPiHLFqjoH2Jr4vCxOOzIVFHsqxyeSIMT8xOPmJxptv6Mxg4cqSj+ebRnGO3vyTvGRcA194u8NDzGceUws7bninFZv2T/5EP/rBhPTMswPHfWU2fER6reXfQV4R4zLKMdgurf169XYF/CF/xODNKk71be6oxrLioyBepWdFsM4OTpmdRa7UY6A4z/bWMrsW8Qewvu9U3YaX0pF+hcfodDymDFHkLuXtMlJoYakxhresG6kxeLNnY42Arey0Bk52QEqw0MjbVpAh0iogjjK0+E+ClyCNK7g+hBPcaQ90nE8L0VspKlSEBZ3EXZT7oQpptnXy7wTdT1nj48I7hzbVl99NLkh7c8w3gf7SFDxHAQWCsH7+0M2Y/6q02JW/45jVfuz33K2duJYLSNTVcOzoimGt6ytxRNuM2dJDMmQCSSvmuV2kV6y9LkYUHDXKu+zSdsfbHtPEDI+D85VjD/e2lR26Jy5142Gmm8Ka/MExD7zntg1jfGMP4udLCPEJYKJZSJEz9rmamaq0UZ6EeNl5Khw7IloSc64CyAePm7EuO37pY9fjnZT/S+veW7qNwCUAAALFTQTmkFOONTSTvT24VS8vTIDERR5cOBfJYXUElE7+HsNgVaKqgDFAZuVOlunh+n/HWwFzX1JHsW4inK87BEdkb5bapFi8bRfycWALdUufpRHENQpNvfFpGECmJi63ZqTSC0LHhAFYCphCiLAAAA=', category: CategoryEnum.VROID, - description: `${OFFICIAL_ROLE_NAME} 是 Vidol 的默认角色,是你的专属私人助理`, + description: t('agent.description', { name: OFFICIAL_ROLE_NAME, ns: 'welcome' }), gender: GenderEnum.FEMALE, model: 'https://r2.vidol.chat/agents/vidol-agent-sample-a/model.vrm', name: OFFICIAL_ROLE_NAME, @@ -36,11 +38,11 @@ export const DEFAULT_VIDOL_AGENT: Agent = { export const DEFAULT_AGENT_CONFIG: Agent = { agentId: '', - greeting: '你好呀', + greeting: t('agent.hello', { ns: 'welcome' }), systemRole: '', meta: { - name: '自定义角色', - description: '这是一个自定义角色', + name: t('agent.meta.name', { ns: 'constants' }), + description: t('agent.meta.description', { ns: 'constants' }), avatar: DEFAULT_AGENT_AVATAR_URL, cover: '', gender: GenderEnum.FEMALE, @@ -53,9 +55,9 @@ export const DEFAULT_AGENT_CONFIG: Agent = { }; export const AGENT_GENDER_OPTIONS = [ - { label: '女性', value: GenderEnum.FEMALE }, - { label: '男性', value: GenderEnum.MALE }, - { label: '其他', value: GenderEnum.OTHER }, + { label: t('agent.gender.male', { ns: 'constants' }), value: GenderEnum.FEMALE }, + { label: t('agent.gender.female', { ns: 'constants' }), value: GenderEnum.MALE }, + { label: t('agent.gender.other', { ns: 'constants' }), value: GenderEnum.OTHER }, ]; export const AGENT_CATEGORY_OPTIONS = [ diff --git a/src/constants/i18n.ts b/src/constants/i18n.ts new file mode 100644 index 00000000..ed4b04b8 --- /dev/null +++ b/src/constants/i18n.ts @@ -0,0 +1,16 @@ +// default language +export const DEFAULT_LANG = 'en-US'; +// locale cookie +export const LOBE_LOCALE_COOKIE = 'LOBE_LOCALE'; +// cookie cache days +export const COOKIE_CACHE_DAYS = 30; +// debug mode +export const getDebugConfig = () => ({ + // developer debug mode + DEBUG_MODE: process.env.NEXT_PUBLIC_DEVELOPER_DEBUG === '1', + + // i18n debug mode + I18N_DEBUG: process.env.NEXT_PUBLIC_I18N_DEBUG === '1', + I18N_DEBUG_BROWSER: process.env.NEXT_PUBLIC_I18N_DEBUG_BROWSER === '1', + I18N_DEBUG_SERVER: process.env.NEXT_PUBLIC_I18N_DEBUG_SERVER === '1', +}); diff --git a/src/constants/locale.ts b/src/constants/locale.ts new file mode 100644 index 00000000..d1e105d3 --- /dev/null +++ b/src/constants/locale.ts @@ -0,0 +1,12 @@ +import { normalizeLocale, supportLocales } from '@/locales/resources'; + +export const DEFAULT_LANG = 'en-US'; +export const LOBE_LOCALE_COOKIE = 'LOBE_LOCALE'; + +/** + * Check if the language is supported + * @param locale + */ +export const isLocaleNotSupport = (locale: string) => { + return normalizeLocale(locale) === DEFAULT_LANG || !supportLocales.includes(locale); +}; diff --git a/src/constants/touch.tsx b/src/constants/touch.tsx index c7ea7d9d..6767d1d1 100644 --- a/src/constants/touch.tsx +++ b/src/constants/touch.tsx @@ -1,40 +1,56 @@ import { VRMExpressionPresetName } from '@pixiv/three-vrm'; +import { t } from 'i18next'; import { TouchActionConfig, TouchAreaEnum } from '@/types/touch'; export const TOUCH_AREA_OPTIONS = [ { - label: '头部', + label: t('touch.area.head', { ns: 'constants' }), value: TouchAreaEnum.Head, }, { - label: '手臂', + label: t('touch.area.arm', { ns: 'constants' }), value: TouchAreaEnum.Arm, }, { - label: '腿部', + label: t('touch.area.leg', { ns: 'constants' }), value: TouchAreaEnum.Leg, }, { - label: '胸部', + label: t('touch.area.chest', { ns: 'constants' }), value: TouchAreaEnum.Chest, }, { - label: '腹部', + label: t('touch.area.belly', { ns: 'constants' }), value: TouchAreaEnum.Belly, }, ]; export const TOUCH_EMOTION_OPTIONS = [ - { label: '自然', value: VRMExpressionPresetName.Neutral }, - { label: '开心', value: VRMExpressionPresetName.Happy }, - { label: '生气', value: VRMExpressionPresetName.Angry }, - { label: '伤心', value: VRMExpressionPresetName.Sad }, - { label: '放松', value: VRMExpressionPresetName.Relaxed }, - { label: '惊讶', value: VRMExpressionPresetName.Surprised }, - { label: '眨眼', value: VRMExpressionPresetName.Blink }, - { label: '眨左眼', value: VRMExpressionPresetName.BlinkLeft }, - { label: '眨右眼', value: VRMExpressionPresetName.BlinkRight }, + { + label: t('touch.emotion.natural', { ns: 'constants' }), + value: VRMExpressionPresetName.Neutral, + }, + { label: t('touch.emotion.happy', { ns: 'constants' }), value: VRMExpressionPresetName.Happy }, + { label: t('touch.emotion.angry', { ns: 'constants' }), value: VRMExpressionPresetName.Angry }, + { label: t('touch.emotion.sad', { ns: 'constants' }), value: VRMExpressionPresetName.Sad }, + { + label: t('touch.emotion.relaxed', { ns: 'constants' }), + value: VRMExpressionPresetName.Relaxed, + }, + { + label: t('touch.emotion.surprised', { ns: 'constants' }), + value: VRMExpressionPresetName.Surprised, + }, + { label: t('touch.emotion.blink', { ns: 'constants' }), value: VRMExpressionPresetName.Blink }, + { + label: t('touch.emotion.blinkLeft', { ns: 'constants' }), + value: VRMExpressionPresetName.BlinkLeft, + }, + { + label: t('touch.emotion.blinkRight', { ns: 'constants' }), + value: VRMExpressionPresetName.BlinkRight, + }, ]; export const EMPTY_TTS_CONFIG: TouchActionConfig = { @@ -51,95 +67,95 @@ export const DEFAULT_TOUCH_ACTION_CONFIG_FEMALE: TouchActionConfig = { [TouchAreaEnum.Head]: [ { emotion: VRMExpressionPresetName.Happy, - text: '哇!最喜欢摸摸头!', + text: t('touch.femaleAction.headAction.happyA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Happy, - text: '感觉又充满了力量呢!', + text: t('touch.femaleAction.headAction.happyB', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Happy, - text: '哇塞,这个摸摸头的感觉好神奇!', + text: t('touch.femaleAction.headAction.happyC', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Happy, - text: '摸摸头让我开心一整天!', + text: t('touch.femaleAction.headAction.happyD', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '听说被摸头是会长不高的呢!', + text: t('touch.femaleAction.headAction.angryA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '干嘛戳我呀?', + text: t('touch.femaleAction.headAction.angryB', { ns: 'constants' }), }, ], [TouchAreaEnum.Arm]: [ { emotion: VRMExpressionPresetName.Happy, - text: '啊,好喜欢呢~', + text: t('touch.femaleAction.armAction.happyA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Relaxed, - text: '主人的手好温暖啊~', + text: t('touch.femaleAction.armAction.relaxedA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Happy, - text: '哈哈,牵手让我感到快乐~', + text: t('touch.femaleAction.armAction.happyB', { ns: 'constants' }), }, ], [TouchAreaEnum.Leg]: [ { emotion: VRMExpressionPresetName.Surprised, - text: '让我们保持纯洁的友谊不好吗?', + text: t('touch.femaleAction.legAction.surprisedA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '喂,你是要作死吗?', + text: t('touch.femaleAction.legAction.angryA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '主人的手又不听指挥了吗?', + text: t('touch.femaleAction.legAction.angryB', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '讨厌~会痒的啦~!', + text: t('touch.femaleAction.legAction.angryC', { ns: 'constants' }), }, ], [TouchAreaEnum.Chest]: [ { emotion: VRMExpressionPresetName.Angry, - text: '不可以这样欺负我啦!快把手拿开!', + text: t('touch.femaleAction.chestAction.angryA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '幺幺零吗?这里有个变态一直在摸我!', + text: t('touch.femaleAction.chestAction.angryB', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '再摸的话我可要报警了', + text: t('touch.femaleAction.chestAction.angryC', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Surprised, - text: '干嘛戳我呀!还能不能愉快地聊天了!', + text: t('touch.femaleAction.chestAction.surprisedA', { ns: 'constants' }), }, ], [TouchAreaEnum.Belly]: [ { emotion: VRMExpressionPresetName.Surprised, - text: '是不小心碰到的吧...', + text: t('touch.femaleAction.bellyAction.surprisedA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '干嘛动我呀,小心我咬你哦!', + text: t('touch.femaleAction.bellyAction.angryA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Relaxed, - text: '醒醒,我们之间没有结果的!', + text: t('touch.femaleAction.bellyAction.relaxedA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Relaxed, - text: '讨厌!我可要生气啦!', + text: t('touch.femaleAction.bellyAction.relaxedB', { ns: 'constants' }), }, ], }; @@ -148,67 +164,67 @@ export const DEFAULT_TOUCH_ACTION_CONFIG_MALE: TouchActionConfig = { [TouchAreaEnum.Head]: [ { emotion: VRMExpressionPresetName.Neutral, - text: '当然了,只有你有资格摸我的头', + text: t('touch.maleAction.headAction.neutralA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Neutral, - text: '我可不是什么普通人允许触碰的哦', + text: t('touch.maleAction.headAction.neutralB', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Neutral, - text: '别担心,摸过我的头后,你的运气会大幅提升的', + text: t('touch.maleAction.headAction.neutralC', { ns: 'constants' }), }, ], [TouchAreaEnum.Arm]: [ { emotion: VRMExpressionPresetName.Neutral, - text: '别问我今天吃没吃鸡,先看看我的肱二头肌', + text: t('touch.maleAction.armAction.neutralA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Neutral, - text: '我的手臂可不是随便让人触碰的,你是个例外而已', + text: t('touch.maleAction.armAction.neutralB', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Neutral, - text: '你很勇敢,敢触碰到传说中的麒麟臂', + text: t('touch.maleAction.armAction.neutralC', { ns: 'constants' }), }, ], [TouchAreaEnum.Leg]: [ { emotion: VRMExpressionPresetName.Neutral, - text: '别害怕,我的大力金刚腿不踢傻瓜', + text: t('touch.maleAction.legAction.neutralA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Neutral, - text: '让你碰到我的腿,是不是觉得你的生活完整了许多?', + text: t('touch.maleAction.legAction.neutralB', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Angry, - text: '别靠近我,你这个腿控', + text: t('touch.maleAction.legAction.angryA', { ns: 'constants' }), }, ], [TouchAreaEnum.Chest]: [ { emotion: VRMExpressionPresetName.Neutral, - text: '这不过时我日常修炼成就的胸肌,没什么好惊讶的。', + text: t('touch.maleAction.chestAction.neutralA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.BlinkLeft, - text: '来,哥的胸肌给你靠!', + text: t('touch.maleAction.chestAction.blinkLeftA', { ns: 'constants' }), }, ], [TouchAreaEnum.Belly]: [ { emotion: VRMExpressionPresetName.Neutral, - text: '我的腹肌只是再修炼深藏不露的内力', + text: t('touch.maleAction.bellyAction.neutralA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Happy, - text: '别挠痒痒,小心我笑出腹肌', + text: t('touch.maleAction.bellyAction.happyA', { ns: 'constants' }), }, { emotion: VRMExpressionPresetName.Neutral, - text: '看到我这团腹肌了吗?它们只是藏得比较深罢了', + text: t('touch.maleAction.bellyAction.neutralB', { ns: 'constants' }), }, ], }; diff --git a/src/features/Actions/Agent.tsx b/src/features/Actions/Agent.tsx index 4c2527f7..aabfb209 100644 --- a/src/features/Actions/Agent.tsx +++ b/src/features/Actions/Agent.tsx @@ -3,6 +3,7 @@ import { ActionIcon } from '@lobehub/ui'; import { Popover } from 'antd'; import { PlusCircle } from 'lucide-react'; import { memo, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import Menu, { type MenuProps } from '@/components/Menu'; import { useAgentStore } from '@/store/agent'; @@ -16,25 +17,25 @@ const genderIcons = { const ThemeButton = memo(() => { const createNewAgent = useAgentStore((s) => s.createNewAgent); - + const { t } = useTranslation('features'); const items: MenuProps['items'] = useMemo( () => [ { icon: genderIcons.female, key: 'light', - label: '女性', + label: t('agent.female'), onClick: () => createNewAgent(GenderEnum.FEMALE), }, { icon: genderIcons.male, key: 'auto', - label: '男性', + label: t('agent.male'), onClick: () => createNewAgent(GenderEnum.MALE), }, { icon: genderIcons.other, key: 'dark', - label: '其他', + label: t('agent.other'), onClick: () => createNewAgent(GenderEnum.OTHER), }, ], diff --git a/src/features/Actions/Chat.tsx b/src/features/Actions/Chat.tsx index f99e3c69..f61c9754 100644 --- a/src/features/Actions/Chat.tsx +++ b/src/features/Actions/Chat.tsx @@ -3,6 +3,7 @@ import { Button } from 'antd'; import { useRouter } from 'next/navigation'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { agentSelectors, useAgentStore } from '@/store/agent'; import { useSessionStore } from '@/store/session'; @@ -12,7 +13,7 @@ export default () => { const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s)); const createSession = useSessionStore((s) => s.createSession); - + const { t } = useTranslation('layout'); return ( ); }; diff --git a/src/features/Actions/ClearSession.tsx b/src/features/Actions/ClearSession.tsx index 60dbb078..21b553a2 100644 --- a/src/features/Actions/ClearSession.tsx +++ b/src/features/Actions/ClearSession.tsx @@ -1,6 +1,7 @@ import { App, Button } from 'antd'; import { ButtonType } from 'antd/es/button'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { useAgentStore } from '@/store/agent'; import { useSessionStore } from '@/store/session'; @@ -10,27 +11,28 @@ interface Props { type?: ButtonType; } export default (props: Props) => { - const { text = '立即清除', type = 'primary' } = props; + const { t } = useTranslation('common'); + const { text = t('actions.clearNow'), type = 'primary' } = props; const clearAgentStorage = useAgentStore((s) => s.clearAgentStorage); const clearSessionStorage = useSessionStore((s) => s.clearSessionStorage); const { message, modal } = App.useApp(); const handleClear = () => { modal.confirm({ - cancelText: '取消', + cancelText: t('cancel'), centered: true, - content: '操作无法撤销,清除后数据将无法恢复,请慎重操作', + content: t('actions.clearTip'), okButtonProps: { danger: true, }, - okText: '确定', + okText: t('confirm'), onOk: () => { clearSessionStorage(); clearAgentStorage().then(() => { - message.success('清除成功'); + message.success(t('actions.clearSuccess')); }); }, - title: '确认清除所有会话消息?', + title: t('actions.clearTitle'), }); }; diff --git a/src/features/Actions/Dance.tsx b/src/features/Actions/Dance.tsx index 3b596f00..c2e44aaf 100644 --- a/src/features/Actions/Dance.tsx +++ b/src/features/Actions/Dance.tsx @@ -1,18 +1,19 @@ import { ActionIcon } from '@lobehub/ui'; import { Music } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { useGlobalStore } from '@/store/global'; export default () => { const [openPanel] = useGlobalStore((s) => [s.openPanel]); - + const { t } = useTranslation('panel'); return ( { openPanel('dance'); }} - title={'音乐与舞蹈'} + title={t('dance.musicAndDance')} /> ); }; diff --git a/src/features/Actions/Discord.tsx b/src/features/Actions/Discord.tsx index ffb15264..2467d6eb 100644 --- a/src/features/Actions/Discord.tsx +++ b/src/features/Actions/Discord.tsx @@ -1,6 +1,7 @@ import { SiDiscord } from '@icons-pack/react-simple-icons'; import { ActionIcon } from '@lobehub/ui'; import { createStyles, useTheme } from 'antd-style'; +import { useTranslation } from 'react-i18next'; const useStyles = createStyles(({ css, token }) => { return { @@ -21,12 +22,13 @@ const useStyles = createStyles(({ css, token }) => { export default () => { const { styles } = useStyles(); const theme = useTheme(); + const { t } = useTranslation('features'); return ( window.open('https://discord.gg/8Gq83ZCK9u', '_blank')} style={{ border: `1px solid ${theme.colorFillSecondary}` }} /> diff --git a/src/features/Actions/History.tsx b/src/features/Actions/History.tsx index e2aef6fd..cb2b5b11 100644 --- a/src/features/Actions/History.tsx +++ b/src/features/Actions/History.tsx @@ -1,20 +1,22 @@ import { ActionIcon } from '@lobehub/ui'; import { Popconfirm } from 'antd'; import { Eraser } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { useSessionStore } from '@/store/session'; const History = () => { const [clearHistory] = useSessionStore((s) => [s.clearHistory]); + const { t } = useTranslation('common'); return ( - + ); }; diff --git a/src/features/Actions/Market.tsx b/src/features/Actions/Market.tsx index 40e3f59b..c26019cc 100644 --- a/src/features/Actions/Market.tsx +++ b/src/features/Actions/Market.tsx @@ -1,17 +1,18 @@ import { ActionIcon } from '@lobehub/ui'; import { PlusCircle } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { DESKTOP_HEADER_ICON_SIZE } from '@/constants/token'; import { useGlobalStore } from '@/store/global'; export default () => { const openPanel = useGlobalStore((s) => s.openPanel); - + const { t } = useTranslation('features'); return ( openPanel('market')} - title={'发现'} + title={t('actions.market')} size={DESKTOP_HEADER_ICON_SIZE} /> ); diff --git a/src/features/Actions/Record.tsx b/src/features/Actions/Record.tsx index 3d8cad12..23b02a5e 100644 --- a/src/features/Actions/Record.tsx +++ b/src/features/Actions/Record.tsx @@ -1,13 +1,14 @@ import { ActionIcon } from '@lobehub/ui'; import { Mic } from 'lucide-react'; import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import { useSpeechRecognition } from '@/hooks/useSpeechRecognition'; import { useSessionStore } from '@/store/session'; const Record = () => { const [sendMessage, setMessageInput] = useSessionStore((s) => [s.sendMessage, s.setMessageInput]); - + const { t } = useTranslation('common'); const handleMessageInput = useCallback( (result: string, isFinal: boolean) => { setMessageInput(result); @@ -22,14 +23,7 @@ const Record = () => { const { isRecording, toggleRecord } = useSpeechRecognition({ onMessage: handleMessageInput, }); - return ( - - ); + return ; }; export default Record; diff --git a/src/features/Actions/ResetConfig.tsx b/src/features/Actions/ResetConfig.tsx index 3e80e4f4..c70cbea0 100644 --- a/src/features/Actions/ResetConfig.tsx +++ b/src/features/Actions/ResetConfig.tsx @@ -1,6 +1,7 @@ import { App, Button } from 'antd'; import { ButtonType } from 'antd/es/button'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { useSettingStore } from '@/store/setting'; @@ -9,24 +10,25 @@ interface Props { type?: ButtonType; } export default (props: Props) => { - const { text = '立即重置', type = 'primary' } = props; + const { t } = useTranslation('common'); + const { text = t('actions.resetNow'), type = 'primary' } = props; const resetConfig = useSettingStore((s) => s.resetConfig); const { message, modal } = App.useApp(); const handleReset = () => { modal.confirm({ - cancelText: '取消', + cancelText: t('cancel'), centered: true, - content: '操作无法撤销,重置后数据将无法恢复,请慎重操作', + content: t('actions.resetTip'), okButtonProps: { danger: true, }, - okText: '确定', + okText: t('confirm'), onOk: () => { resetConfig(); - message.success('重置成功'); + message.success(t('actions.resetSuccess')); }, - title: '确认重置所有系统设置?', + title: t('actions.resetTitle'), }); }; diff --git a/src/features/Actions/ShareButton/ShareModal.tsx b/src/features/Actions/ShareButton/ShareModal.tsx index da037aba..5946584e 100644 --- a/src/features/Actions/ShareButton/ShareModal.tsx +++ b/src/features/Actions/ShareButton/ShareModal.tsx @@ -1,6 +1,7 @@ import { Form, type FormItemProps, Modal, type ModalProps } from '@lobehub/ui'; import { Button, Segmented, SegmentedProps, Switch } from 'antd'; import { memo, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { FORM_STYLE } from '@/constants/token'; @@ -45,6 +46,7 @@ const DEFAULT_FIELD_VALUE: FieldType = { const ShareModal = memo(({ onCancel, open }) => { const [fieldValue, setFieldValue] = useState(DEFAULT_FIELD_VALUE); const [tab, setTab] = useState(Tab.Screenshot); + const { t } = useTranslation('features'); const [shareLoading, shareToShareGPT] = useSessionStore((s) => [ s.shareLoading, s.shareToShareGPT, @@ -54,11 +56,11 @@ const ShareModal = memo(({ onCancel, open }) => { const options: SegmentedProps['options'] = useMemo( () => [ { - label: '截图', + label: t('share.screenshot'), value: Tab.Screenshot, }, { - label: 'ShareGPT', + label: t('share.shareGPT'), value: Tab.ShareGPT, }, ], @@ -69,7 +71,7 @@ const ShareModal = memo(({ onCancel, open }) => { () => [ { children: , - label: '包含助手角色设定', + label: t('share.withSystemRole'), minWidth: undefined, name: 'withSystemRole', valuePropName: 'checked', @@ -77,7 +79,7 @@ const ShareModal = memo(({ onCancel, open }) => { { children: , hidden: tab !== Tab.Screenshot, - label: '包含背景图片', + label: t('share.withBackground'), minWidth: undefined, name: 'withBackground', valuePropName: 'checked', @@ -85,7 +87,7 @@ const ShareModal = memo(({ onCancel, open }) => { { children: , hidden: tab !== Tab.Screenshot, - label: '包含页脚', + label: t('share.withFooter'), minWidth: undefined, name: 'withFooter', valuePropName: 'checked', @@ -93,7 +95,7 @@ const ShareModal = memo(({ onCancel, open }) => { { children: , hidden: tab !== Tab.Screenshot, - label: '图片格式', + label: t('share.imageType'), minWidth: undefined, name: 'imageType', }, @@ -110,7 +112,7 @@ const ShareModal = memo(({ onCancel, open }) => { <> {tab === Tab.Screenshot && ( )} {tab === Tab.ShareGPT && ( @@ -121,7 +123,7 @@ const ShareModal = memo(({ onCancel, open }) => { size={'large'} type={'primary'} > - 生成 ShareGPT 分享链接 + {t('share.shareToGPT')} )} @@ -129,7 +131,7 @@ const ShareModal = memo(({ onCancel, open }) => { maxHeight={false} onCancel={onCancel} open={open} - title={'分享'} + title={t('share.share')} > (({ className, style }) => { const [isModalOpen, setIsModalOpen] = useState(false); const [shareLoading] = useSessionStore((s) => [s.shareLoading]); - + const { t } = useTranslation('common'); return ( <> (({ className, style }) => { loading={shareLoading} onClick={() => setIsModalOpen(true)} size={DESKTOP_HEADER_ICON_SIZE} - title={'分享'} + title={t('actions.share')} /> setIsModalOpen(false)} open={isModalOpen} /> diff --git a/src/features/Actions/SubmitAgentButton/SubmitAgentModal.tsx b/src/features/Actions/SubmitAgentButton/SubmitAgentModal.tsx index 1f39ffdd..5105fca9 100644 --- a/src/features/Actions/SubmitAgentButton/SubmitAgentModal.tsx +++ b/src/features/Actions/SubmitAgentButton/SubmitAgentModal.tsx @@ -8,6 +8,7 @@ import { kebabCase } from 'lodash-es'; import { Dices } from 'lucide-react'; import qs from 'query-string'; import React, { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import AgentCard from '@/components/agent/AgentCard'; @@ -22,6 +23,7 @@ const SubmitAgentModal = memo(({ open, onCancel }) => { const theme = useTheme(); const currentAgent: Agent = useAgentStore((s) => agentSelectors.currentAgentItem(s), isEqual); const { meta } = currentAgent; + const { t } = useTranslation('features'); const { uploading, uploadAgentData, percent } = useUploadAgent(); @@ -111,34 +113,28 @@ const SubmitAgentModal = memo(({ open, onCancel }) => { type={'primary'} loading={uploading} > - 提交助手 + {t('submit.submitAssistant')} } onCancel={onCancel} open={open} - title={'分享到助手市场'} + title={t('share.shareToMarket')} > - {!isFormPass && ( - - )} + {!isFormPass && } * - agentId 助手标识符 + agentId {t('submit.assistantId')} setAgentId(e.target.value)} - placeholder={'请输入助手的标识符,需要是唯一的,比如 vidol-agent-klee'} + placeholder={t('submit.assistantIdTip')} value={agentId} /> ) : ( setIsModalOpen(true)} size={DESKTOP_HEADER_ICON_SIZE} - title={'分享到助手市场'} + title={shareToMarket} /> )} setIsModalOpen(false)} open={isModalOpen} /> diff --git a/src/features/Actions/ThemeMode/index.tsx b/src/features/Actions/ThemeMode/index.tsx index 6c8925bb..b99273f9 100644 --- a/src/features/Actions/ThemeMode/index.tsx +++ b/src/features/Actions/ThemeMode/index.tsx @@ -3,6 +3,7 @@ import { Popover } from 'antd'; import { useTheme } from 'antd-style'; import { Monitor, Moon, Sun } from 'lucide-react'; import { memo, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import Menu, { type MenuProps } from '@/components/Menu'; import { useGlobalStore } from '@/store/global'; @@ -16,25 +17,25 @@ const themeIcons = { const ThemeButton = memo(() => { const theme = useTheme(); const [themeMode, switchThemeMode] = useGlobalStore((s) => [s.themeMode, s.setThemeMode]); - + const { t } = useTranslation('features'); const items: MenuProps['items'] = useMemo( () => [ { icon: , key: 'auto', - label: '跟随系统', + label: t('theme.auto'), onClick: () => switchThemeMode('auto'), }, { icon: , key: 'light', - label: '亮色模式', + label: t('theme.light'), onClick: () => switchThemeMode('light'), }, { icon: , key: 'dark', - label: '暗黑模式', + label: t('theme.dark'), onClick: () => switchThemeMode('dark'), }, ], diff --git a/src/features/Actions/ToggleChatDialog.tsx b/src/features/Actions/ToggleChatDialog.tsx index 00c35e2d..704d330c 100644 --- a/src/features/Actions/ToggleChatDialog.tsx +++ b/src/features/Actions/ToggleChatDialog.tsx @@ -1,5 +1,6 @@ import { ActionIcon } from '@lobehub/ui'; import { MessageCircle, MessageCircleOff } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { useGlobalStore } from '@/store/global'; @@ -8,12 +9,12 @@ export default () => { s.showChatDialog, s.toggleChatDialog, ]); - + const { t } = useTranslation('layout'); return ( toggleChatDialog()} - title={'对话框'} + title={t('dialog')} /> ); }; diff --git a/src/features/Actions/ToggleChatSideBar.tsx b/src/features/Actions/ToggleChatSideBar.tsx index 88782fd4..53fc5f3f 100644 --- a/src/features/Actions/ToggleChatSideBar.tsx +++ b/src/features/Actions/ToggleChatSideBar.tsx @@ -1,6 +1,7 @@ import { ActionIcon } from '@lobehub/ui'; import { PanelRightClose, PanelRightOpen } from 'lucide-react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { DESKTOP_HEADER_ICON_SIZE } from '@/constants/token'; import { useGlobalStore } from '@/store/global'; @@ -10,12 +11,12 @@ export default () => { s.showChatSidebar, s.toggleChatSideBar, ]); - + const { t } = useTranslation('layout'); return ( toggleChatSideBar()} - title={'侧边栏'} + title={t('siderBar')} size={DESKTOP_HEADER_ICON_SIZE} /> ); diff --git a/src/features/Actions/ToggleSessionList.tsx b/src/features/Actions/ToggleSessionList.tsx index bccfa37f..ad70a2ae 100644 --- a/src/features/Actions/ToggleSessionList.tsx +++ b/src/features/Actions/ToggleSessionList.tsx @@ -1,6 +1,7 @@ import { ActionIcon } from '@lobehub/ui'; import { AlignLeft, ChevronsLeft } from 'lucide-react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { DESKTOP_HEADER_ICON_SIZE } from '@/constants/token'; import { useGlobalStore } from '@/store/global'; @@ -10,12 +11,12 @@ export default () => { s.showSessionList, s.toggleSessionList, ]); - + const { t } = useTranslation('layout'); return ( toggleSessionList()} - title={'会话列表'} + title={t('sessionList')} size={DESKTOP_HEADER_ICON_SIZE} /> ); diff --git a/src/features/Actions/Token.tsx b/src/features/Actions/Token.tsx index cec8c0ef..4a50c205 100644 --- a/src/features/Actions/Token.tsx +++ b/src/features/Actions/Token.tsx @@ -1,4 +1,5 @@ import { TokenTag } from '@lobehub/ui'; +import { useTranslation } from 'react-i18next'; import { OPENAI_MODEL_LIST } from '@/constants/openai'; import { useCalculateToken } from '@/hooks/useCalculateToken'; @@ -7,12 +8,12 @@ import useSessionContext from '@/hooks/useSessionContext'; const Token = () => { const model = useSessionContext()?.sessionAgent?.model; const usedTokens = useCalculateToken(); - + const { t } = useTranslation('features'); return ( item.id === model)?.tokens || 4096} value={usedTokens} - text={{ overload: 'Token 超出', remained: 'Token 剩余', used: 'Token 已使用' }} + text={{ overload: t('token.overload'), remained: t('token.remained'), used: t('token.used') }} /> ); }; diff --git a/src/features/Actions/TokenMini.tsx b/src/features/Actions/TokenMini.tsx index 3804f830..8e543715 100644 --- a/src/features/Actions/TokenMini.tsx +++ b/src/features/Actions/TokenMini.tsx @@ -1,4 +1,5 @@ import { Tooltip, Typography } from 'antd'; +import { useTranslation } from 'react-i18next'; import { OPENAI_MODEL_LIST } from '@/constants/openai'; import { useCalculateToken } from '@/hooks/useCalculateToken'; @@ -8,13 +9,15 @@ const TokenMini = () => { const model = useSessionContext()?.sessionAgent?.model; const usedTokens = useCalculateToken(); + const { t } = useTranslation('features'); const maxValue = OPENAI_MODEL_LIST.find((item) => item.id === model)?.tokens || 4096; return ( - - Token Count: {usedTokens} + + + {t('token.tokenCount')}: {usedTokens} + ); }; - export default TokenMini; diff --git a/src/features/Actions/UnSubscribeButton.tsx b/src/features/Actions/UnSubscribeButton.tsx index a5c6361c..82f51a02 100644 --- a/src/features/Actions/UnSubscribeButton.tsx +++ b/src/features/Actions/UnSubscribeButton.tsx @@ -1,5 +1,6 @@ import { Button, Popconfirm } from 'antd'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { agentSelectors, useAgentStore } from '@/store/agent'; import { useSessionStore } from '@/store/session'; @@ -8,21 +9,22 @@ export default () => { const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s)); const removeLocalAgent = useAgentStore((s) => s.removeLocalAgent); const removeSession = useSessionStore((s) => s.removeSession); + const { t } = useTranslation(['common', 'role']); return ( { if (!currentAgent) return; removeLocalAgent(currentAgent.agentId); removeSession(currentAgent.agentId); }} - title="取消订阅?" + title={t('actions.unsubscribe') + '?'} > - + ); }; diff --git a/src/features/Actions/Video.tsx b/src/features/Actions/Video.tsx index a97c4f7e..9791201d 100644 --- a/src/features/Actions/Video.tsx +++ b/src/features/Actions/Video.tsx @@ -1,5 +1,6 @@ import { ActionIcon } from '@lobehub/ui'; import { Video, VideoOff } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { DESKTOP_HEADER_ICON_SIZE } from '@/constants/token'; import { useSessionStore } from '@/store/session'; @@ -9,12 +10,12 @@ export default () => { setViewerMode: s.setViewerMode, viewerMode: s.viewerMode, })); - + const { t } = useTranslation('features'); return ( { if (viewerMode) { setViewerMode(false); diff --git a/src/features/Actions/ViewerMode.tsx b/src/features/Actions/ViewerMode.tsx index 604fbb5f..81850a6c 100644 --- a/src/features/Actions/ViewerMode.tsx +++ b/src/features/Actions/ViewerMode.tsx @@ -1,4 +1,5 @@ import { Segmented } from 'antd'; +import { useTranslation } from 'react-i18next'; import { useSessionStore } from '@/store/session'; @@ -7,6 +8,7 @@ const ViewerMode = () => { setViewerMode: s.setViewerMode, viewerMode: s.viewerMode, })); + const { t } = useTranslation('features'); return ( { } }} options={[ - { label: '聊天', value: 'false' }, - { label: '视频', value: 'true' }, + { label: t('mode.chat'), value: 'false' }, + { label: t('mode.video'), value: 'true' }, ]} value={viewerMode ? 'true' : 'false'} /> diff --git a/src/features/Actions/Voice.tsx b/src/features/Actions/Voice.tsx index 30a0fc03..be0dd6f5 100644 --- a/src/features/Actions/Voice.tsx +++ b/src/features/Actions/Voice.tsx @@ -2,6 +2,7 @@ import { ActionIcon } from '@lobehub/ui'; import { createStyles } from 'antd-style'; import classNames from 'classnames'; import { Volume2, VolumeXIcon } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { DESKTOP_HEADER_ICON_SIZE } from '@/constants/token'; import { toggleVoice } from '@/services/chat'; @@ -20,14 +21,14 @@ const useStyles = createStyles(({ token, css }) => ({ const VoiceSwitch = () => { const { styles } = useStyles(); const [voiceOn] = useSessionStore((s) => [s.voiceOn]); - + const { t } = useTranslation('common'); return ( ); }; diff --git a/src/features/AgentViewer/ToolBar/index.tsx b/src/features/AgentViewer/ToolBar/index.tsx index 3c0139b4..4b451772 100644 --- a/src/features/AgentViewer/ToolBar/index.tsx +++ b/src/features/AgentViewer/ToolBar/index.tsx @@ -1,6 +1,7 @@ import { ActionIconGroup } from '@lobehub/ui'; import { Grid3x3, LandPlot, Orbit, RotateCw, SwitchCamera } from 'lucide-react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { Viewer } from '@/features/vrmViewer/viewer'; @@ -12,22 +13,23 @@ interface ToolBarProps { const ToolBar = (props: ToolBarProps) => { const { style, className, viewer } = props; + const { t } = useTranslation('features'); const dropdownMenu = [ { icon: SwitchCamera, key: 'cameraHelper', - label: '镜头辅助', + label: t('toolBar.cameraHelper'), }, { icon: Orbit, key: 'cameraControl', - label: '镜头控制', + label: t('toolBar.cameraControl'), }, { icon: LandPlot, key: 'floor', - label: '切换地板', + label: t('toolBar.floor'), }, ]; @@ -40,12 +42,12 @@ const ToolBar = (props: ToolBarProps) => { { icon: RotateCw, key: 'resetCamera', - label: '重置镜头', + label: t('toolBar.resetCamera'), }, { icon: Grid3x3, key: 'grid', - label: '网格', + label: t('toolBar.grid'), }, ]} onActionClick={(action) => { diff --git a/src/features/AgentViewer/index.tsx b/src/features/AgentViewer/index.tsx index d179971a..cd116c96 100644 --- a/src/features/AgentViewer/index.tsx +++ b/src/features/AgentViewer/index.tsx @@ -1,6 +1,7 @@ import { Progress } from 'antd'; import classNames from 'classnames'; import React, { memo, useCallback, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; import PageLoading from '@/components/PageLoading'; import { useLoadModel } from '@/hooks/useLoadModel'; @@ -25,6 +26,7 @@ function AgentViewer(props: Props) { const { styles } = useStyles(); const ref = useRef(null); const viewer = useGlobalStore((s) => s.viewer); + const { t } = useTranslation('features'); const { downloading, percent, fetchModelBlob } = useLoadModel(); @@ -61,7 +63,7 @@ function AgentViewer(props: Props) { {downloading ? ( } className={styles.loading} /> diff --git a/src/features/AudioPlayer/MiniPlayer/index.tsx b/src/features/AudioPlayer/MiniPlayer/index.tsx index 0c0a74ab..f1a5fd7e 100644 --- a/src/features/AudioPlayer/MiniPlayer/index.tsx +++ b/src/features/AudioPlayer/MiniPlayer/index.tsx @@ -3,6 +3,7 @@ import { Tooltip } from 'antd'; import { createStyles } from 'antd-style'; import { ListMusic } from 'lucide-react'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { DESKTOP_HEADER_ICON_SIZE } from '@/constants/token'; @@ -37,6 +38,7 @@ interface Props { export default (props: Props) => { const { style, className } = props; const [open, setOpen] = useState(false); + const { t } = useTranslation('common'); const [playlist, currentPlay] = useDanceStore((s) => [ s.playlist, playListSelectors.currentPlay(s), @@ -59,7 +61,7 @@ export default (props: Props) => { setOpen(true)} - title={'播放列表'} + title={t('playlist')} size={DESKTOP_HEADER_ICON_SIZE} /> diff --git a/src/features/AudioPlayer/PlayList/Item/index.tsx b/src/features/AudioPlayer/PlayList/Item/index.tsx index d77e813c..67b19886 100644 --- a/src/features/AudioPlayer/PlayList/Item/index.tsx +++ b/src/features/AudioPlayer/PlayList/Item/index.tsx @@ -3,6 +3,7 @@ import { useHover } from 'ahooks'; import { List, Typography, theme } from 'antd'; import { Pause, Play, Trash2 } from 'lucide-react'; import { memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; import { useDanceStore } from '@/store/dance'; import { playListSelectors } from '@/store/dance/selectors/playlist'; @@ -21,6 +22,8 @@ const PlayItem = (props: PlayItemProps) => { const { playItemId } = props; const { styles } = useStyles(); const { token } = theme.useToken(); + const { t } = useTranslation('common'); + const { playItem, removePlayItem, currentPlayId, isPlaying, setIsPlaying, getDanceItemByPlayId } = useDanceStore((s) => ({ clearPlayList: s.clearPlayList, @@ -45,7 +48,7 @@ const PlayItem = (props: PlayItemProps) => { removePlayItem(playItemId)} size="small" /> @@ -78,7 +81,7 @@ const PlayItem = (props: PlayItemProps) => { > diff --git a/src/features/AudioPlayer/PlayList/index.tsx b/src/features/AudioPlayer/PlayList/index.tsx index 9f3a5eee..bca854f9 100644 --- a/src/features/AudioPlayer/PlayList/index.tsx +++ b/src/features/AudioPlayer/PlayList/index.tsx @@ -2,6 +2,7 @@ import { DeleteOutlined } from '@ant-design/icons'; import { Button, Drawer, List } from 'antd'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { SIDEBAR_WIDTH } from '@/constants/token'; import { DanceStore, useDanceStore } from '@/store/dance'; @@ -25,12 +26,13 @@ const PlayList = (props: PlayListProps) => { const { open = false, onClose } = props; const { styles } = useStyles(); const { playlist, clearPlayList } = useDanceStore((s) => playListSelectors(s)); + const { t } = useTranslation('common'); return ( } onClick={() => clearPlayList()} size="small"> - 清空 + {t('actions.clearAll')} } onClose={onClose} @@ -40,7 +42,7 @@ const PlayList = (props: PlayListProps) => { body: styles.body, header: styles.header, }} - title="播放列表" + title={t('playlist')} width={SIDEBAR_WIDTH} getContainer={false} > diff --git a/src/features/AudioPlayer/index.tsx b/src/features/AudioPlayer/index.tsx index 55d1c5f3..0dfd1d95 100644 --- a/src/features/AudioPlayer/index.tsx +++ b/src/features/AudioPlayer/index.tsx @@ -4,6 +4,7 @@ import classNames from 'classnames'; import { isEqual } from 'lodash-es'; import { ListMusic } from 'lucide-react'; import React, { memo, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import Control from '@/features/AudioPlayer/Control'; import Duration from '@/features/AudioPlayer/Duration'; @@ -41,6 +42,7 @@ function Player(props: PlayerProps) { const { downloading: audioDownloading, percent: audioPercent, fetchAudioUrl } = useLoadAudio(); const { downloading: danceDownloading, percent: dancePercent, fetchDanceBuffer } = useLoadDance(); + const { t } = useTranslation('common'); const { styles } = useStyles(); @@ -96,11 +98,11 @@ function Player(props: PlayerProps) {
- {currentPlay?.name || '请从舞蹈列表中选取'} + {currentPlay?.name || t('selectInDanceList')}
- setOpen(true)} title={'播放列表'} /> + setOpen(true)} title={t('playlist')} />
diff --git a/src/features/ChatInfo/Operations/index.tsx b/src/features/ChatInfo/Operations/index.tsx index 895efd2c..73b0d6a9 100644 --- a/src/features/ChatInfo/Operations/index.tsx +++ b/src/features/ChatInfo/Operations/index.tsx @@ -2,6 +2,7 @@ import { ExclamationCircleFilled } from '@ant-design/icons'; import { Modal } from 'antd'; import { Eraser, Music } from 'lucide-react'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { useGlobalStore } from '@/store/global'; import { useSessionStore } from '@/store/session'; @@ -17,7 +18,7 @@ export interface MyListProps { const Operations = memo(({ mobile }) => { const [openPanel] = useGlobalStore((s) => [s.openPanel]); const [clearHistory] = useSessionStore((s) => [s.clearHistory]); - + const { t } = useTranslation(['panel', 'common']); const items = [ // { // icon: SquarePen, @@ -50,22 +51,22 @@ const Operations = memo(({ mobile }) => { { icon: Music, key: 'music', - label: '音乐与舞蹈', + label: t('dance.musicAndDance'), onClick: () => { openPanel('dance'); }, }, { icon: Eraser, - label: '清除上下文', + label: t('actions.clearContext'), key: 'context', onClick: () => { confirm({ - title: '确定删除历史消息?', + title: t('actions.clearHistoryTitle'), icon: , - content: '该操作不可逆,请谨慎操作', - okText: '确定', - cancelText: '取消', + content: t('actions.clearHistoryTip'), + okText: t('confirm'), + cancelText: t('cancel'), onOk() { clearHistory(); }, diff --git a/src/features/ChatInput/Footer/index.tsx b/src/features/ChatInput/Footer/index.tsx index 467913cf..6c5148ae 100644 --- a/src/features/ChatInput/Footer/index.tsx +++ b/src/features/ChatInput/Footer/index.tsx @@ -1,10 +1,15 @@ import { ChatSendButton } from '@lobehub/ui'; +import { useTranslation } from 'react-i18next'; import useChatInput from '../../../hooks/useSendMessage'; const Footer = () => { const onSend = useChatInput(); - return ; + const { t } = useTranslation('common'); + + return ( + + ); }; export default Footer; diff --git a/src/features/ChatInput/TextArea.tsx b/src/features/ChatInput/TextArea.tsx index fab79424..c54af3d5 100644 --- a/src/features/ChatInput/TextArea.tsx +++ b/src/features/ChatInput/TextArea.tsx @@ -2,6 +2,7 @@ import { TextArea } from '@lobehub/ui'; import { createStyles } from 'antd-style'; import { TextAreaRef } from 'antd/es/input/TextArea'; import React, { memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; import useChatInput from '@/hooks/useSendMessage'; import { useSessionStore } from '@/store/session'; @@ -35,6 +36,7 @@ const InputArea = memo(({ setExpand }) => { const ref = useRef(null); const isChineseInput = useRef(false); const onSend = useChatInput(); + const { t } = useTranslation('common'); const [loading, messageInput, setMessageInput] = useSessionStore((s) => [ !!s.chatLoadingId, @@ -75,7 +77,7 @@ const InputArea = memo(({ setExpand }) => { send(e); }} - placeholder="请输入内容开始聊天" + placeholder={t('startChat')} ref={ref} type={'pure'} value={messageInput} diff --git a/src/features/ChatItem/Actions/Assistant.tsx b/src/features/ChatItem/Actions/Assistant.tsx index 876c10ad..bd456d38 100644 --- a/src/features/ChatItem/Actions/Assistant.tsx +++ b/src/features/ChatItem/Actions/Assistant.tsx @@ -2,19 +2,21 @@ import { ActionIconGroup } from '@lobehub/ui'; import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup'; import { Play } from 'lucide-react'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import type { RenderAction } from '@/features/ChatItem/type'; import { useChatListActionsBar } from '@/hooks/useChatListActionsBar'; const AssistantActionsBar: RenderAction = ({ onActionClick, id }) => { const { copy, regenerate, divider, del, delAndRegenerate, edit } = useChatListActionsBar(); + const { t } = useTranslation('common'); if (id === 'default') return; const tts = { icon: Play, key: 'tts', - label: '语音合成', + label: t('ttsCombine'), } as ActionIconGroupItems; return ( diff --git a/src/features/ChatItem/Actions/System.tsx b/src/features/ChatItem/Actions/System.tsx index 15a979d6..859e3513 100644 --- a/src/features/ChatItem/Actions/System.tsx +++ b/src/features/ChatItem/Actions/System.tsx @@ -1,11 +1,13 @@ import { ActionIconGroup, useChatListActionsBar } from '@lobehub/ui'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import type { RenderAction } from '@/features/ChatItem/type'; const SystemActionsBar: RenderAction = ({ onActionClick }) => { + const { t } = useTranslation('common'); const { del } = useChatListActionsBar({ - delete: '删除', + delete: t('actions.del'), }); return ( diff --git a/src/features/ChatItem/Actions/index.tsx b/src/features/ChatItem/Actions/index.tsx index 162c4e65..0d7128ee 100644 --- a/src/features/ChatItem/Actions/index.tsx +++ b/src/features/ChatItem/Actions/index.tsx @@ -1,6 +1,7 @@ import { copyToClipboard } from '@lobehub/ui'; import { App } from 'antd'; import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import { OnActionsClick, RenderAction } from '@/features/ChatItem/type'; import { handleSpeakAi } from '@/services/chat'; @@ -23,12 +24,13 @@ export const useActionsClick = (): OnActionsClick => { s.regenerateMessage, ]); const { message } = App.useApp(); + const { t } = useTranslation('common'); return useCallback(async (action, { id, content, error }) => { switch (action.key) { case 'copy': { await copyToClipboard(content); - message.success('复制成功'); + message.success(t('actions.copySuccess')); break; } diff --git a/src/features/ChatItem/Error/ApiKeyForm.tsx b/src/features/ChatItem/Error/ApiKeyForm.tsx index a6e1b17f..0638423d 100644 --- a/src/features/ChatItem/Error/ApiKeyForm.tsx +++ b/src/features/ChatItem/Error/ApiKeyForm.tsx @@ -2,6 +2,7 @@ import { Icon } from '@lobehub/ui'; import { Button, Input } from 'antd'; import { Network } from 'lucide-react'; import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Center, Flexbox } from 'react-layout-kit'; import { useSessionStore } from '@/store/session'; @@ -15,6 +16,7 @@ interface APIKeyFormProps { const APIKeyForm = ({ id }: APIKeyFormProps) => { const [showProxy, setShow] = useState(false); + const { t } = useTranslation('features'); const [currentOpenAIConfig, setConfig] = useSettingStore((s) => [ configSelectors.currentOpenAIConfig(s), @@ -27,8 +29,8 @@ const APIKeyForm = ({ id }: APIKeyFormProps) => {
{ }} type={'text'} > - 添加 OpenAI 代理地址(可选) + {t('feature.addProxy')} )} @@ -70,14 +72,14 @@ const APIKeyForm = ({ id }: APIKeyFormProps) => { style={{ marginTop: 8 }} type={'primary'} > - 确认并重试 + {t('feature.comfirmRetry')}
diff --git a/src/features/ChatItem/index.tsx b/src/features/ChatItem/index.tsx index 6f3531bf..768a465f 100644 --- a/src/features/ChatItem/index.tsx +++ b/src/features/ChatItem/index.tsx @@ -3,6 +3,7 @@ import { createStyles } from 'antd-style'; import classNames from 'classnames'; import isEqual from 'fast-deep-equal'; import { ReactNode, memo, useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import ChatItem, { ChatItemProps } from '@/components/ChatItem'; import { CHAT_INPUT_WIDTH } from '@/constants/token'; @@ -43,6 +44,7 @@ const Item = memo( ({ index, id, showTitle = false, type = 'block', className }) => { const { styles } = useStyles(); const [editing, setEditing] = useState(false); + const { t } = useTranslation('common'); const item = useSessionStore((s) => { const chats = sessionSelectors.currentChatsWithGreetingMessage(s); @@ -104,9 +106,9 @@ const Item = memo( )} showTitle={showTitle} text={{ - cancel: '取消', - confirm: '确定', - edit: '编辑', + cancel: t('cancel'), + confirm: t('confirm'), + edit: t('actions.edit'), }} time={item.updatedAt || item.createdAt} type={type} diff --git a/src/features/ChatList/BackBottom/index.tsx b/src/features/ChatList/BackBottom/index.tsx index 7d7c70d1..9918ff90 100644 --- a/src/features/ChatList/BackBottom/index.tsx +++ b/src/features/ChatList/BackBottom/index.tsx @@ -2,6 +2,7 @@ import { Icon } from '@lobehub/ui'; import { Button } from 'antd'; import { ListEnd } from 'lucide-react'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { useStyles } from './style'; @@ -12,6 +13,7 @@ export interface BackBottomProps { const BackBottom = memo(({ visible, onScrollToBottom }) => { const { styles, cx } = useStyles(); + const { t } = useTranslation('common'); return ( ); }); diff --git a/src/features/DebugUI/index.tsx b/src/features/DebugUI/index.tsx index 534d9536..388b03ed 100644 --- a/src/features/DebugUI/index.tsx +++ b/src/features/DebugUI/index.tsx @@ -4,6 +4,7 @@ import { Icon } from '@lobehub/ui'; import { FloatButton } from 'antd'; import { LucideBugPlay } from 'lucide-react'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { AGENT_STORAGE_KEY } from '@/store/agent'; import { DANCE_STORAGE_KEY } from '@/store/dance'; @@ -13,6 +14,7 @@ import { SETTING_STORAGE_KEY } from '@/store/setting'; import { agents, dances, sessions, settings } from './data'; const DebugUI = memo(() => { + const { t } = useTranslation('common'); return ( { localStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(sessions)); localStorage.setItem(SETTING_STORAGE_KEY, JSON.stringify(settings)); }} - tooltip={'设置 LocalStorage'} + tooltip={t('setLocalStorage')} /> {/* { const isSubscribed = subscribed(agent.agentId); + const { t } = useTranslation('common'); + return ( { - 下载封面 + {t('actions.downloadCover')} - 下载头像 + {t('actions.downloadAvatar')} - 下载模型 + {t('actions.downloadModel')} } @@ -48,7 +51,7 @@ const SubscribeButton = memo((props: SubscribeButtonProps) => { onClick={async () => { if (isSubscribed) { removeLocalAgent(agent.agentId).then(() => { - message.success('已取消订阅'); + message.success(t('actions.unsubscribeSuccess')); }); } else { await fetchAgentData(agent); @@ -56,7 +59,7 @@ const SubscribeButton = memo((props: SubscribeButtonProps) => { }} type={isSubscribed ? 'default' : 'primary'} > - {isSubscribed ? '取消订阅' : '下载订阅'} + {isSubscribed ? t('actions.unsubscribe') : t('actions.downloadSubscribe')} ); diff --git a/src/features/MarketInfo/index.tsx b/src/features/MarketInfo/index.tsx index d7d04aec..0de19114 100644 --- a/src/features/MarketInfo/index.tsx +++ b/src/features/MarketInfo/index.tsx @@ -3,6 +3,7 @@ import { Button } from 'antd'; import { createStyles } from 'antd-style'; import { useRouter } from 'next/navigation'; import React, { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import Author from '@/components/Author'; import AgentCard from '@/components/agent/AgentCard'; @@ -29,6 +30,7 @@ const useStyles = createStyles(({ css, token }) => ({ const Header = () => { const { styles } = useStyles(); const router = useRouter(); + const { t } = useTranslation('chat'); const [tempId, setTempId] = useState(''); const [showAgentSidebar, activateAgent, deactivateAgent, currentAgentItem] = useMarketStore( (s) => [ @@ -58,7 +60,7 @@ const Header = () => { }} type={'primary'} > - 聊天 + {t('chat')} , ); } diff --git a/src/features/MessageInput/index.tsx b/src/features/MessageInput/index.tsx index 221af7e7..9cf16c49 100644 --- a/src/features/MessageInput/index.tsx +++ b/src/features/MessageInput/index.tsx @@ -5,6 +5,7 @@ import { useTheme } from 'antd-style'; import { InputRef } from 'antd/es/input/Input'; import { ChevronUp, CornerDownLeft, LucideCommand } from 'lucide-react'; import React, { memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; import { Center, Flexbox } from 'react-layout-kit'; import StopLoadingIcon from '@/components/StopLoading'; @@ -34,6 +35,7 @@ const InputArea = memo((props: InputAreaProps) => { const onSend = useChatInput(); const { styles } = useStyles(); const theme = useTheme(); + const { t } = useTranslation('common'); const { className, style } = props; @@ -60,10 +62,10 @@ const InputArea = memo((props: InputAreaProps) => { const ShortCuts = ( {enter} - 发送 + {t('actions.send')} / {cmdEnter} - 换行 + {t('actions.warp')} ); @@ -107,7 +109,7 @@ const InputArea = memo((props: InputAreaProps) => { e.preventDefault(); onSend(); }} - placeholder="请输入内容开始聊天" + placeholder={t('inputStartChat')} ref={ref} autoSize={true} type={'block'} @@ -126,7 +128,7 @@ const InputArea = memo((props: InputAreaProps) => { />
-
请谨记:智能体所说的一切都是由 AI 生成的
+
{t('aiAlert')}
{ShortCuts}
diff --git a/src/features/RoleList/List/Elsa/index.tsx b/src/features/RoleList/List/Elsa/index.tsx index 7f74fd2a..f2e87e7d 100644 --- a/src/features/RoleList/List/Elsa/index.tsx +++ b/src/features/RoleList/List/Elsa/index.tsx @@ -1,5 +1,6 @@ import { Space, Tag } from 'antd'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { LOBE_VIDOL_DEFAULT_AGENT_ID } from '@/constants/agent'; import { useAgentStore } from '@/store/agent'; @@ -7,6 +8,7 @@ import { useAgentStore } from '@/store/agent'; import ListItem from '../../ListItem'; const V = memo(() => { + const { t } = useTranslation('common'); const [activeId, activateAgent, defaultAgent] = useAgentStore((s) => [ s.currentIdentifier, s.activateAgent, @@ -23,7 +25,7 @@ const V = memo(() => { title={ {defaultAgent.meta.name} - 默认助手 + {t('defaultAssistant')} } description={defaultAgent.meta.description} diff --git a/src/features/RoleList/List/Item/Actions.tsx b/src/features/RoleList/List/Item/Actions.tsx index c64e9738..1c46698e 100644 --- a/src/features/RoleList/List/Item/Actions.tsx +++ b/src/features/RoleList/List/Item/Actions.tsx @@ -2,6 +2,7 @@ import { ActionIcon } from '@lobehub/ui'; import { App, Dropdown, MenuProps } from 'antd'; import { MessageCircle, MoreVertical, Trash2 } from 'lucide-react'; import { useRouter } from 'next/navigation'; +import { useTranslation } from 'react-i18next'; import { useAgentStore } from '@/store/agent'; import { useSessionStore } from '@/store/session'; @@ -15,6 +16,7 @@ export default (props: ActionsProps) => { const { id, setOpen } = props; const { modal } = App.useApp(); const router = useRouter(); + const { t } = useTranslation('common'); const [removeLocalAgent] = useAgentStore((s) => [s.removeLocalAgent]); const currentAgent = useAgentStore((s) => s.getAgentById(id)); const createSession = useSessionStore((s) => s.createSession); @@ -22,7 +24,7 @@ export default (props: ActionsProps) => { const items: MenuProps['items'] = [ { icon: , - label: '开始聊天', + label: t('startChat'), key: 'chat', onClick: ({ domEvent }) => { domEvent.stopPropagation(); @@ -35,7 +37,7 @@ export default (props: ActionsProps) => { danger: true, icon: , key: 'delete', - label: '删除角色', + label: t('delRole'), onClick: ({ domEvent }) => { domEvent.stopPropagation(); modal.confirm({ @@ -44,9 +46,9 @@ export default (props: ActionsProps) => { onOk: () => { removeLocalAgent(id); }, - okText: '删除', - cancelText: '取消', - title: '确认删除角色以及相关联的会话消息吗?删除后无法恢复, 请谨慎操作!', + okText: t('actions.del'), + cancelText: t('cancel'), + title: t('delAlert'), }); }, }, diff --git a/src/features/RoleList/List/index.tsx b/src/features/RoleList/List/index.tsx index e1e6ce34..89a6e803 100644 --- a/src/features/RoleList/List/index.tsx +++ b/src/features/RoleList/List/index.tsx @@ -1,6 +1,7 @@ import { Empty } from 'antd'; import { createStyles } from 'antd-style'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import LazyLoad from 'react-lazy-load'; import { agentSelectors, useAgentStore } from '@/store/agent'; @@ -24,6 +25,7 @@ const SessionList = memo(({ filter }) => { agentSelectors.agentListIds(s), ]); const { styles } = useStyles(); + const { t } = useTranslation('role'); return ( <> @@ -38,10 +40,7 @@ const SessionList = memo(({ filter }) => { ))} {agentListIds.length === 0 && ( - + )} ); diff --git a/src/features/RoleList/index.tsx b/src/features/RoleList/index.tsx index b52f77fb..ca3f86d9 100644 --- a/src/features/RoleList/index.tsx +++ b/src/features/RoleList/index.tsx @@ -3,6 +3,7 @@ import { Collapse } from 'antd'; import { createStyles } from 'antd-style'; import { ChevronDown } from 'lucide-react'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { HEADER_HEIGHT } from '@/constants/token'; @@ -51,6 +52,7 @@ const useStyles = createStyles(({ css, token, prefixCls }) => ({ const RoleList = () => { const { styles } = useStyles(); const [searchName, setSearchName] = useState(); + const { t } = useTranslation(['role', 'common']); return (
@@ -65,7 +67,7 @@ const RoleList = () => { onChange={(e) => { setSearchName(e.target.value); }} - placeholder="搜索" + placeholder={t('search')} shortKey="f" spotlight type={'block'} @@ -93,7 +95,7 @@ const RoleList = () => { items={[ { children: , - label: '角色列表', + label: t('roleList'), key: 'default', }, ]} diff --git a/src/features/SessionList/Elsa/index.tsx b/src/features/SessionList/Elsa/index.tsx index 379743c8..17412c6a 100644 --- a/src/features/SessionList/Elsa/index.tsx +++ b/src/features/SessionList/Elsa/index.tsx @@ -1,5 +1,6 @@ import { Space, Tag } from 'antd'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { LOBE_VIDOL_DEFAULT_AGENT_ID } from '@/constants/agent'; import useSessionContext from '@/hooks/useSessionContext'; @@ -8,6 +9,7 @@ import { useAgentStore } from '@/store/agent'; import ListItem from '../ListItem'; const Elsa = memo(() => { + const { t } = useTranslation('common'); const defaultAgent = useAgentStore((s) => s.defaultAgent); const { activeSessionId, switchSession } = useSessionContext(); @@ -19,7 +21,7 @@ const Elsa = memo(() => { title={ {defaultAgent.meta.name} - 默认助手 + {t('defaultAssistant')} } description={defaultAgent.greeting || defaultAgent.meta.description || ''} diff --git a/src/features/SessionList/List/Item/Actions.tsx b/src/features/SessionList/List/Item/Actions.tsx index 2d6a5b98..e6a652d3 100644 --- a/src/features/SessionList/List/Item/Actions.tsx +++ b/src/features/SessionList/List/Item/Actions.tsx @@ -1,6 +1,7 @@ import { ActionIcon } from '@lobehub/ui'; import { App, Dropdown, MenuProps } from 'antd'; import { MoreVertical, Trash2 } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { useSessionStore } from '@/store/session'; @@ -12,6 +13,7 @@ interface ActionsProps { export default (props: ActionsProps) => { const { id, setOpen } = props; const { modal } = App.useApp(); + const { t } = useTranslation('common'); const [removeSession] = useSessionStore((s) => [s.removeSession]); const items: MenuProps['items'] = [ @@ -19,7 +21,7 @@ export default (props: ActionsProps) => { danger: true, icon: , key: 'delete', - label: '删除会话', + label: t('delSession'), onClick: ({ domEvent }) => { domEvent.stopPropagation(); modal.confirm({ @@ -28,9 +30,9 @@ export default (props: ActionsProps) => { onOk: () => { removeSession(id); }, - okText: '删除', - cancelText: '取消', - title: '确认删除对话吗?删除后无法恢复, 请谨慎操作!', + okText: t('actions.del'), + cancelText: t('cancel'), + title: t('delSessionAlert'), }); }, }, diff --git a/src/features/SessionList/index.tsx b/src/features/SessionList/index.tsx index e009fdc6..01278211 100644 --- a/src/features/SessionList/index.tsx +++ b/src/features/SessionList/index.tsx @@ -1,6 +1,7 @@ import { SearchBar } from '@lobehub/ui'; import { createStyles } from 'antd-style'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { HEADER_HEIGHT } from '@/constants/token'; @@ -45,7 +46,7 @@ const useStyles = createStyles(({ css, token, prefixCls }) => ({ const SideBar = () => { const { styles } = useStyles(); const [searchName, setSearchName] = useState(); - + const { t } = useTranslation('common'); return ( <> { onChange={(e) => { setSearchName(e.target.value); }} - placeholder="搜索" + placeholder={t('search')} shortKey="f" spotlight type={'block'} diff --git a/src/features/Settings/common.tsx b/src/features/Settings/common.tsx index 4ce5afeb..981f31f4 100644 --- a/src/features/Settings/common.tsx +++ b/src/features/Settings/common.tsx @@ -3,10 +3,12 @@ import { createStyles } from 'antd-style'; import classNames from 'classnames'; import { Monitor, Settings2, User2Icon } from 'lucide-react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import ClearSession from '@/features/Actions/ClearSession'; import ResetConfig from '@/features/Actions/ResetConfig'; import BackgroundEffect from '@/features/Settings/features/BackgroundEffect'; +import LanguageSetting from '@/features/Settings/features/LanguageSetting'; import NickName from '@/features/Settings/features/NickName'; import ThemeSwatchesNetural from '@/features/Settings/features/ThemeSwatchesNetural'; import ThemeSwatchesPrimary from '@/features/Settings/features/ThemeSwatchesPrimary'; @@ -33,46 +35,65 @@ const useStyles = createStyles(({ css }) => ({ const CommonConfig = (props: CommonConfigProps) => { const { style, className } = props; const { styles } = useStyles(); - + const { t } = useTranslation('common'); + t('words.'); return (
- - + + - + - - + + - + + + + - + diff --git a/src/features/Settings/features/BackgroundEffect/index.tsx b/src/features/Settings/features/BackgroundEffect/index.tsx index 76b7eb8d..21149cb2 100644 --- a/src/features/Settings/features/BackgroundEffect/index.tsx +++ b/src/features/Settings/features/BackgroundEffect/index.tsx @@ -1,6 +1,7 @@ import { Segmented } from 'antd'; import { isEqual } from 'lodash-es'; import React, { CSSProperties, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { useSettingStore } from '@/store/setting'; import { BackgroundEffect } from '@/types/config'; @@ -11,6 +12,7 @@ interface Props { export default memo((props) => { const { style } = props; + const { t } = useTranslation('features'); const [backgroundEffect, setBackgroundEffect] = useSettingStore( (s) => [s.config.backgroundEffect, s.setBackgroundEffect], isEqual, @@ -25,11 +27,11 @@ export default memo((props) => { }} options={[ { - label: '光辉', + label: t('settings.glow'), value: 'glow', }, { - label: '无背景', + label: t('settings.none'), value: 'none', }, ]} diff --git a/src/features/Settings/features/LanguageSetting/index.tsx b/src/features/Settings/features/LanguageSetting/index.tsx new file mode 100644 index 00000000..a8738d3d --- /dev/null +++ b/src/features/Settings/features/LanguageSetting/index.tsx @@ -0,0 +1,18 @@ +import { Select } from 'antd'; +import React, { CSSProperties, memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { localeOptions } from '@/locales/resources'; +import { switchLang } from '@/utils/switchLang'; + +interface Props { + style?: CSSProperties; +} + +export default memo((props) => { + const { style } = props; + const { t } = useTranslation('features'); + const options = [{ label: t('theme.auto'), value: 'auto' }, ...localeOptions]; + + return { diff --git a/src/features/Settings/index.tsx b/src/features/Settings/index.tsx index deed6526..d0de1736 100644 --- a/src/features/Settings/index.tsx +++ b/src/features/Settings/index.tsx @@ -1,5 +1,6 @@ import { TabsNav } from '@lobehub/ui'; import React, { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import CommonConfig from './common'; @@ -13,22 +14,25 @@ interface ConfigProps { const Config = (props: ConfigProps) => { const { style, className } = props; const [tab, setTab] = useState('common'); + const { t } = useTranslation('common'); + + const options = [ + { + key: 'common', + label: t('commonSetting'), + }, + { + key: 'languageModel', + label: t('languageModel'), + }, + ]; return (
{ setTab(key); }} diff --git a/src/features/Settings/model/openai.tsx b/src/features/Settings/model/openai.tsx index da9f470f..74fec521 100644 --- a/src/features/Settings/model/openai.tsx +++ b/src/features/Settings/model/openai.tsx @@ -6,6 +6,7 @@ import classNames from 'classnames'; import { debounce, isEqual } from 'lodash-es'; import { BotIcon } from 'lucide-react'; import React, { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { chatCompletion } from '@/services/chat'; import { configSelectors, useSettingStore } from '@/store/setting'; @@ -28,6 +29,7 @@ const Config = (props: ConfigProps) => { const { style, className } = props; const { styles } = useStyles(); const [form] = AForm.useForm(); + const { t } = useTranslation('common'); const openAIConfig = useSettingStore((s) => configSelectors.currentOpenAIConfig(s), isEqual); const setOpenAIConfig = useSettingStore((s) => s.setOpenAIConfig); @@ -39,10 +41,10 @@ const Config = (props: ConfigProps) => { manual: true, onSuccess: (res) => { if (!res.ok) { - message.error('调用接口失败,请检查 APIKey 和接口代理地址是否设置正确'); + message.error(t('openai.callError')); return; } - message.success('检查通过'); + message.success(t('openai.checkOk')); }, }); @@ -53,14 +55,14 @@ const Config = (props: ConfigProps) => { onValuesChange={debounce(setOpenAIConfig, 100)} style={{ display: 'flex', flexGrow: 1 }} > - - + + - + - + diff --git a/src/features/constants/ttsParam.ts b/src/features/constants/ttsParam.ts index b861de12..05ca5539 100644 --- a/src/features/constants/ttsParam.ts +++ b/src/features/constants/ttsParam.ts @@ -1,9 +1,11 @@ +import { t } from 'i18next'; + import { TTS } from '@/types/tts'; export const DEFAULT_TTS: TTS = { engine: 'edge', locale: 'zh-CN', - message: '正在为你准备我的整个世界', + message: t('waitting', { ns: 'welcome' }), pitch: 1, speed: 1, voice: 'zh-CN-XiaoyiNeural', diff --git a/src/hooks/useChatListActionsBar.tsx b/src/hooks/useChatListActionsBar.tsx index 67eadcc1..ca5150eb 100644 --- a/src/hooks/useChatListActionsBar.tsx +++ b/src/hooks/useChatListActionsBar.tsx @@ -1,6 +1,7 @@ import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup'; import { Copy, Edit, ListRestart, RotateCcw, Trash } from 'lucide-react'; import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; interface ChatListActionsBar { copy: ActionIconGroupItems; @@ -12,23 +13,24 @@ interface ChatListActionsBar { } export const useChatListActionsBar = (): ChatListActionsBar => { + const { t } = useTranslation('common'); return useMemo( () => ({ copy: { icon: Copy, key: 'copy', - label: '复制', + label: t('actions.copy'), }, del: { danger: true, icon: Trash, key: 'del', - label: '删除', + label: t('actions.del'), }, delAndRegenerate: { icon: ListRestart, key: 'delAndRegenerate', - label: '删除并重新生成', + label: t('actions.delAndRegenerate'), }, divider: { type: 'divider', @@ -36,12 +38,12 @@ export const useChatListActionsBar = (): ChatListActionsBar => { edit: { icon: Edit, key: 'edit', - label: '编辑', + label: t('actions.edit'), }, regenerate: { icon: RotateCcw, key: 'regenerate', - label: '重新生成', + label: t('actions.regenerate'), }, }), [], diff --git a/src/hooks/useDownloadAgent.tsx b/src/hooks/useDownloadAgent.tsx index 3955ae5b..6f5d2d24 100644 --- a/src/hooks/useDownloadAgent.tsx +++ b/src/hooks/useDownloadAgent.tsx @@ -1,5 +1,6 @@ import { message } from 'antd'; import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useAgentStore } from '@/store/agent'; import { Agent } from '@/types/agent'; @@ -14,6 +15,8 @@ export const useDownloadAgent = () => { const [coverProgress, setCoverProgress] = useState(0); const [modelProgress, setModelProgress] = useState(0); + const { t } = useTranslation('common'); + const [addLocalAgent] = useAgentStore((s) => [s.addLocalAgent]); const fetchAgentData = async (agent: Agent) => { @@ -46,10 +49,10 @@ export const useDownloadAgent = () => { await setItem(modelKey, model); addLocalAgent({ ...agent, meta: { ...agent.meta, avatar, cover } }); - message.success(agent.meta.name + '下载成功'); + message.success(agent.meta.name + t('actions.downloadSuccess')); } catch (e) { console.error(e); - message.error(agent.meta.name + '下载失败'); + message.error(agent.meta.name + t('actions.downloadFailed')); } finally { setDownloading(false); } diff --git a/src/hooks/useDownloadDance.tsx b/src/hooks/useDownloadDance.tsx index ad753dcc..66127fb2 100644 --- a/src/hooks/useDownloadDance.tsx +++ b/src/hooks/useDownloadDance.tsx @@ -1,5 +1,6 @@ import { message } from 'antd'; import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useDanceStore } from '@/store/dance'; import { Dance } from '@/types/dance'; @@ -14,6 +15,7 @@ export const useDownloadDance = () => { const [coverProgress, setCoverProgress] = useState(0); const [danceProgress, setDanceProgress] = useState(0); + const { t } = useTranslation('common'); const [addDanceItem] = useDanceStore((s) => [s.addDanceItem]); const fetchDanceData = async (dance: Dance) => { setDownloading(true); @@ -52,10 +54,10 @@ export const useDownloadDance = () => { await setItem(audioKey, audioBlob); addDanceItem({ ...dance, cover: coverBase64 }); - message.success(dance.name + '下载成功'); + message.success(dance.name + t('actions.downloadSuccess')); } catch (e) { console.error(e); - message.error(dance.name + '下载失败'); + message.error(dance.name + t('actions.downloadFailed')); } finally { setDownloading(false); } diff --git a/src/layout/Header/index.tsx b/src/layout/Header/index.tsx index d0d56314..38f738d2 100644 --- a/src/layout/Header/index.tsx +++ b/src/layout/Header/index.tsx @@ -5,6 +5,7 @@ import { Space, Tag, Tooltip } from 'antd'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import Discord from '@/features/Actions/Discord'; import Github from '@/features/Actions/Github'; @@ -18,6 +19,7 @@ interface Props { const Header = (props: Props) => { const { headerKey } = props; const router = useRouter(); + const { t } = useTranslation('layout'); return ( { - + WIP @@ -49,19 +51,19 @@ const Header = (props: Props) => { items={[ { key: HeaderNavKey.Chat, - label: '聊天', + label: t('header.chat'), }, { key: HeaderNavKey.Role, - label: '角色', + label: t('header.role'), }, { key: HeaderNavKey.Market, - label: '发现', + label: t('header.market'), }, { key: HeaderNavKey.Settings, - label: '设置', + label: t('header.settings'), }, ]} onChange={(key) => { diff --git a/src/layout/Locale.tsx b/src/layout/Locale.tsx new file mode 100644 index 00000000..b51bdf56 --- /dev/null +++ b/src/layout/Locale.tsx @@ -0,0 +1,54 @@ +'use client'; + +import { ConfigProvider } from 'antd'; +import { PropsWithChildren, memo, useEffect, useState } from 'react'; + +import { createI18nNext } from '@/locales/create'; +import { isOnServerSide } from '@/utils/env'; +import { getAntdLocale } from '@/utils/locale'; + +interface LocaleLayoutProps extends PropsWithChildren { + antdLocale?: any; + defaultLang?: string; +} + +const Locale = memo(({ children, defaultLang, antdLocale }) => { + const [i18n] = useState(createI18nNext(defaultLang)); + const [lang, setLang] = useState(defaultLang); + const [locale, setLocale] = useState(antdLocale); + + // if run on server side, init i18n instance everytime + if (isOnServerSide) { + i18n.init(); + } else { + // if on browser side, init i18n instance only once + if (!i18n.instance.isInitialized) + // console.debug('locale', lang); + i18n.init().then(() => { + // console.debug('inited.'); + }); + } + + // handle i18n instance language change + useEffect(() => { + const handleLang = async (lng: string) => { + setLang(lng); + + if (lang === lng) return; + + const newLocale = await getAntdLocale(lng); + setLocale(newLocale); + }; + + i18n.instance.on('languageChanged', handleLang); + return () => { + i18n.instance.off('languageChanged', handleLang); + }; + }, [i18n, lang]); + + return {children}; +}); + +Locale.displayName = 'Locale'; + +export default Locale; diff --git a/src/layout/index.tsx b/src/layout/index.tsx index f3473050..51fa6cd6 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -1,13 +1,19 @@ import { PrimaryColors } from '@lobehub/ui'; import { ThemeAppearance } from 'antd-style'; import dynamic from 'next/dynamic'; -import { cookies } from 'next/headers'; +import { cookies, headers } from 'next/headers'; import { FC, ReactNode } from 'react'; +import { resolveAcceptLanguage } from 'resolve-accept-language'; +import { LOBE_LOCALE_COOKIE } from '@/constants/locale'; import { VIDOL_THEME_NEUTRAL_COLOR, VIDOL_THEME_PRIMARY_COLOR } from '@/constants/theme'; import AppTheme from '@/layout/AppTheme'; import StoreHydration from '@/layout/StoreHydration'; import StyleRegistry from '@/layout/StyleRegistry'; +import { locales } from '@/locales/resources'; +import { getAntdLocale } from '@/utils/locale'; + +import Locale from './Locale'; let DebugUI: FC = () => null; @@ -21,23 +27,42 @@ export interface LayoutProps { defaultPrimaryColor?: PrimaryColors; } -const Layout = (props: LayoutProps) => { +const parserFallbackLang = () => { + let fallbackLang: string = resolveAcceptLanguage( + headers().get('accept-language') || '', + locales, + 'en-US', + ); + + return fallbackLang; +}; + +const Layout = async (props: LayoutProps) => { const { children } = props; const cookieStore = cookies(); const primaryColor = cookieStore.get(VIDOL_THEME_PRIMARY_COLOR); const neutralColor = cookieStore.get(VIDOL_THEME_NEUTRAL_COLOR); + const defaultLang = cookieStore.get(LOBE_LOCALE_COOKIE); + const fallbackLang = parserFallbackLang(); + + const userLocale = defaultLang?.value || fallbackLang; + + const antdLocale = await getAntdLocale(userLocale); + return ( - - - - {children} - + + + + + {children} + + ); }; diff --git a/src/locales/create.ts b/src/locales/create.ts new file mode 100644 index 00000000..31da1e15 --- /dev/null +++ b/src/locales/create.ts @@ -0,0 +1,50 @@ +import i18n from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import resourcesToBackend from 'i18next-resources-to-backend'; +import { initReactI18next } from 'react-i18next'; + +import { + COOKIE_CACHE_DAYS, + DEFAULT_LANG, + LOBE_LOCALE_COOKIE, + getDebugConfig, +} from '@/constants/i18n'; +import { normalizeLocale } from '@/locales/resources'; +import { isDev, isOnServerSide } from '@/utils/env'; + +const { I18N_DEBUG, I18N_DEBUG_BROWSER, I18N_DEBUG_SERVER } = getDebugConfig(); +const debugMode = I18N_DEBUG ?? isOnServerSide ? I18N_DEBUG_SERVER : I18N_DEBUG_BROWSER; + +export const createI18nNext = (lang?: string) => { + const instance = i18n + .use(initReactI18next) + .use(LanguageDetector) + .use( + resourcesToBackend(async (lng: string, ns: string) => { + if (isDev && lng === 'zh-CN') return import(`./default/${ns}`); + + return import(`@/../locales/${normalizeLocale(lng)}/${ns}.json`); + }), + ); + return { + init: () => + instance.init({ + debug: debugMode, + defaultNS: ['error', 'common', 'chat'], + detection: { + caches: ['cookie'], + cookieMinutes: 60 * 24 * COOKIE_CACHE_DAYS, + cookieOptions: { + sameSite: 'lax', + }, + lookupCookie: LOBE_LOCALE_COOKIE, + }, + fallbackLng: DEFAULT_LANG, + interpolation: { + escapeValue: false, + }, + lng: lang, + }), + instance, + }; +}; diff --git a/src/locales/default/chat.ts b/src/locales/default/chat.ts new file mode 100644 index 00000000..7ed5f4b3 --- /dev/null +++ b/src/locales/default/chat.ts @@ -0,0 +1,14 @@ +export default { + header: { + session: '对话', + role: '角色', + }, + chatDialog: { + close: '关闭', + }, + dance: '跳舞', + chat: '聊天', + market: '发现', + helloChat: '你好,让我们来聊天吧', + helloDance: '嗨,让我们一起跳舞吧', +}; diff --git a/src/locales/default/common.ts b/src/locales/default/common.ts new file mode 100644 index 00000000..57aebdf9 --- /dev/null +++ b/src/locales/default/common.ts @@ -0,0 +1,100 @@ +export default { + uploadTip: '点击或拖拽文件到此区域上传', + aiAlert: '请谨记:智能体所说的一切都是由 AI 生成的', + ttsTip: '语音识别(需科学上网)', + ttsCombine: '语音合成', + defaultAssistant: '默认助手', + loading: '加载中...', + noData: '暂无数据', + commonSetting: '通用设置', + languageModel: '语言模型', + selectModel: '请选择模型', + selectInDanceList: '请从舞蹈列表中选取', + inputStartChat: '请输入内容开始聊天', + playlist: '播放列表', + cancel: '取消', + confirm: '确定', + search: '搜索', + startChat: '开始聊天', + delRole: '删除角色', + delSession: '删除会话', + delAlert: '确认删除角色以及相关联的会话消息吗?删除后无法恢复, 请谨慎操作!', + delSessionAlert: '确认删除对话吗?删除后无法恢复, 请谨慎操作!', + setLocalStorage: '设置 LocalStorage', + actions: { + copy: '复制', + del: '删除', + send: '发送', + warp: '换行', + confirmDel: '确定删除吗?', + add: '添加', + delAndRegenerate: '删除并重新生成', + edit: '编辑', + save: '保存', + share: '分享', + regenerate: '重新生成', + reset: '重置', + resetNow: '立即重置', + play: '播放', + pause: '暂停', + copySuccess: '复制成功', + removeInList: '从列表中移除', + downloadSuccess: '下载成功', + downloadFailed: '下载失败', + subscribeRole: '订阅角色', + subscribeDance: '订阅舞蹈', + subscribe: '订阅', + subscribed: '已订阅', + unsubscribe: '取消订阅', + unsubscribeSuccess: '已取消订阅', + downloadSubscribe: '下载订阅', + market: '发现', + clearAll: '清空', + clearNow: '立即清除', + clearContext: '清除上下文', + clearTip: '操作无法撤销,清除后数据将无法恢复,请慎重操作', + clearHistoryTip: '该操作不可逆,请谨慎操作', + clearSuccess: '清除成功', + clearTitle: '确认清除所有会话消息?', + clearHistoryTitle: '确定删除历史消息?', + resetTip: '操作无法撤销,重置后数据将无法恢复,请慎重操作', + resetSuccess: '重置成功', + resetTitle: '确认重置所有系统设置?', + goBottom: '返回底部', + downloadCover: '下载封面', + downloadAvatar: '下载头像', + downloadModel: '下载模型', + }, + openai: { + callError: '调用接口失败,请检查 APIKey 和接口代理地址是否设置正确', + checkOk: '检查通过', + langModel: 'OpenAI 语言模型', + roleModel: 'Role GPT 模型', + model: '模型', + useOwnKey: '请使用自己的 OpenAI Key', + proxyUrl: '接口代理地址', + checkAll: '检查 APIKey 和接口代理地址是否设置正确', + checkConnect: '连通性检查', + check: '检查', + }, + words: { + chatSetting: '聊天设置', + topicSetting: '主题设置', + systemSetting: '系统设置', + languageSetting: '语言设置', + resetSystemSetting: '重置系统设置', + resetSystemSettingDesc: '将会重置所有系统设置,包括主题设置、聊天设置、语言模型设置等', + clearAllSession: '清除所有会话消息', + clearAllSessionDesc: '将会清除所有会话与角色数据,包括会话列表,角色列表、会话消息等', + DIYAvatar: '自定义头像', + avatar: '头像', + DIYNickname: '自定义昵称', + nickname: '昵称', + DIYTopicColor: '自定义主题色', + topicColor: '主题色', + midColor: '中性色', + DIYColor: '不同色彩倾向的灰阶自定义', + DIYBackgroundEffect: '自定义背景效果', + backgroundEffect: '背景效果', + }, +}; diff --git a/src/locales/default/constants.ts b/src/locales/default/constants.ts new file mode 100644 index 00000000..a2b5cb18 --- /dev/null +++ b/src/locales/default/constants.ts @@ -0,0 +1,92 @@ +export default { + agent: { + meta: { + name: '自定义角色', + description: '这是一个自定义角色', + }, + gender: { + male: '男', + female: '女', + other: '其他', + }, + }, + touch: { + area: { + head: '头部', + arm: '手臂', + leg: '腿部', + chest: '胸部', + belly: '腹部', + }, + emotion: { + natural: '自然', + happy: '开心', + angry: '生气', + sad: '伤心', + relaxed: '放松', + surprised: '惊讶', + blink: '眨眼', + blinkLeft: '眨左眼', + blinkRight: '眨右眼', + }, + femaleAction: { + headAction: { + happyA: '哇!最喜欢摸摸头!', + happyB: '感觉又充满了力量呢!', + happyC: '哇塞,这个摸摸头的感觉好神奇!', + happyD: '摸摸头让我开心一整天!', + angryA: '听说被摸头是会长不高的呢!', + angryB: '干嘛戳我呀?', + }, + armAction: { + happyA: '啊,好喜欢呢~', + happyB: '哈哈,牵手让我感到快乐~', + relaxedA: '主人的手好温暖啊~', + }, + legAction: { + surprisedA: '让我们保持纯洁的友谊不好吗?', + angryA: '喂,你是要作死吗?', + angryB: '主人的手又不听指挥了吗?', + angryC: '讨厌~会痒的啦~!', + }, + chestAction: { + angryA: '不可以这样欺负我啦!快把手拿开!', + angryB: '幺幺零吗?这里有个变态一直在摸我!', + angryC: '再摸的话我可要报警了', + surprisedA: '干嘛戳我呀!还能不能愉快地聊天了!', + }, + bellyAction: { + surprisedA: '是不小心碰到的吧...', + angryA: '干嘛动我呀,小心我咬你哦!', + relaxedA: '醒醒,我们之间没有结果的!', + relaxedB: '讨厌!我可要生气啦!', + }, + }, + maleAction: { + headAction: { + neutralA: '当然了,只有你有资格摸我的头', + neutralB: '我可不是什么普通人允许触碰的哦', + neutralC: '别担心,摸过我的头后,你的运气会大幅提升的', + }, + armAction: { + neutralA: '别问我今天吃没吃鸡,先看看我的肱二头肌', + neutralB: '我的手臂可不是随便让人触碰的,你是个例外而已', + neutralC: '你很勇敢,敢触碰到传说中的麒麟臂', + }, + legAction: { + neutralA: '别害怕,我的大力金刚腿不踢傻瓜', + neutralB: '让你碰到我的腿,是不是觉得你的生活完整了许多?', + angryA: '别靠近我,你这个腿控', + }, + chestAction: { + neutralA: '这不过时我日常修炼成就的胸肌,没什么好惊讶的。', + blinkLeftA: '来,哥的胸肌给你靠!', + }, + bellyAction: { + neutralA: '我的腹肌只是再修炼深藏不露的内力', + happyA: '别挠痒痒,小心我笑出腹肌', + neutralB: '看到我这团腹肌了吗?它们只是藏得比较深罢了', + }, + }, + }, +}; diff --git a/src/locales/default/error.ts b/src/locales/default/error.ts new file mode 100644 index 00000000..14e7e518 --- /dev/null +++ b/src/locales/default/error.ts @@ -0,0 +1,19 @@ +export default { + error: '错误', + triggerError: '触发错误', + errorTip: { + problem: '页面遇到一点问题...', + description: '项目当前正在施工中,不保证数据稳定性,如果遇到问题可以尝试', + or: '或', + forgive: ',造成不便敬请谅解', + clearSession: '清除会话消息', + resetSystem: '重置系统设置', + }, + reload: '重新加载', + goBack: '返回首页', + apiKeyMiss: 'OpenAI API Key 为空,请添加自定义 OpenAI API Key', + serverError: '服务器错误,请联系管理员', + openaiError: 'OpenAI API 错误,请检查 OpenAI API Key 和 Endpoint 是否正确', + unknownError: '未知错误', + s3envError: 'S3 环境变量未完全设置,请检查您的环境变量', +}; diff --git a/src/locales/default/features.ts b/src/locales/default/features.ts new file mode 100644 index 00000000..e6e19fca --- /dev/null +++ b/src/locales/default/features.ts @@ -0,0 +1,65 @@ +export default { + support: '社区支持', + token: { + overload: 'Token 超出', + remained: 'Token 剩余', + used: 'Token 已使用', + useToken: '消耗 Token 数量计算,包括消息,角色设定与上下文:{{usedTokens}} / {{maxValue}}', + tokenCount: 'Token 数量', + }, + share: { + screenshot: '截图', + shareGPT: '分享GPT', + withSystemRole: '包含助手角色设定', + withBackground: '包含背景图片', + withFooter: '包含页脚', + imageType: '图片格式', + downloadScreenshot: '下载截图', + shareToGPT: '生成 ShareGPT 分享链接', + share: '分享', + shareToMarket: '分享到助手市场', + }, + submit: { + submitAssistant: '提交助手', + submitWarning: '请补全助手信息后提交,需要包含名称、描述、头像和封面', + assistantId: '助手标识符', + assistantIdTip: '请输入助手的标识符,需要是唯一的,比如 vidol-agent-klee', + }, + theme: { + auto: '跟随系统', + light: '亮色模式', + dark: '暗黑模式', + }, + agent: { + female: '女性', + male: '男性', + other: '其他', + }, + actions: { + useVideo: '切换视频模式', + }, + mode: { + chat: '聊天', + video: '视频', + }, + toolBar: { + cameraHelper: '镜头辅助', + cameraControl: '镜头控制', + floor: '切换地板', + resetCamera: '重置镜头', + grid: '网格', + downloadModel: '模型下载中,请稍后...', + }, + feature: { + startDesc: '输入你的 OpenAI API Key 即可开始会话。应用不会记录你的 API Key', + startTitle: '自定义 API Key', + addProxy: '添加 OpenAI 代理地址(可选)', + comfirmRetry: '确认并重试', + closeTip: '关闭提示', + }, + settings: { + glow: '光辉', + none: '无背景', + nickName: '请输入昵称', + }, +}; diff --git a/src/locales/default/index.ts b/src/locales/default/index.ts new file mode 100644 index 00000000..866da34c --- /dev/null +++ b/src/locales/default/index.ts @@ -0,0 +1,25 @@ +import chat from './chat'; +import common from './common'; +import constants from './constants'; +import error from './error'; +import features from './features'; +import layout from './layout'; +import my from './my'; +import panel from './panel'; +import role from './role'; +import welcome from './welcome'; + +const resources = { + my, + chat, + common, + error, + role, + welcome, + constants, + layout, + panel, + features, +} as const; + +export default resources; diff --git a/src/locales/default/layout.ts b/src/locales/default/layout.ts new file mode 100644 index 00000000..97b69941 --- /dev/null +++ b/src/locales/default/layout.ts @@ -0,0 +1,12 @@ +export default { + header: { + tips: '项目当前正在施工中,不保证数据稳定性,如果遇到问题可以在系统设置中清除会话消息与重置系统设置,造成不便敬请谅解', + chat: '聊天', + role: '角色', + market: '发现', + settings: '设置', + }, + dialog: '对话框', + siderBar: '侧边栏', + sessionList: '会话列表', +}; diff --git a/src/locales/default/my.ts b/src/locales/default/my.ts new file mode 100644 index 00000000..8ead3ae8 --- /dev/null +++ b/src/locales/default/my.ts @@ -0,0 +1,5 @@ +export default { + myRole: '我的角色', + myDance: '我的舞蹈', + my: '我的', +}; diff --git a/src/locales/default/panel.ts b/src/locales/default/panel.ts new file mode 100644 index 00000000..8aaecf07 --- /dev/null +++ b/src/locales/default/panel.ts @@ -0,0 +1,83 @@ +export default { + dance: { + play: '播放', + addPlay: '添加到列表', + addPlaySuccess: '已添加到播放列表', + cancelAddPlay: '确定取消订阅音乐{{musicName}}吗?', + cancelSubscribed: '取消订阅', + findDance: '找到你最喜欢的舞蹈', + musicAndDance: '音乐与舞蹈', + }, + market: { + findVidol: '找到你最爱的偶像', + }, + role: { + uploadSize: '支持单个文件上传,推荐尺寸为 {{width}} * {{height}} 的倍数', + greetTip: '请输入角色与你打招呼时的用语', + roleReadmeTip: '请输入角色说明', + roleDescriptionTip: '请输入角色描述', + roleNameTip: '请输入角色名称', + inputRoleSetting: '请输入角色的系统设定', + roleSettingLabel: '系统角色设定', + roleSettingDescription: '角色的背景设定,在与角色聊天时会发送给模型', + }, + info: { + avatarLabel: '头像', + avatarDescription: '自定义头像,点击头像自定义上传', + nameLabel: '名称', + nameDescription: '角色名称,与角色聊天时的称呼', + genderLabel: '性别', + genderDescription: '角色性别,影响角色的触摸响应', + descLabel: '描述', + descDescription: '角色描述,用于角色的简单介绍', + greetLabel: '招呼', + greetDescription: '与角色初次聊天时的招呼用语', + readmeLabel: '角色说明', + readmeDescription: '角色的说明文件,用于发现页展示角色的详细说明', + coverLabel: '封面', + coverDescription: '用于发现页展示角色,推荐尺寸 {{width}} * {{height}} ', + textLabel: '文案', + textDescription: '自定义响应文案', + emotionLabel: '表情与情绪', + emotionDescription: '选择响应时的情绪,会影响角色的表情变化', + modelLabel: '模型预览', + modelDescription: '模型预览,可拖动模型文件以替换', + categoryLabel: '类别', + categoryDescription: '角色类别,用于展示分类', + }, + touch: { + editAction: '编辑响应动作', + addAction: '添加响应动作', + inputDIYText: '请输入自定义文案', + inputActionText: '请输入响应文案', + inputActionEmotion: '请输入角色响应时的表情', + touchActionList: '触摸{{touchArea}}时的反应列表', + touchArea: '触摸区域', + }, + upload: { + support: '支持单个文件上传,当前仅支持 .vrm 格式文件', + }, + tts: { + transfromSuccess: '转换成功', + selectLanguage: '请先选择语言', + selectVoice: '请先选择语音', + audition: '试听', + engineLabel: '语音引擎', + engineDescription: '语音合成引擎,建议优先选择 Edge 浏览器', + localeLabel: '语言', + localeDescription: '语音合成的语种,当前仅支持最常见的几种语言,如有需要请联系', + voiceLabel: '语音', + voiceDescription: '根据引擎和语种不同', + speedLabel: '语速', + speedDescription: '控制语速,取值范围 0 ~ 3,默认为 1', + pitchLabel: '音调', + pitchDescription: '控制音调,取值范围 0 ~ 2,默认为 1', + auditionDescription: '试听文案根据语言不同', + }, + nav: { + info: '基本信息', + role: '角色设定', + voice: '语音', + model: '3D模型', + }, +}; diff --git a/src/locales/default/role.ts b/src/locales/default/role.ts new file mode 100644 index 00000000..ba4a97c5 --- /dev/null +++ b/src/locales/default/role.ts @@ -0,0 +1,11 @@ +export default { + header: { + session: '对话', + role: '角色', + }, + roleList: '角色列表', + topBannerTitle: '角色预览和设置', + delRole: '删除角色', + delRoleDesc: '确定删除角色 {{name}} 以及相关联的会话消息吗?删除后无法恢复, 请谨慎操作!', + noRole: '暂无角色,可以通过 + 创建自定义角色,也可通过发现页添加角色', +}; diff --git a/src/locales/default/welcome.ts b/src/locales/default/welcome.ts new file mode 100644 index 00000000..adb308ce --- /dev/null +++ b/src/locales/default/welcome.ts @@ -0,0 +1,14 @@ +export default { + loadingTitle: '应用初始化中,请稍后...', + waitting: '正在为你准备我的整个世界', + agent: { + greeting: '哈喽,亲爱的主人!我是你的私人助理 {{name}},愉快地为你服务!有什么我可以帮你的吗?', + description: '{{name}}是 Vidol 的默认角色,是你的专属私人助理', + hello: '你好呀', + meta: { + name: '自定义角色', + description: '这是一个自定义角色', + }, + }, + greet: '你好,我是{{name}},有什么可以帮助你的吗?', +}; diff --git a/src/locales/resources.test.ts b/src/locales/resources.test.ts new file mode 100644 index 00000000..f389a278 --- /dev/null +++ b/src/locales/resources.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, it } from 'vitest'; + +import { normalizeLocale } from './resources'; + +describe('normalizeLocale', () => { + it('should return "en-US" when locale is undefined', () => { + expect(normalizeLocale()).toBe('en-US'); + }); + + it('should return "zh-CN" when locale is "zh-CN"', () => { + expect(normalizeLocale('zh-CN')).toBe('zh-CN'); + }); + + it('should return "zh-CN" when locale is "zh"', () => { + expect(normalizeLocale('zh')).toBe('zh-CN'); + }); + + it('should return "de-DE" when locale is "de"', () => { + expect(normalizeLocale('de')).toBe('de-DE'); + }); + + it('should return "ru-RU" when locale is "ru"', () => { + expect(normalizeLocale('ru')).toBe('ru-RU'); + }); + + it('should return "en-US" when locale is "en"', () => { + expect(normalizeLocale('en')).toBe('en-US'); + }); + + it('should return the input locale for other valid locales', () => { + expect(normalizeLocale('fr-FR')).toBe('fr-FR'); + expect(normalizeLocale('ja-JP')).toBe('ja-JP'); + expect(normalizeLocale('ko-KR')).toBe('ko-KR'); + expect(normalizeLocale('pt-BR')).toBe('pt-BR'); + expect(normalizeLocale('tr-TR')).toBe('tr-TR'); + expect(normalizeLocale('vi-VN')).toBe('vi-VN'); + expect(normalizeLocale('zh-TW')).toBe('zh-TW'); + }); + + it('should return the input locale for unknown locales', () => { + expect(normalizeLocale('unknown')).toBe('en-US'); + expect(normalizeLocale('fr')).toBe('fr-FR'); + }); +}); diff --git a/src/locales/resources.ts b/src/locales/resources.ts new file mode 100644 index 00000000..54d16983 --- /dev/null +++ b/src/locales/resources.ts @@ -0,0 +1,107 @@ +import resources from './default'; + +export const locales = [ + 'bg-BG', + 'de-DE', + 'en-US', + 'es-ES', + 'fr-FR', + 'ja-JP', + 'ko-KR', + 'pt-BR', + 'ru-RU', + 'tr-TR', + 'zh-CN', + 'zh-TW', + 'vi-VN', +] as const; + +export type DefaultResources = typeof resources; +export type NS = keyof DefaultResources; +export type Locales = (typeof locales)[number]; + +export const normalizeLocale = (locale?: string): string => { + if (!locale) return 'en-US'; + + for (const l of locales) { + if (l.startsWith(locale)) { + return l; + } + } + + return 'en-US'; +}; + +type LocaleOptions = { + label: string; + value: Locales; +}[]; + +export const localeOptions: LocaleOptions = [ + { + label: 'English', + value: 'en-US', + }, + { + label: '简体中文', + value: 'zh-CN', + }, + { + label: '繁體中文', + value: 'zh-TW', + }, + { + label: '日本語', + value: 'ja-JP', + }, + { + label: '한국어', + value: 'ko-KR', + }, + { + label: 'Deutsch', + value: 'de-DE', + }, + { + label: 'Español', + value: 'es-ES', + }, + { + label: 'Français', + value: 'fr-FR', + }, + { + label: 'Português', + value: 'pt-BR', + }, + { + label: 'Русский', + value: 'ru-RU', + }, + { + label: 'Türkçe', + value: 'tr-TR', + }, + { + label: 'Polski', + value: 'pl-PL', + }, + { + label: 'Nederlands', + value: 'nl-NL', + }, + { + label: 'Italiano', + value: 'it-IT', + }, + { + label: 'Tiếng Việt', + value: 'vi-VN', + }, + { + label: 'Български', + value: 'bg-BG', + }, +] as LocaleOptions; + +export const supportLocales: string[] = [...locales, 'en', 'zh']; diff --git a/src/panels/AgentPanel/Agent/List/index.tsx b/src/panels/AgentPanel/Agent/List/index.tsx index e36add99..0976278a 100644 --- a/src/panels/AgentPanel/Agent/List/index.tsx +++ b/src/panels/AgentPanel/Agent/List/index.tsx @@ -1,6 +1,7 @@ import { GradientButton } from '@lobehub/ui'; import { useRouter } from 'next/navigation'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import GridList from '@/components/GridList'; import { useAgentStore } from '@/store/agent'; @@ -13,6 +14,7 @@ interface AgentListProps { const AgentList = (props: AgentListProps) => { const { className, style } = props; const router = useRouter(); + const { t } = useTranslation('common'); const [localAgentList, activateAgent, currentIdentifier] = useAgentStore((s) => [ s.localAgentList, @@ -43,7 +45,7 @@ const AgentList = (props: AgentListProps) => { router.push('/market'); }} > - + 订阅角色 + + {t('actions.subscribeRole')} , ], }} diff --git a/src/panels/AgentPanel/Agent/index.tsx b/src/panels/AgentPanel/Agent/index.tsx index 8c013dd6..b5ad693d 100644 --- a/src/panels/AgentPanel/Agent/index.tsx +++ b/src/panels/AgentPanel/Agent/index.tsx @@ -1,6 +1,7 @@ import { createStyles } from 'antd-style'; import classNames from 'classnames'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import TopBanner from '@/components/TopBanner'; @@ -32,11 +33,12 @@ interface AgentProps { const Agent = (props: AgentProps) => { const { styles } = useStyles(); const { style, className } = props; + const { t } = useTranslation('chat'); return (
- +
diff --git a/src/panels/DancePanel/Dance/Card/index.tsx b/src/panels/DancePanel/Dance/Card/index.tsx index f32790b5..2f10a2c4 100644 --- a/src/panels/DancePanel/Dance/Card/index.tsx +++ b/src/panels/DancePanel/Dance/Card/index.tsx @@ -2,6 +2,7 @@ import { DraggablePanel } from '@lobehub/ui'; import { Button, Popconfirm, message } from 'antd'; import { createStyles } from 'antd-style'; import React, { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import DanceInfo from '@/components/DanceInfo'; import { SIDEBAR_MAX_WIDTH, SIDEBAR_WIDTH } from '@/constants/token'; @@ -39,7 +40,7 @@ const SideBar = memo(() => { ]); const currentDance = useDanceStore((s) => danceListSelectors.currentDanceItem(s)); - + const { t } = useTranslation(['panel', 'common']); return ( { }} type={'primary'} > - 播放 + {t('dance.play')} , , { if (currentDance) { removeDanceItem(currentDance.danceId); } }} - title="取消订阅?" + title={t('dance.cancelSubscribed') + '?'} > - + , ]} dance={currentDance} diff --git a/src/panels/DancePanel/Dance/List/index.tsx b/src/panels/DancePanel/Dance/List/index.tsx index 1df68c94..08a8a616 100644 --- a/src/panels/DancePanel/Dance/List/index.tsx +++ b/src/panels/DancePanel/Dance/List/index.tsx @@ -1,5 +1,6 @@ import { GradientButton } from '@lobehub/ui'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import GridList from '@/components/GridList'; import { useDanceStore } from '@/store/dance'; @@ -17,6 +18,7 @@ const DanceList = (props: DanceListProps) => { s.activateDance, s.currentIdentifier, ]); + const { t } = useTranslation('common'); return ( { } }} > - + 订阅舞蹈 + + {t('actions.subscribeDance')} , ], }} diff --git a/src/panels/DancePanel/Dance/index.tsx b/src/panels/DancePanel/Dance/index.tsx index 50f37e5e..30f6ac76 100644 --- a/src/panels/DancePanel/Dance/index.tsx +++ b/src/panels/DancePanel/Dance/index.tsx @@ -1,5 +1,6 @@ import classNames from 'classnames'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import TopBanner from '@/components/TopBanner'; @@ -16,10 +17,12 @@ interface DanceProps { const Dance = (props: DanceProps) => { const { style, className, setTab } = props; const { styles } = useStyles(); + const { t } = useTranslation('chat'); + return (
- +
diff --git a/src/panels/DancePanel/Market/Card/SubscribeButton.tsx b/src/panels/DancePanel/Market/Card/SubscribeButton.tsx index f40d09aa..de15267f 100644 --- a/src/panels/DancePanel/Market/Card/SubscribeButton.tsx +++ b/src/panels/DancePanel/Market/Card/SubscribeButton.tsx @@ -1,5 +1,6 @@ import { Button, Progress, message } from 'antd'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { useDownloadDance } from '@/hooks/useDownloadDance'; @@ -22,13 +23,15 @@ const SubscribeButton = (props: SubscribeButtonProps) => { const { downloading, percent, fetchDanceData } = useDownloadDance(); + const { t } = useTranslation('common'); + return ( , , ]); } diff --git a/src/panels/DancePanel/Market/index.tsx b/src/panels/DancePanel/Market/index.tsx index 82332ed3..f165b7a8 100644 --- a/src/panels/DancePanel/Market/index.tsx +++ b/src/panels/DancePanel/Market/index.tsx @@ -1,5 +1,6 @@ import classNames from 'classnames'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import TopBanner from '@/components/TopBanner'; @@ -15,10 +16,11 @@ interface DanceProps { const Dance = (props: DanceProps) => { const { style, className } = props; const { styles } = useStyles(); + const { t } = useTranslation('panel'); return (
- +
diff --git a/src/panels/DancePanel/index.tsx b/src/panels/DancePanel/index.tsx index 5e3f67a7..3eb4bd6f 100644 --- a/src/panels/DancePanel/index.tsx +++ b/src/panels/DancePanel/index.tsx @@ -3,6 +3,7 @@ import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons'; import { Segmented } from 'antd'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import AudioPlayer from '@/features/AudioPlayer'; @@ -19,10 +20,11 @@ interface DancePanelProps { const DancePanel = (props: DancePanelProps) => { const { style, className } = props; const [tab, setTab] = useState('dance'); + const { t } = useTranslation(['common', 'panel']); const options = [ - { value: 'dance', label: '已订阅', icon: }, - { value: 'market', label: '发现', icon: }, + { value: 'dance', label: t('actions.subscribed'), icon: }, + { value: 'market', label: t('actions.market'), icon: }, ]; return ( @@ -30,7 +32,7 @@ const DancePanel = (props: DancePanelProps) => { className={className} panelKey="dance" style={style} - title="音乐与舞蹈" + title={t('dance.musicAndDance')} extra={} footer={ diff --git a/src/panels/MarketPanel/Market/index.tsx b/src/panels/MarketPanel/Market/index.tsx index 5628737f..703f249d 100644 --- a/src/panels/MarketPanel/Market/index.tsx +++ b/src/panels/MarketPanel/Market/index.tsx @@ -1,5 +1,6 @@ import { createStyles } from 'antd-style'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import TopBanner from '@/components/TopBanner'; @@ -30,12 +31,13 @@ const useStyles = createStyles(({ css }) => ({ const Agent = () => { const { styles } = useStyles(); + const { t } = useTranslation('panel'); return (
- +
diff --git a/src/panels/RolePanel/RoleEdit/Info/CoverWithUpload/index.tsx b/src/panels/RolePanel/RoleEdit/Info/CoverWithUpload/index.tsx index 99b89618..a097a72d 100644 --- a/src/panels/RolePanel/RoleEdit/Info/CoverWithUpload/index.tsx +++ b/src/panels/RolePanel/RoleEdit/Info/CoverWithUpload/index.tsx @@ -1,5 +1,6 @@ import { Upload } from 'antd'; import React, { CSSProperties, memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import EmptyGuide from '@/components/EmptyGuide'; import HolographicCard from '@/components/HolographicCard'; @@ -47,6 +48,7 @@ const CoverWithUpload = memo( }), [], ); + const { t } = useTranslation('panel'); return (
@@ -56,7 +58,7 @@ const CoverWithUpload = memo( ) : ( )} diff --git a/src/panels/RolePanel/RoleEdit/Info/Greeting/index.tsx b/src/panels/RolePanel/RoleEdit/Info/Greeting/index.tsx index bc8b8dc5..c6159ab6 100644 --- a/src/panels/RolePanel/RoleEdit/Info/Greeting/index.tsx +++ b/src/panels/RolePanel/RoleEdit/Info/Greeting/index.tsx @@ -1,5 +1,6 @@ import { Input } from 'antd'; import React, { CSSProperties, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { MAX_GREETING_LENGTH } from '@/constants/common'; import { agentSelectors, useAgentStore } from '@/store/agent'; @@ -11,6 +12,7 @@ interface Props { export default memo((props) => { const { style, className } = props; + const { t } = useTranslation('panel'); const [agent, updateAgentConfig] = useAgentStore((s) => [ agentSelectors.currentAgentItem(s), s.updateAgentConfig, @@ -22,7 +24,7 @@ export default memo((props) => { style={style} value={agent?.greeting} autoSize={{ minRows: 2, maxRows: 4 }} - placeholder="请输入角色与你打招呼时的用语" + placeholder={t('role.greetTip')} showCount maxLength={MAX_GREETING_LENGTH} onChange={(e) => { diff --git a/src/panels/RolePanel/RoleEdit/Info/ReadMe/index.tsx b/src/panels/RolePanel/RoleEdit/Info/ReadMe/index.tsx index 5ee7c36d..a87c8cc9 100644 --- a/src/panels/RolePanel/RoleEdit/Info/ReadMe/index.tsx +++ b/src/panels/RolePanel/RoleEdit/Info/ReadMe/index.tsx @@ -1,5 +1,6 @@ import { Input } from 'antd'; import React, { CSSProperties, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { MAX_README_LENGTH } from '@/constants/common'; import { agentSelectors, useAgentStore } from '@/store/agent'; @@ -11,6 +12,7 @@ interface Props { export default memo((props) => { const { style, className } = props; + const { t } = useTranslation('panel'); const [meta, updateAgentMeta] = useAgentStore((s) => [ agentSelectors.currentAgentMeta(s), s.updateAgentMeta, @@ -22,7 +24,7 @@ export default memo((props) => { style={style} value={meta?.readme} autoSize={{ minRows: 10, maxRows: 10 }} - placeholder="请输入角色说明" + placeholder={t('role.roleReadmeTip')} showCount maxLength={MAX_README_LENGTH} onChange={(e) => { diff --git a/src/panels/RolePanel/RoleEdit/Info/RoleDescription/index.tsx b/src/panels/RolePanel/RoleEdit/Info/RoleDescription/index.tsx index f7b2e4be..6d86fdd1 100644 --- a/src/panels/RolePanel/RoleEdit/Info/RoleDescription/index.tsx +++ b/src/panels/RolePanel/RoleEdit/Info/RoleDescription/index.tsx @@ -1,5 +1,6 @@ import { Input } from 'antd'; import React, { CSSProperties, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { MAX_DESCRIPTION_LENGTH } from '@/constants/common'; import { agentSelectors, useAgentStore } from '@/store/agent'; @@ -11,6 +12,7 @@ interface Props { export default memo((props) => { const { style, className } = props; + const { t } = useTranslation('panel'); const [meta, updateAgentMeta] = useAgentStore((s) => [ agentSelectors.currentAgentMeta(s), s.updateAgentMeta, @@ -21,7 +23,7 @@ export default memo((props) => { className={className} style={style} value={meta?.description} - placeholder="请输入角色描述" + placeholder={t('role.roleDescriptionTip')} maxLength={MAX_DESCRIPTION_LENGTH} showCount onChange={(e) => { diff --git a/src/panels/RolePanel/RoleEdit/Info/RoleName/index.tsx b/src/panels/RolePanel/RoleEdit/Info/RoleName/index.tsx index 2f124481..55876778 100644 --- a/src/panels/RolePanel/RoleEdit/Info/RoleName/index.tsx +++ b/src/panels/RolePanel/RoleEdit/Info/RoleName/index.tsx @@ -1,5 +1,6 @@ import { Input } from 'antd'; import React, { CSSProperties, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { MAX_NAME_LENGTH } from '@/constants/common'; import { agentSelectors, useAgentStore } from '@/store/agent'; @@ -11,6 +12,7 @@ interface Props { export default memo((props) => { const { style, className } = props; + const { t } = useTranslation('panel'); const [meta, updateAgentMeta] = useAgentStore((s) => [ agentSelectors.currentAgentMeta(s), s.updateAgentMeta, @@ -21,7 +23,7 @@ export default memo((props) => { className={className} style={style} value={meta?.name} - placeholder="请输入角色名称" + placeholder={t('role.roleNameTip')} maxLength={MAX_NAME_LENGTH} showCount onChange={(e) => { diff --git a/src/panels/RolePanel/RoleEdit/Info/index.tsx b/src/panels/RolePanel/RoleEdit/Info/index.tsx index 5e0d884c..6b7ef858 100644 --- a/src/panels/RolePanel/RoleEdit/Info/index.tsx +++ b/src/panels/RolePanel/RoleEdit/Info/index.tsx @@ -2,6 +2,7 @@ import { Form, FormItem } from '@lobehub/ui'; import { createStyles } from 'antd-style'; import classNames from 'classnames'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { COVER_COMPRESS_HEIGHT, COVER_COMPRESS_WIDTH } from '@/constants/common'; import { INPUT_WIDTH_L, INPUT_WIDTH_M } from '@/constants/token'; @@ -51,6 +52,7 @@ const Info = (props: InfoProps) => { const { style, className } = props; const { styles } = useStyles(); const [form] = Form.useForm(); + const { t } = useTranslation('panel'); return ( @@ -58,16 +60,16 @@ const Info = (props: InfoProps) => {
{ { - +
diff --git a/src/panels/RolePanel/RoleEdit/Model/Touch/ActionList/Actions/AddOrEdit.tsx b/src/panels/RolePanel/RoleEdit/Model/Touch/ActionList/Actions/AddOrEdit.tsx index 47906c6a..fe28be81 100644 --- a/src/panels/RolePanel/RoleEdit/Model/Touch/ActionList/Actions/AddOrEdit.tsx +++ b/src/panels/RolePanel/RoleEdit/Model/Touch/ActionList/Actions/AddOrEdit.tsx @@ -3,6 +3,7 @@ import { VRMExpressionPresetName } from '@pixiv/three-vrm'; import { Input, Modal, Select } from 'antd'; import { Edit2Icon, Plus } from 'lucide-react'; import React, { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { INPUT_WIDTH_M, INPUT_WIDTH_S } from '@/constants/token'; import { MAX_TOUCH_ACTION_TEXT_LENGTH, TOUCH_EMOTION_OPTIONS } from '@/constants/touch'; @@ -20,6 +21,7 @@ export default memo((props: Props) => { const { touchArea, index, touchAction, isEdit = true } = props; const [open, setOpen] = useState(false); const [form] = Form.useForm(); + const { t } = useTranslation(['common', 'panel']); const [updateTouchAction, createTouchAction] = useAgentStore((s) => [ s.updateTouchAction, @@ -49,7 +51,7 @@ export default memo((props: Props) => { <> { open={open} width={800} destroyOnClose - title={isEdit ? '编辑响应动作' : '添加响应动作'} - okText={'确定'} - cancelText={'取消'} + title={isEdit ? t('touch.editAction') : t('touch.addAction')} + okText={t('confirm')} + cancelText={t('cancel')} > { preserve={false} > { />