feat: added i18n
@@ -16,10 +16,13 @@
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"axios": "^1.13.2",
|
||||
"dayjs": "^1.11.19",
|
||||
"i18next": "^25.7.4",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"jsonpath": "^1.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-i18next": "^16.5.3",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^7.12.0",
|
||||
"react-router-dom": "^7.12.0",
|
||||
|
||||
@@ -20,6 +20,12 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^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:
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
@@ -32,6 +38,9 @@ importers:
|
||||
react-dom:
|
||||
specifier: ^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:
|
||||
specifier: ^9.2.0
|
||||
version: 9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1)
|
||||
@@ -152,6 +161,10 @@ packages:
|
||||
peerDependencies:
|
||||
'@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':
|
||||
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -798,6 +811,20 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
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:
|
||||
resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==}
|
||||
|
||||
@@ -959,6 +986,22 @@ packages:
|
||||
peerDependencies:
|
||||
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:
|
||||
resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==}
|
||||
peerDependencies:
|
||||
@@ -1119,6 +1162,10 @@ packages:
|
||||
yaml:
|
||||
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:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1217,6 +1264,8 @@ snapshots:
|
||||
'@babel/core': 7.28.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/runtime@7.28.6': {}
|
||||
|
||||
'@babel/template@7.28.6':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.28.6
|
||||
@@ -1733,6 +1782,20 @@ snapshots:
|
||||
dependencies:
|
||||
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: {}
|
||||
|
||||
jiti@2.6.1: {}
|
||||
@@ -1857,6 +1920,17 @@ snapshots:
|
||||
react: 19.2.3
|
||||
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):
|
||||
dependencies:
|
||||
'@types/use-sync-external-store': 0.0.6
|
||||
@@ -1987,6 +2061,8 @@ snapshots:
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.30.2
|
||||
|
||||
void-elements@3.1.0: {}
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
@@ -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
|
||||
@@ -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 +1,2 @@
|
||||
import "./dayjs"
|
||||
import "./dayjs"
|
||||
import "./i18n"
|
||||
|
||||