Files
web-petting/src/i18n.rs
T

638 lines
25 KiB
Rust
Raw Normal View History

2026-04-29 17:49:07 +03:00
/// Supported languages.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lang {
Ru,
En,
}
impl Lang {
pub fn code(self) -> &'static str {
match self {
Lang::Ru => "ru",
Lang::En => "en",
}
}
pub fn from_code(code: &str) -> Option<Self> {
match code {
"ru" => Some(Lang::Ru),
"en" => Some(Lang::En),
_ => None,
}
}
/// Parse Accept-Language header and pick best match.
pub fn from_accept_language(header: &str) -> Self {
for part in header.split(',') {
let tag = part.split(';').next().unwrap_or("").trim().to_lowercase();
if tag.starts_with("ru") {
return Lang::Ru;
}
if tag.starts_with("en") {
return Lang::En;
}
}
Lang::En
}
pub fn t(self) -> &'static Translations {
match self {
Lang::Ru => &RU,
Lang::En => &EN,
}
}
/// The other language (for the switcher).
pub fn other(self) -> Self {
match self {
Lang::Ru => Lang::En,
Lang::En => Lang::Ru,
}
}
pub fn label(self) -> &'static str {
match self {
Lang::Ru => "Русский",
Lang::En => "English",
}
}
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct Translations {
// Nav
pub nav_leads: &'static str,
pub nav_clients: &'static str,
pub nav_visits: &'static str,
pub nav_users: &'static str,
pub nav_settings: &'static str,
pub nav_title: &'static str,
// Leads
pub leads_title: &'static str,
pub leads_empty: &'static str,
pub leads_name: &'static str,
pub leads_phone: &'static str,
pub leads_email: &'static str,
pub leads_comment: &'static str,
pub leads_status: &'static str,
pub leads_created: &'static str,
pub leads_actions: &'static str,
// Lead statuses
pub status_new: &'static str,
pub status_in_progress: &'static str,
pub status_converted: &'static str,
pub status_rejected: &'static str,
// Leads (add)
pub leads_add_title: &'static str,
pub leads_add_button: &'static str,
// Clients
pub clients_title: &'static str,
pub clients_empty: &'static str,
pub clients_name: &'static str,
pub clients_phone: &'static str,
pub clients_email: &'static str,
pub clients_address: &'static str,
pub clients_notes: &'static str,
pub clients_status: &'static str,
pub clients_created: &'static str,
pub clients_media_link: &'static str,
pub clients_add_title: &'static str,
pub clients_add_button: &'static str,
pub client_status_active: &'static str,
pub client_status_archived: &'static str,
// Users
pub users_title: &'static str,
pub users_login: &'static str,
pub users_display_name: &'static str,
pub users_status: &'static str,
pub users_created: &'static str,
pub users_password: &'static str,
pub users_password_confirm: &'static str,
pub users_add_title: &'static str,
pub users_add_button: &'static str,
pub users_error_passwords_mismatch: &'static str,
pub users_error_login_taken: &'static str,
// Settings
pub settings_title: &'static str,
pub settings_key: &'static str,
pub settings_value: &'static str,
pub settings_save: &'static str,
pub settings_saved: &'static str,
pub settings_empty: &'static str,
pub settings_telegram_bot_token: &'static str,
pub settings_telegram_chat_id: &'static str,
pub settings_contact_info: &'static str,
pub landing_contact_label: &'static str,
// Dashboard
pub dashboard_title: &'static str,
pub dashboard_today_visits: &'static str,
pub dashboard_no_visits: &'static str,
pub dashboard_recent_feedbacks: &'static str,
pub dashboard_no_feedbacks: &'static str,
// Login / Setup
pub login_title: &'static str,
pub login_button: &'static str,
pub login_error: &'static str,
pub logout: &'static str,
pub setup_title: &'static str,
pub setup_description: &'static str,
pub setup_button: &'static str,
// Landing page
pub landing_meta_description: &'static str,
pub landing_hero_title: &'static str,
pub landing_hero_subtitle: &'static str,
pub landing_hero_cta: &'static str,
pub landing_services_title: &'static str,
pub landing_service_cats_title: &'static str,
pub landing_service_cats_text: &'static str,
pub landing_service_dogs_title: &'static str,
pub landing_service_dogs_text: &'static str,
pub landing_service_home_title: &'static str,
pub landing_service_home_text: &'static str,
pub landing_how_title: &'static str,
pub landing_how_step1_title: &'static str,
pub landing_how_step1_text: &'static str,
pub landing_how_step2_title: &'static str,
pub landing_how_step2_text: &'static str,
pub landing_how_step3_title: &'static str,
pub landing_how_step3_text: &'static str,
pub landing_form_title: &'static str,
pub landing_form_subtitle: &'static str,
pub landing_form_name: &'static str,
pub landing_form_phone: &'static str,
pub landing_form_comment: &'static str,
pub landing_form_comment_placeholder: &'static str,
pub landing_form_submit: &'static str,
pub landing_thank_you_title: &'static str,
pub landing_thank_you_text: &'static str,
pub landing_thank_you_back: &'static str,
pub landing_footer_text: &'static str,
// Client edit
pub clients_edit_title: &'static str,
pub clients_save: &'static str,
pub clients_color: &'static str,
// Filters
pub filter_show_all: &'static str,
pub filter_show_active: &'static str,
// Schedule
pub nav_schedule: &'static str,
pub schedule_title: &'static str,
pub schedule_new: &'static str,
pub schedule_new_title: &'static str,
pub schedule_client: &'static str,
pub schedule_admin: &'static str,
pub schedule_default_time: &'static str,
pub schedule_time_start: &'static str,
pub schedule_time_end: &'static str,
pub schedule_pick_dates: &'static str,
pub schedule_range_from: &'static str,
pub schedule_range_to: &'static str,
pub schedule_fill_range: &'static str,
pub schedule_selected_days: &'static str,
pub schedule_no_days: &'static str,
pub schedule_notes: &'static str,
pub schedule_public_notes: &'static str,
pub schedule_client_feedback: &'static str,
pub schedule_create: &'static str,
pub schedule_remove_day: &'static str,
pub visit_status_scheduled: &'static str,
pub visit_status_completed: &'static str,
pub visit_status_cancelled: &'static str,
pub schedule_mark_done: &'static str,
pub schedule_cancel: &'static str,
pub schedule_edit_title: &'static str,
pub schedule_date: &'static str,
pub schedule_status: &'static str,
pub schedule_save: &'static str,
pub schedule_delete: &'static str,
pub schedule_delete_confirm: &'static str,
// Media
pub nav_media: &'static str,
pub media_title: &'static str,
pub media_upload: &'static str,
pub media_upload_title: &'static str,
pub media_caption: &'static str,
pub media_choose_files: &'static str,
pub media_empty: &'static str,
pub media_delete: &'static str,
pub media_delete_confirm: &'static str,
pub media_all_clients: &'static str,
// Client portal
pub portal_title: &'static str,
pub portal_upcoming: &'static str,
pub portal_past: &'static str,
pub portal_no_upcoming: &'static str,
pub portal_no_past: &'static str,
pub portal_photos: &'static str,
pub portal_feedback_placeholder: &'static str,
pub portal_feedback_submit: &'static str,
pub portal_feedback_thanks: &'static str,
pub portal_link: &'static str,
// Common
pub no_value: &'static str,
pub action_convert: &'static str,
pub action_reject: &'static str,
pub action_in_progress: &'static str,
pub action_archive: &'static str,
pub action_activate: &'static str,
}
static RU: Translations = Translations {
nav_leads: "Заявки",
nav_clients: "Клиенты",
nav_visits: "Визиты",
nav_users: "Админы",
nav_settings: "Настройки",
nav_title: "Пет-ситтинг",
leads_title: "Заявки",
leads_empty: "Заявок пока нет.",
leads_name: "Имя",
leads_phone: "Телефон",
leads_email: "Email",
leads_comment: "Комментарий",
leads_status: "Статус",
leads_created: "Создана",
leads_actions: "Действия",
status_new: "Новая",
status_in_progress: "В работе",
status_converted: "Конвертирована",
status_rejected: "Отклонена",
leads_add_title: "Добавить заявку",
leads_add_button: "Добавить",
clients_title: "Клиенты",
clients_empty: "Клиентов пока нет.",
clients_name: "Имя",
clients_phone: "Телефон",
clients_email: "Email",
clients_address: "Адрес",
clients_notes: "Заметки",
clients_status: "Статус",
clients_created: "Добавлен",
clients_media_link: "Медиа",
clients_add_title: "Добавить клиента",
clients_add_button: "Добавить",
client_status_active: "Активный",
client_status_archived: "Архив",
users_title: "Администраторы",
users_login: "Логин",
users_display_name: "Отображаемое имя",
users_status: "Статус",
users_created: "Создан",
users_password: "Пароль",
users_password_confirm: "Подтверждение пароля",
users_add_title: "Добавить администратора",
users_add_button: "Добавить",
users_error_passwords_mismatch: "Пароли не совпадают.",
users_error_login_taken: "Этот логин уже занят.",
settings_title: "Настройки",
settings_key: "Параметр",
settings_value: "Значение",
settings_save: "Сохранить",
settings_saved: "Сохранено!",
settings_empty: "Настройки не заданы.",
settings_telegram_bot_token: "Токен Telegram бота",
settings_telegram_chat_id: "Chat ID для уведомлений",
settings_contact_info: "Контактная информация (отображается на лендинге)",
landing_contact_label: "Или свяжитесь с нами напрямую",
dashboard_title: "Главная",
dashboard_today_visits: "Визиты на сегодня",
dashboard_no_visits: "На сегодня визитов нет.",
dashboard_recent_feedbacks: "Недавние отзывы клиентов",
dashboard_no_feedbacks: "Новых отзывов нет.",
nav_media: "Медиа",
media_title: "Медиа",
media_upload: "Загрузить",
media_upload_title: "Загрузить медиа",
media_caption: "Подпись",
media_choose_files: "Выберите файлы",
media_empty: "Медиа нет.",
media_delete: "Удалить",
media_delete_confirm: "Удалить этот файл?",
media_all_clients: "Все клиенты",
portal_title: "Мои визиты",
portal_upcoming: "Предстоящие визиты",
portal_past: "Прошлые визиты",
portal_no_upcoming: "Нет предстоящих визитов.",
portal_no_past: "Прошлых визитов пока нет.",
portal_photos: "Фото и видео",
portal_feedback_placeholder: "Оставьте отзыв о визите...",
portal_feedback_submit: "Отправить",
portal_feedback_thanks: "Спасибо за отзыв!",
portal_link: "Ссылка клиента",
login_title: "Вход в систему",
login_button: "Войти",
login_error: "Неверный логин или пароль.",
logout: "Выйти",
setup_title: "Создание администратора",
setup_description: "В системе нет ни одного администратора. Создайте первого для начала работы.",
setup_button: "Создать и войти",
clients_edit_title: "Редактировать клиента",
clients_save: "Сохранить",
clients_color: "Цвет в календаре",
filter_show_all: "Показать все",
filter_show_active: "Только активные",
nav_schedule: "Расписание",
schedule_title: "Расписание",
schedule_new: "Новые визиты",
schedule_new_title: "Запланировать визиты",
schedule_client: "Клиент",
schedule_admin: "Исполнитель",
schedule_default_time: "Время по умолчанию",
schedule_time_start: "С",
schedule_time_end: "До",
schedule_pick_dates: "Добавить дату",
schedule_range_from: "С",
schedule_range_to: "По",
schedule_fill_range: "Заполнить диапазон",
schedule_selected_days: "Выбранные дни",
schedule_no_days: "Дни не выбраны",
schedule_notes: "Приватные заметки",
schedule_public_notes: "Комментарий для клиента",
schedule_client_feedback: "Отзыв клиента",
schedule_create: "Создать визиты",
schedule_remove_day: "Убрать",
visit_status_scheduled: "Запланирован",
visit_status_completed: "Выполнен",
visit_status_cancelled: "Отменён",
schedule_mark_done: "Выполнен",
schedule_cancel: "Отменить",
schedule_edit_title: "Редактировать визит",
schedule_date: "Дата",
schedule_status: "Статус",
schedule_save: "Сохранить",
schedule_delete: "Удалить визит",
schedule_delete_confirm: "Точно удалить этот визит?",
landing_meta_description: "Профессиональный пет-ситтинг: кормление кошек, выгул собак, уход за питомцами пока вы в отпуске. Оставьте заявку — позаботимся о вашем любимце!",
landing_hero_title: "Позаботимся о вашем питомце, пока вас нет дома",
landing_hero_subtitle: "Кормление кошек, выгул собак, ежедневные визиты — ваш питомец в надёжных руках, пока вы в отпуске или командировке",
landing_hero_cta: "Оставить заявку",
landing_services_title: "Наши услуги",
landing_service_cats_title: "Кормление кошек",
landing_service_cats_text: "Приедем к вам домой, покормим кошку, поменяем воду и лоток, поиграем и проверим, что всё в порядке",
landing_service_dogs_title: "Выгул собак",
landing_service_dogs_text: "Погуляем с вашей собакой по привычному маршруту, покормим и проследим за самочувствием питомца",
landing_service_home_title: "Домашние визиты",
landing_service_home_text: "Регулярные визиты к вам домой: проверим питомца, польём цветы, заберём почту — всё будет как при вас",
landing_how_title: "Как это работает",
landing_how_step1_title: "Оставьте заявку",
landing_how_step1_text: "Заполните форму ниже — укажите имя и телефон. Мы свяжемся с вами в течение часа",
landing_how_step2_title: "Обсудим детали",
landing_how_step2_text: "Познакомимся с вашим питомцем, обсудим расписание визитов и особые пожелания",
landing_how_step3_title: "Заботимся о питомце",
landing_how_step3_text: "Пока вас нет — мы рядом. После каждого визита отправим фото и отчёт о самочувствии",
landing_form_title: "Оставить заявку",
landing_form_subtitle: "Расскажите о себе, и мы свяжемся с вами в ближайшее время",
landing_form_name: "Ваше имя",
landing_form_phone: "Телефон",
landing_form_comment: "Комментарий",
landing_form_comment_placeholder: "Расскажите о питомце и когда нужна помощь...",
landing_form_submit: "Отправить заявку",
landing_thank_you_title: "Спасибо за заявку!",
landing_thank_you_text: "Мы получили вашу заявку и свяжемся с вами в ближайшее время.",
landing_thank_you_back: "Вернуться на главную",
landing_footer_text: "Пет-ситтинг — забота о вашем питомце",
no_value: "",
action_convert: "Конвертировать",
action_reject: "Отклонить",
action_in_progress: "В работу",
action_archive: "В архив",
action_activate: "Активировать",
};
static EN: Translations = Translations {
nav_leads: "Leads",
nav_clients: "Clients",
nav_visits: "Visits",
nav_users: "Admins",
nav_settings: "Settings",
nav_title: "Pet Sitting",
leads_title: "Leads",
leads_empty: "No leads yet.",
leads_name: "Name",
leads_phone: "Phone",
leads_email: "Email",
leads_comment: "Comment",
leads_status: "Status",
leads_created: "Created",
leads_actions: "Actions",
status_new: "New",
status_in_progress: "In Progress",
status_converted: "Converted",
status_rejected: "Rejected",
leads_add_title: "Add Lead",
leads_add_button: "Add",
clients_title: "Clients",
clients_empty: "No clients yet.",
clients_name: "Name",
clients_phone: "Phone",
clients_email: "Email",
clients_address: "Address",
clients_notes: "Notes",
clients_status: "Status",
clients_created: "Created",
clients_media_link: "Media",
clients_add_title: "Add Client",
clients_add_button: "Add",
client_status_active: "Active",
client_status_archived: "Archived",
users_title: "Administrators",
users_login: "Login",
users_display_name: "Display Name",
users_status: "Status",
users_created: "Created",
users_password: "Password",
users_password_confirm: "Confirm Password",
users_add_title: "Add Administrator",
users_add_button: "Add",
users_error_passwords_mismatch: "Passwords do not match.",
users_error_login_taken: "This login is already taken.",
settings_title: "Settings",
settings_key: "Parameter",
settings_value: "Value",
settings_save: "Save",
settings_saved: "Saved!",
settings_empty: "No settings configured.",
settings_telegram_bot_token: "Telegram Bot Token",
settings_telegram_chat_id: "Notification Chat ID",
settings_contact_info: "Contact info (shown on landing page)",
landing_contact_label: "Or contact us directly",
dashboard_title: "Home",
dashboard_today_visits: "Today's visits",
dashboard_no_visits: "No visits for today.",
dashboard_recent_feedbacks: "Recent client feedback",
dashboard_no_feedbacks: "No recent feedback.",
nav_media: "Media",
media_title: "Media",
media_upload: "Upload",
media_upload_title: "Upload Media",
media_caption: "Caption",
media_choose_files: "Choose files",
media_empty: "No media yet.",
media_delete: "Delete",
media_delete_confirm: "Delete this file?",
media_all_clients: "All clients",
portal_title: "My Visits",
portal_upcoming: "Upcoming visits",
portal_past: "Past visits",
portal_no_upcoming: "No upcoming visits.",
portal_no_past: "No past visits yet.",
portal_photos: "Photos & Videos",
portal_feedback_placeholder: "Leave feedback about this visit...",
portal_feedback_submit: "Submit",
portal_feedback_thanks: "Thank you for your feedback!",
portal_link: "Client link",
login_title: "Sign In",
login_button: "Sign In",
login_error: "Invalid login or password.",
logout: "Sign Out",
setup_title: "Create Administrator",
setup_description: "There are no administrators yet. Create the first one to get started.",
setup_button: "Create & Sign In",
clients_edit_title: "Edit Client",
clients_save: "Save",
clients_color: "Calendar color",
filter_show_all: "Show all",
filter_show_active: "Active only",
nav_schedule: "Schedule",
schedule_title: "Schedule",
schedule_new: "New Visits",
schedule_new_title: "Plan Visits",
schedule_client: "Client",
schedule_admin: "Assigned to",
schedule_default_time: "Default Time",
schedule_time_start: "From",
schedule_time_end: "To",
schedule_pick_dates: "Add date",
schedule_range_from: "From",
schedule_range_to: "To",
schedule_fill_range: "Fill range",
schedule_selected_days: "Selected days",
schedule_no_days: "No days selected",
schedule_notes: "Private notes",
schedule_public_notes: "Note for client",
schedule_client_feedback: "Client feedback",
schedule_create: "Create visits",
schedule_remove_day: "Remove",
visit_status_scheduled: "Scheduled",
visit_status_completed: "Completed",
visit_status_cancelled: "Cancelled",
schedule_mark_done: "Done",
schedule_cancel: "Cancel",
schedule_edit_title: "Edit Visit",
schedule_date: "Date",
schedule_status: "Status",
schedule_save: "Save",
schedule_delete: "Delete visit",
schedule_delete_confirm: "Are you sure you want to delete this visit?",
landing_meta_description: "Professional pet sitting: cat feeding, dog walking, home visits while you're away. Leave a request — we'll take care of your pet!",
landing_hero_title: "We'll take care of your pet while you're away",
landing_hero_subtitle: "Cat feeding, dog walking, daily visits — your pet is in safe hands while you're on vacation or a business trip",
landing_hero_cta: "Leave a Request",
landing_services_title: "Our Services",
landing_service_cats_title: "Cat Feeding",
landing_service_cats_text: "We'll visit your home, feed the cat, change water and litter, play and make sure everything is fine",
landing_service_dogs_title: "Dog Walking",
landing_service_dogs_text: "We'll walk your dog on their usual route, feed them and keep an eye on their well-being",
landing_service_home_title: "Home Visits",
landing_service_home_text: "Regular home visits: check on your pet, water the plants, collect mail — everything as if you were home",
landing_how_title: "How It Works",
landing_how_step1_title: "Leave a Request",
landing_how_step1_text: "Fill out the form below — just your name and phone. We'll contact you within an hour",
landing_how_step2_title: "Discuss the Details",
landing_how_step2_text: "We'll meet your pet, discuss the visit schedule and any special requirements",
landing_how_step3_title: "We Take Care",
landing_how_step3_text: "While you're away — we're here. After each visit we'll send photos and a wellness report",
landing_form_title: "Leave a Request",
landing_form_subtitle: "Tell us about yourself and we'll get back to you shortly",
landing_form_name: "Your Name",
landing_form_phone: "Phone",
landing_form_comment: "Comment",
landing_form_comment_placeholder: "Tell us about your pet and when you need help...",
landing_form_submit: "Submit Request",
landing_thank_you_title: "Thank you!",
landing_thank_you_text: "We've received your request and will contact you shortly.",
landing_thank_you_back: "Back to Home",
landing_footer_text: "Pet Sitting — caring for your pet",
no_value: "",
action_convert: "Convert",
action_reject: "Reject",
action_in_progress: "In Progress",
action_archive: "Archive",
action_activate: "Activate",
};
impl Translations {
pub fn lead_status(&self, status: &str) -> &'static str {
match status {
"new" => self.status_new,
"in_progress" => self.status_in_progress,
"converted" => self.status_converted,
"rejected" => self.status_rejected,
_ => "?",
}
}
pub fn visit_status(&self, status: &str) -> &'static str {
match status {
"scheduled" => self.visit_status_scheduled,
"completed" => self.visit_status_completed,
"cancelled" => self.visit_status_cancelled,
_ => "?",
}
}
pub fn client_status(&self, status: &str) -> &'static str {
match status {
"active" => self.client_status_active,
"archived" => self.client_status_archived,
_ => "?",
}
}
}