From 9c336dbda48ba5758928ad2fb50e701caff3afbf Mon Sep 17 00:00:00 2001 From: wj-xiao Date: Mon, 26 Aug 2024 14:15:35 +0800 Subject: [PATCH] optimizing i18n and language setting --- web/.prettierrc.yaml | 1 + web/src/i18n/README.md | 4 +++ web/src/i18n/index.ts | 26 ++++++++++++++----- web/src/i18n/languages.ts | 6 +++++ web/src/i18n/{ => locales}/en.ts | 4 ++- web/src/i18n/{ => locales}/fr.ts | 4 ++- web/src/i18n/{ => locales}/ru.ts | 14 ++++++---- web/src/i18n/{ => locales}/zh.ts | 4 ++- .../desktop/menu-phone/settings/language.tsx | 18 +++++-------- .../pages/desktop/menu/settings/language.tsx | 18 +++++-------- 10 files changed, 60 insertions(+), 39 deletions(-) create mode 100644 web/src/i18n/README.md create mode 100644 web/src/i18n/languages.ts rename web/src/i18n/{ => locales}/en.ts (99%) rename web/src/i18n/{ => locales}/fr.ts (99%) rename web/src/i18n/{ => locales}/ru.ts (93%) rename web/src/i18n/{ => locales}/zh.ts (99%) diff --git a/web/.prettierrc.yaml b/web/.prettierrc.yaml index 5db185d..d560dc1 100644 --- a/web/.prettierrc.yaml +++ b/web/.prettierrc.yaml @@ -11,6 +11,7 @@ importOrder: - ^types$ - ^@/assets(.*)$ - ^@/api/(.*)$ + - ^@/i18n/(.*)$ - ^@/types$ - ^@/lib/(.*)$ - ^@/jotai/(.*)$ diff --git a/web/src/i18n/README.md b/web/src/i18n/README.md new file mode 100644 index 0000000..765b789 --- /dev/null +++ b/web/src/i18n/README.md @@ -0,0 +1,4 @@ +# How to add a language + +1. Add a language file in i18n/locales folder (for example: en.ts). +2. Add language key and name in i18n/languages.ts (for example: { key: 'en', name: 'English' }). diff --git a/web/src/i18n/index.ts b/web/src/i18n/index.ts index 3c32aa7..55d5d25 100644 --- a/web/src/i18n/index.ts +++ b/web/src/i18n/index.ts @@ -1,14 +1,23 @@ import i18n from 'i18next'; +import type { Resource } from 'i18next'; import { initReactI18next } from 'react-i18next'; import { getLanguage } from '@/lib/localstorage.ts'; -import { en } from './en'; -import { fr } from './fr'; -import { zh } from './zh'; -import { ru } from './ru'; +function getResources(): Resource { + const resources: Resource = {}; -const resources = { en, fr, ru, zh }; + const modules: Record = import.meta.glob('./locales/*.ts', { eager: true }); + + for (const path in modules) { + const moduleName = path.split('/').pop()?.replace('.ts', ''); + if (moduleName) { + resources[moduleName] = modules[path].default; + } + } + + return resources; +} function getCurrentLanguage(): string { const languages = Object.keys(resources); @@ -26,11 +35,14 @@ function getCurrentLanguage(): string { return 'en'; } +const resources = getResources(); +const lng = getCurrentLanguage(); + i18n .use(initReactI18next) .init({ - resources: resources, - lng: getCurrentLanguage(), + resources, + lng, fallbackLng: 'en', interpolation: { escapeValue: false diff --git a/web/src/i18n/languages.ts b/web/src/i18n/languages.ts new file mode 100644 index 0000000..7eee039 --- /dev/null +++ b/web/src/i18n/languages.ts @@ -0,0 +1,6 @@ +export const languages = [ + { key: 'en', name: 'English' }, + { key: 'fr', name: 'Français' }, + { key: 'ru', name: 'Русский' }, + { key: 'zh', name: '中文' } +]; diff --git a/web/src/i18n/en.ts b/web/src/i18n/locales/en.ts similarity index 99% rename from web/src/i18n/en.ts rename to web/src/i18n/locales/en.ts index 9d88e0a..76a4403 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/locales/en.ts @@ -1,4 +1,4 @@ -export const en = { +const en = { translation: { language: 'Language', changePassword: 'Change Password', @@ -159,3 +159,5 @@ export const en = { } } }; + +export default en; diff --git a/web/src/i18n/fr.ts b/web/src/i18n/locales/fr.ts similarity index 99% rename from web/src/i18n/fr.ts rename to web/src/i18n/locales/fr.ts index 0402824..646f46d 100644 --- a/web/src/i18n/fr.ts +++ b/web/src/i18n/locales/fr.ts @@ -1,4 +1,4 @@ -export const fr = { +const fr = { translation: { language: 'Langue', changePassword: 'Changer le mot de passe', @@ -163,3 +163,5 @@ export const fr = { } } }; + +export default fr; diff --git a/web/src/i18n/ru.ts b/web/src/i18n/locales/ru.ts similarity index 93% rename from web/src/i18n/ru.ts rename to web/src/i18n/locales/ru.ts index 5b68fba..b006d9c 100644 --- a/web/src/i18n/ru.ts +++ b/web/src/i18n/locales/ru.ts @@ -1,4 +1,4 @@ -export const ru = { +const ru = { translation: { language: 'Язык', changePassword: 'Изменить пароль', @@ -17,7 +17,8 @@ export const ru = { hddLed: 'Индикатор активности хранилища', checkLibFailed: 'Не удалось проверить библиотеку среды выполнения, попробуйте еще раз', updateLibFailed: 'Не удалось обновить библиотеку среды выполнения, попробуйте еще раз', - updatingLib: 'Обновление библиотеки среды выполнения. Пожалуйста, обновите страницу после обновления.', + updatingLib: + 'Обновление библиотеки среды выполнения. Пожалуйста, обновите страницу после обновления.', checkForUpdate: 'Проверить обновления', head: { desktop: 'Удаленный рабочий стол', @@ -32,7 +33,8 @@ export const ru = { placeholderPassword2: 'Введите пароль снова', noEmptyUsername: 'Имя пользователя не может быть пустым', noEmptyPassword: 'Пароль не может быть пустым', - noAccount: 'Не удалось получить информацию о пользователе, пожалуйста, обновите веб-страницу или сбросьте пароль', + noAccount: + 'Не удалось получить информацию о пользователе, пожалуйста, обновите веб-страницу или сбросьте пароль', invalidUser: 'Неверное имя пользователя или пароль', error: 'Непредвиденная ошибка', changePassword: 'Изменить пароль', @@ -55,7 +57,7 @@ export const ru = { quality: 'Качество', frameDetect: 'Экономия трафика', frameDetectTip: - "Вычисляет разницу между кадрами и прекращает передачу видеопотока, если на экране удаленного узла не обнаружено никаких изменений." + 'Вычисляет разницу между кадрами и прекращает передачу видеопотока, если на экране удаленного узла не обнаружено никаких изменений.' }, cursor: { default: 'Курсор по умолчанию', @@ -88,7 +90,7 @@ export const ru = { tf3: 'Вставьте карту памяти в картридер и подключите его в свой компьютер.', tf4: 'Скопируйте файл образа в директорию /data на карте памяти.', tf5: 'Вставьте карту памяти в NanoKVM.' - }, + } }, script: { title: 'Скрипты', @@ -162,3 +164,5 @@ export const ru = { } } }; + +export default ru; diff --git a/web/src/i18n/zh.ts b/web/src/i18n/locales/zh.ts similarity index 99% rename from web/src/i18n/zh.ts rename to web/src/i18n/locales/zh.ts index 552b0f6..50ef7ed 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/locales/zh.ts @@ -1,4 +1,4 @@ -export const zh = { +const zh = { translation: { currentVersion: '版本', latestVersion: '最新版本:', @@ -158,3 +158,5 @@ export const zh = { } } }; + +export default zh; diff --git a/web/src/pages/desktop/menu-phone/settings/language.tsx b/web/src/pages/desktop/menu-phone/settings/language.tsx index c708663..d933ae9 100644 --- a/web/src/pages/desktop/menu-phone/settings/language.tsx +++ b/web/src/pages/desktop/menu-phone/settings/language.tsx @@ -3,6 +3,7 @@ import clsx from 'clsx'; import { LanguagesIcon } from 'lucide-react'; import { useTranslation } from 'react-i18next'; +import { languages } from '@/i18n/languages.ts'; import { setLanguage } from '@/lib/localstorage.ts'; export const Language = () => { @@ -15,25 +16,18 @@ export const Language = () => { setLanguage(lng); } - const languageItems = [ - { lng: 'en', name: 'English' }, - { lng: 'fr', name: 'Français' }, - { lng: 'ru', name: 'Русский' }, - { lng: 'zh', name: '中文' } - ]; - const content = ( <> - {languageItems.map((item) => ( + {languages.map((lng) => (
changeLanguage(item.lng)} + onClick={() => changeLanguage(lng.key)} > - {item.name} + {lng.name}
))} diff --git a/web/src/pages/desktop/menu/settings/language.tsx b/web/src/pages/desktop/menu/settings/language.tsx index c708663..d933ae9 100644 --- a/web/src/pages/desktop/menu/settings/language.tsx +++ b/web/src/pages/desktop/menu/settings/language.tsx @@ -3,6 +3,7 @@ import clsx from 'clsx'; import { LanguagesIcon } from 'lucide-react'; import { useTranslation } from 'react-i18next'; +import { languages } from '@/i18n/languages.ts'; import { setLanguage } from '@/lib/localstorage.ts'; export const Language = () => { @@ -15,25 +16,18 @@ export const Language = () => { setLanguage(lng); } - const languageItems = [ - { lng: 'en', name: 'English' }, - { lng: 'fr', name: 'Français' }, - { lng: 'ru', name: 'Русский' }, - { lng: 'zh', name: '中文' } - ]; - const content = ( <> - {languageItems.map((item) => ( + {languages.map((lng) => (
changeLanguage(item.lng)} + onClick={() => changeLanguage(lng.key)} > - {item.name} + {lng.name}
))}