Files
daily-timer/frontend/src/lib/i18n.js
2026-02-10 15:53:26 +03:00

379 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { writable, derived } from 'svelte/store';
export const locale = writable('ru');
export const translations = {
ru: {
// Navigation
nav: {
timer: 'Таймер',
setup: 'Участники',
history: 'История',
settings: 'Настройки',
},
// Setup page
setup: {
title: 'Название собрания',
participants: 'Участники',
addParticipant: 'Добавить участника',
namePlaceholder: 'Имя участника',
noParticipants: 'Добавьте участников для начала собрания',
selectAll: 'Выбрать всех',
deselectAll: 'Снять выбор',
startMeeting: 'Начать собрание',
speakerTime: 'Время на спикера',
totalTime: 'Общее время',
minutes: 'мин',
unlimited: 'Без ограничения',
dragHint: 'перетащите для изменения порядка, ✓/✗ присутствие',
},
// Timer page
timer: {
currentSpeaker: 'Текущий спикер',
currentlySpeaking: 'Сейчас говорит',
speakerTime: 'Время спикера',
totalTime: 'Общее время',
remaining: 'Осталось',
queue: 'Очередь',
participants: 'Участники',
finished: 'Выступили',
noSpeaker: 'Нет спикера',
noActiveMeeting: 'Собрание не запущено',
goToParticipants: 'Перейдите в раздел Участники, чтобы добавить участников',
readyToStart: 'Всё готово к началу',
editParticipants: 'Редактировать участников',
noParticipants: 'Участники не добавлены',
registeredParticipants: 'Зарегистрированные участники',
},
// Controls
controls: {
next: 'Следующий',
skip: 'Пропустить',
pause: 'Пауза',
resume: 'Продолжить',
stop: 'Завершить',
},
// History page
history: {
title: 'История собраний',
noHistory: 'История пуста',
date: 'Дата',
duration: 'Длительность',
participants: 'Участники',
avgTime: 'Среднее время',
export: 'Экспорт',
exportJSON: 'Экспорт JSON',
exportCSV: 'Экспорт CSV',
delete: 'Удалить',
deleteAll: 'Удалить историю',
deleteSession: 'Удалить запись',
confirmDelete: 'Удалить эту запись?',
confirmDeleteTitle: 'Подтверждение удаления',
confirmDeleteSession: 'Вы уверены, что хотите удалить эту запись? Действие необратимо.',
confirmDeleteAllTitle: 'Удалить всю историю?',
confirmDeleteAll: 'Вы уверены, что хотите удалить ВСЮ историю собраний? Это действие необратимо!',
overtimeRate: 'Процент превышения',
avgAttendance: 'Средняя явка',
recentSessions: 'Последние собрания',
noSessions: 'Собраний пока нет',
participantBreakdown: 'Статистика по участникам',
name: 'Имя',
sessions: 'Собрания',
overtime: 'Превышение',
attendance: 'Явка',
},
// Settings page
settings: {
title: 'Настройки собрания',
language: 'Язык',
sound: 'Звуковые уведомления',
soundEnabled: 'Включены',
soundDisabled: 'Выключены',
warningTime: 'Предупреждение за',
seconds: 'сек',
defaultSpeakerTime: 'Время на спикера по умолчанию',
defaultTotalTime: 'Общее время собрания (мин)',
theme: 'Тема оформления',
themeDark: 'Тёмная',
themeLight: 'Светлая',
save: 'Сохранить',
saved: 'Сохранено!',
windowWidth: 'Настройка окна',
windowWidthHint: 'Ширина окна (мин. 480 пикселей)',
windowFullHeight: 'Окно на всю высоту экрана',
},
// Updates
updates: {
title: 'Обновления',
currentVersion: 'Текущая версия',
checkingForUpdates: 'Проверка обновлений...',
updateAvailable: 'Доступно обновление',
rebuildAvailable: 'Доступна пересборка',
upToDate: 'У вас последняя версия',
downloadAndInstall: 'Скачать и установить',
downloading: 'Загрузка...',
installing: 'Установка...',
restartRequired: 'Для завершения обновления требуется перезапуск',
restart: 'Перезапустить',
later: 'Позже',
error: 'Ошибка проверки обновлений',
downloadError: 'Ошибка загрузки обновления',
checkNow: 'Проверить сейчас',
},
// Participant management
participants: {
title: 'Управление участниками',
add: 'Добавить',
edit: 'Редактировать',
delete: 'Удалить',
name: 'Имя',
stats: 'Статистика',
avgSpeakTime: 'Среднее время выступления',
totalMeetings: 'Всего собраний',
confirmDelete: 'Удалить участника?',
},
// Common
common: {
cancel: 'Отмена',
confirm: 'Подтвердить',
save: 'Сохранить',
close: 'Закрыть',
delete: 'Удалить',
yes: 'Да',
no: 'Нет',
loading: 'Загрузка...',
error: 'Ошибка',
errorStartMeeting: 'Ошибка запуска планёрки',
},
// Time formats
time: {
hours: 'ч',
minutes: 'мин',
seconds: 'сек',
},
// Hotkeys
hotkeys: {
title: 'Горячие клавиши',
next: 'Следующий спикер',
skip: 'Пропустить',
pauseResume: 'Пауза/Продолжить',
stop: 'Остановить митинг',
},
},
en: {
// Navigation
nav: {
timer: 'Timer',
setup: 'Participants',
history: 'History',
settings: 'Settings',
},
// Setup page
setup: {
title: 'Meeting Name',
participants: 'Participants',
addParticipant: 'Add Participant',
namePlaceholder: 'Participant name',
noParticipants: 'Add participants to start a meeting',
selectAll: 'Select All',
deselectAll: 'Deselect All',
startMeeting: 'Start Meeting',
speakerTime: 'Speaker Time',
totalTime: 'Total Time',
minutes: 'min',
unlimited: 'Unlimited',
dragHint: 'drag to reorder, ✓/✗ attendance',
},
// Timer page
timer: {
currentSpeaker: 'Current Speaker',
currentlySpeaking: 'Currently speaking',
speakerTime: 'Speaker Time',
totalTime: 'Total Time',
remaining: 'Remaining',
queue: 'Queue',
participants: 'Participants',
finished: 'Finished',
noSpeaker: 'No speaker',
noActiveMeeting: 'No active meeting',
goToParticipants: 'Go to Participants to add participants',
readyToStart: 'Ready to start',
editParticipants: 'Edit participants',
noParticipants: 'No participants added',
registeredParticipants: 'Registered participants',
},
// Controls
controls: {
next: 'Next',
skip: 'Skip',
pause: 'Pause',
resume: 'Resume',
stop: 'Stop',
},
// History page
history: {
title: 'Meeting History',
noHistory: 'No history yet',
date: 'Date',
duration: 'Duration',
participants: 'Participants',
avgTime: 'Avg Time',
export: 'Export',
exportJSON: 'Export JSON',
exportCSV: 'Export CSV',
delete: 'Delete',
deleteAll: 'Delete History',
deleteSession: 'Delete session',
confirmDelete: 'Delete this record?',
confirmDeleteTitle: 'Confirm Deletion',
confirmDeleteSession: 'Are you sure you want to delete this session? This action cannot be undone.',
confirmDeleteAllTitle: 'Delete All History?',
confirmDeleteAll: 'Are you sure you want to delete ALL meeting history? This action cannot be undone!',
overtimeRate: 'Overtime Rate',
avgAttendance: 'Avg. Attendance',
recentSessions: 'Recent Sessions',
noSessions: 'No sessions yet',
participantBreakdown: 'Participant Breakdown',
name: 'Name',
sessions: 'Sessions',
overtime: 'Overtime',
attendance: 'Attendance',
},
// Settings page
settings: {
title: 'Meeting Settings',
language: 'Language',
sound: 'Sound Notifications',
soundEnabled: 'Enabled',
soundDisabled: 'Disabled',
warningTime: 'Warning before',
seconds: 'sec',
defaultSpeakerTime: 'Default Speaker Time',
defaultTotalTime: 'Total meeting time (min)',
theme: 'Theme',
themeDark: 'Dark',
themeLight: 'Light',
save: 'Save',
saved: 'Saved!',
windowWidth: 'Window Settings',
windowWidthHint: 'Window width (min. 480 pixels)',
windowFullHeight: 'Full screen height window',
},
// Updates
updates: {
title: 'Updates',
currentVersion: 'Current version',
checkingForUpdates: 'Checking for updates...',
updateAvailable: 'Update available',
rebuildAvailable: 'Rebuild available',
upToDate: 'You have the latest version',
downloadAndInstall: 'Download and install',
downloading: 'Downloading...',
installing: 'Installing...',
restartRequired: 'Restart required to complete the update',
restart: 'Restart',
later: 'Later',
error: 'Error checking for updates',
downloadError: 'Error downloading update',
checkNow: 'Check now',
},
// Participant management
participants: {
title: 'Manage Participants',
add: 'Add',
edit: 'Edit',
delete: 'Delete',
name: 'Name',
stats: 'Statistics',
avgSpeakTime: 'Avg Speaking Time',
totalMeetings: 'Total Meetings',
confirmDelete: 'Delete participant?',
},
// Common
common: {
cancel: 'Cancel',
confirm: 'Confirm',
save: 'Save',
close: 'Close',
delete: 'Delete',
yes: 'Yes',
no: 'No',
loading: 'Loading...',
error: 'Error',
errorStartMeeting: 'Failed to start meeting',
},
// Time formats
time: {
hours: 'h',
minutes: 'min',
seconds: 'sec',
},
// Hotkeys
hotkeys: {
title: 'Hotkeys',
next: 'Next speaker',
skip: 'Skip speaker',
pauseResume: 'Pause/Resume',
stop: 'Stop meeting',
},
},
};
export const t = derived(locale, ($locale) => {
return (key) => {
const keys = key.split('.');
let value = translations[$locale];
for (const k of keys) {
if (value && typeof value === 'object' && k in value) {
value = value[k];
} else {
console.warn(`Translation missing: ${key} for locale ${$locale}`);
return key;
}
}
return value;
};
});
export function setLocale(lang) {
if (translations[lang]) {
locale.set(lang);
localStorage.setItem('daily-timer-locale', lang);
}
}
export function initLocale() {
const saved = localStorage.getItem('daily-timer-locale');
if (saved && translations[saved]) {
locale.set(saved);
} else {
const browserLang = navigator.language.split('-')[0];
if (translations[browserLang]) {
locale.set(browserLang);
}
}
}