use crate::prelude::*; use entity::locale::LocaleType; use std::future::Future; use std::sync::OnceLock; static LOCALES: OnceLock = OnceLock::new(); pub struct LocaleStore { eng: Locale, ru: Locale, } impl LocaleStore { pub fn init() { let ru = serde_yaml::from_slice(include_bytes!("../locales/ru.yaml")) .expect("Error parsing russian locale"); let eng = serde_yaml::from_slice(include_bytes!("../locales/eng.yaml")) .expect("Error parsing english locale"); assert!( LOCALES.set(Self { eng, ru }).is_ok(), "Locales are already intialized" ); } } #[derive(serde::Deserialize, derive_more::Display, derive_more::Deref)] #[deref(forward)] #[repr(transparent)] pub struct LocaleString(Box); impl LocaleString { pub const fn as_str(&self) -> &str { &self.0 } } impl From<&LocaleString> for String { fn from(value: &LocaleString) -> Self { value.0.as_ref().to_owned() } } #[derive(serde::Deserialize)] pub struct Locale { pub master_password_is_not_set: LocaleString, pub hide_button: LocaleString, pub change_name_button: LocaleString, pub change_login_button: LocaleString, pub change_password_button: LocaleString, pub delete_account_button: LocaleString, pub couldnt_get_user_info_send_again: LocaleString, pub unknown_command_use_help: LocaleString, pub help_command: LocaleString, pub no_file_send: LocaleString, pub file_too_large: LocaleString, pub couldnt_get_file_name: LocaleString, pub following_accounts_have_problems: LocaleString, pub duplicate_names: LocaleString, pub accounts_already_in_db: LocaleString, pub invalid_fields: LocaleString, pub fix_that_and_send_again: LocaleString, pub error_downloading_file: LocaleString, pub error_getting_account_names: LocaleString, pub error_parsing_json_file: LocaleString, pub successfully_canceled: LocaleString, pub invalid_password: LocaleString, pub couldnt_get_message_text: LocaleString, pub invalid_file_name: LocaleString, pub account_already_exists: LocaleString, pub master_password_too_weak: LocaleString, pub no_lowercase: LocaleString, pub no_uppercase: LocaleString, pub no_numbers: LocaleString, pub master_pass_too_short: LocaleString, pub change_master_password_and_send_again: LocaleString, pub wrong_master_password: LocaleString, pub invalid_login: LocaleString, pub start_command: LocaleString, pub master_password_dont_match: LocaleString, pub success: LocaleString, pub send_master_password_again: LocaleString, pub master_password_is_set: LocaleString, pub send_new_master_password: LocaleString, pub no_accounts_found: LocaleString, pub choose_account: LocaleString, pub couldnt_create_following_accounts: LocaleString, pub send_master_password: LocaleString, pub something_went_wrong: LocaleString, pub nothing_to_cancel: LocaleString, pub send_account_name: LocaleString, pub send_login: LocaleString, pub error_deleting_message: LocaleString, pub account_not_found: LocaleString, pub send_new_name: LocaleString, pub send_new_login: LocaleString, pub send_new_password: LocaleString, pub send_json_file: LocaleString, pub send_master_pass_to_delete_everything: LocaleString, pub everything_was_deleted: LocaleString, pub send_password: LocaleString, pub send_master_pass_to_delete_account: LocaleString, pub no_special_characters: LocaleString, pub invalid_name: LocaleString, pub decrypt_button: LocaleString, pub delete_message_button: LocaleString, pub menu_button: LocaleString, pub choose_language: LocaleString, word_name: LocaleString, word_login: LocaleString, word_password: LocaleString, } impl Locale { pub async fn from_update(update: Update, db: Pool) -> &'static Self { let locale_type = LocaleType::locale_for_update(&update, &db).await; locale_type.get_locale() } pub fn show_account(&self, name: &str, login: &str, password: &str) -> String { format!( "{}:\n`{name}`\n{}:\n`{login}`\n{}:\n`{password}`", self.word_name, self.word_login, self.word_password ) } pub fn show_hidden_account(&self, name: &str) -> String { format!( "{}:\n`{name}`\n{}:\n\\*\\*\\*\n{}:\n\\*\\*\\*", self.word_name, self.word_login, self.word_password ) } } pub type LocaleRef = &'static Locale; pub trait LocaleTypeExt: Sized { fn locale_for_update(update: &Update, db: &Pool) -> impl Future + Send; fn from_language_code(code: &str) -> Option; fn get_locale(self) -> &'static Locale; } impl LocaleTypeExt for LocaleType { async fn locale_for_update(update: &Update, db: &Pool) -> Self { let Some(from) = update.user() else { return Self::default(); }; match Self::get_from_db(from.id.0, db).await { Ok(Some(locale)) => return locale, Ok(None) => (), Err(err) => handle_error(err), } from.language_code .as_deref() .and_then(Self::from_language_code) .unwrap_or_default() } fn from_language_code(code: &str) -> Option { match code { "ru" => Some(Self::Ru), "en" => Some(Self::Eng), _ => None, } } fn get_locale(self) -> &'static Locale { let Some(store) = LOCALES.get() else { panic!("Locales are not initialized") }; match self { Self::Eng => &store.eng, Self::Ru => &store.ru, } } }