diff --git a/.gitignore b/.gitignore index 7d4797c..bc1cc4f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /venv .cargo assets +out.json diff --git a/Cargo.lock b/Cargo.lock index 10cf93c..fd4ae5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,7 +1336,7 @@ dependencies = [ [[package]] name = "reminder_rs" -version = "1.2.3" +version = "1.3.0-dev" dependencies = [ "Inflector", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index f4169ec..d960ac7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "reminder_rs" -version = "1.2.3" +version = "1.3.0-dev" authors = ["jellywx "] edition = "2018" diff --git a/src/commands/info_cmds.rs b/src/commands/info_cmds.rs index b90196a..8312350 100644 --- a/src/commands/info_cmds.rs +++ b/src/commands/info_cmds.rs @@ -10,6 +10,7 @@ use crate::{ SQLPool, THEME_COLOR, }; +use crate::language_manager::LanguageManager; use std::time::{SystemTime, UNIX_EPOCH}; #[command] @@ -31,16 +32,18 @@ async fn ping(ctx: &Context, msg: &Message, _args: String) { #[command] #[can_blacklist(false)] async fn help(ctx: &Context, msg: &Message, _args: String) { - let pool = ctx - .data - .read() - .await + let data = ctx.data.read().await; + + let pool = data .get::() .cloned() .expect("Could not get SQLPool from data"); - let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap(); - let desc = user_data.response(&pool, "help").await; + let lm = data.get::().unwrap(); + + let language = UserData::language_of(&msg.author, &ctx, &pool).await; + + let desc = lm.get(&language, "help"); let _ = msg .channel_id @@ -63,22 +66,22 @@ async fn help(ctx: &Context, msg: &Message, _args: String) { #[command] async fn info(ctx: &Context, msg: &Message, _args: String) { - let pool = ctx - .data - .read() - .await + let data = ctx.data.read().await; + + let pool = data .get::() .cloned() .expect("Could not get SQLPool from data"); - let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap(); + let lm = data.get::().unwrap(); + + let language = UserData::language_of(&msg.author, &ctx, &pool).await; let guild_data = GuildData::from_guild(msg.guild(&ctx).await.unwrap(), &pool) .await .unwrap(); - let desc = user_data - .response(&pool, "info") - .await + let desc = lm + .get(&language, "info") .replacen("{user}", &ctx.cache.current_user().await.name, 1) .replace("{default_prefix}", &*DEFAULT_PREFIX) .replace("{prefix}", &guild_data.prefix); @@ -104,16 +107,17 @@ async fn info(ctx: &Context, msg: &Message, _args: String) { #[command] async fn donate(ctx: &Context, msg: &Message, _args: String) { - let pool = ctx - .data - .read() - .await + let data = ctx.data.read().await; + + let pool = data .get::() .cloned() .expect("Could not get SQLPool from data"); - let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap(); - let desc = user_data.response(&pool, "donate").await; + let lm = data.get::().unwrap(); + + let language = UserData::language_of(&msg.author, &ctx, &pool).await; + let desc = lm.get(&language, "donate"); let _ = msg .channel_id diff --git a/src/language_manager.rs b/src/language_manager.rs new file mode 100644 index 0000000..fa861f1 --- /dev/null +++ b/src/language_manager.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; + +use serde::Deserialize; +use serde_json::from_reader; +use serenity::prelude::TypeMapKey; +use std::error::Error; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; + +#[derive(Deserialize)] +pub struct LanguageManager { + languages: HashMap, + strings: HashMap>, +} + +impl LanguageManager { + pub(crate) fn from_compiled

(path: P) -> Result> + where + P: AsRef, + { + let file = File::open(path)?; + let reader = BufReader::new(file); + + let new: Self = from_reader(reader)?; + + Ok(new) + } + + pub(crate) fn get(&self, language: &str, name: &'static str) -> &str { + self.strings + .get(language) + .map(|sm| sm.get(name)) + .expect(&format!(r#"Language does not exist: "{}""#, language)) + .expect(&format!(r#"String does not exist: "{}""#, name)) + } + + fn all_languages(&self) -> Vec<(&str, &str)> { + self.languages + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect() + } +} + +impl TypeMapKey for LanguageManager { + type Value = Self; +} diff --git a/src/main.rs b/src/main.rs index 44eb721..ffe4671 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate lazy_static; mod commands; mod consts; mod framework; +mod language_manager; mod models; mod time_parser; @@ -33,6 +34,7 @@ use crate::{ commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds}, consts::{CNC_GUILD, DEFAULT_PREFIX, SUBSCRIPTION_ROLES, THEME_COLOR}, framework::RegexFramework, + language_manager::LanguageManager, }; use serenity::futures::TryFutureExt; @@ -229,11 +231,14 @@ async fn main() -> Result<(), Box> { .await .unwrap(); + let language_manager = LanguageManager::from_compiled("out.json")?; + let mut data = client.data.write().await; data.insert::(pool); data.insert::(Arc::new(reqwest::Client::new())); data.insert::(framework_arc); + data.insert::(language_manager) } if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| { diff --git a/src/models.rs b/src/models.rs index edfd23a..f223ea4 100644 --- a/src/models.rs +++ b/src/models.rs @@ -191,6 +191,25 @@ pub struct UserData { } impl UserData { + pub async fn language_of(user: &User, ctx: impl CacheHttp, pool: &MySqlPool) -> String { + let user_id = user.id.as_u64().to_owned(); + + match sqlx::query!( + " +SELECT IF(language IS NULL, ?, language) AS language FROM users WHERE user = ? + ", + *LOCAL_LANGUAGE, + user_id + ) + .fetch_one(pool) + .await + { + Ok(r) => r.language.unwrap(), + + Err(_) => LOCAL_LANGUAGE.clone(), + } + } + pub async fn from_user( user: &User, ctx: impl CacheHttp, @@ -266,25 +285,8 @@ UPDATE users SET name = ?, language = ?, timezone = ? WHERE id = ? .unwrap(); } - pub async fn response(&self, pool: &MySqlPool, name: &str) -> String { - struct StringRow { - value: String, - } - - sqlx::query_as!( - StringRow, - " -SELECT value FROM strings WHERE (language = ? OR language = ?) AND name = ? ORDER BY language = ? - ", - self.language, - &*LOCAL_LANGUAGE, - name, - &*LOCAL_LANGUAGE - ) - .fetch_one(pool) - .await - .unwrap() - .value + pub async fn response(&self, _pool: &MySqlPool, _name: &str) -> String { + unimplemented!() } pub fn timezone(&self) -> Tz {