Все UI-строки приложения переведены и переключаются на лету через
Settings → Язык интерфейса.
== i18n архитектура ==
- src/renderer/src/i18n/dict.ts — плоский словарь ru/en с ~190 ключами,
поддержка интерполяции {var} и плюрализации
- src/renderer/src/i18n/index.ts — useT() React hook + чистые
translate/translateN функции (для ReminderApp вне store context)
- Settings.language: 'ru' | 'en', default 'ru'
- Изменение языка применяется немедленно через Zustand reactive update
== Что переведено ==
- Sidebar nav + slogan + status
- Titlebar window controls (aria-labels)
- Dashboard: hero, 3 stat-карточки (Активных / До следующего /
Трекинг матчей), Paused banner, empty state
- Exercises: hero, секции (активные / выключенные), row meta, empty
- Challenges: hero, formula subtitle, warning, row format
«{stat} × {mult} → {exercise}», empty
- Games: hero, status badges (Live/Ready/Queued/Installed/Not found),
queued/no_user banners, dev panel
- Settings: все секции + новый Language selector
- UpdaterCard: все состояния (checking/available/downloading/
downloaded/error/idle) с интерполяцией версии и MB/s
- ReminderApp: kicker «Время тренировки», reps подпись, snooze label
с динамическими минутами, кнопки done/skip
- Match summary: победа/поражение, плюрализация «N челлендж/-а/-ей»
vs «N challenge/-s»
- Format helpers (formatCountdown, formatInterval) — теперь принимают
Language параметр
== Локалезависимая дата ==
Dashboard hero показывает today в текущей локали:
ru-RU → "воскресенье, 17 мая"
en-US → "Sunday, May 17"
== STAT_LABELS bilingual ==
- shared/types.ts: STAT_LABELS_EN + statLabel(stat, lang) helper
- ChallengeResult получил поле stat?: GameStat (для resolve на стороне
renderer'а с актуальным языком, вместо baked-in label)
- main/games/registry.ts кладёт stat в результат
== Тесты ==
- src/renderer/src/i18n/i18n.test.ts: 10 кейсов
* translate: lookup, fallback, interpolation, multi-var, lang fallback
* translateN: ru plural rules (1/21/101 → one; 2-4 → few; 0/5-20 → many)
и en (1 → one, else → many)
- Всего 33 теста зелёные
== Известное ограничение ==
SAMPLE_EXERCISES (5-6 русских "Приседания / Отжимания / ...") остаются
русскими — это seed данных на первый запуск. Английский юзер сразу
переключит язык и сможет переименовать вручную. Делать seed-per-locale
оверкилл — слишком много кода ради малого.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
96 lines
2.8 KiB
JSON
96 lines
2.8 KiB
JSON
{
|
|
"name": "laude",
|
|
"version": "0.4.0",
|
|
"description": "Exercise reminder — Windows desktop app",
|
|
"main": "out/main/index.js",
|
|
"author": "AnRil",
|
|
"private": true,
|
|
"scripts": {
|
|
"dev": "electron-vite dev",
|
|
"build": "electron-vite build",
|
|
"preview": "electron-vite preview",
|
|
"typecheck:node": "tsc --noEmit -p tsconfig.node.json",
|
|
"typecheck:web": "tsc --noEmit -p tsconfig.web.json",
|
|
"typecheck": "npm run typecheck:node && npm run typecheck:web",
|
|
"test": "vitest",
|
|
"test:run": "vitest run",
|
|
"dist": "electron-vite build && electron-builder --win --x64",
|
|
"dist:dir": "electron-vite build && electron-builder --win --x64 --dir",
|
|
"publish": "electron-vite build && electron-builder --win --x64 --publish always",
|
|
"release": "powershell -ExecutionPolicy Bypass -File scripts/release.ps1",
|
|
"gen:icons": "powershell -ExecutionPolicy Bypass -File scripts/gen-icons.ps1"
|
|
},
|
|
"dependencies": {
|
|
"electron-updater": "^6.8.3",
|
|
"framer-motion": "^11.11.17",
|
|
"lucide-react": "^0.460.0",
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1",
|
|
"react-router-dom": "^6.28.0",
|
|
"zustand": "^5.0.1"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^22.19.19",
|
|
"@types/react": "^18.3.12",
|
|
"@types/react-dom": "^18.3.1",
|
|
"@vitejs/plugin-react": "^4.3.3",
|
|
"autoprefixer": "^10.4.20",
|
|
"electron": "^33.2.0",
|
|
"electron-builder": "^25.1.8",
|
|
"electron-vite": "^2.3.0",
|
|
"postcss": "^8.4.49",
|
|
"tailwindcss": "^3.4.15",
|
|
"typescript": "^5.6.3",
|
|
"vite": "^5.4.11",
|
|
"vitest": "^4.1.6"
|
|
},
|
|
"build": {
|
|
"appId": "com.anril.exercise-reminder",
|
|
"productName": "Exercise Reminder",
|
|
"directories": {
|
|
"output": "release",
|
|
"buildResources": "resources"
|
|
},
|
|
"files": [
|
|
"out/**/*",
|
|
"resources/**/*"
|
|
],
|
|
"win": {
|
|
"target": [
|
|
{
|
|
"target": "nsis",
|
|
"arch": [
|
|
"x64"
|
|
]
|
|
}
|
|
],
|
|
"icon": "resources/icon.ico"
|
|
},
|
|
"nsis": {
|
|
"oneClick": false,
|
|
"perMachine": false,
|
|
"allowToChangeInstallationDirectory": true,
|
|
"allowElevation": true,
|
|
"createDesktopShortcut": true,
|
|
"createStartMenuShortcut": true,
|
|
"shortcutName": "Exercise Reminder",
|
|
"uninstallDisplayName": "Exercise Reminder",
|
|
"installerLanguages": [
|
|
"ru_RU",
|
|
"en_US"
|
|
],
|
|
"displayLanguageSelector": true,
|
|
"menuCategory": false,
|
|
"runAfterFinish": true,
|
|
"deleteAppDataOnUninstall": false,
|
|
"differentialPackage": true,
|
|
"artifactName": "Exercise-Reminder-Setup-${version}.${ext}"
|
|
},
|
|
"publish": {
|
|
"provider": "generic",
|
|
"url": "https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/download/v${version}",
|
|
"channel": "latest"
|
|
}
|
|
}
|
|
}
|