i18n for offline settings (en/ru/cu)

This commit is contained in:
catarrh committed 2026-08-01 22:08:39 +03:00
1 parent 84c8ceb172
commit 8ef5f63300
2 files changed
+67 -29

No files matched your search

+48
View File
@@ -483,6 +483,18 @@ export interface Translations {
aboutText: string; aboutText: string;
aboutLicense: string; aboutLicense: string;
installPwa: string; installPwa: string;
offlineContent: string;
offlineLangs: string;
offlineDataTypes: string;
offlineLives: string;
offlineCalendar: string;
offlineMenaion: string;
offlinePreload: string;
offlineClearCache: string;
offlineCalculating: string;
offlineDone: string;
offlineSelectLang: string;
offlineCleared: string;
}; };
// Common // Common
@@ -1007,6 +1019,18 @@ const translations: Record<LanguageCode, Translations> = {
aboutText: 'Ponomar is an Orthodox Church calendar application providing liturgical information, service texts, and Bible readings in multiple languages.', aboutText: 'Ponomar is an Orthodox Church calendar application providing liturgical information, service texts, and Bible readings in multiple languages.',
aboutLicense: 'Based on the Ponomar Java desktop application by Aleksandr Andreev and Yuri Shardt. Licensed under GPL v3.', aboutLicense: 'Based on the Ponomar Java desktop application by Aleksandr Andreev and Yuri Shardt. Licensed under GPL v3.',
installPwa: 'Install Ponomar', installPwa: 'Install Ponomar',
offlineContent: 'Offline Content',
offlineLangs: 'Languages to cache',
offlineDataTypes: 'Data to cache',
offlineLives: 'Lives',
offlineCalendar: 'Calendar',
offlineMenaion: 'Menaion',
offlinePreload: 'Preload',
offlineClearCache: 'Clear cache',
offlineCalculating: 'Calculating storage...',
offlineDone: 'Done! Data cached for offline use.',
offlineSelectLang: 'Please select at least one language.',
offlineCleared: 'Cache cleared.',
}, },
common: { common: {
@@ -1529,6 +1553,18 @@ const translations: Record<LanguageCode, Translations> = {
aboutText: 'Понома́рь — приложение православного календаря, предоставляющее литургическую информацию, тексты служб и библейские чтения на нескольких языках.', aboutText: 'Понома́рь — приложение православного календаря, предоставляющее литургическую информацию, тексты служб и библейские чтения на нескольких языках.',
aboutLicense: 'Основано на Java-приложении Понома́рь от Александра Андреева и Юрия Шардт. Лицензия GPL v3.', aboutLicense: 'Основано на Java-приложении Понома́рь от Александра Андреева и Юрия Шардт. Лицензия GPL v3.',
installPwa: 'Установить Пономарь', installPwa: 'Установить Пономарь',
offlineContent: 'Офлайн-контент',
offlineLangs: 'Языки для кэширования',
offlineDataTypes: 'Типы данных',
offlineLives: 'Жития',
offlineCalendar: 'Календарь',
offlineMenaion: 'Минея',
offlinePreload: 'Загрузить',
offlineClearCache: 'Очистить кэш',
offlineCalculating: 'Расчёт размера...',
offlineDone: 'Готово! Данные закэшированы для офлайн-использования.',
offlineSelectLang: 'Пожалуйста, выберите хотя бы один язык.',
offlineCleared: 'Кэш очищен.',
}, },
common: { common: {
@@ -2051,6 +2087,18 @@ const translations: Record<LanguageCode, Translations> = {
aboutText: 'Понома́рь — приложенiе православнаго календаря, предоставляющее литургическiю информацию, тексты службъ и библейскія чтения на нескольких языкахъ.', aboutText: 'Понома́рь — приложенiе православнаго календаря, предоставляющее литургическiю информацию, тексты службъ и библейскія чтения на нескольких языкахъ.',
aboutLicense: 'Основано на Java-приложенiи Понома́рь отъ Александра Андреева и Юрия Шардт. Лицензия GPL v3.', aboutLicense: 'Основано на Java-приложенiи Понома́рь отъ Александра Андреева и Юрия Шардт. Лицензия GPL v3.',
installPwa: 'Оустановити Понома́рь', installPwa: 'Оустановити Понома́рь',
offlineContent: 'Офлайн-контентъ',
offlineLangs: 'Языки для кеширования',
offlineDataTypes: 'Типы данныхъ',
offlineLives: 'Житїя',
offlineCalendar: 'Календарь',
offlineMenaion: 'Минїа',
offlinePreload: 'Загрузити',
offlineClearCache: 'Очистити кешъ',
offlineCalculating: 'Расчётъ размѣра...',
offlineDone: 'Готово! Данныя закешированы для офлайн-потребленїя.',
offlineSelectLang: 'Пожалуйста, изберите хотя бы единъ языкъ.',
offlineCleared: 'Кешъ очищенъ.',
}, },
common: { common: {
+19 -29
View File
@@ -238,59 +238,49 @@ export class SettingsView {
<!-- Offline Content --> <!-- Offline Content -->
<div class="mb-6"> <div class="mb-6">
<h3 class="text-lg font-bold text-red mb-3">Offline Content</h3> <h3 class="text-lg font-bold text-red mb-3">${t.settings.offlineContent}</h3>
<!-- Language selection for offline --> <!-- Language selection for offline -->
<div class="mb-3"> <div class="mb-3">
<label class="block text-sm font-bold text-navy mb-2">Languages to cache</label> <label class="block text-sm font-bold text-navy mb-2">${t.settings.offlineLangs}</label>
<div id="offline-langs" class="flex flex-wrap gap-3"> <div id="offline-langs" class="flex flex-wrap gap-3">
<label class="flex items-center gap-1 cursor-pointer"> ${LANGUAGES.map(l => `
<input type="checkbox" value="ru" class="offline-lang accent-gold"> <span class="text-sm">Русский</span> <label class="flex items-center gap-1 cursor-pointer">
</label> <input type="checkbox" value="${l.code}" class="offline-lang accent-gold"> <span class="text-sm">${l.local}</span>
<label class="flex items-center gap-1 cursor-pointer"> </label>
<input type="checkbox" value="cu" class="offline-lang accent-gold"> <span class="text-sm">Церковнославянский</span> `).join('')}
</label>
<label class="flex items-center gap-1 cursor-pointer">
<input type="checkbox" value="en" class="offline-lang accent-gold"> <span class="text-sm">English</span>
</label>
<label class="flex items-center gap-1 cursor-pointer">
<input type="checkbox" value="el" class="offline-lang accent-gold"> <span class="text-sm">Ελληνικά</span>
</label>
<label class="flex items-center gap-1 cursor-pointer">
<input type="checkbox" value="fr" class="offline-lang accent-gold"> <span class="text-sm">Français</span>
</label>
</div> </div>
</div> </div>
<!-- Data type selection --> <!-- Data type selection -->
<div class="mb-3"> <div class="mb-3">
<label class="block text-sm font-bold text-navy mb-2">Data to cache</label> <label class="block text-sm font-bold text-navy mb-2">${t.settings.offlineDataTypes}</label>
<div id="offline-types" class="flex flex-wrap gap-3"> <div id="offline-types" class="flex flex-wrap gap-3">
<label class="flex items-center gap-1 cursor-pointer"> <label class="flex items-center gap-1 cursor-pointer">
<input type="checkbox" value="lives" checked class="offline-type accent-gold"> <span class="text-sm">Lives</span> <input type="checkbox" value="lives" checked class="offline-type accent-gold"> <span class="text-sm">${t.settings.offlineLives}</span>
</label> </label>
<label class="flex items-center gap-1 cursor-pointer"> <label class="flex items-center gap-1 cursor-pointer">
<input type="checkbox" value="calendar" checked class="offline-type accent-gold"> <span class="text-sm">Calendar</span> <input type="checkbox" value="calendar" checked class="offline-type accent-gold"> <span class="text-sm">${t.settings.offlineCalendar}</span>
</label> </label>
<label class="flex items-center gap-1 cursor-pointer"> <label class="flex items-center gap-1 cursor-pointer">
<input type="checkbox" value="menaion" class="offline-type accent-gold"> <span class="text-sm">Menaion</span> <input type="checkbox" value="menaion" class="offline-type accent-gold"> <span class="text-sm">${t.settings.offlineMenaion}</span>
</label> </label>
</div> </div>
</div> </div>
<!-- Storage info and controls --> <!-- Storage info and controls -->
<div class="flex items-center justify-between gap-3 mb-2"> <div class="flex items-center justify-between gap-3 mb-2">
<span id="offline-stats" class="text-sm text-navy-light">Calculating storage...</span> <span id="offline-stats" class="text-sm text-navy-light">${t.settings.offlineCalculating}</span>
<div class="flex gap-2"> <div class="flex gap-2">
<button id="offline-preload" class="bg-gold text-navy rounded px-3 py-1 text-sm font-bold hover:bg-gold-dark transition-colors">Preload</button> <button id="offline-preload" class="bg-gold text-navy rounded px-3 py-1 text-sm font-bold hover:bg-gold-dark transition-colors">${t.settings.offlinePreload}</button>
<button id="offline-clear" class="bg-red text-parchment rounded px-3 py-1 text-sm hover:bg-red-dark transition-colors">Clear cache</button> <button id="offline-clear" class="bg-red text-parchment rounded px-3 py-1 text-sm hover:bg-red-dark transition-colors">${t.settings.offlineClearCache}</button>
</div> </div>
</div> </div>
<div id="offline-progress" class="hidden"> <div id="offline-progress" class="hidden">
<div class="w-full bg-parchment-dark rounded-full h-2 mb-1"> <div class="w-full bg-parchment-dark rounded-full h-2 mb-1">
<div id="offline-progress-bar" class="bg-gold h-2 rounded-full" style="width: 0%"></div> <div id="offline-progress-bar" class="bg-gold h-2 rounded-full" style="width: 0%"></div>
</div> </div>
<p id="offline-progress-text" class="text-xs text-navy-light">0 / 0 files</p> <p id="offline-progress-text" class="text-xs text-navy-light">0 / 0 ${t.settings.offlineDataTypes}</p>
</div> </div>
</div> </div>
@@ -383,7 +373,7 @@ export class SettingsView {
if (selectedLangs.length === 0) { if (selectedLangs.length === 0) {
const progressText = document.getElementById('offline-progress-text'); const progressText = document.getElementById('offline-progress-text');
if (progressText) progressText.textContent = 'Please select at least one language.'; if (progressText) progressText.textContent = t.settings.offlineSelectLang;
return; return;
} }
@@ -395,7 +385,7 @@ export class SettingsView {
// Start preloading in background // Start preloading in background
OfflineManager.preload({ languages: selectedLangs, types: selectedTypes }).then(() => { OfflineManager.preload({ languages: selectedLangs, types: selectedTypes }).then(() => {
if (progressBar) progressBar.style.width = '100%'; if (progressBar) progressBar.style.width = '100%';
if (progressText) progressText.textContent = 'Done! Data cached for offline use.'; if (progressText) progressText.textContent = t.settings.offlineDone;
OfflineManager.getStats().then(stats => { OfflineManager.getStats().then(stats => {
const statsEl = document.getElementById('offline-stats'); const statsEl = document.getElementById('offline-stats');
if (statsEl) { if (statsEl) {
@@ -410,7 +400,7 @@ export class SettingsView {
if (prog && prog.total > 0) { if (prog && prog.total > 0) {
const pct = Math.round((prog.current / prog.total) * 100); const pct = Math.round((prog.current / prog.total) * 100);
if (progressBar) progressBar.style.width = `${pct}%`; if (progressBar) progressBar.style.width = `${pct}%`;
if (progressText) progressText.textContent = `${prog.current} / ${prog.total} files — ${prog.file.substring(0, 60)}...`; if (progressText) progressText.textContent = `${prog.current} / ${prog.total} ${t.settings.offlineDataTypes} — ${prog.file.substring(0, 60)}...`;
} }
if (!prog || prog.done) clearInterval(pollInterval); if (!prog || prog.done) clearInterval(pollInterval);
}, 200); }, 200);
@@ -420,7 +410,7 @@ export class SettingsView {
document.getElementById('offline-clear')?.addEventListener('click', async () => { document.getElementById('offline-clear')?.addEventListener('click', async () => {
await OfflineManager.clearCache(); await OfflineManager.clearCache();
const statsEl = document.getElementById('offline-stats'); const statsEl = document.getElementById('offline-stats');
if (statsEl) statsEl.textContent = 'Cache cleared.'; if (statsEl) statsEl.textContent = t.settings.offlineCleared;
const progressDiv = document.getElementById('offline-progress'); const progressDiv = document.getElementById('offline-progress');
if (progressDiv) progressDiv.classList.add('hidden'); if (progressDiv) progressDiv.classList.add('hidden');
}); });