feat: set lang
This commit is contained in:
parent
11f6f1edbf
commit
e633c61820
6 changed files with 174 additions and 31 deletions
|
|
@ -1,24 +1,46 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::{Context as _, anyhow, bail};
|
||||
use serenity::all::{
|
||||
CommandInteraction, CommandOptionType, CommandType, Context, CreateCommand,
|
||||
CreateCommandOption, CreateComponent, CreateContainer, CreateContainerComponent,
|
||||
CreateInputText, CreateInteractionResponseMessage, CreateLabel, CreateModal,
|
||||
CreateModalComponent, CreateTextDisplay, InputTextStyle, MessageFlags, Permissions,
|
||||
ResolvedTarget,
|
||||
ResolvedTarget, ResolvedValue,
|
||||
};
|
||||
|
||||
use crate::handler::{Handler, get_guild};
|
||||
use crate::{
|
||||
handler::{Handler, get_guild},
|
||||
lang::{Lang, ParseLocale},
|
||||
};
|
||||
|
||||
pub fn config_command() -> CreateCommand<'static> {
|
||||
CreateCommand::new("starboard")
|
||||
.description("스타보드 설정")
|
||||
.add_option(CreateCommandOption::new(
|
||||
CommandOptionType::SubCommand,
|
||||
"script",
|
||||
"스크립트 수정",
|
||||
))
|
||||
.description("Configure starboard")
|
||||
.description_localized("ko", "스타보드 설정")
|
||||
.add_option(
|
||||
CreateCommandOption::new(
|
||||
CommandOptionType::SubCommand,
|
||||
"script",
|
||||
"Edit starboard script",
|
||||
)
|
||||
.description_localized("ko", "스크립트 설정"),
|
||||
)
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "lang", "Change language")
|
||||
.description_localized("ko", "이 서버에 대한 언어 변경")
|
||||
.add_sub_option(
|
||||
CreateCommandOption::new(
|
||||
CommandOptionType::String,
|
||||
"lang",
|
||||
"Set language for this server",
|
||||
)
|
||||
.description_localized("ko", "사용할 언어 선택")
|
||||
.add_string_choice("한국어", "ko")
|
||||
.add_string_choice("English", "en")
|
||||
.required(true),
|
||||
),
|
||||
)
|
||||
.default_member_permissions(Permissions::ADMINISTRATOR)
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +73,7 @@ impl Handler {
|
|||
&ctx.http,
|
||||
serenity::all::CreateInteractionResponse::Message(
|
||||
CreateInteractionResponseMessage::new()
|
||||
.content("관리자 권한이 필요합니다")
|
||||
.content(interaction.locale().admin_required())
|
||||
.ephemeral(true),
|
||||
),
|
||||
)
|
||||
|
|
@ -59,7 +81,9 @@ impl Handler {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
for option in interaction.data.options() {
|
||||
debug!("got options: {:?}", &interaction.data.options());
|
||||
|
||||
if let Some(option) = interaction.data.options().first() {
|
||||
if option.name == "script" {
|
||||
let script = get_guild(&self.db, guild_id)
|
||||
.await?
|
||||
|
|
@ -84,8 +108,9 @@ impl Handler {
|
|||
|
||||
예시 스크립트:
|
||||
```rs
|
||||
if reactions["⭐"] >= 3 || removed {
|
||||
return result("0000000000000000000", reactions["⭐"], "⭐")
|
||||
let emoji = "⭐";
|
||||
if reactions[emoji] >= 3 || removed {
|
||||
return result("0000000000000000000", reactions[emoji], emoji)
|
||||
}
|
||||
```"#,
|
||||
)),
|
||||
|
|
@ -99,6 +124,41 @@ if reactions["⭐"] >= 3 || removed {
|
|||
),
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
} else if option.name == "lang" {
|
||||
let lang = Some(&option.value)
|
||||
.and_then(|x| match x {
|
||||
ResolvedValue::SubCommand(value) => Some(value),
|
||||
_ => None,
|
||||
})
|
||||
.and_then(|x| x.first())
|
||||
.filter(|x| x.name == "lang")
|
||||
.and_then(|x| match x.value {
|
||||
ResolvedValue::String(x) => Some(x),
|
||||
_ => None,
|
||||
})
|
||||
.context("lang option not found")?;
|
||||
|
||||
let Ok(lang) = Lang::from_str(lang) else {
|
||||
bail!("unknown lang value");
|
||||
};
|
||||
|
||||
sqlx::query(
|
||||
"insert into guilds (id, lang) values ($1, $2) on conflict (id) do update set lang = excluded.lang",
|
||||
).bind(guild_id.to_string())
|
||||
.bind(lang)
|
||||
.execute(&self.db).await?;
|
||||
|
||||
interaction
|
||||
.create_response(
|
||||
&ctx.http,
|
||||
serenity::all::CreateInteractionResponse::Message(
|
||||
CreateInteractionResponseMessage::new()
|
||||
.content(interaction.locale().lang_changed(lang))
|
||||
.ephemeral(true),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
use sqlx::prelude::FromRow;
|
||||
|
||||
use crate::lang::Lang;
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
pub struct GuildRow {
|
||||
// pub id: String,
|
||||
pub script: Option<String>,
|
||||
pub lang: Lang,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ impl Handler {
|
|||
ctx.cache
|
||||
.guild(guild_id)
|
||||
.as_ref()
|
||||
.and_then(|x| x.channel(channel_id).clone())
|
||||
.and_then(|x| x.channel(channel_id))
|
||||
);
|
||||
|
||||
let channel = channel_id
|
||||
|
|
@ -379,10 +379,11 @@ impl Handler {
|
|||
|
||||
components.push(CreateComponent::TextDisplay(CreateTextDisplay::new(
|
||||
format!(
|
||||
"-# {} {} · [원본 메시지]({})",
|
||||
"-# {} {} · [{original_message}]({})",
|
||||
result.icon,
|
||||
result.count,
|
||||
msg.link().to_string()
|
||||
msg.link(),
|
||||
original_message = guild.lang.to_locale().original_message()
|
||||
),
|
||||
)));
|
||||
|
||||
|
|
@ -434,26 +435,22 @@ pub async fn get_guild(
|
|||
executor: impl PgExecutor<'_>,
|
||||
id: GuildId,
|
||||
) -> anyhow::Result<Option<GuildRow>> {
|
||||
Ok(
|
||||
sqlx::query_as::<_, GuildRow>("select * from guilds where id = $1")
|
||||
.bind(id.to_string())
|
||||
.fetch_optional(executor)
|
||||
.await
|
||||
.context("failed to get guild data from db")?,
|
||||
)
|
||||
sqlx::query_as::<_, GuildRow>("select * from guilds where id = $1")
|
||||
.bind(id.to_string())
|
||||
.fetch_optional(executor)
|
||||
.await
|
||||
.context("failed to get guild data from db")
|
||||
}
|
||||
|
||||
async fn get_message(
|
||||
executor: impl PgExecutor<'_>,
|
||||
message_id: MessageId,
|
||||
) -> anyhow::Result<Option<MessageRow>> {
|
||||
Ok(
|
||||
sqlx::query_as::<_, MessageRow>("select * from messages where message_id = $1")
|
||||
.bind(message_id.to_string())
|
||||
.fetch_optional(executor)
|
||||
.await
|
||||
.context("failed to get message data from db")?,
|
||||
)
|
||||
sqlx::query_as::<_, MessageRow>("select * from messages where message_id = $1")
|
||||
.bind(message_id.to_string())
|
||||
.fetch_optional(executor)
|
||||
.await
|
||||
.context("failed to get message data from db")
|
||||
}
|
||||
|
||||
async fn get_or_create_webhook(
|
||||
|
|
|
|||
81
src/bot/lang.rs
Normal file
81
src/bot/lang.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use serenity::all::CommandInteraction;
|
||||
|
||||
#[derive(sqlx::Type, Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
#[sqlx(rename_all = "snake_case", type_name = "TEXT")]
|
||||
pub enum Lang {
|
||||
#[default]
|
||||
Ko,
|
||||
En,
|
||||
}
|
||||
|
||||
impl Lang {
|
||||
pub fn to_locale(self) -> Box<dyn Locale> {
|
||||
match self {
|
||||
Lang::Ko => Box::new(Korean),
|
||||
Lang::En => Box::new(English),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseLocale {
|
||||
fn locale(&self) -> Box<dyn Locale>;
|
||||
}
|
||||
|
||||
impl ParseLocale for CommandInteraction {
|
||||
fn locale(&self) -> Box<dyn Locale> {
|
||||
Lang::from_str(&self.locale).unwrap_or_default().to_locale()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Lang {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ko" => Ok(Lang::Ko),
|
||||
"en" => Ok(Lang::En),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Locale: Send + Sync {
|
||||
fn original_message(&self) -> &'static str;
|
||||
fn admin_required(&self) -> &'static str;
|
||||
|
||||
fn lang_changed(&self, new_lang: Lang) -> String;
|
||||
}
|
||||
|
||||
struct Korean;
|
||||
|
||||
impl Locale for Korean {
|
||||
fn original_message(&self) -> &'static str {
|
||||
"원본 메시지"
|
||||
}
|
||||
|
||||
fn lang_changed(&self, new_lang: Lang) -> String {
|
||||
format!("서버 언어가 {new_lang:?}(으)로 변경되었습니다")
|
||||
}
|
||||
|
||||
fn admin_required(&self) -> &'static str {
|
||||
"관리자 권한이 필요합니다"
|
||||
}
|
||||
}
|
||||
|
||||
struct English;
|
||||
|
||||
impl Locale for English {
|
||||
fn original_message(&self) -> &'static str {
|
||||
"Original Message"
|
||||
}
|
||||
|
||||
fn lang_changed(&self, new_lang: Lang) -> String {
|
||||
format!("Server language changed to {new_lang:?}")
|
||||
}
|
||||
|
||||
fn admin_required(&self) -> &'static str {
|
||||
"Administrator permission is required"
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ mod commands;
|
|||
mod config;
|
||||
mod db;
|
||||
mod handler;
|
||||
mod lang;
|
||||
mod modal;
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue