coai/app/src/i18n.ts
2023-10-18 23:29:17 +08:00

589 lines
24 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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`);
}