| @@ -1,4 +1,5 @@ | |||||
| using System; | using System; | ||||
| using System.Collections; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text.RegularExpressions; | using System.Text.RegularExpressions; | ||||
| @@ -12,6 +13,8 @@ namespace Discord | |||||
| { | { | ||||
| private string _name; | private string _name; | ||||
| private string _description; | private string _description; | ||||
| private IDictionary<string, string> _nameLocalizations = new Dictionary<string, string>(); | |||||
| private IDictionary<string, string> _descriptionLocalizations = new Dictionary<string, string>(); | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the name of this option. | /// Gets or sets the name of this option. | ||||
| @@ -21,18 +24,7 @@ namespace Discord | |||||
| get => _name; | get => _name; | ||||
| set | set | ||||
| { | { | ||||
| if (value == null) | |||||
| throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null."); | |||||
| if (value.Length > 32) | |||||
| throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 32."); | |||||
| if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) | |||||
| throw new FormatException($"{nameof(value)} must match the regex ^[\\w-]{{1,32}}$"); | |||||
| if (value.Any(x => char.IsUpper(x))) | |||||
| throw new FormatException("Name cannot contain any uppercase characters."); | |||||
| EnsureValidOptionName(value); | |||||
| _name = value; | _name = value; | ||||
| } | } | ||||
| } | } | ||||
| @@ -43,12 +35,11 @@ namespace Discord | |||||
| public string Description | public string Description | ||||
| { | { | ||||
| get => _description; | get => _description; | ||||
| set => _description = value?.Length switch | |||||
| set | |||||
| { | { | ||||
| > 100 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be less than or equal to 100."), | |||||
| 0 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be at least 1."), | |||||
| _ => value | |||||
| }; | |||||
| EnsureValidOptionDescription(value); | |||||
| _description = value; | |||||
| } | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -95,5 +86,73 @@ namespace Discord | |||||
| /// Gets or sets the allowed channel types for this option. | /// Gets or sets the allowed channel types for this option. | ||||
| /// </summary> | /// </summary> | ||||
| public List<ChannelType> ChannelTypes { get; set; } | public List<ChannelType> ChannelTypes { get; set; } | ||||
| public IDictionary<string, string> NameLocalizations | |||||
| { | |||||
| get => _nameLocalizations; | |||||
| set | |||||
| { | |||||
| foreach (var (locale, name) in value) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| EnsureValidOptionName(name); | |||||
| } | |||||
| _nameLocalizations = value; | |||||
| } | |||||
| } | |||||
| public IDictionary<string, string> DescriptionLocalizations | |||||
| { | |||||
| get => _descriptionLocalizations; | |||||
| set | |||||
| { | |||||
| foreach (var (locale, description) in value) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| EnsureValidOptionDescription(description); | |||||
| } | |||||
| _nameLocalizations = value; | |||||
| } | |||||
| } | |||||
| private static void EnsureValidOptionName(string name) | |||||
| { | |||||
| if (name == null) | |||||
| throw new ArgumentNullException(nameof(name), $"{nameof(Name)} cannot be null."); | |||||
| if (name.Length > 32) | |||||
| throw new ArgumentOutOfRangeException(nameof(name), "Name length must be less than or equal to 32."); | |||||
| if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||||
| throw new FormatException($"{nameof(name)} must match the regex ^[\\w-]{{1,32}}$"); | |||||
| if (name.Any(x => char.IsUpper(x))) | |||||
| throw new FormatException("Name cannot contain any uppercase characters."); | |||||
| } | |||||
| private static void EnsureValidOptionDescription(string description) | |||||
| { | |||||
| switch (description.Length) | |||||
| { | |||||
| case > 100: | |||||
| throw new ArgumentOutOfRangeException(nameof(description), | |||||
| "Description length must be less than or equal to 100."); | |||||
| case 0: | |||||
| throw new ArgumentOutOfRangeException(nameof(description), "Description length must at least 1."); | |||||
| } | |||||
| } | |||||
| } | |||||
| public static class Test | |||||
| { | |||||
| public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> kvp, out T1 key, out T2 value) | |||||
| { | |||||
| key = kvp.Key; | |||||
| value = kvp.Value; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,8 @@ | |||||
| using System; | using System; | ||||
| using System.Collections; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text.RegularExpressions; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| @@ -9,6 +13,7 @@ namespace Discord | |||||
| { | { | ||||
| private string _name; | private string _name; | ||||
| private object _value; | private object _value; | ||||
| private IDictionary<string, string> _nameLocalizations = new Dictionary<string, string>(); | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the name of this choice. | /// Gets or sets the name of this choice. | ||||
| @@ -40,5 +45,29 @@ namespace Discord | |||||
| _value = value; | _value = value; | ||||
| } | } | ||||
| } | } | ||||
| public IDictionary<string, string> NameLocalizations | |||||
| { | |||||
| get => _nameLocalizations; | |||||
| set | |||||
| { | |||||
| foreach (var (locale, name) in value) | |||||
| { | |||||
| if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException("Key values of the dictionary must be valid language codes."); | |||||
| switch (name.Length) | |||||
| { | |||||
| case > 100: | |||||
| throw new ArgumentOutOfRangeException(nameof(value), | |||||
| "Name length must be less than or equal to 100."); | |||||
| case 0: | |||||
| throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."); | |||||
| } | |||||
| } | |||||
| _nameLocalizations = value; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,3 +1,6 @@ | |||||
| using System.Collections; | |||||
| using System.Collections.Generic; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -17,6 +20,10 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| public Optional<bool> IsDefaultPermission { get; set; } | public Optional<bool> IsDefaultPermission { get; set; } | ||||
| public Optional<IDictionary<string, string>> NameLocalizations { get; set; } | |||||
| public Optional<IDictionary<string, string>> DescriptionLocalizations { get; set; } | |||||
| internal ApplicationCommandProperties() { } | internal ApplicationCommandProperties() { } | ||||
| } | } | ||||
| } | } | ||||
| @@ -39,6 +39,14 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| IReadOnlyCollection<IApplicationCommandOption> Options { get; } | IReadOnlyCollection<IApplicationCommandOption> Options { get; } | ||||
| IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||||
| IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; } | |||||
| string? NameLocalized { get; } | |||||
| string? DescriptionLocalized { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Modifies the current application command. | /// Modifies the current application command. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -61,5 +61,13 @@ namespace Discord | |||||
| /// Gets the allowed channel types for this option. | /// Gets the allowed channel types for this option. | ||||
| /// </summary> | /// </summary> | ||||
| IReadOnlyCollection<ChannelType> ChannelTypes { get; } | IReadOnlyCollection<ChannelType> ChannelTypes { get; } | ||||
| IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||||
| IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; } | |||||
| string? NameLocalized { get; } | |||||
| string? DescriptionLocalized { get; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,3 +1,5 @@ | |||||
| using System.Collections.Generic; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -14,5 +16,9 @@ namespace Discord | |||||
| /// Gets the value of the choice. | /// Gets the value of the choice. | ||||
| /// </summary> | /// </summary> | ||||
| object Value { get; } | object Value { get; } | ||||
| IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||||
| string? NameLocalized { get; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,6 +1,9 @@ | |||||
| using System; | using System; | ||||
| using System.Collections; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Net.Sockets; | |||||
| using System.Text.RegularExpressions; | using System.Text.RegularExpressions; | ||||
| namespace Discord | namespace Discord | ||||
| @@ -76,6 +79,10 @@ namespace Discord | |||||
| } | } | ||||
| } | } | ||||
| public IReadOnlyDictionary<string, string> NameLocalizations => _nameLocalizations; | |||||
| public IReadOnlyDictionary<string, string> DescriptionLocalizations => _descriptionLocalizations; | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets whether the command is enabled by default when the app is added to a guild | /// Gets or sets whether the command is enabled by default when the app is added to a guild | ||||
| /// </summary> | /// </summary> | ||||
| @@ -83,6 +90,8 @@ namespace Discord | |||||
| private string _name; | private string _name; | ||||
| private string _description; | private string _description; | ||||
| private Dictionary<string, string> _nameLocalizations; | |||||
| private Dictionary<string, string> _descriptionLocalizations; | |||||
| private List<SlashCommandOptionBuilder> _options; | private List<SlashCommandOptionBuilder> _options; | ||||
| /// <summary> | /// <summary> | ||||
| @@ -96,6 +105,8 @@ namespace Discord | |||||
| Name = Name, | Name = Name, | ||||
| Description = Description, | Description = Description, | ||||
| IsDefaultPermission = IsDefaultPermission, | IsDefaultPermission = IsDefaultPermission, | ||||
| NameLocalizations = _nameLocalizations, | |||||
| DescriptionLocalizations = _descriptionLocalizations, | |||||
| }; | }; | ||||
| if (Options != null && Options.Any()) | if (Options != null && Options.Any()) | ||||
| @@ -162,7 +173,8 @@ namespace Discord | |||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type, | public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type, | ||||
| string description, bool? isRequired = null, bool? isDefault = null, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, | string description, bool? isRequired = null, bool? isDefault = null, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, | ||||
| List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||||
| List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, IDictionary<string, string> nameLocalizations = null, | |||||
| IDictionary<string, string> descriptionLocalizations = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||||
| { | { | ||||
| // Make sure the name matches the requirements from discord | // Make sure the name matches the requirements from discord | ||||
| Preconditions.NotNullOrEmpty(name, nameof(name)); | Preconditions.NotNullOrEmpty(name, nameof(name)); | ||||
| @@ -195,9 +207,15 @@ namespace Discord | |||||
| Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(), | Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(), | ||||
| ChannelTypes = channelTypes, | ChannelTypes = channelTypes, | ||||
| MinValue = minValue, | MinValue = minValue, | ||||
| MaxValue = maxValue, | |||||
| MaxValue = maxValue | |||||
| }; | }; | ||||
| if (nameLocalizations is not null) | |||||
| option.WithNameLocalizations(nameLocalizations); | |||||
| if (descriptionLocalizations is not null) | |||||
| option.WithDescriptionLocalizations(descriptionLocalizations); | |||||
| return AddOption(option); | return AddOption(option); | ||||
| } | } | ||||
| @@ -239,6 +257,74 @@ namespace Discord | |||||
| Options.AddRange(options); | Options.AddRange(options); | ||||
| return this; | return this; | ||||
| } | } | ||||
| public SlashCommandBuilder WithNameLocalizations(IDictionary<string, string> nameLocalizations) | |||||
| { | |||||
| if (nameLocalizations is null) | |||||
| throw new ArgumentNullException(nameof(nameLocalizations)); | |||||
| foreach (var (locale, name) in nameLocalizations) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||||
| Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||||
| if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||||
| throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||||
| } | |||||
| _nameLocalizations = new Dictionary<string, string>(nameLocalizations); | |||||
| return this; | |||||
| } | |||||
| public SlashCommandBuilder WithDescriptionLocalizations(IDictionary<string, string> descriptionLocalizations) | |||||
| { | |||||
| if (descriptionLocalizations is null) | |||||
| throw new ArgumentNullException(nameof(descriptionLocalizations)); | |||||
| foreach (var (locale, description) in _descriptionLocalizations) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||||
| Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||||
| } | |||||
| _descriptionLocalizations = new Dictionary<string, string>(descriptionLocalizations); | |||||
| return this; | |||||
| } | |||||
| public SlashCommandBuilder AddNameLocalization(string locale, string name) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||||
| Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||||
| if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||||
| throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||||
| _descriptionLocalizations ??= new(); | |||||
| _nameLocalizations.Add(locale, name); | |||||
| return this; | |||||
| } | |||||
| public SlashCommandBuilder AddDescriptionLocalization(string locale, string description) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||||
| Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||||
| _descriptionLocalizations ??= new(); | |||||
| _descriptionLocalizations.Add(locale, description); | |||||
| return this; | |||||
| } | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -258,6 +344,8 @@ namespace Discord | |||||
| private string _name; | private string _name; | ||||
| private string _description; | private string _description; | ||||
| private Dictionary<string, string> _nameLocalizations; | |||||
| private Dictionary<string, string> _descriptionLocalizations; | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the name of this option. | /// Gets or sets the name of this option. | ||||
| @@ -342,6 +430,10 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| public List<ChannelType> ChannelTypes { get; set; } | public List<ChannelType> ChannelTypes { get; set; } | ||||
| public IReadOnlyDictionary<string, string> NameLocalizations => _nameLocalizations; | |||||
| public IReadOnlyDictionary<string, string> DescriptionLocalizations => _descriptionLocalizations; | |||||
| /// <summary> | /// <summary> | ||||
| /// Builds the current option. | /// Builds the current option. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -377,7 +469,9 @@ namespace Discord | |||||
| IsAutocomplete = IsAutocomplete, | IsAutocomplete = IsAutocomplete, | ||||
| ChannelTypes = ChannelTypes, | ChannelTypes = ChannelTypes, | ||||
| MinValue = MinValue, | MinValue = MinValue, | ||||
| MaxValue = MaxValue | |||||
| MaxValue = MaxValue, | |||||
| NameLocalizations = _nameLocalizations, | |||||
| DescriptionLocalizations = _descriptionLocalizations | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -398,7 +492,8 @@ namespace Discord | |||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandOptionBuilder AddOption(string name, ApplicationCommandOptionType type, | public SlashCommandOptionBuilder AddOption(string name, ApplicationCommandOptionType type, | ||||
| string description, bool? isRequired = null, bool isDefault = false, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, | string description, bool? isRequired = null, bool isDefault = false, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, | ||||
| List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||||
| List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, IDictionary<string, string> nameLocalizations = null, | |||||
| IDictionary<string, string> descriptionLocalizations = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||||
| { | { | ||||
| // Make sure the name matches the requirements from discord | // Make sure the name matches the requirements from discord | ||||
| Preconditions.NotNullOrEmpty(name, nameof(name)); | Preconditions.NotNullOrEmpty(name, nameof(name)); | ||||
| @@ -431,9 +526,15 @@ namespace Discord | |||||
| Options = options, | Options = options, | ||||
| Type = type, | Type = type, | ||||
| Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(), | Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(), | ||||
| ChannelTypes = channelTypes | |||||
| ChannelTypes = channelTypes, | |||||
| }; | }; | ||||
| if(nameLocalizations is not null) | |||||
| option.WithNameLocalizations(nameLocalizations); | |||||
| if(descriptionLocalizations is not null) | |||||
| option.WithDescriptionLocalizations(descriptionLocalizations); | |||||
| return AddOption(option); | return AddOption(option); | ||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -460,9 +561,9 @@ namespace Discord | |||||
| /// <param name="name">The name of the choice.</param> | /// <param name="name">The name of the choice.</param> | ||||
| /// <param name="value">The value of the choice.</param> | /// <param name="value">The value of the choice.</param> | ||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandOptionBuilder AddChoice(string name, int value) | |||||
| public SlashCommandOptionBuilder AddChoice(string name, int value, IDictionary<string, string> nameLocalizations = null) | |||||
| { | { | ||||
| return AddChoiceInternal(name, value); | |||||
| return AddChoiceInternal(name, value, nameLocalizations); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -471,9 +572,9 @@ namespace Discord | |||||
| /// <param name="name">The name of the choice.</param> | /// <param name="name">The name of the choice.</param> | ||||
| /// <param name="value">The value of the choice.</param> | /// <param name="value">The value of the choice.</param> | ||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandOptionBuilder AddChoice(string name, string value) | |||||
| public SlashCommandOptionBuilder AddChoice(string name, string value, IDictionary<string, string> nameLocalizations = null) | |||||
| { | { | ||||
| return AddChoiceInternal(name, value); | |||||
| return AddChoiceInternal(name, value, nameLocalizations); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -482,9 +583,9 @@ namespace Discord | |||||
| /// <param name="name">The name of the choice.</param> | /// <param name="name">The name of the choice.</param> | ||||
| /// <param name="value">The value of the choice.</param> | /// <param name="value">The value of the choice.</param> | ||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandOptionBuilder AddChoice(string name, double value) | |||||
| public SlashCommandOptionBuilder AddChoice(string name, double value, IDictionary<string, string> nameLocalizations = null) | |||||
| { | { | ||||
| return AddChoiceInternal(name, value); | |||||
| return AddChoiceInternal(name, value, nameLocalizations); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -493,9 +594,9 @@ namespace Discord | |||||
| /// <param name="name">The name of the choice.</param> | /// <param name="name">The name of the choice.</param> | ||||
| /// <param name="value">The value of the choice.</param> | /// <param name="value">The value of the choice.</param> | ||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandOptionBuilder AddChoice(string name, float value) | |||||
| public SlashCommandOptionBuilder AddChoice(string name, float value, IDictionary<string, string> nameLocalizations = null) | |||||
| { | { | ||||
| return AddChoiceInternal(name, value); | |||||
| return AddChoiceInternal(name, value, nameLocalizations); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -504,12 +605,12 @@ namespace Discord | |||||
| /// <param name="name">The name of the choice.</param> | /// <param name="name">The name of the choice.</param> | ||||
| /// <param name="value">The value of the choice.</param> | /// <param name="value">The value of the choice.</param> | ||||
| /// <returns>The current builder.</returns> | /// <returns>The current builder.</returns> | ||||
| public SlashCommandOptionBuilder AddChoice(string name, long value) | |||||
| public SlashCommandOptionBuilder AddChoice(string name, long value, IDictionary<string, string> nameLocalizations = null) | |||||
| { | { | ||||
| return AddChoiceInternal(name, value); | |||||
| return AddChoiceInternal(name, value, nameLocalizations); | |||||
| } | } | ||||
| private SlashCommandOptionBuilder AddChoiceInternal(string name, object value) | |||||
| private SlashCommandOptionBuilder AddChoiceInternal(string name, object value, IDictionary<string, string> nameLocalizations = null) | |||||
| { | { | ||||
| Choices ??= new List<ApplicationCommandOptionChoiceProperties>(); | Choices ??= new List<ApplicationCommandOptionChoiceProperties>(); | ||||
| @@ -531,7 +632,8 @@ namespace Discord | |||||
| Choices.Add(new ApplicationCommandOptionChoiceProperties | Choices.Add(new ApplicationCommandOptionChoiceProperties | ||||
| { | { | ||||
| Name = name, | Name = name, | ||||
| Value = value | |||||
| Value = value, | |||||
| NameLocalizations = nameLocalizations | |||||
| }); | }); | ||||
| return this; | return this; | ||||
| @@ -617,7 +719,7 @@ namespace Discord | |||||
| MinValue = value; | MinValue = value; | ||||
| return this; | return this; | ||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Sets the current builders max value field. | /// Sets the current builders max value field. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -639,5 +741,73 @@ namespace Discord | |||||
| Type = type; | Type = type; | ||||
| return this; | return this; | ||||
| } | } | ||||
| public SlashCommandOptionBuilder WithNameLocalizations(IDictionary<string, string> nameLocalizations) | |||||
| { | |||||
| if (nameLocalizations is null) | |||||
| throw new ArgumentNullException(nameof(nameLocalizations)); | |||||
| foreach (var (locale, name) in nameLocalizations) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||||
| Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||||
| if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||||
| throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||||
| } | |||||
| _nameLocalizations = new Dictionary<string, string>(nameLocalizations); | |||||
| return this; | |||||
| } | |||||
| public SlashCommandOptionBuilder WithDescriptionLocalizations(IDictionary<string, string> descriptionLocalizations) | |||||
| { | |||||
| if (descriptionLocalizations is null) | |||||
| throw new ArgumentNullException(nameof(descriptionLocalizations)); | |||||
| foreach (var (locale, description) in _descriptionLocalizations) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||||
| Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||||
| } | |||||
| _descriptionLocalizations = new Dictionary<string, string>(descriptionLocalizations); | |||||
| return this; | |||||
| } | |||||
| public SlashCommandOptionBuilder AddNameLocalization(string locale, string name) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||||
| Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||||
| if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||||
| throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||||
| _descriptionLocalizations ??= new(); | |||||
| _nameLocalizations.Add(locale, name); | |||||
| return this; | |||||
| } | |||||
| public SlashCommandOptionBuilder AddDescriptionLocalization(string locale, string description) | |||||
| { | |||||
| if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||||
| throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||||
| Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||||
| Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||||
| _descriptionLocalizations ??= new(); | |||||
| _descriptionLocalizations.Add(locale, description); | |||||
| return this; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -55,7 +55,7 @@ namespace Discord | |||||
| if (obj.Value == null) throw CreateNotNullException(name, msg); | if (obj.Value == null) throw CreateNotNullException(name, msg); | ||||
| if (obj.Value.Trim().Length == 0) throw CreateNotEmptyException(name, msg); | if (obj.Value.Trim().Length == 0) throw CreateNotEmptyException(name, msg); | ||||
| } | } | ||||
| } | |||||
| } | |||||
| private static ArgumentException CreateNotEmptyException(string name, string msg) | private static ArgumentException CreateNotEmptyException(string name, string msg) | ||||
| => new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | => new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | ||||
| @@ -129,7 +129,7 @@ namespace Discord | |||||
| private static ArgumentException CreateNotEqualException<T>(string name, string msg, T value) | private static ArgumentException CreateNotEqualException<T>(string name, string msg, T value) | ||||
| => new ArgumentException(message: msg ?? $"Value may not be equal to {value}.", paramName: name); | => new ArgumentException(message: msg ?? $"Value may not be equal to {value}.", paramName: name); | ||||
| /// <exception cref="ArgumentException">Value must be at least <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be at least <paramref name="value"/>.</exception> | ||||
| public static void AtLeast(sbyte obj, sbyte value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); } | public static void AtLeast(sbyte obj, sbyte value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); } | ||||
| /// <exception cref="ArgumentException">Value must be at least <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be at least <paramref name="value"/>.</exception> | ||||
| @@ -165,7 +165,7 @@ namespace Discord | |||||
| private static ArgumentException CreateAtLeastException<T>(string name, string msg, T value) | private static ArgumentException CreateAtLeastException<T>(string name, string msg, T value) | ||||
| => new ArgumentException(message: msg ?? $"Value must be at least {value}.", paramName: name); | => new ArgumentException(message: msg ?? $"Value must be at least {value}.", paramName: name); | ||||
| /// <exception cref="ArgumentException">Value must be greater than <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be greater than <paramref name="value"/>.</exception> | ||||
| public static void GreaterThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); } | public static void GreaterThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); } | ||||
| /// <exception cref="ArgumentException">Value must be greater than <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be greater than <paramref name="value"/>.</exception> | ||||
| @@ -201,7 +201,7 @@ namespace Discord | |||||
| private static ArgumentException CreateGreaterThanException<T>(string name, string msg, T value) | private static ArgumentException CreateGreaterThanException<T>(string name, string msg, T value) | ||||
| => new ArgumentException(message: msg ?? $"Value must be greater than {value}.", paramName: name); | => new ArgumentException(message: msg ?? $"Value must be greater than {value}.", paramName: name); | ||||
| /// <exception cref="ArgumentException">Value must be at most <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be at most <paramref name="value"/>.</exception> | ||||
| public static void AtMost(sbyte obj, sbyte value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); } | public static void AtMost(sbyte obj, sbyte value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); } | ||||
| /// <exception cref="ArgumentException">Value must be at most <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be at most <paramref name="value"/>.</exception> | ||||
| @@ -237,7 +237,7 @@ namespace Discord | |||||
| private static ArgumentException CreateAtMostException<T>(string name, string msg, T value) | private static ArgumentException CreateAtMostException<T>(string name, string msg, T value) | ||||
| => new ArgumentException(message: msg ?? $"Value must be at most {value}.", paramName: name); | => new ArgumentException(message: msg ?? $"Value must be at most {value}.", paramName: name); | ||||
| /// <exception cref="ArgumentException">Value must be less than <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be less than <paramref name="value"/>.</exception> | ||||
| public static void LessThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); } | public static void LessThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); } | ||||
| /// <exception cref="ArgumentException">Value must be less than <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value must be less than <paramref name="value"/>.</exception> | ||||
| @@ -1,4 +1,5 @@ | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System.Collections.Generic; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| @@ -24,5 +25,17 @@ namespace Discord.API | |||||
| [JsonProperty("default_permission")] | [JsonProperty("default_permission")] | ||||
| public Optional<bool> DefaultPermissions { get; set; } | public Optional<bool> DefaultPermissions { get; set; } | ||||
| [JsonProperty("name_localizations")] | |||||
| public Optional<Dictionary<string, string>?> NameLocalizations { get; set; } | |||||
| [JsonProperty("description_localizations")] | |||||
| public Optional<Dictionary<string, string>?> DescriptionLocalizations { get; set; } | |||||
| [JsonProperty("name_localized")] | |||||
| public Optional<string?> NameLocalized { get; set; } | |||||
| [JsonProperty("description_localized")] | |||||
| public Optional<string?> DescriptionLocalized { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,5 @@ | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System.Collections.Generic; | |||||
| using System.Linq; | using System.Linq; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| @@ -38,6 +39,18 @@ namespace Discord.API | |||||
| [JsonProperty("channel_types")] | [JsonProperty("channel_types")] | ||||
| public Optional<ChannelType[]> ChannelTypes { get; set; } | public Optional<ChannelType[]> ChannelTypes { get; set; } | ||||
| [JsonProperty("name_localizations")] | |||||
| public Optional<Dictionary<string, string>?> NameLocalizations { get; set; } | |||||
| [JsonProperty("description_localizations")] | |||||
| public Optional<Dictionary<string, string>?> DescriptionLocalizations { get; set; } | |||||
| [JsonProperty("name_localized")] | |||||
| public Optional<string?> NameLocalized { get; set; } | |||||
| [JsonProperty("description_localized")] | |||||
| public Optional<string?> DescriptionLocalized { get; set; } | |||||
| public ApplicationCommandOption() { } | public ApplicationCommandOption() { } | ||||
| public ApplicationCommandOption(IApplicationCommandOption cmd) | public ApplicationCommandOption(IApplicationCommandOption cmd) | ||||
| @@ -61,6 +74,11 @@ namespace Discord.API | |||||
| Name = cmd.Name; | Name = cmd.Name; | ||||
| Type = cmd.Type; | Type = cmd.Type; | ||||
| Description = cmd.Description; | Description = cmd.Description; | ||||
| NameLocalizations = cmd.NameLocalizations?.ToDictionary(x => x.Key, x => x.Value) ?? Optional<Dictionary<string, string>>.Unspecified; | |||||
| DescriptionLocalizations = cmd.DescriptionLocalizations?.ToDictionary(x => x.Key, x => x.Value) ?? Optional<Dictionary<string, string>>.Unspecified; | |||||
| NameLocalized = cmd.NameLocalized; | |||||
| DescriptionLocalized = cmd.DescriptionLocalized; | |||||
| } | } | ||||
| public ApplicationCommandOption(ApplicationCommandOptionProperties option) | public ApplicationCommandOption(ApplicationCommandOptionProperties option) | ||||
| { | { | ||||
| @@ -1,4 +1,5 @@ | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System.Collections.Generic; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| @@ -9,5 +10,11 @@ namespace Discord.API | |||||
| [JsonProperty("value")] | [JsonProperty("value")] | ||||
| public object Value { get; set; } | public object Value { get; set; } | ||||
| [JsonProperty("name_localizations")] | |||||
| public Optional<Dictionary<string, string>?> NameLocalizations { get; set; } | |||||
| [JsonProperty("name_localized")] | |||||
| public Optional<string?> NameLocalized { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -32,6 +32,14 @@ namespace Discord.Rest | |||||
| /// </summary> | /// </summary> | ||||
| public IReadOnlyCollection<RestApplicationCommandOption> Options { get; private set; } | public IReadOnlyCollection<RestApplicationCommandOption> Options { get; private set; } | ||||
| public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||||
| public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||||
| public string? NameLocalized { get; private set; } | |||||
| public string? DescriptionLocalized { get; private set; } | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public DateTimeOffset CreatedAt | public DateTimeOffset CreatedAt | ||||
| => SnowflakeUtils.FromSnowflake(Id); | => SnowflakeUtils.FromSnowflake(Id); | ||||
| @@ -57,6 +65,15 @@ namespace Discord.Rest | |||||
| Options = model.Options.IsSpecified | Options = model.Options.IsSpecified | ||||
| ? model.Options.Value.Select(RestApplicationCommandOption.Create).ToImmutableArray() | ? model.Options.Value.Select(RestApplicationCommandOption.Create).ToImmutableArray() | ||||
| : ImmutableArray.Create<RestApplicationCommandOption>(); | : ImmutableArray.Create<RestApplicationCommandOption>(); | ||||
| NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||||
| DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||||
| } | } | ||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| @@ -1,3 +1,5 @@ | |||||
| using System.Collections.Generic; | |||||
| using System.Collections.Immutable; | |||||
| using Model = Discord.API.ApplicationCommandOptionChoice; | using Model = Discord.API.ApplicationCommandOptionChoice; | ||||
| namespace Discord.Rest | namespace Discord.Rest | ||||
| @@ -13,10 +15,16 @@ namespace Discord.Rest | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public object Value { get; } | public object Value { get; } | ||||
| public IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||||
| public string? NameLocalized { get; } | |||||
| internal RestApplicationCommandChoice(Model model) | internal RestApplicationCommandChoice(Model model) | ||||
| { | { | ||||
| Name = model.Name; | Name = model.Name; | ||||
| Value = model.Value; | Value = model.Value; | ||||
| NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary(); | |||||
| NameLocalized = model.NameLocalized.GetValueOrDefault(null); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -27,7 +27,7 @@ namespace Discord.Rest | |||||
| public bool? IsRequired { get; private set; } | public bool? IsRequired { get; private set; } | ||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public bool? IsAutocomplete { get; private set; } | |||||
| public bool? IsAutocomplete { get; private set; } | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public double? MinValue { get; private set; } | public double? MinValue { get; private set; } | ||||
| @@ -48,6 +48,14 @@ namespace Discord.Rest | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public IReadOnlyCollection<ChannelType> ChannelTypes { get; private set; } | public IReadOnlyCollection<ChannelType> ChannelTypes { get; private set; } | ||||
| public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||||
| public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||||
| public string? NameLocalized { get; private set; } | |||||
| public string? DescriptionLocalized { get; private set; } | |||||
| internal RestApplicationCommandOption() { } | internal RestApplicationCommandOption() { } | ||||
| internal static RestApplicationCommandOption Create(Model model) | internal static RestApplicationCommandOption Create(Model model) | ||||
| @@ -89,6 +97,15 @@ namespace Discord.Rest | |||||
| ChannelTypes = model.ChannelTypes.IsSpecified | ChannelTypes = model.ChannelTypes.IsSpecified | ||||
| ? model.ChannelTypes.Value.ToImmutableArray() | ? model.ChannelTypes.Value.ToImmutableArray() | ||||
| : ImmutableArray.Create<ChannelType>(); | : ImmutableArray.Create<ChannelType>(); | ||||
| NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||||
| DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||||
| } | } | ||||
| #endregion | #endregion | ||||
| @@ -44,6 +44,14 @@ namespace Discord.WebSocket | |||||
| /// </remarks> | /// </remarks> | ||||
| public IReadOnlyCollection<SocketApplicationCommandOption> Options { get; private set; } | public IReadOnlyCollection<SocketApplicationCommandOption> Options { get; private set; } | ||||
| public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||||
| public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||||
| public string? NameLocalized { get; private set; } | |||||
| public string? DescriptionLocalized { get; private set; } | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public DateTimeOffset CreatedAt | public DateTimeOffset CreatedAt | ||||
| => SnowflakeUtils.FromSnowflake(Id); | => SnowflakeUtils.FromSnowflake(Id); | ||||
| @@ -86,6 +94,15 @@ namespace Discord.WebSocket | |||||
| Options = model.Options.IsSpecified | Options = model.Options.IsSpecified | ||||
| ? model.Options.Value.Select(SocketApplicationCommandOption.Create).ToImmutableArray() | ? model.Options.Value.Select(SocketApplicationCommandOption.Create).ToImmutableArray() | ||||
| : ImmutableArray.Create<SocketApplicationCommandOption>(); | : ImmutableArray.Create<SocketApplicationCommandOption>(); | ||||
| NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||||
| DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||||
| } | } | ||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| @@ -1,3 +1,5 @@ | |||||
| using System.Collections.Generic; | |||||
| using System.Collections.Immutable; | |||||
| using Model = Discord.API.ApplicationCommandOptionChoice; | using Model = Discord.API.ApplicationCommandOptionChoice; | ||||
| namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
| @@ -13,6 +15,10 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public object Value { get; private set; } | public object Value { get; private set; } | ||||
| public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||||
| public string? NameLocalized { get; private set; } | |||||
| internal SocketApplicationCommandChoice() { } | internal SocketApplicationCommandChoice() { } | ||||
| internal static SocketApplicationCommandChoice Create(Model model) | internal static SocketApplicationCommandChoice Create(Model model) | ||||
| { | { | ||||
| @@ -24,6 +30,8 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| Name = model.Name; | Name = model.Name; | ||||
| Value = model.Value; | Value = model.Value; | ||||
| NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary(); | |||||
| NameLocalized = model.NameLocalized.GetValueOrDefault(null); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -48,6 +48,14 @@ namespace Discord.WebSocket | |||||
| /// </summary> | /// </summary> | ||||
| public IReadOnlyCollection<ChannelType> ChannelTypes { get; private set; } | public IReadOnlyCollection<ChannelType> ChannelTypes { get; private set; } | ||||
| public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||||
| public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||||
| public string? NameLocalized { get; private set; } | |||||
| public string? DescriptionLocalized { get; private set; } | |||||
| internal SocketApplicationCommandOption() { } | internal SocketApplicationCommandOption() { } | ||||
| internal static SocketApplicationCommandOption Create(Model model) | internal static SocketApplicationCommandOption Create(Model model) | ||||
| { | { | ||||
| @@ -83,6 +91,15 @@ namespace Discord.WebSocket | |||||
| ChannelTypes = model.ChannelTypes.IsSpecified | ChannelTypes = model.ChannelTypes.IsSpecified | ||||
| ? model.ChannelTypes.Value.ToImmutableArray() | ? model.ChannelTypes.Value.ToImmutableArray() | ||||
| : ImmutableArray.Create<ChannelType>(); | : ImmutableArray.Create<ChannelType>(); | ||||
| NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||||
| ImmutableDictionary<string, string>.Empty; | |||||
| NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||||
| DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||||
| } | } | ||||
| IReadOnlyCollection<IApplicationCommandOptionChoice> IApplicationCommandOption.Choices => Choices; | IReadOnlyCollection<IApplicationCommandOptionChoice> IApplicationCommandOption.Choices => Choices; | ||||