mirror of
https://github.com/coaidev/coai.git
synced 2025-05-19 13:00:14 +09:00
589 lines
24 KiB
TypeScript
589 lines
24 KiB
TypeScript
import i18n from "i18next";
|
||
import { initReactI18next } from "react-i18next";
|
||
|
||
// the translations
|
||
// (tip move them in a JSON file and import them,
|
||
// or even better, manage them separated from your code: https://react.i18next.com/guides/multiple-translation-files)
|
||
const resources = {
|
||
en: {
|
||
translation: {
|
||
end: ".", // end of sentence
|
||
"not-found": "Page not found",
|
||
home: "Home",
|
||
login: "Login",
|
||
"login-require": "You need to login to use this feature",
|
||
logout: "Logout",
|
||
quota: "Quota",
|
||
"try-again": "Try again",
|
||
"invalid-token": "Invalid token",
|
||
"invalid-token-prompt": "Please try again.",
|
||
"login-failed": "Login failed",
|
||
"login-failed-prompt":
|
||
"Login failed! Please check your token expiration and try again.",
|
||
"login-success": "Login successful",
|
||
"login-success-prompt": "You have been logged in successfully.",
|
||
"server-error": "Server error",
|
||
"server-error-prompt":
|
||
"There was an error logging you in. Please try again.",
|
||
"request-failed":
|
||
"Request failed. Please check your network and try again.",
|
||
close: "Close",
|
||
edit: "Edit",
|
||
conversation: {
|
||
title: "Conversation",
|
||
empty: "Empty",
|
||
"refresh-failed": "Refresh failed",
|
||
"refresh-failed-prompt":
|
||
"There was an error during your request. Please try again.",
|
||
"remove-title": "Are you absolutely sure?",
|
||
"remove-description":
|
||
"This action cannot be undone. This will permanently delete the conversation ",
|
||
cancel: "Cancel",
|
||
delete: "Delete",
|
||
"delete-conversation": "Delete Conversation",
|
||
"delete-success": "Conversation deleted",
|
||
"delete-success-prompt": "Conversation has been deleted.",
|
||
"delete-failed": "Delete failed",
|
||
"delete-failed-prompt":
|
||
"Failed to delete conversation. Please check your network and try again.",
|
||
},
|
||
chat: {
|
||
web: "web searching feature",
|
||
"web-aria": "Toggle web searching feature",
|
||
placeholder: "Write something (/image to generate image)",
|
||
},
|
||
message: {
|
||
copy: "Copy",
|
||
save: "Save as File",
|
||
use: "Use Message",
|
||
},
|
||
"quota-description": "spending quota for the message",
|
||
buy: {
|
||
choose: "Choose an amount",
|
||
other: "Other",
|
||
"other-desc": "How many points?",
|
||
buy: "Buy {{amount}} points",
|
||
dalle: "DALL·E Image Generator",
|
||
"dalle-free": "5 free quotas per day",
|
||
flex: "Flexible Billing",
|
||
input: "Input",
|
||
output: "Output",
|
||
tip: "Prices have been aligned (or lower) to OpenAI models",
|
||
"learn-more": "Learn more",
|
||
"dialog-title": "Buy Points",
|
||
"dialog-desc": "Are you sure you want to buy {{amount}} points?",
|
||
"dialog-cancel": "Cancel",
|
||
"dialog-buy": "Buy",
|
||
success: "Purchase successful",
|
||
"success-prompt": "You have successfully purchased {{amount}} points.",
|
||
failed: "Purchase failed",
|
||
"failed-prompt":
|
||
"Failed to purchase points. Please make sure you have enough balance, you will soon jump to deeptrain wallet to pay balance.",
|
||
"gpt4-tip": "Tip: web searching feature may consume more input points",
|
||
},
|
||
pkg: {
|
||
title: "Packages",
|
||
go: "Go to Verify",
|
||
cert: "Certification Package",
|
||
"cert-desc":
|
||
"After real-name certification, you can get 50 points (worth 5 CNY)",
|
||
teen: "Teenager Package",
|
||
"teen-desc":
|
||
"After real-name certification, teenagers (18 years old and below) can get an additional 150 points (worth 15 CNY)",
|
||
close: "Close",
|
||
state: {
|
||
true: "Received",
|
||
false: "Not Received",
|
||
},
|
||
},
|
||
sub: {
|
||
title: "Subscription",
|
||
"dialog-title": "Subscription Plan",
|
||
free: "Free",
|
||
"free-price": "Free Forever",
|
||
pro: "Pro",
|
||
"pro-price": "8 CNY/Month",
|
||
"free-gpt3": "GPT-3.5 (16k) Free Forever",
|
||
"free-dalle": "5 free quotas per day",
|
||
"free-web": "web searching feature",
|
||
"free-conversation": "conversation storage",
|
||
"free-api": "API calls",
|
||
"pro-gpt4": "GPT-4 50 requests per day",
|
||
"pro-dalle": "50 quotas per day",
|
||
"pro-service": "Priority Service Support",
|
||
"pro-thread": "Concurrency Increase",
|
||
current: "Current Plan",
|
||
upgrade: "Upgrade",
|
||
renew: "Renew",
|
||
"cannot-select": "Cannot Select",
|
||
"select-time": "Select Subscription Time",
|
||
price: "Price {{price}} CNY",
|
||
expired: "Your Pro subscription will expire in {{expired}} days",
|
||
time: {
|
||
1: "1 Month",
|
||
3: "3 Months",
|
||
6: "6 Months",
|
||
12: "1 Year",
|
||
36: "3 Years",
|
||
},
|
||
success: "Subscribe success",
|
||
"success-prompt":
|
||
"You have successfully subscribed to {{month}} months of Pro.",
|
||
failed: "Subscribe failed",
|
||
"failed-prompt":
|
||
"Failed to subscribe, please make sure you have enough balance, you will soon jump to deeptrain wallet to pay balance.",
|
||
},
|
||
cancel: "Cancel",
|
||
confirm: "Confirm",
|
||
percent: "{{cent}}0%",
|
||
file: {
|
||
upload: "Upload File",
|
||
type: "Currently only text files are supported for upload",
|
||
drop: "Drag and drop files here or click to upload",
|
||
"parse-error": "Parse Error",
|
||
"parse-error-prompt":
|
||
"Parse error, currently only text files are supported",
|
||
"max-length": "Content too long",
|
||
"max-length-prompt":
|
||
"The content has been truncated due to the context length limit",
|
||
},
|
||
generate: {
|
||
title: "AI Project Generator",
|
||
"input-placeholder": "generate a python game",
|
||
failed: "Generate failed",
|
||
reason: "Reason: ",
|
||
success: "Generate success",
|
||
"success-prompt":
|
||
"Project generated successfully! Please select the download format.",
|
||
empty: "generating...",
|
||
download: "Download {{name}} format",
|
||
},
|
||
api: {
|
||
title: "API Settings",
|
||
copied: "Copied",
|
||
"copied-description": "API key has been copied to clipboard",
|
||
"learn-more": "Learn more",
|
||
},
|
||
service: {
|
||
title: "New Version Available",
|
||
description: "A new version is available. Do you want to update now?",
|
||
update: "Update",
|
||
"offline-title": "Offline Mode",
|
||
offline: "App is currently offline.",
|
||
"update-success": "Update Success",
|
||
"update-success-prompt": "You have been updated to the latest version.",
|
||
},
|
||
share: {
|
||
title: "Share",
|
||
"share-conversation": "Share Conversation",
|
||
description: "Share this conversation with others: ",
|
||
"copy-link": "Copy Link",
|
||
"view": "View",
|
||
success: "Share success",
|
||
failed: "Share failed",
|
||
copied: "Copied",
|
||
"copied-description": "Link has been copied to clipboard",
|
||
"not-found": "Conversation not found",
|
||
"not-found-description": "Conversation not found, please check if the link is correct or the conversation has been deleted",
|
||
}
|
||
},
|
||
},
|
||
cn: {
|
||
translation: {
|
||
end: "",
|
||
"not-found": "页面未找到",
|
||
home: "首页",
|
||
login: "登录",
|
||
"login-require": "您需要登录才能使用此功能",
|
||
logout: "登出",
|
||
quota: "配额",
|
||
"try-again": "重试",
|
||
"invalid-token": "无效的令牌",
|
||
"invalid-token-prompt": "请重试。",
|
||
"login-failed": "登录失败",
|
||
"login-failed-prompt": "登录失败!请检查您的令牌过期时间并重试。",
|
||
"login-success": "登录成功",
|
||
"login-success-prompt": "您已成功登录。",
|
||
"server-error": "服务器错误",
|
||
"server-error-prompt": "登录出错,请重试。",
|
||
"request-failed": "请求失败,请检查您的网络并重试。",
|
||
close: "关闭",
|
||
edit: "编辑",
|
||
conversation: {
|
||
title: "对话",
|
||
empty: "空空如也",
|
||
"refresh-failed": "刷新失败",
|
||
"refresh-failed-prompt": "请求出错,请重试。",
|
||
"remove-title": "是否确定?",
|
||
"remove-description": "此操作无法撤消。这将永久删除对话 ",
|
||
cancel: "取消",
|
||
delete: "删除",
|
||
"delete-conversation": "删除对话",
|
||
"delete-success": "对话已删除",
|
||
"delete-success-prompt": "对话已删除。",
|
||
"delete-failed": "删除失败",
|
||
"delete-failed-prompt": "删除对话失败,请检查您的网络并重试。",
|
||
},
|
||
chat: {
|
||
web: "联网搜索功能",
|
||
"web-aria": "切换网络搜索功能",
|
||
placeholder: "写点什么 (/image 生成图片)",
|
||
},
|
||
message: {
|
||
copy: "复制",
|
||
save: "保存为文件",
|
||
use: "使用消息",
|
||
},
|
||
"quota-description": "消息的配额支出",
|
||
buy: {
|
||
choose: "选择一个金额",
|
||
other: "其他",
|
||
"other-desc": "多少点数?",
|
||
buy: "购买 {{amount}} 点数",
|
||
dalle: "DALL·E AI 绘图",
|
||
"dalle-free": "每天 5 次免费绘图配额",
|
||
flex: "灵活计费",
|
||
input: "输入",
|
||
output: "输出",
|
||
tip: "价格已对齐OpenAI模型或低于官方价格",
|
||
"learn-more": "了解更多",
|
||
"dialog-title": "购买点数",
|
||
"dialog-desc": "您确定要购买 {{amount}} 点数吗?",
|
||
"dialog-cancel": "取消",
|
||
"dialog-buy": "购买",
|
||
success: "购买成功",
|
||
"success-prompt": "您已成功购买 {{amount}} 点数。",
|
||
failed: "购买失败",
|
||
"failed-prompt":
|
||
"购买点数失败。请确保您有足够的余额,您即将跳转到 deeptrain 钱包支付余额。",
|
||
"gpt4-tip": "提示:web 联网版功能可能会带来更多的输入点数消耗",
|
||
},
|
||
pkg: {
|
||
title: "礼包",
|
||
go: "前往实名认证",
|
||
cert: "实名认证礼包",
|
||
"cert-desc": "实名认证后可获得 50 点数 (价值 5 元)",
|
||
teen: "未成年人福利",
|
||
"teen-desc":
|
||
"实名认证后未成年人(18 周岁及以下)可额外获得 150 点数 (价值 15 元)",
|
||
close: "关闭",
|
||
state: {
|
||
true: "已领取",
|
||
false: "无法领取",
|
||
},
|
||
},
|
||
sub: {
|
||
title: "订阅",
|
||
"dialog-title": "订阅计划",
|
||
free: "免费版",
|
||
"free-price": "永久免费",
|
||
pro: "专业版",
|
||
"pro-price": "8 元/月",
|
||
"free-gpt3": "GPT-3.5 (16k) 永久免费",
|
||
"free-dalle": "每日 5 次免费绘图",
|
||
"free-web": "联网搜索功能",
|
||
"free-conversation": "对话存储记录",
|
||
"free-api": "API 调用",
|
||
"pro-gpt4": "GPT-4 每日请求 50 次",
|
||
"pro-dalle": "每日 50 次绘图",
|
||
"pro-service": "优先服务支持",
|
||
"pro-thread": "并发数提升",
|
||
current: "当前计划",
|
||
upgrade: "升级",
|
||
renew: "续费",
|
||
"cannot-select": "无法选择",
|
||
"select-time": "选择订阅时间",
|
||
price: "价格 {{price}} 元",
|
||
expired: "您的专业版订阅还有 {{expired}} 天到期",
|
||
time: {
|
||
1: "1个月",
|
||
3: "3个月",
|
||
6: "半年",
|
||
12: "1年",
|
||
36: "3年",
|
||
},
|
||
success: "订阅成功",
|
||
"success-prompt": "您已成功订阅 {{month}} 月专业版。",
|
||
failed: "订阅失败",
|
||
"failed-prompt":
|
||
"订阅失败,请确保您有足够的余额,您即将跳转到 deeptrain 钱包支付余额。",
|
||
},
|
||
cancel: "取消",
|
||
confirm: "确认",
|
||
percent: "{{cent}}折",
|
||
file: {
|
||
upload: "上传文件",
|
||
type: "当前仅支持上传文本类型文件",
|
||
drop: "拖拽文件到此处或点击上传",
|
||
"parse-error": "解析失败",
|
||
"parse-error-prompt": "解析失败,当前仅支持文本类型文件",
|
||
"max-length": "内容过长",
|
||
"max-length-prompt": "由于上下文长度限制,内容已被截取",
|
||
},
|
||
generate: {
|
||
title: "AI 项目生成器",
|
||
"input-placeholder": "生成一个python小游戏",
|
||
failed: "生成失败",
|
||
reason: "原因:",
|
||
success: "生成成功",
|
||
"success-prompt": "成功生成项目!请选择下载格式。",
|
||
empty: "生成中...",
|
||
download: "下载 {{name}} 格式",
|
||
},
|
||
api: {
|
||
title: "API 设置",
|
||
copied: "复制成功",
|
||
"copied-description": "API 密钥已复制到剪贴板",
|
||
"learn-more": "了解更多",
|
||
},
|
||
service: {
|
||
title: "发现新版本",
|
||
description: "发现新版本,是否立即更新?",
|
||
update: "更新",
|
||
"offline-title": "离线模式",
|
||
offline: "应用当前处于离线状态。",
|
||
"update-success": "更新成功",
|
||
"update-success-prompt": "您已更新至最新版本。",
|
||
},
|
||
share: {
|
||
title: "分享",
|
||
"share-conversation": "分享对话",
|
||
description: "将此对话与他人分享:",
|
||
"copy-link": "复制链接",
|
||
"view": "查看",
|
||
success: "分享成功",
|
||
failed: "分享失败",
|
||
copied: "复制成功",
|
||
"copied-description": "链接已复制到剪贴板",
|
||
"not-found": "对话未找到",
|
||
"not-found-description": "对话未找到,请检查链接是否正确或对话是否已被删除",
|
||
}
|
||
},
|
||
},
|
||
ru: {
|
||
translation: {
|
||
end: "",
|
||
"not-found": "Страница не найдена",
|
||
home: "Главная",
|
||
login: "Войти",
|
||
"login-require": "Вам нужно войти, чтобы использовать эту функцию",
|
||
logout: "Выйти",
|
||
quota: "Квота",
|
||
"try-again": "Попробуйте еще раз",
|
||
"invalid-token": "Неверный токен",
|
||
"invalid-token-prompt": "Пожалуйста, попробуйте еще раз.",
|
||
"login-failed": "Ошибка входа",
|
||
"login-failed-prompt":
|
||
"Ошибка входа! Пожалуйста, проверьте срок действия вашего токена и попробуйте еще раз.",
|
||
"login-success": "Успешный вход",
|
||
"login-success-prompt": "Вы успешно вошли в систему.",
|
||
"server-error": "Ошибка сервера",
|
||
"server-error-prompt":
|
||
"При входе произошла ошибка. Пожалуйста, попробуйте еще раз.",
|
||
"request-failed":
|
||
"Ошибка запроса. Пожалуйста, проверьте свою сеть и попробуйте еще раз.",
|
||
close: "Закрыть",
|
||
edit: "Редактировать",
|
||
conversation: {
|
||
title: "Разговор",
|
||
empty: "Пусто",
|
||
"refresh-failed": "Ошибка обновления",
|
||
"refresh-failed-prompt":
|
||
"При выполнении запроса произошла ошибка. Пожалуйста, попробуйте еще раз.",
|
||
"remove-title": "Вы уверены?",
|
||
"remove-description":
|
||
"Это действие нельзя отменить. Это навсегда удалит разговор ",
|
||
cancel: "Отмена",
|
||
delete: "Удалить",
|
||
"delete-conversation": "Удалить разговор",
|
||
"delete-success": "Разговор удален",
|
||
"delete-success-prompt": "Разговор был удален.",
|
||
"delete-failed": "Ошибка удаления",
|
||
"delete-failed-prompt":
|
||
"Не удалось удалить разговор. Пожалуйста, проверьте свою сеть и попробуйте еще раз.",
|
||
},
|
||
chat: {
|
||
web: "веб-поиск",
|
||
"web-aria": "Переключить веб-поиск",
|
||
placeholder: "Напишите что-нибудь (/image для генерации изображения)",
|
||
},
|
||
message: {
|
||
copy: "Копировать",
|
||
save: "Сохранить как файл",
|
||
use: "Использовать сообщение",
|
||
},
|
||
"quota-description": "квота расходов на сообщение",
|
||
buy: {
|
||
choose: "Выберите сумму",
|
||
other: "Другое",
|
||
"other-desc": "Сколько очков?",
|
||
buy: "Купить {{amount}} очков",
|
||
dalle: "Генератор изображений DALL·E",
|
||
"dalle-free": "5 бесплатных квот в день",
|
||
flex: "Гибкая тарификация",
|
||
input: "Вход",
|
||
output: "Выход",
|
||
tip: "Цены выровнены (или ниже) по моделям OpenAI",
|
||
"learn-more": "Узнать больше",
|
||
"dialog-title": "Купить очки",
|
||
"dialog-desc": "Вы уверены, что хотите купить {{amount}} очков?",
|
||
"dialog-cancel": "Отмена",
|
||
"dialog-buy": "Купить",
|
||
success: "Покупка прошла успешно",
|
||
"success-prompt": "Вы успешно приобрели {{amount}} очков.",
|
||
failed: "Покупка не удалась",
|
||
"failed-prompt":
|
||
"Не удалось приобрести очки. Пожалуйста, убедитесь, что у вас достаточно баланса, вы скоро перейдете в кошелек deeptrain для оплаты баланса.",
|
||
"gpt4-tip":
|
||
"Совет: функция веб-поиска может потреблять больше входных очков",
|
||
},
|
||
pkg: {
|
||
title: "Пакеты",
|
||
go: "Перейти к проверке",
|
||
cert: "Пакет сертификации",
|
||
"cert-desc":
|
||
"После сертификации подлинности вы можете получить 50 очков (стоимостью 5 CNY)",
|
||
teen: "Подростковый пакет",
|
||
"teen-desc":
|
||
"После сертификации подлинности подростки (до 18 лет) могут получить дополнительно 150 очков (стоимостью 15 CNY)",
|
||
close: "Закрыть",
|
||
state: {
|
||
true: "Получено",
|
||
false: "Не получено",
|
||
},
|
||
},
|
||
sub: {
|
||
title: "Подписка",
|
||
"dialog-title": "Подписка",
|
||
free: "Бесплатно",
|
||
"free-price": "Бесплатно навсегда",
|
||
pro: "Профессиональный",
|
||
"pro-price": "8 CNY/месяц",
|
||
"free-gpt3": "GPT-3.5 (16k) бесплатно навсегда",
|
||
"free-dalle": "5 бесплатных квот в день",
|
||
"free-web": "веб-поиск",
|
||
"free-conversation": "хранение разговоров",
|
||
"free-api": "API вызовы",
|
||
"pro-gpt4": "GPT-4 50 запросов в день",
|
||
"pro-dalle": "50 квот в день",
|
||
"pro-service": "Приоритетная служба поддержки",
|
||
"pro-thread": "Увеличение параллелизма",
|
||
current: "Текущая подписка",
|
||
upgrade: "Обновить",
|
||
renew: "Продлить",
|
||
"cannot-select": "Невозможно выбрать",
|
||
"select-time": "Выберите время подписки",
|
||
price: "Цена {{price}} CNY",
|
||
expired: "Ваша подписка Pro истечет через {{expired}} дней",
|
||
time: {
|
||
1: "1 месяц",
|
||
3: "3 месяца",
|
||
6: "6 месяцев",
|
||
12: "1 год",
|
||
36: "3 года",
|
||
},
|
||
success: "Подписка успешна",
|
||
"success-prompt": "Вы успешно подписались на {{month}} месяцев Pro.",
|
||
failed: "Подписка не удалась",
|
||
"failed-prompt":
|
||
"Не удалось подписаться, пожалуйста, убедитесь, что у вас достаточно баланса, вы скоро перейдете в кошелек deeptrain для оплаты баланса.",
|
||
},
|
||
cancel: "Отмена",
|
||
confirm: "Подтвердить",
|
||
percent: "{{cent}}0%",
|
||
file: {
|
||
upload: "Загрузить файл",
|
||
type: "В настоящее время поддерживаются только текстовые файлы для загрузки",
|
||
drop: "Перетащите файлы сюда или нажмите, чтобы загрузить",
|
||
"parse-error": "Ошибка разбора",
|
||
"parse-error-prompt":
|
||
"Ошибка разбора, в настоящее время поддерживаются только текстовые файлы",
|
||
"max-length": "Слишком длинный контент",
|
||
"max-length-prompt":
|
||
"Содержимое было усечено из-за ограничения длины контекста",
|
||
},
|
||
generate: {
|
||
title: "Генератор AI проектов",
|
||
"input-placeholder": "сгенерировать python игру",
|
||
failed: "Генерация не удалась",
|
||
reason: "Причина: ",
|
||
success: "Генерация успешна",
|
||
"success-prompt":
|
||
"Проект успешно сгенерирован! Пожалуйста, выберите формат загрузки.",
|
||
empty: "генерация...",
|
||
download: "Загрузить {{name}} формат",
|
||
},
|
||
api: {
|
||
title: "Настройки API",
|
||
copied: "Скопировано",
|
||
"copied-description": "Ключ API скопирован в буфер обмена",
|
||
"learn-more": "Узнать больше",
|
||
},
|
||
service: {
|
||
title: "Доступна новая версия",
|
||
description: "Доступна новая версия. Хотите обновить сейчас?",
|
||
update: "Обновить",
|
||
"offline-title": "Режим оффлайн",
|
||
offline: "Приложение в настоящее время находится в автономном режиме.",
|
||
"update-success": "Обновление успешно",
|
||
"update-success-prompt": "Вы обновились до последней версии.",
|
||
},
|
||
share: {
|
||
title: "Поделиться",
|
||
"share-conversation": "Поделиться разговором",
|
||
description: "Поделитесь этим разговором с другими: ",
|
||
"copy-link": "Скопировать ссылку",
|
||
"view": "Посмотреть",
|
||
success: "Поделиться успешно",
|
||
failed: "Поделиться не удалось",
|
||
copied: "Скопировано",
|
||
"copied-description": "Ссылка скопирована в буфер обмена",
|
||
"not-found": "Разговор не найден",
|
||
"not-found-description": "Разговор не найден, пожалуйста, проверьте, правильная ли ссылка или разговор был удален",
|
||
}
|
||
},
|
||
},
|
||
};
|
||
|
||
export const supportedLanguages = ["en", "cn", "ru"];
|
||
|
||
i18n
|
||
.use(initReactI18next)
|
||
.init({
|
||
resources,
|
||
lng: getStorage(),
|
||
fallbackLng: "en",
|
||
interpolation: {
|
||
escapeValue: false, // react already safes from xss
|
||
},
|
||
})
|
||
.then(() => console.debug(`[i18n] initialized (language: ${i18n.language})`));
|
||
|
||
export default i18n;
|
||
|
||
export function getStorage(): string {
|
||
const storage = localStorage.getItem("language");
|
||
if (storage && supportedLanguages.includes(storage)) {
|
||
return storage;
|
||
}
|
||
// get browser language
|
||
const lang = navigator.language.split("-")[0];
|
||
if (supportedLanguages.includes(lang)) {
|
||
return lang;
|
||
}
|
||
return "cn";
|
||
}
|
||
|
||
export function setLanguage(i18n: any, lang: string): void {
|
||
if (supportedLanguages.includes(lang)) {
|
||
i18n
|
||
.changeLanguage(lang)
|
||
.then(() =>
|
||
console.debug(`[i18n] language changed (language: ${i18n.language})`),
|
||
);
|
||
localStorage.setItem("language", lang);
|
||
return;
|
||
}
|
||
console.warn(`[i18n] language ${lang} is not supported`);
|
||
}
|