new language manager that loads strings from compiled json file
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -3,3 +3,4 @@
 | 
				
			|||||||
/venv
 | 
					/venv
 | 
				
			||||||
.cargo
 | 
					.cargo
 | 
				
			||||||
assets
 | 
					assets
 | 
				
			||||||
 | 
					out.json
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -1336,7 +1336,7 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "reminder_rs"
 | 
					name = "reminder_rs"
 | 
				
			||||||
version = "1.2.3"
 | 
					version = "1.3.0-dev"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "Inflector",
 | 
					 "Inflector",
 | 
				
			||||||
 "async-trait",
 | 
					 "async-trait",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "reminder_rs"
 | 
					name = "reminder_rs"
 | 
				
			||||||
version = "1.2.3"
 | 
					version = "1.3.0-dev"
 | 
				
			||||||
authors = ["jellywx <judesouthworth@pm.me>"]
 | 
					authors = ["jellywx <judesouthworth@pm.me>"]
 | 
				
			||||||
edition = "2018"
 | 
					edition = "2018"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ use crate::{
 | 
				
			|||||||
    SQLPool, THEME_COLOR,
 | 
					    SQLPool, THEME_COLOR,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::language_manager::LanguageManager;
 | 
				
			||||||
use std::time::{SystemTime, UNIX_EPOCH};
 | 
					use std::time::{SystemTime, UNIX_EPOCH};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[command]
 | 
					#[command]
 | 
				
			||||||
@@ -31,16 +32,18 @@ async fn ping(ctx: &Context, msg: &Message, _args: String) {
 | 
				
			|||||||
#[command]
 | 
					#[command]
 | 
				
			||||||
#[can_blacklist(false)]
 | 
					#[can_blacklist(false)]
 | 
				
			||||||
async fn help(ctx: &Context, msg: &Message, _args: String) {
 | 
					async fn help(ctx: &Context, msg: &Message, _args: String) {
 | 
				
			||||||
    let pool = ctx
 | 
					    let data = ctx.data.read().await;
 | 
				
			||||||
        .data
 | 
					
 | 
				
			||||||
        .read()
 | 
					    let pool = data
 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .get::<SQLPool>()
 | 
					        .get::<SQLPool>()
 | 
				
			||||||
        .cloned()
 | 
					        .cloned()
 | 
				
			||||||
        .expect("Could not get SQLPool from data");
 | 
					        .expect("Could not get SQLPool from data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
 | 
					    let lm = data.get::<LanguageManager>().unwrap();
 | 
				
			||||||
    let desc = user_data.response(&pool, "help").await;
 | 
					
 | 
				
			||||||
 | 
					    let language = UserData::language_of(&msg.author, &ctx, &pool).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let desc = lm.get(&language, "help");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let _ = msg
 | 
					    let _ = msg
 | 
				
			||||||
        .channel_id
 | 
					        .channel_id
 | 
				
			||||||
@@ -63,22 +66,22 @@ async fn help(ctx: &Context, msg: &Message, _args: String) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[command]
 | 
					#[command]
 | 
				
			||||||
async fn info(ctx: &Context, msg: &Message, _args: String) {
 | 
					async fn info(ctx: &Context, msg: &Message, _args: String) {
 | 
				
			||||||
    let pool = ctx
 | 
					    let data = ctx.data.read().await;
 | 
				
			||||||
        .data
 | 
					
 | 
				
			||||||
        .read()
 | 
					    let pool = data
 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .get::<SQLPool>()
 | 
					        .get::<SQLPool>()
 | 
				
			||||||
        .cloned()
 | 
					        .cloned()
 | 
				
			||||||
        .expect("Could not get SQLPool from data");
 | 
					        .expect("Could not get SQLPool from data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
 | 
					    let lm = data.get::<LanguageManager>().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let language = UserData::language_of(&msg.author, &ctx, &pool).await;
 | 
				
			||||||
    let guild_data = GuildData::from_guild(msg.guild(&ctx).await.unwrap(), &pool)
 | 
					    let guild_data = GuildData::from_guild(msg.guild(&ctx).await.unwrap(), &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .unwrap();
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let desc = user_data
 | 
					    let desc = lm
 | 
				
			||||||
        .response(&pool, "info")
 | 
					        .get(&language, "info")
 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .replacen("{user}", &ctx.cache.current_user().await.name, 1)
 | 
					        .replacen("{user}", &ctx.cache.current_user().await.name, 1)
 | 
				
			||||||
        .replace("{default_prefix}", &*DEFAULT_PREFIX)
 | 
					        .replace("{default_prefix}", &*DEFAULT_PREFIX)
 | 
				
			||||||
        .replace("{prefix}", &guild_data.prefix);
 | 
					        .replace("{prefix}", &guild_data.prefix);
 | 
				
			||||||
@@ -104,16 +107,17 @@ async fn info(ctx: &Context, msg: &Message, _args: String) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[command]
 | 
					#[command]
 | 
				
			||||||
async fn donate(ctx: &Context, msg: &Message, _args: String) {
 | 
					async fn donate(ctx: &Context, msg: &Message, _args: String) {
 | 
				
			||||||
    let pool = ctx
 | 
					    let data = ctx.data.read().await;
 | 
				
			||||||
        .data
 | 
					
 | 
				
			||||||
        .read()
 | 
					    let pool = data
 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .get::<SQLPool>()
 | 
					        .get::<SQLPool>()
 | 
				
			||||||
        .cloned()
 | 
					        .cloned()
 | 
				
			||||||
        .expect("Could not get SQLPool from data");
 | 
					        .expect("Could not get SQLPool from data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
 | 
					    let lm = data.get::<LanguageManager>().unwrap();
 | 
				
			||||||
    let desc = user_data.response(&pool, "donate").await;
 | 
					
 | 
				
			||||||
 | 
					    let language = UserData::language_of(&msg.author, &ctx, &pool).await;
 | 
				
			||||||
 | 
					    let desc = lm.get(&language, "donate");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let _ = msg
 | 
					    let _ = msg
 | 
				
			||||||
        .channel_id
 | 
					        .channel_id
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								src/language_manager.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/language_manager.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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<String, String>,
 | 
				
			||||||
 | 
					    strings: HashMap<String, HashMap<String, String>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl LanguageManager {
 | 
				
			||||||
 | 
					    pub(crate) fn from_compiled<P>(path: P) -> Result<Self, Box<dyn Error + Send + Sync>>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        P: AsRef<Path>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,7 @@ extern crate lazy_static;
 | 
				
			|||||||
mod commands;
 | 
					mod commands;
 | 
				
			||||||
mod consts;
 | 
					mod consts;
 | 
				
			||||||
mod framework;
 | 
					mod framework;
 | 
				
			||||||
 | 
					mod language_manager;
 | 
				
			||||||
mod models;
 | 
					mod models;
 | 
				
			||||||
mod time_parser;
 | 
					mod time_parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,6 +34,7 @@ use crate::{
 | 
				
			|||||||
    commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds},
 | 
					    commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds},
 | 
				
			||||||
    consts::{CNC_GUILD, DEFAULT_PREFIX, SUBSCRIPTION_ROLES, THEME_COLOR},
 | 
					    consts::{CNC_GUILD, DEFAULT_PREFIX, SUBSCRIPTION_ROLES, THEME_COLOR},
 | 
				
			||||||
    framework::RegexFramework,
 | 
					    framework::RegexFramework,
 | 
				
			||||||
 | 
					    language_manager::LanguageManager,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use serenity::futures::TryFutureExt;
 | 
					use serenity::futures::TryFutureExt;
 | 
				
			||||||
@@ -229,11 +231,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
 | 
				
			|||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .unwrap();
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let language_manager = LanguageManager::from_compiled("out.json")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut data = client.data.write().await;
 | 
					        let mut data = client.data.write().await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data.insert::<SQLPool>(pool);
 | 
					        data.insert::<SQLPool>(pool);
 | 
				
			||||||
        data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
 | 
					        data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
 | 
				
			||||||
        data.insert::<FrameworkCtx>(framework_arc);
 | 
					        data.insert::<FrameworkCtx>(framework_arc);
 | 
				
			||||||
 | 
					        data.insert::<LanguageManager>(language_manager)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| {
 | 
					    if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -191,6 +191,25 @@ pub struct UserData {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl 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(
 | 
					    pub async fn from_user(
 | 
				
			||||||
        user: &User,
 | 
					        user: &User,
 | 
				
			||||||
        ctx: impl CacheHttp,
 | 
					        ctx: impl CacheHttp,
 | 
				
			||||||
@@ -266,25 +285,8 @@ UPDATE users SET name = ?, language = ?, timezone = ? WHERE id = ?
 | 
				
			|||||||
        .unwrap();
 | 
					        .unwrap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn response(&self, pool: &MySqlPool, name: &str) -> String {
 | 
					    pub async fn response(&self, _pool: &MySqlPool, _name: &str) -> String {
 | 
				
			||||||
        struct StringRow {
 | 
					        unimplemented!()
 | 
				
			||||||
            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 fn timezone(&self) -> Tz {
 | 
					    pub fn timezone(&self) -> Tz {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user