Skip to content

Commit

Permalink
feat!(model): typed locales
Browse files Browse the repository at this point in the history
Adds a typed Locale struct with associated constants for all known
values, replacing the Strings used in the codebase. The Locale type has
two methods of note: `english_name` and `native_name`.

These values are taken from the Discord documentation:
<https://discord.com/developers/docs/reference#locales>

This PR is meant to show how the new raw value representation introduced
in PR #2045 looks when "typing" a value. This was previously left to the
user to know what localizations might exist and to ensure a typo isn't
made. This `Locale` type is still functionally a string in all but name
(literally, as it implements the same traits and derefs in the same way
String does), but it contains methods and the known values registered by
Twilight as "sugar" on top of it.
  • Loading branch information
zeylahellyer committed Jan 15, 2023
1 parent 44d259a commit 0f8a886
Show file tree
Hide file tree
Showing 32 changed files with 649 additions and 144 deletions.
5 changes: 3 additions & 2 deletions twilight-cache-inmemory/src/event/guild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl UpdateCache for GuildUpdate {
guild.owner = self.owner;
guild.owner_id = self.owner_id;
guild.permissions = self.permissions;
guild.preferred_locale = self.preferred_locale.clone();
guild.preferred_locale = self.preferred_locale;
guild.premium_tier = self.premium_tier;
guild
.premium_subscription_count
Expand Down Expand Up @@ -293,6 +293,7 @@ mod tests {
VerificationLevel,
},
id::Id,
user::Locale,
util::datetime::{Timestamp, TimestampParseError},
};

Expand Down Expand Up @@ -420,7 +421,7 @@ mod tests {
owner_id: Id::new(456),
owner: Some(false),
permissions: Some(Permissions::SEND_MESSAGES),
preferred_locale: "en-GB".to_owned(),
preferred_locale: Locale::ENGLISH_UK,
premium_progress_bar_enabled: true,
premium_subscription_count: Some(0),
premium_tier: PremiumTier::NONE,
Expand Down
4 changes: 2 additions & 2 deletions twilight-cache-inmemory/src/event/interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ mod tests {
gateway::payload::incoming::InteractionCreate,
guild::{PartialMember, Permissions, Role},
id::Id,
user::User,
user::{Locale, User},
util::{image_hash::ImageHashParseError, ImageHash, Timestamp},
};

Expand Down Expand Up @@ -231,7 +231,7 @@ mod tests {
guild_locale: None,
id: Id::new(4),
kind: InteractionType::APPLICATION_COMMAND,
locale: Some("en-GB".to_owned()),
locale: Some(Locale::ENGLISH_UK),
member: Some(PartialMember {
avatar: None,
communication_disabled_until: None,
Expand Down
10 changes: 6 additions & 4 deletions twilight-cache-inmemory/src/model/guild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use twilight_model::{
marker::{ApplicationMarker, ChannelMarker, GuildMarker, UserMarker},
Id,
},
user::Locale,
util::{ImageHash, Timestamp},
};

Expand Down Expand Up @@ -41,7 +42,7 @@ pub struct CachedGuild {
pub(crate) owner_id: Id<UserMarker>,
pub(crate) owner: Option<bool>,
pub(crate) permissions: Option<Permissions>,
pub(crate) preferred_locale: String,
pub(crate) preferred_locale: Locale,
pub(crate) premium_progress_bar_enabled: bool,
pub(crate) premium_subscription_count: Option<u64>,
pub(crate) premium_tier: PremiumTier,
Expand Down Expand Up @@ -190,9 +191,10 @@ impl CachedGuild {

/// Preferred locale for Community guilds.
///
/// Used in server discovery and notices from Discord. Defaults to "en-US".
pub fn preferred_locale(&self) -> &str {
&self.preferred_locale
/// Used in server discovery and notices from Discord. Defaults to
/// [`Locale::ENGLISH_US`].
pub const fn preferred_locale(&self) -> Locale {
self.preferred_locale
}

/// Whether the premium progress bar is enabled.
Expand Down
4 changes: 2 additions & 2 deletions twilight-cache-inmemory/src/model/sticker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ mod tests {
Sticker,
},
id::Id,
user::{PremiumType, User, UserFlags},
user::{Locale, PremiumType, User, UserFlags},
util::{image_hash::ImageHashParseError, ImageHash},
};

Expand Down Expand Up @@ -207,7 +207,7 @@ mod tests {
email: Some("[email protected]".to_owned()),
flags: Some(UserFlags::PREMIUM_EARLY_SUPPORTER | UserFlags::VERIFIED_DEVELOPER),
id: Id::new(1),
locale: Some("en-us".to_owned()),
locale: Some(Locale::ENGLISH_US),
mfa_enabled: Some(true),
name: "test".to_owned(),
premium_type: Some(PremiumType::NITRO),
Expand Down
3 changes: 2 additions & 1 deletion twilight-cache-inmemory/src/permission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ mod tests {
marker::{ChannelMarker, GuildMarker, RoleMarker, UserMarker},
Id,
},
user::Locale,
util::Timestamp,
};

Expand Down Expand Up @@ -731,7 +732,7 @@ mod tests {
owner: Some(false),
owner_id: OWNER_ID,
permissions: None,
preferred_locale: "en-GB".to_owned(),
preferred_locale: Locale::ENGLISH_UK,
premium_progress_bar_enabled: false,
premium_subscription_count: Some(0),
premium_tier: PremiumTier::NONE,
Expand Down
4 changes: 2 additions & 2 deletions twilight-cache-inmemory/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use twilight_model::{
marker::{ChannelMarker, EmojiMarker, GuildMarker, RoleMarker, StickerMarker, UserMarker},
Id,
},
user::{CurrentUser, User},
user::{CurrentUser, Locale, User},
util::{ImageHash, Timestamp},
voice::VoiceState,
};
Expand Down Expand Up @@ -390,7 +390,7 @@ pub fn guild(id: Id<GuildMarker>, member_count: Option<u64>) -> Guild {
owner_id: Id::new(1),
owner: None,
permissions: None,
preferred_locale: "en_us".to_owned(),
preferred_locale: Locale::ENGLISH_US,
premium_progress_bar_enabled: false,
premium_subscription_count: None,
premium_tier: PremiumTier::NONE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use twilight_model::{
application::command::{Command, CommandOption, CommandType},
guild::Permissions,
id::{marker::ApplicationMarker, Id},
user::Locale,
};
use twilight_validate::command::{
chat_input_name as validate_chat_input_name, description as validate_description,
Expand All @@ -31,10 +32,10 @@ pub struct CreateGlobalChatInputCommand<'a> {
default_member_permissions: Option<Permissions>,
dm_permission: Option<bool>,
description: &'a str,
description_localizations: Option<&'a HashMap<String, String>>,
description_localizations: Option<&'a HashMap<Locale, String>>,
http: &'a Client,
name: &'a str,
name_localizations: Option<&'a HashMap<String, String>>,
name_localizations: Option<&'a HashMap<Locale, String>>,
nsfw: Option<bool>,
options: Option<&'a [CommandOption]>,
}
Expand Down Expand Up @@ -116,7 +117,7 @@ impl<'a> CreateGlobalChatInputCommand<'a> {
/// [`DescriptionInvalid`]: twilight_validate::command::CommandValidationErrorType::DescriptionInvalid
pub fn description_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for description in localizations.values() {
validate_description(description)?;
Expand All @@ -143,7 +144,7 @@ impl<'a> CreateGlobalChatInputCommand<'a> {
/// [`NameCharacterInvalid`]: twilight_validate::command::CommandValidationErrorType::NameCharacterInvalid
pub fn name_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for name in localizations.values() {
validate_chat_input_name(name)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use twilight_model::{
application::command::{Command, CommandType},
guild::Permissions,
id::{marker::ApplicationMarker, Id},
user::Locale,
};
use twilight_validate::command::{name as validate_name, CommandValidationError};

Expand All @@ -28,7 +29,7 @@ pub struct CreateGlobalMessageCommand<'a> {
dm_permission: Option<bool>,
http: &'a Client,
name: &'a str,
name_localizations: Option<&'a HashMap<String, String>>,
name_localizations: Option<&'a HashMap<Locale, String>>,
nsfw: Option<bool>,
}

Expand Down Expand Up @@ -80,7 +81,7 @@ impl<'a> CreateGlobalMessageCommand<'a> {
/// [`NameLengthInvalid`]: twilight_validate::command::CommandValidationErrorType::NameLengthInvalid
pub fn name_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for name in localizations.values() {
validate_name(name)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use twilight_model::{
application::command::{Command, CommandType},
guild::Permissions,
id::{marker::ApplicationMarker, Id},
user::Locale,
};
use twilight_validate::command::{name as validate_name, CommandValidationError};

Expand All @@ -28,7 +29,7 @@ pub struct CreateGlobalUserCommand<'a> {
dm_permission: Option<bool>,
http: &'a Client,
name: &'a str,
name_localizations: Option<&'a HashMap<String, String>>,
name_localizations: Option<&'a HashMap<Locale, String>>,
nsfw: Option<bool>,
}

Expand Down Expand Up @@ -80,7 +81,7 @@ impl<'a> CreateGlobalUserCommand<'a> {
/// [`NameLengthInvalid`]: twilight_validate::command::CommandValidationErrorType::NameLengthInvalid
pub fn name_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for name in localizations.values() {
validate_name(name)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use twilight_model::{
marker::{ApplicationMarker, GuildMarker},
Id,
},
user::Locale,
};
use twilight_validate::command::{
chat_input_name as validate_chat_input_name, description as validate_description,
Expand All @@ -33,12 +34,12 @@ pub struct CreateGuildChatInputCommand<'a> {
application_id: Id<ApplicationMarker>,
default_member_permissions: Option<Permissions>,
description: &'a str,
description_localizations: Option<&'a HashMap<String, String>>,
description_localizations: Option<&'a HashMap<Locale, String>>,
guild_id: Id<GuildMarker>,
http: &'a Client,
name: &'a str,
nsfw: Option<bool>,
name_localizations: Option<&'a HashMap<String, String>>,
name_localizations: Option<&'a HashMap<Locale, String>>,
options: Option<&'a [CommandOption]>,
}

Expand Down Expand Up @@ -111,7 +112,7 @@ impl<'a> CreateGuildChatInputCommand<'a> {
/// [`DescriptionInvalid`]: twilight_validate::command::CommandValidationErrorType::DescriptionInvalid
pub fn description_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for description in localizations.values() {
validate_description(description)?;
Expand All @@ -138,7 +139,7 @@ impl<'a> CreateGuildChatInputCommand<'a> {
/// [`NameCharacterInvalid`]: twilight_validate::command::CommandValidationErrorType::NameCharacterInvalid
pub fn name_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for name in localizations.values() {
validate_chat_input_name(name)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use twilight_model::{
marker::{ApplicationMarker, GuildMarker},
Id,
},
user::Locale,
};
use twilight_validate::command::{name as validate_name, CommandValidationError};

Expand All @@ -31,7 +32,7 @@ pub struct CreateGuildMessageCommand<'a> {
guild_id: Id<GuildMarker>,
http: &'a Client,
name: &'a str,
name_localizations: Option<&'a HashMap<String, String>>,
name_localizations: Option<&'a HashMap<Locale, String>>,
nsfw: Option<bool>,
}

Expand Down Expand Up @@ -75,7 +76,7 @@ impl<'a> CreateGuildMessageCommand<'a> {
/// [`NameLengthInvalid`]: twilight_validate::command::CommandValidationErrorType::NameLengthInvalid
pub fn name_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for name in localizations.values() {
validate_name(name)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use twilight_model::{
marker::{ApplicationMarker, GuildMarker},
Id,
},
user::Locale,
};
use twilight_validate::command::{name as validate_name, CommandValidationError};

Expand All @@ -31,7 +32,7 @@ pub struct CreateGuildUserCommand<'a> {
guild_id: Id<GuildMarker>,
http: &'a Client,
name: &'a str,
name_localizations: Option<&'a HashMap<String, String>>,
name_localizations: Option<&'a HashMap<Locale, String>>,
nsfw: Option<bool>,
}

Expand Down Expand Up @@ -75,7 +76,7 @@ impl<'a> CreateGuildUserCommand<'a> {
/// [`NameLengthInvalid`]: twilight_validate::command::CommandValidationErrorType::NameLengthInvalid
pub fn name_localizations(
mut self,
localizations: &'a HashMap<String, String>,
localizations: &'a HashMap<Locale, String>,
) -> Result<Self, CommandValidationError> {
for name in localizations.values() {
validate_name(name)?;
Expand Down
10 changes: 6 additions & 4 deletions twilight-http/src/request/application/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use twilight_model::{
application::command::{CommandOption, CommandType},
guild::Permissions,
id::{marker::ApplicationMarker, Id},
user::Locale,
};

/// Version of [`Command`] but with borrowed fields.
Expand All @@ -48,12 +49,12 @@ struct CommandBorrowed<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description_localizations: Option<&'a HashMap<String, String>>,
pub description_localizations: Option<&'a HashMap<Locale, String>>,
#[serde(rename = "type")]
pub kind: CommandType,
pub name: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub name_localizations: Option<&'a HashMap<String, String>>,
pub name_localizations: Option<&'a HashMap<Locale, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nsfw: Option<bool>,
#[serde(default)]
Expand All @@ -68,6 +69,7 @@ mod tests {
application::command::{Command, CommandType},
guild::Permissions,
id::Id,
user::Locale,
};

/// Test to convert a `Command` to a `CommandBorrowed`.
Expand All @@ -83,15 +85,15 @@ mod tests {
dm_permission: Some(true),
description: "command description".to_owned(),
description_localizations: Some(HashMap::from([(
"en-US".to_owned(),
Locale::ENGLISH_US,
"command description".to_owned(),
)])),
guild_id: Some(Id::new(2)),
id: Some(Id::new(3)),
kind: CommandType::CHAT_INPUT,
name: "command name".to_owned(),
name_localizations: Some(HashMap::from([(
"en-US".to_owned(),
Locale::ENGLISH_US,
"command name".to_owned(),
)])),
nsfw: Some(true),
Expand Down
7 changes: 4 additions & 3 deletions twilight-http/src/request/guild/update_guild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use twilight_model::{
marker::{ChannelMarker, GuildMarker, UserMarker},
Id,
},
user::Locale,
};
use twilight_validate::request::{
audit_reason as validate_audit_reason, guild_name as validate_guild_name, ValidationError,
Expand Down Expand Up @@ -56,7 +57,7 @@ struct UpdateGuildFields<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
public_updates_channel_id: Option<Nullable<Id<ChannelMarker>>>,
#[serde(skip_serializing_if = "Option::is_none")]
preferred_locale: Option<Nullable<&'a str>>,
preferred_locale: Option<Nullable<Locale>>,
#[serde(skip_serializing_if = "Option::is_none")]
premium_progress_bar_enabled: Option<bool>,
}
Expand Down Expand Up @@ -276,8 +277,8 @@ impl<'a> UpdateGuild<'a> {

/// Set the preferred locale for the guild.
///
/// Defaults to `en-US`. Requires the guild to be `PUBLIC`.
pub const fn preferred_locale(mut self, preferred_locale: Option<&'a str>) -> Self {
/// Defaults to [`Locale::ENGLISH_US`]. Requires the guild to be `PUBLIC`.
pub const fn preferred_locale(mut self, preferred_locale: Option<Locale>) -> Self {
self.fields.preferred_locale = Some(Nullable(preferred_locale));

self
Expand Down
Loading

0 comments on commit 0f8a886

Please sign in to comment.