230 lines
7.4 KiB
JavaScript
230 lines
7.4 KiB
JavaScript
|
|
"use strict";
|
|||
|
|
|
|||
|
|
// Translation dictionary. Add a language by adding a key here and an <option>
|
|||
|
|
// to #lang-select in index.html.
|
|||
|
|
const I18N = {
|
|||
|
|
ru: {
|
|||
|
|
subtitle: "веб-панель управления мостом",
|
|||
|
|
sync_now: "⟳ Синхронизировать",
|
|||
|
|
pause: "Пауза",
|
|||
|
|
resume: "Возобновить",
|
|||
|
|
tab_dashboard: "Дашборд",
|
|||
|
|
tab_feeds: "Фиды",
|
|||
|
|
tab_settings: "Настройки",
|
|||
|
|
|
|||
|
|
// dashboard cards
|
|||
|
|
card_feeds: "Фидов (активно)",
|
|||
|
|
card_topics: "Топиков",
|
|||
|
|
card_sent: "Отправлено всего",
|
|||
|
|
card_history: "В истории",
|
|||
|
|
|
|||
|
|
// status panel
|
|||
|
|
status: "Состояние",
|
|||
|
|
engine: "Движок",
|
|||
|
|
last_sync: "Последняя синхронизация",
|
|||
|
|
next_sync: "Следующая",
|
|||
|
|
interval: "Интервал",
|
|||
|
|
error: "Ошибка",
|
|||
|
|
test_notification: "Тестовое уведомление",
|
|||
|
|
ph_topic: "топик (напр. news)",
|
|||
|
|
ph_message: "сообщение",
|
|||
|
|
send: "Отправить",
|
|||
|
|
|
|||
|
|
// log panel
|
|||
|
|
log: "Журнал",
|
|||
|
|
clear_history: "Очистить историю",
|
|||
|
|
|
|||
|
|
// feeds
|
|||
|
|
feeds: "Фиды",
|
|||
|
|
add_feed: "+ Добавить фид",
|
|||
|
|
import_opml: "Импорт OPML",
|
|||
|
|
export_opml: "Экспорт OPML",
|
|||
|
|
feeds_empty: "Фидов пока нет. Нажмите «Добавить фид».",
|
|||
|
|
no_name: "(без названия)",
|
|||
|
|
priority: "приоритет",
|
|||
|
|
quiet: "тихо",
|
|||
|
|
edit: "Изменить",
|
|||
|
|
delete: "Удалить",
|
|||
|
|
|
|||
|
|
// settings
|
|||
|
|
settings_global: "Глобальные настройки",
|
|||
|
|
s_ntfy_url: "ntfy сервер (URL)",
|
|||
|
|
s_ntfy_token: "ntfy токен (необязательно)",
|
|||
|
|
s_interval: "Интервал синхронизации (сек)",
|
|||
|
|
s_tz: "Часовой пояс (IANA)",
|
|||
|
|
s_batch: "Лимит новых записей за цикл",
|
|||
|
|
s_maxdesc: "Макс. длина описания",
|
|||
|
|
s_ua: "User-Agent",
|
|||
|
|
s_flood: "Флуд-защита (задержки для низкого приоритета)",
|
|||
|
|
save: "Сохранить",
|
|||
|
|
|
|||
|
|
// feed modal
|
|||
|
|
feed_new: "Новый фид",
|
|||
|
|
feed_edit: "Изменить фид",
|
|||
|
|
f_name: "Название",
|
|||
|
|
f_url: "URL фида *",
|
|||
|
|
f_topic: "Топик ntfy *",
|
|||
|
|
f_priority: "Приоритет (1–5)",
|
|||
|
|
f_icon: "Иконка (URL)",
|
|||
|
|
f_quiet_hours: "Тихие часы (напр. 22-7)",
|
|||
|
|
f_quiet_priority: "Приоритет в тихие часы",
|
|||
|
|
f_include: "Include regex (показывать только совпадения)",
|
|||
|
|
f_exclude: "Exclude regex (отбрасывать совпадения)",
|
|||
|
|
f_enabled: "Включён",
|
|||
|
|
check_feed: "Проверить фид",
|
|||
|
|
|
|||
|
|
// dynamic / toasts
|
|||
|
|
sync_started: "Синхронизация запущена",
|
|||
|
|
history_cleared: "История очищена",
|
|||
|
|
need_topic: "Укажите топик",
|
|||
|
|
notify_sent: "Уведомление отправлено",
|
|||
|
|
saved: "Сохранено",
|
|||
|
|
feed_deleted: "Фид удалён",
|
|||
|
|
feed_saved: "Фид сохранён",
|
|||
|
|
confirm_delete_feed: "Удалить этот фид?",
|
|||
|
|
confirm_clear_history: "Очистить историю отправленных записей? Старые записи могут прийти повторно.",
|
|||
|
|
checking: "Проверяю…",
|
|||
|
|
need_url: "Укажите URL",
|
|||
|
|
preview_ok: "OK:",
|
|||
|
|
preview_entries: "записей:",
|
|||
|
|
err_prefix: "Ошибка: ",
|
|||
|
|
no_connection: "нет связи",
|
|||
|
|
st_syncing: "синхронизация…",
|
|||
|
|
st_running: "работает",
|
|||
|
|
st_paused: "на паузе",
|
|||
|
|
pill_syncing: "● синхронизация",
|
|||
|
|
pill_running: "● работает",
|
|||
|
|
pill_paused: "‖ пауза",
|
|||
|
|
sec: "сек",
|
|||
|
|
err_suffix_sync_failed: " (ошибка)",
|
|||
|
|
import_done: "Импорт OPML: добавлено {n} из {total}",
|
|||
|
|
import_choose: "Выберите .opml файл",
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
en: {
|
|||
|
|
subtitle: "web control panel for the bridge",
|
|||
|
|
sync_now: "⟳ Sync now",
|
|||
|
|
pause: "Pause",
|
|||
|
|
resume: "Resume",
|
|||
|
|
tab_dashboard: "Dashboard",
|
|||
|
|
tab_feeds: "Feeds",
|
|||
|
|
tab_settings: "Settings",
|
|||
|
|
|
|||
|
|
card_feeds: "Feeds (active)",
|
|||
|
|
card_topics: "Topics",
|
|||
|
|
card_sent: "Sent total",
|
|||
|
|
card_history: "In history",
|
|||
|
|
|
|||
|
|
status: "Status",
|
|||
|
|
engine: "Engine",
|
|||
|
|
last_sync: "Last sync",
|
|||
|
|
next_sync: "Next",
|
|||
|
|
interval: "Interval",
|
|||
|
|
error: "Error",
|
|||
|
|
test_notification: "Test notification",
|
|||
|
|
ph_topic: "topic (e.g. news)",
|
|||
|
|
ph_message: "message",
|
|||
|
|
send: "Send",
|
|||
|
|
|
|||
|
|
log: "Log",
|
|||
|
|
clear_history: "Clear history",
|
|||
|
|
|
|||
|
|
feeds: "Feeds",
|
|||
|
|
add_feed: "+ Add feed",
|
|||
|
|
import_opml: "Import OPML",
|
|||
|
|
export_opml: "Export OPML",
|
|||
|
|
feeds_empty: "No feeds yet. Click \"Add feed\".",
|
|||
|
|
no_name: "(no name)",
|
|||
|
|
priority: "priority",
|
|||
|
|
quiet: "quiet",
|
|||
|
|
edit: "Edit",
|
|||
|
|
delete: "Delete",
|
|||
|
|
|
|||
|
|
settings_global: "Global settings",
|
|||
|
|
s_ntfy_url: "ntfy server (URL)",
|
|||
|
|
s_ntfy_token: "ntfy token (optional)",
|
|||
|
|
s_interval: "Sync interval (sec)",
|
|||
|
|
s_tz: "Timezone (IANA)",
|
|||
|
|
s_batch: "New items per cycle limit",
|
|||
|
|
s_maxdesc: "Max description length",
|
|||
|
|
s_ua: "User-Agent",
|
|||
|
|
s_flood: "Flood protection (delay low-priority items)",
|
|||
|
|
save: "Save",
|
|||
|
|
|
|||
|
|
feed_new: "New feed",
|
|||
|
|
feed_edit: "Edit feed",
|
|||
|
|
f_name: "Name",
|
|||
|
|
f_url: "Feed URL *",
|
|||
|
|
f_topic: "ntfy topic *",
|
|||
|
|
f_priority: "Priority (1–5)",
|
|||
|
|
f_icon: "Icon (URL)",
|
|||
|
|
f_quiet_hours: "Quiet hours (e.g. 22-7)",
|
|||
|
|
f_quiet_priority: "Priority during quiet hours",
|
|||
|
|
f_include: "Include regex (only matching items)",
|
|||
|
|
f_exclude: "Exclude regex (drop matching items)",
|
|||
|
|
f_enabled: "Enabled",
|
|||
|
|
check_feed: "Check feed",
|
|||
|
|
|
|||
|
|
sync_started: "Sync started",
|
|||
|
|
history_cleared: "History cleared",
|
|||
|
|
need_topic: "Enter a topic",
|
|||
|
|
notify_sent: "Notification sent",
|
|||
|
|
saved: "Saved",
|
|||
|
|
feed_deleted: "Feed deleted",
|
|||
|
|
feed_saved: "Feed saved",
|
|||
|
|
confirm_delete_feed: "Delete this feed?",
|
|||
|
|
confirm_clear_history: "Clear the history of sent items? Old items may be delivered again.",
|
|||
|
|
checking: "Checking…",
|
|||
|
|
need_url: "Enter a URL",
|
|||
|
|
preview_ok: "OK:",
|
|||
|
|
preview_entries: "items:",
|
|||
|
|
err_prefix: "Error: ",
|
|||
|
|
no_connection: "no connection",
|
|||
|
|
st_syncing: "syncing…",
|
|||
|
|
st_running: "running",
|
|||
|
|
st_paused: "paused",
|
|||
|
|
pill_syncing: "● syncing",
|
|||
|
|
pill_running: "● running",
|
|||
|
|
pill_paused: "‖ paused",
|
|||
|
|
sec: "sec",
|
|||
|
|
err_suffix_sync_failed: " (error)",
|
|||
|
|
import_done: "OPML import: added {n} of {total}",
|
|||
|
|
import_choose: "Choose an .opml file",
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
let LANG = localStorage.getItem("lang") || "ru";
|
|||
|
|
|
|||
|
|
function t(key) {
|
|||
|
|
const dict = I18N[LANG] || I18N.ru;
|
|||
|
|
return (key in dict) ? dict[key] : (I18N.ru[key] || key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function locale() {
|
|||
|
|
return LANG === "ru" ? "ru-RU" : "en-US";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function applyI18n() {
|
|||
|
|
document.documentElement.lang = LANG;
|
|||
|
|
document.querySelectorAll("[data-i18n]").forEach((el) => {
|
|||
|
|
el.textContent = t(el.dataset.i18n);
|
|||
|
|
});
|
|||
|
|
document.querySelectorAll("[data-i18n-ph]").forEach((el) => {
|
|||
|
|
el.placeholder = t(el.dataset.i18nPh);
|
|||
|
|
});
|
|||
|
|
document.querySelectorAll("[data-i18n-title]").forEach((el) => {
|
|||
|
|
el.title = t(el.dataset.i18nTitle);
|
|||
|
|
});
|
|||
|
|
const sel = document.getElementById("lang-select");
|
|||
|
|
if (sel) sel.value = LANG;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function setLang(lang) {
|
|||
|
|
LANG = lang;
|
|||
|
|
localStorage.setItem("lang", lang);
|
|||
|
|
applyI18n();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DOM is fully parsed (scripts sit at the end of <body>).
|
|||
|
|
applyI18n();
|