diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 1adb06a..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.cargo.features": [ - "full" - ], -} \ No newline at end of file diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..efe17b6 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,18 @@ +// Folder-specific settings +// +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#settings-files +{ + "lsp": { + "rust-analyzer": { + "initialization_options": { + "check": { + "command": "clippy" + } + }, + "cargo": { + "features": "all" + } + } + } +} diff --git a/Cargo.toml b/Cargo.toml index 3be83ae..8760d53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,13 @@ license = "BSD-3-Clause" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -telegram = [ "dep:teloxide", "dep:url", "dep:tokio", "dep:async-trait" ] +telegram = [ + "dep:teloxide", + "dep:url", + "dep:tokio", + "dep:async-trait", + "dep:toml", +] string = [] cli = [] full = ["telegram", "string", "cli"] @@ -22,6 +28,7 @@ teloxide = { version = "0.12", optional = true } url = { version = "2.5.0", optional = true } tokio = { version = "1.36.0", optional = true } async-trait = { version = "0.1.77", optional = true } +toml = { version = "0.8", optional = true } [dev-dependencies] serde = "1.0.196" diff --git a/locales/en.toml b/locales/en.toml new file mode 100644 index 0000000..a2f0693 --- /dev/null +++ b/locales/en.toml @@ -0,0 +1,2 @@ +lorem = "ipsum shit" +dablayob = "and is something shit" \ No newline at end of file diff --git a/src/telegram/i18n/i18n.rs b/src/telegram/i18n/i18n.rs new file mode 100644 index 0000000..1e62147 --- /dev/null +++ b/src/telegram/i18n/i18n.rs @@ -0,0 +1,79 @@ +use super::language::Language; +use std::collections::HashMap; + +#[derive(Debug, Clone, Default)] +struct I18n { + users: HashMap, + pub languages: HashMap, +} + +impl I18n { + pub fn new() -> Self { + I18n::default() + } + + pub fn load_translations(&mut self) -> () { + let locales = std::fs::read_dir("locales").unwrap(); + + for locale in locales { + let safe = locale.unwrap(); + + let path = safe.path(); + let file = path.to_str().unwrap(); + + let mut language = Language::new(); + language.parse_translation(file); + + let name = file.split("/").last().unwrap().split(".").next().unwrap(); + + self.languages.insert(name.to_owned(), language); + } + } + + pub fn add_user(&mut self, user_id: i64, language: &str) { + self.users.insert(user_id, language.to_string()); + } + + pub fn get_translation(&self, language: &str, key: &str) -> Option<&String> { + self.languages.get(language)?.get_translation(key) + } + + pub fn get_user_translation(&self, user_id: i64, key: &str) -> Option<&String> { + let language = self.users.get(&user_id)?; + self.get_translation(language, key) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_i18n_init() { + // Create instance and load locales + let mut i18n = I18n::new(); + i18n.load_translations(); + + // Get a translation + let translation = i18n.get_translation("en", "lorem"); + + // Test + assert_eq!(translation, Some(&"ipsum shit".to_string())); + } + + #[test] + fn test_user() { + // Create instance and load locales + let mut i18n = I18n::new(); + i18n.load_translations(); + + // + i18n.add_user(123123123123, "en"); + + // Let's try sending request + let translation = i18n.get_user_translation(123123123123, "lorem"); + + // Test + assert_eq!(translation, Some(&"ipsum shit".to_string())); + } +} \ No newline at end of file diff --git a/src/telegram/i18n/language.rs b/src/telegram/i18n/language.rs new file mode 100644 index 0000000..ee1bad4 --- /dev/null +++ b/src/telegram/i18n/language.rs @@ -0,0 +1,58 @@ +use std::collections::HashMap; + +#[derive(Debug, Clone, Default)] +pub struct Language { + translations: HashMap, +} + +impl Language { + pub fn new() -> Self { + Language::default() + } + + pub fn parse_translation(&mut self, file: &str) { + let content = std::fs::read_to_string(file).unwrap(); + + let translations: HashMap = toml::from_str(&content).unwrap(); + + for (key, value) in translations { + self.add_translation(key.to_string(), value.as_str().to_string()); + } + } + + pub fn add_translation(&mut self, key: String, value: String) { + self.translations.insert(key, value); + } + + pub fn get_translation(&self, key: &str) -> Option<&String> { + self.translations.get(key) + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_language_kv() { + let mut language = Language::new(); + language.add_translation("hello".to_string(), "Hello, World!".to_string()); + + let translation = language.get_translation("hello"); + + // Test + assert_eq!(translation, Some(&"Hello, World!".to_string())); + } + + #[test] + fn test_language_read_file() { + let mut language = Language::new(); + language.parse_translation("./locales/en.toml"); + + let translation = language.get_translation("lorem"); + + // Test + assert_eq!(translation, Some(&"ipsum shit".to_string())); + } +} \ No newline at end of file diff --git a/src/telegram/i18n/mod.rs b/src/telegram/i18n/mod.rs new file mode 100644 index 0000000..b52a0ef --- /dev/null +++ b/src/telegram/i18n/mod.rs @@ -0,0 +1,2 @@ +pub mod i18n; +pub mod language; diff --git a/src/telegram/mod.rs b/src/telegram/mod.rs index 2904d39..a58d1f3 100644 --- a/src/telegram/mod.rs +++ b/src/telegram/mod.rs @@ -1,3 +1,5 @@ +pub mod i18n; pub mod keyboard; pub mod timer; pub mod topic; +