Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:添加国际化 #935

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"file-saver": "^2.0.5",
"howler": "^2.2.3",
"html-to-image": "^1.11.11",
"i18next": "^24.2.2",
"immer": "^9.0.21",
"jotai": "^2.0.3",
"lucide-react": "^0.294.0",
Expand All @@ -44,6 +45,7 @@
"react-app-polyfill": "^3.0.0",
"react-dom": "^18.2.0",
"react-hotkeys-hook": "^4.3.7",
"react-i18next": "^15.4.0",
"react-router-dom": "^6.8.2",
"react-timer-hook": "^3.0.5",
"react-tooltip": "^5.18.0",
Expand Down
18 changes: 18 additions & 0 deletions src/hooks/useI18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useTranslation } from 'react-i18next'

const useI18n = () => {
const { t } = useTranslation()
const getI18n = (key: string, values?: Array<string>): string => {
let i18nStr = t(key)
if (values && values.length > 0) {
values.forEach((item, index) => {
i18nStr = i18nStr.replace('{' + index + '}', item)
})
}
return i18nStr
}

return getI18n
}

export default useI18n
23 changes: 23 additions & 0 deletions src/i18n/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import en from './en.json'
import zh from './zh.json'
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'

const resources = {
en: {
translation: en,
},
zh: {
translation: zh,
},
}

i18n.use(initReactI18next).init({
resources,
lng: 'zh',
interpolation: {
escapeValue: false,
},
})

export default i18n
140 changes: 140 additions & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"Home_Press_Any_Key_To_Start": "Press Any Key to Start",
"Home_Time": "Time",
"Home_Input_Count": "Input Count",
"Home_WPM": "WPM",
"Home_Correct_Count": "Correct Count",
"Home_Accuracy": "Accuracy",
"Home_Tooltip_Section_Switch": "Chapter Switch",
"Home_Chapter": "Chapter {0}",
"Home_Tooltip_Pronunciation_Toggle": "Pronunciation & Phonetic Toggle",
"Home_Toggle_Phonetics_Display_Title": "Toggle Phonetics Display",
"Home_Phonetics_Started": "Phonetics Enabled",
"Home_Phonetics_Closed": "Phonetics Disabled",
"Home_Toggle_Word_Pronunciation_Title": "Toggle Word Pronunciation",
"Home_Word_Pronunciation_Started": "Word Pronunciation Enabled",
"Home_Word_Pronunciation_Closed": "Word Pronunciation Disabled",
"Home_Toggle_Definition_Pronunciation_Title": "Toggle Definition Pronunciation",
"Home_Definition_Pronunciation_Started": "Definition Pronunciation Enabled",
"Home_Definition_Pronunciation_Closed": "Definition Pronunciation Disabled",
"Home_Toggle_Loop_Pronunciation_Title": "Toggle Loop Pronunciation",
"Home_Loop_Closed": "Loop Disabled",
"Home_Loop_Started": "Loop Enabled",
"Home_Toggle_Word_Pronunciation_Accent": "Word Pronunciation Accent",
"Home_Accent_American": "American",
"Home_Accent_British": "British",
"Home_Tips_Pronunciation_Shortcut": "Tips: Pronunciation Shortcut (Ctrl + J)",
"Home_Tooltip_Sound_Effects": "Sound Effects Settings",
"Home_Toggle_Key_Sound": "Toggle Key Sound",
"Home_Key_Sound_Started": "Key Sound Enabled",
"Home_Key_Sound_Closed": "Key Sound Disabled",
"Home_Toggle_Effect_Sound": "Toggle Effect Sound",
"Home_Effect_Sound_Started": "Effect Sound Enabled",
"Home_Effect_Sound_Closed": "Effect Sound Disabled",
"Home_Tooltip_Set_Single_Word_Loop": "Set Single Word Loop",
"Home_Choose_Loop_Count_Title": "Choose Word Loop Count",
"Home_Loop_Infinite": "Infinite",
"Home_Tooltip_Dictation_Mode": "Toggle Dictation Mode",
"Home_Dictation_Started": "Dictation Enabled",
"Home_Dictation_Closed": "Dictation Disabled",
"Home_Toggle_Dictation_Mode_Title": "Toggle Dictation Mode",
"Home_Dictation_Mode": "Dictation Mode",
"Home_Hide_All": "Hide All",
"Home_Hide_Vowels": "Hide Vowels",
"Home_Hide_Consonants": "Hide Consonants",
"Home_Hide_Random": "Hide Random",
"Home_Tooltip_Definition_Display": "Toggle Definition Display (Ctrl + Shift + V)",
"Home_Tooltip_Dark_Mode": "Toggle Dark Mode",
"Home_Tooltip_Finger_Guide": "Finger Guide",
"Home_Finger_Guide_Recommended": "Recommended Typing Finger Guide",
"Home_Tooltip_Start": "Start (Enter)",
"Home_Start": "Start",
"Home_Restart": "Restart",
"Dictionary_Tooltip_Switch": "Dictionary Switch",
"Dictionary_Not_Found": "Can't Find the Desired Dictionary?",
"Dictionary_Language": "Language",
"Dictionary_English": "English",
"Dictionary_College_English": "College English",
"Dictionary_English_For_Postgraduate": "Postgraduate English",
"Dictionary_Professional_English": "Professional English",
"Dictionary_PET": "PET",
"Dictionary_Self_Taught_English_2": "Self-Taught English Level 2",
"Dictionary_Other": "Other",
"Dictionary_Japanese": "Japanese",
"Dictionary_Basic_Japanese": "Basic",
"Dictionary_German": "German",
"Dictionary_Basic_German": "Basic",
"Dictionary_Kazakh": "Kazakh Language",
"Dictionary_Old_Writing": "Old Script",
"Dictionary_Kazakh_Latin": "Kazakh Latin",
"Dictionary_Kazakh_Cyrillic": "Kazakh Cyrillic",
"Dictionary_Indonesian": "Indonesian",
"Dictionary_Basic_Indonesian": "Basic",
"Dictionary_Code": "Code",
"Dictionary_Common_Code": "Common",
"Dictionary_Children_Programming": "Children's Programming",
"Dictionary_Python": "Python",
"Dictionary_CPP": "C++",
"Dictionary_Arduino": "Arduino",
"Dictionary_JavaScript": "JavaScript",
"Dictionary_Java": "Java",
"Dictionary_Linux": "Linux",
"Dictionary_CSharp": "C#",
"Dictionary_SQL": "SQL",
"Dictionary_AI": "AI",
"Dictionary_Golang": "Golang",
"Dictionary_Rust": "Rust",
"Dictionary_Warning": "Warning: The dictionary data for this project comes from various open-source projects and contributions from the community. We deeply appreciate and respect the intellectual property rights of every contributor. This data is for personal learning and research use only, and any commercial use is strictly prohibited. If you are the copyright holder of any data and believe our use infringes your rights, please contact us via the email at the bottom of the website. Upon receiving a valid copyright complaint, we will remove the related content or seek the necessary permissions as soon as possible. We also encourage all users of this data to respect the rights of the copyright holders and comply with all relevant laws and regulations. Please note, while we strive to ensure the legality and accuracy of all data, we cannot guarantee the accuracy, completeness, legality, or reliability of any data. Users assume all risks associated with the use of this data.",
"Mistakes_Book_Tooltip": "Mistake Book",
"Mistakes_Book_Tips": "Tips: Click on the wrong word to view detailed information",
"Mistakes_Book_Word": "Word",
"Mistakes_Book_Definition": "Definition",
"Mistakes_Book_Error_Count": "Error Count",
"Mistakes_Book_Dictionary": "Dictionary",
"Mistakes_Book_Export": "Export",
"Data_Stats_Tooltip": "View Data Stats",
"Data_Stats_Year_Exercise_Heatmap": "Past Year Exercise Heatmap",
"Data_Stats_Year_Exercise_Count": "Total {} Exercises in the Past Year",
"Data_Stats_Low": "Low",
"Data_Stats_High": "High",
"Data_Stats_Year_Word_Count_Heatmap": "Past Year Word Count Heatmap",
"Data_Stats_Year_WPM_Trend": "Past Year WPM Trend",
"Data_Stats_Year_Accuracy_Trend": "Past Year Accuracy Trend",
"Data_Stats_Key_Error_Count_Rank": "Key Error Count Ranking",
"Setting_Sound_Settings": "Sound Settings",
"Setting_Sound_Word_Pronunciation": "Word Pronunciation",
"Setting_Sound_Volume": "Volume",
"Setting_Sound_Speed": "Speed",
"Setting_Sound_Definition_Pronunciation": "Definition Pronunciation",
"Setting_Sound_Key_Sound": "Key Sound",
"Setting_Sound_Key_Sound_Effect": "Key Sound Effect",
"Setting_Sound_Effect_Sound": "Effect Sound",
"Setting_Advanced_Settings": "Advanced Settings",
"Setting_Advanced_Chapter_Randomization": "Chapter Randomization",
"Setting_Advanced_Randomization_Enabled": "Randomization Enabled",
"Setting_Advanced_Randomization_Disabled": "Randomization Disabled",
"Setting_Advanced_Show_Previous_Next_Word": "Show Previous/Next Word in Practice",
"Setting_Advanced_Show_Word_Enabled": "Show Word Enabled",
"Setting_Advanced_Show_Word_Disabled": "Show Word Disabled",
"Setting_Advanced_Ignore_Case": "Ignore Case",
"Setting_Advanced_Ignore_Case_Enabled": "Ignore Case Enabled",
"Setting_Advanced_Ignore_Case_Disabled": "Ignore Case Disabled",
"Setting_Advanced_Allow_Select_Text": "Allow Text Selection",
"Setting_Advanced_Select_Text_Enabled": "Text Selection Enabled",
"Setting_Advanced_Select_Text_Disabled": "Text Selection Disabled",
"Setting_Advanced_Show_Tips_In_Dictation": "Show Tips in Dictation Mode",
"Setting_Advanced_Show_Tips_Enabled": "Show Tips Enabled",
"Setting_Advanced_Show_Tips_Disabled": "Show Tips Disabled",
"Setting_Font_Settings": "Font Settings",
"Setting_Font_Foreign_Font": "Foreign Language Font",
"Setting_Font_Chinese_Font": "Chinese Font",
"Setting_Font_Reset": "Reset Font Settings",
"Setting_Data_Settings": "Data Settings",
"Setting_Data_Export": "Data Export",
"Setting_Data_Export_Description": "Currently, your practice data is stored locally. If you wish to use Qwerty Learner on different devices, browsers, or unofficial deployments, you need to manually sync and save your data. We recommend backing up your data in time for progress retention and upcoming data analysis features.",
"Setting_Data_Export_Warning": "Please do not modify the exported data files for your safety.",
"Setting_Data_Export_Button": "Export Data",
"Setting_Data_Import": "Data Import",
"Setting_Data_Import_Warning": "Please proceed with caution, importing data will completely overwrite the current data.",
"Setting_Data_Import_Button": "Import Data"
}
140 changes: 140 additions & 0 deletions src/i18n/zh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"Home_Press_Any_Key_To_Start": "按任意键开始",
"Home_Time": "时间",
"Home_Input_Count": "输入数",
"Home_WPM": "WPM",
"Home_Correct_Count": "正确数",
"Home_Accuracy": "正确率",
"Home_Tooltip_Section_Switch": "章节切换",
"Home_Chapter": "第{0}章",
"Home_Tooltip_Pronunciation_Toggle": "发音及音标切换",
"Home_Toggle_Phonetics_Display_Title": "开关音标显示",
"Home_Phonetics_Started": "音标已开始",
"Home_Phonetics_Closed": "音标已关闭",
"Home_Toggle_Word_Pronunciation_Title": "开关单词发音",
"Home_Word_Pronunciation_Started": "发音已开启",
"Home_Word_Pronunciation_Closed": "发音已关闭",
"Home_Toggle_Definition_Pronunciation_Title": "开关释义发音",
"Home_Definition_Pronunciation_Started": "发音已开启",
"Home_Definition_Pronunciation_Closed": "发音已关闭",
"Home_Toggle_Loop_Pronunciation_Title": "开关循环发音",
"Home_Loop_Closed": "循环已关闭",
"Home_Loop_Started": "循环已开启",
"Home_Toggle_Word_Pronunciation_Accent": "单词发音口音",
"Home_Accent_American": "美音",
"Home_Accent_British": "英音",
"Home_Tips_Pronunciation_Shortcut": "Tips: 朗读发音快捷键(Ctrl + J)",
"Home_Tooltip_Sound_Effects": "音效设置",
"Home_Toggle_Key_Sound": "开关按键音",
"Home_Key_Sound_Started": "发音已开启",
"Home_Key_Sound_Closed": "发音已关闭",
"Home_Toggle_Effect_Sound": "开关效果音",
"Home_Effect_Sound_Started": "发音已开启",
"Home_Effect_Sound_Closed": "发音已关闭",
"Home_Tooltip_Set_Single_Word_Loop": "设置单个单词循环",
"Home_Choose_Loop_Count_Title": "选择单词的循环次数",
"Home_Loop_Infinite": "无限",
"Home_Tooltip_Dictation_Mode": "开关默写模式",
"Home_Dictation_Started": "默写已开启",
"Home_Dictation_Closed": "默写已关闭",
"Home_Toggle_Dictation_Mode_Title": "开关默写模式",
"Home_Dictation_Mode": "默写模式",
"Home_Hide_All": "全部隐藏",
"Home_Hide_Vowels": "隐藏元音",
"Home_Hide_Consonants": "隐藏辅音",
"Home_Hide_Random": "随机隐藏",
"Home_Tooltip_Definition_Display": "开关释义显示(Ctrl + Shift + V)",
"Home_Tooltip_Dark_Mode": "开关深色模式",
"Home_Tooltip_Finger_Guide": "指法图示",
"Home_Finger_Guide_Recommended": "推荐打字指法图示",
"Home_Tooltip_Start": "开始(Enter)",
"Home_Start": "Start",
"Home_Restart": "Restart",
"Dictionary_Tooltip_Switch": "词典切换",
"Dictionary_Not_Found": "没有找到想要的词典?",
"Dictionary_Language": "Language",
"Dictionary_English": "英语",
"Dictionary_College_English": "大学英语",
"Dictionary_English_For_Postgraduate": "考研",
"Dictionary_Professional_English": "专业英语",
"Dictionary_PET": "PET",
"Dictionary_Self_Taught_English_2": "自考英语二",
"Dictionary_Other": "其他",
"Dictionary_Japanese": "日语",
"Dictionary_Basic_Japanese": "基础",
"Dictionary_German": "德语",
"Dictionary_Basic_German": "基础",
"Dictionary_Kazakh": "哈萨克语言",
"Dictionary_Old_Writing": "老文字",
"Dictionary_Kazakh_Latin": "哈拼",
"Dictionary_Kazakh_Cyrillic": "西里尔字母",
"Dictionary_Indonesian": "印尼语",
"Dictionary_Basic_Indonesian": "基础",
"Dictionary_Code": "Code",
"Dictionary_Common_Code": "通用",
"Dictionary_Children_Programming": "少儿编程",
"Dictionary_Python": "Python",
"Dictionary_CPP": "C++",
"Dictionary_Arduino": "Arduino",
"Dictionary_JavaScript": "JavaScript",
"Dictionary_Java": "Java",
"Dictionary_Linux": "Linux",
"Dictionary_CSharp": "C#",
"Dictionary_SQL": "SQL",
"Dictionary_AI": "AI",
"Dictionary_Golang": "Golang",
"Dictionary_Rust": "Rust",
"Dictionary_Warning": "warning: 本项目的词典数据来自多个开源项目以及社区贡献者的无偿提供。我们深感感激并尊重每一位贡献者的知识产权。 这些数据仅供个人学习和研究使用,严禁用于任何商业目的。如果你是数据的版权所有者,并且认为我们的使用方式侵犯了你的权利,请通过网站底部的电子邮件与我们联系。一旦收到有效的版权投诉,我们将在最短的时间内删除相关内容或寻求必要的许可。 同时,我们也鼓励所有使用这些数据的人尊重版权所有者的权利,并且在使用这些数据时遵守所有相关的法律和规定。 请注意,虽然我们尽力确保所有数据的合法性和准确性,但我们不能对任何数据的准确性、完整性、合法性或可靠性做出任何保证。使用这些数据的风险完全由用户自己承担。",
"Mistakes_Book_Tooltip": "错题本",
"Mistakes_Book_Tips": "Tips: 点击错误单词查看详细信息",
"Mistakes_Book_Word": "单词",
"Mistakes_Book_Definition": "释义",
"Mistakes_Book_Error_Count": "错误次数",
"Mistakes_Book_Dictionary": "词典",
"Mistakes_Book_Export": "导出",
"Data_Stats_Tooltip": "查看数据统计",
"Data_Stats_Year_Exercise_Heatmap": "过去一年练习次数热力图",
"Data_Stats_Year_Exercise_Count": "过去一年总计{}次",
"Data_Stats_Low": "少",
"Data_Stats_High": "多",
"Data_Stats_Year_Word_Count_Heatmap": "过去一年练习词数热力图",
"Data_Stats_Year_WPM_Trend": "过去一年WPM趋势图",
"Data_Stats_Year_Accuracy_Trend": "过去一年正确率趋势图",
"Data_Stats_Key_Error_Count_Rank": "按键错误次数排行",
"Setting_Sound_Settings": "音效设置",
"Setting_Sound_Word_Pronunciation": "单词发音",
"Setting_Sound_Volume": "音量",
"Setting_Sound_Speed": "倍速",
"Setting_Sound_Definition_Pronunciation": "释义发音",
"Setting_Sound_Key_Sound": "按键音",
"Setting_Sound_Key_Sound_Effect": "按键音效",
"Setting_Sound_Effect_Sound": "效果音",
"Setting_Advanced_Settings": "高级设置",
"Setting_Advanced_Chapter_Randomization": "章节乱序",
"Setting_Advanced_Randomization_Enabled": "随机已开启",
"Setting_Advanced_Randomization_Disabled": "随机已关闭",
"Setting_Advanced_Show_Previous_Next_Word": "练习时展示上一个/下一个单词",
"Setting_Advanced_Show_Word_Enabled": "展示单词已开启",
"Setting_Advanced_Show_Word_Disabled": "展示单词已关闭",
"Setting_Advanced_Ignore_Case": "是否忽略大小写",
"Setting_Advanced_Ignore_Case_Enabled": "忽略大小写已开启",
"Setting_Advanced_Ignore_Case_Disabled": "忽略大小写已关闭",
"Setting_Advanced_Allow_Select_Text": "是否允许选择文本",
"Setting_Advanced_Select_Text_Enabled": "选择文本已开启",
"Setting_Advanced_Select_Text_Disabled": "选择文本已关闭",
"Setting_Advanced_Show_Tips_In_Dictation": "是否允许默写模式下显示提示",
"Setting_Advanced_Show_Tips_Enabled": "显示提示已开启",
"Setting_Advanced_Show_Tips_Disabled": "显示提示已关闭",
"Setting_Font_Settings": "字体设置",
"Setting_Font_Foreign_Font": "外语字体",
"Setting_Font_Chinese_Font": "中文字体",
"Setting_Font_Reset": "重置字体设置",
"Setting_Data_Settings": "数据设置",
"Setting_Data_Export": "数据导出",
"Setting_Data_Export_Description": "目前,您的练习数据仅保存在本地。如果您需要在不同的设备、浏览器或者其他非官方部署上使用 Qwerty Learner, 您需要手动进行数据同步和保存。为了保留您的练习进度,以及使用近期即将上线的数据分析和智能训练功能, 我们建议您及时备份您的数据。",
"Setting_Data_Export_Warning": "为了您的数据安全,请不要修改导出的数据文件。",
"Setting_Data_Export_Button": "导出数据",
"Setting_Data_Import": "数据导入",
"Setting_Data_Import_Warning": "请注意,导入数据将完全覆盖当前数据。请谨慎操作。",
"Setting_Data_Import_Button": "导入数据"
}
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Loading from './components/Loading'
import './i18n/config'
import './index.css'
import { ErrorBook } from './pages/ErrorBook'
import { FriendLinks } from './pages/FriendLinks'
Expand Down
6 changes: 4 additions & 2 deletions src/pages/Typing/components/DictChapterButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Tooltip from '@/components/Tooltip'
import useI18n from '@/hooks/useI18n'
import { currentChapterAtom, currentDictInfoAtom, isReviewModeAtom } from '@/store'
import range from '@/utils/range'
import { Listbox, Transition } from '@headlessui/react'
Expand All @@ -8,6 +9,7 @@ import { NavLink } from 'react-router-dom'
import IconCheck from '~icons/tabler/check'

export const DictChapterButton = () => {
const getI18n = useI18n()
const currentDictInfo = useAtomValue(currentDictInfoAtom)
const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom)
const chapterCount = currentDictInfo.chapterCount
Expand All @@ -20,7 +22,7 @@ export const DictChapterButton = () => {
}
return (
<>
<Tooltip content="词典切换">
<Tooltip content={getI18n('Dictionary_Tooltip_Switch')}>
<NavLink
className="block rounded-lg px-3 py-1 text-lg transition-colors duration-300 ease-in-out hover:bg-indigo-400 hover:text-white focus:outline-none dark:text-white dark:text-opacity-60 dark:hover:text-opacity-100"
to="/gallery"
Expand All @@ -35,7 +37,7 @@ export const DictChapterButton = () => {
onKeyDown={handleKeyDown}
className="rounded-lg px-3 py-1 text-lg transition-colors duration-300 ease-in-out hover:bg-indigo-400 hover:text-white focus:outline-none dark:text-white dark:text-opacity-60 dark:hover:text-opacity-100"
>
{currentChapter + 1}
{getI18n('Home_Chapter', [`${currentChapter + 1}`])}
</Listbox.Button>
<Transition as={Fragment} leave="transition ease-in duration-100" leaveFrom="opacity-100" leaveTo="opacity-0">
<Listbox.Options className="listbox-options z-10 w-32">
Expand Down
Loading