feat: added i18n

This commit is contained in:
siujamo
2026-01-19 14:45:49 +08:00
parent f52ca401cf
commit b7ecd69469
6 changed files with 211 additions and 1 deletions
+3
View File
@@ -16,10 +16,13 @@
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"axios": "^1.13.2", "axios": "^1.13.2",
"dayjs": "^1.11.19", "dayjs": "^1.11.19",
"i18next": "^25.7.4",
"i18next-browser-languagedetector": "^8.2.0",
"jsonpath": "^1.1.1", "jsonpath": "^1.1.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^19.2.3", "react": "^19.2.3",
"react-dom": "^19.2.3", "react-dom": "^19.2.3",
"react-i18next": "^16.5.3",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router": "^7.12.0", "react-router": "^7.12.0",
"react-router-dom": "^7.12.0", "react-router-dom": "^7.12.0",
+76
View File
@@ -20,6 +20,12 @@ importers:
dayjs: dayjs:
specifier: ^1.11.19 specifier: ^1.11.19
version: 1.11.19 version: 1.11.19
i18next:
specifier: ^25.7.4
version: 25.7.4(typescript@5.9.3)
i18next-browser-languagedetector:
specifier: ^8.2.0
version: 8.2.0
jsonpath: jsonpath:
specifier: ^1.1.1 specifier: ^1.1.1
version: 1.1.1 version: 1.1.1
@@ -32,6 +38,9 @@ importers:
react-dom: react-dom:
specifier: ^19.2.3 specifier: ^19.2.3
version: 19.2.3(react@19.2.3) version: 19.2.3(react@19.2.3)
react-i18next:
specifier: ^16.5.3
version: 16.5.3(i18next@25.7.4(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)
react-redux: react-redux:
specifier: ^9.2.0 specifier: ^9.2.0
version: 9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1) version: 9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1)
@@ -152,6 +161,10 @@ packages:
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
'@babel/runtime@7.28.6':
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'}
'@babel/template@7.28.6': '@babel/template@7.28.6':
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -798,6 +811,20 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
html-parse-stringify@3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
i18next-browser-languagedetector@8.2.0:
resolution: {integrity: sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==}
i18next@25.7.4:
resolution: {integrity: sha512-hRkpEblXXcXSNbw8mBNq9042OEetgyB/ahc/X17uV/khPwzV+uB8RHceHh3qavyrkPJvmXFKXME2Sy1E0KjAfw==}
peerDependencies:
typescript: ^5
peerDependenciesMeta:
typescript:
optional: true
immer@11.1.3: immer@11.1.3:
resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==} resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==}
@@ -959,6 +986,22 @@ packages:
peerDependencies: peerDependencies:
react: ^19.2.3 react: ^19.2.3
react-i18next@16.5.3:
resolution: {integrity: sha512-fo+/NNch37zqxOzlBYrWMx0uy/yInPkRfjSuy4lqKdaecR17nvCHnEUt3QyzA8XjQ2B/0iW/5BhaHR3ZmukpGw==}
peerDependencies:
i18next: '>= 25.6.2'
react: '>= 16.8.0'
react-dom: '*'
react-native: '*'
typescript: ^5
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
typescript:
optional: true
react-redux@9.2.0: react-redux@9.2.0:
resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==}
peerDependencies: peerDependencies:
@@ -1119,6 +1162,10 @@ packages:
yaml: yaml:
optional: true optional: true
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
word-wrap@1.2.5: word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -1217,6 +1264,8 @@ snapshots:
'@babel/core': 7.28.6 '@babel/core': 7.28.6
'@babel/helper-plugin-utils': 7.28.6 '@babel/helper-plugin-utils': 7.28.6
'@babel/runtime@7.28.6': {}
'@babel/template@7.28.6': '@babel/template@7.28.6':
dependencies: dependencies:
'@babel/code-frame': 7.28.6 '@babel/code-frame': 7.28.6
@@ -1733,6 +1782,20 @@ snapshots:
dependencies: dependencies:
function-bind: 1.1.2 function-bind: 1.1.2
html-parse-stringify@3.0.1:
dependencies:
void-elements: 3.1.0
i18next-browser-languagedetector@8.2.0:
dependencies:
'@babel/runtime': 7.28.6
i18next@25.7.4(typescript@5.9.3):
dependencies:
'@babel/runtime': 7.28.6
optionalDependencies:
typescript: 5.9.3
immer@11.1.3: {} immer@11.1.3: {}
jiti@2.6.1: {} jiti@2.6.1: {}
@@ -1857,6 +1920,17 @@ snapshots:
react: 19.2.3 react: 19.2.3
scheduler: 0.27.0 scheduler: 0.27.0
react-i18next@16.5.3(i18next@25.7.4(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3):
dependencies:
'@babel/runtime': 7.28.6
html-parse-stringify: 3.0.1
i18next: 25.7.4(typescript@5.9.3)
react: 19.2.3
use-sync-external-store: 1.6.0(react@19.2.3)
optionalDependencies:
react-dom: 19.2.3(react@19.2.3)
typescript: 5.9.3
react-redux@9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1): react-redux@9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1):
dependencies: dependencies:
'@types/use-sync-external-store': 0.0.6 '@types/use-sync-external-store': 0.0.6
@@ -1987,6 +2061,8 @@ snapshots:
jiti: 2.6.1 jiti: 2.6.1
lightningcss: 1.30.2 lightningcss: 1.30.2
void-elements@3.1.0: {}
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
yallist@3.1.1: {} yallist@3.1.1: {}
+36
View File
@@ -0,0 +1,36 @@
import i18n from "i18next"
import { initReactI18next } from "react-i18next"
import LanguageDetector from "i18next-browser-languagedetector"
// Import translation files
import BritishEnglishTranslations from "./locales/BritishEnglish.json"
import SimplifiedChineseTranslations from "./locales/SimplifiedChinese.json"
const resources = {
"en-GB": {
translation: BritishEnglishTranslations as Record<string, unknown>,
},
"zh-CN": {
translation: SimplifiedChineseTranslations as Record<string, unknown>,
},
} as const
void i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources,
fallbackLng: "en-GB",
debug: process.env.NODE_ENV === "development",
interpolation: {
escapeValue: false, // React already does escaping
},
detection: {
order: ["localStorage", "navigator", "htmlTag"],
caches: ["localStorage"],
},
})
export default i18n
+47
View File
@@ -0,0 +1,47 @@
{
"app": {
"title": "DevHub",
"pageTitle": "DevHub",
"copyright": "© {{year}} OnixByte. Built with React & TypeScript."
},
"navigation": {
"home": "Home"
},
"language": {
"switch": "Switch Language",
"english": "English (Great Britain)",
"chinese": "简体中文"
},
"bmi": {
"title": "BMI Calculator",
"description": "Calculate your Body Mass Index (BMI) to assess your weight status and health.",
"weight": {
"label": "Weight",
"placeholder": "Enter your weight"
},
"height": {
"label": "Height",
"placeholder": "Enter your height"
},
"calculate": "Calculate BMI",
"reset": "Reset",
"result": {
"title": "Your BMI Result"
},
"category": {
"underweight": "Underweight",
"normal": "Normal Weight",
"overweight": "Overweight",
"obese": "Obese"
},
"advice": {
"underweight": "You may need to gain weight. Consider consulting with a healthcare professional for personalised advice.",
"normal": "You have a healthy weight for your height. Maintain your current lifestyle with regular exercise and balanced nutrition.",
"overweight": "You may benefit from losing some weight. Consider increasing physical activity and improving your diet.",
"obese": "You may be at increased health risk. It's recommended to consult with a healthcare professional for guidance."
},
"scale": {
"title": "BMI Categories"
}
}
}
@@ -0,0 +1,47 @@
{
"app": {
"title": "DevHub",
"pageTitle": "DevHub",
"copyright": "© {{year}} OnixByte。 使用 React 和 TypeScript 构建。"
},
"navigation": {
"home": "首页"
},
"language": {
"switch": "切换语言",
"english": "English (Great Britain)",
"chinese": "简体中文"
},
"bmi": {
"title": "BMI 计算器",
"description": "计算您的身体质量指数(BMI)以评估您的体重状态和健康状况。",
"weight": {
"label": "体重",
"placeholder": "请输入您的体重"
},
"height": {
"label": "身高",
"placeholder": "请输入您的身高"
},
"calculate": "计算 BMI",
"reset": "重置",
"result": {
"title": "您的 BMI 结果"
},
"category": {
"underweight": "体重过轻",
"normal": "正常体重",
"overweight": "超重",
"obese": "肥胖"
},
"advice": {
"underweight": "您可能需要增加体重。建议咨询医疗专业人士获取个性化建议。",
"normal": "您的体重对于您的身高来说是健康的。保持目前的生活方式,规律运动和均衡营养。",
"overweight": "您可能需要减轻一些体重。建议增加体育活动并改善饮食。",
"obese": "您可能面临健康风险增加。建议咨询医疗专业人士获取指导。"
},
"scale": {
"title": "BMI 分类"
}
}
}
+1
View File
@@ -1 +1,2 @@
import "./dayjs" import "./dayjs"
import "./i18n"