diff --git a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs index b4327c85..8eccc500 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class CalcCommands : ModuleBase + public class CalcCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] public async Task Calculate([Remainder] string expression) @@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Utility expr.EvaluateParameter += Expr_EvaluateParameter; var result = expr.Evaluate(); if (expr.Error == null) - await Context.Channel.SendConfirmAsync("Result", $"{result}"); + await Context.Channel.SendConfirmAsync("⚙ " + GetText("result"), result.ToString()); else - await Context.Channel.SendErrorAsync($"⚙ Error", expr.Error); + await Context.Channel.SendErrorAsync("⚙ " + GetText("error"), expr.Error); } private static void Expr_EvaluateParameter(string name, NCalc.ParameterArgs args) @@ -42,29 +42,26 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] public async Task CalcOps() { - var selection = typeof(Math).GetTypeInfo().GetMethods().Except(typeof(object).GetTypeInfo().GetMethods()).Distinct(new MethodInfoEqualityComparer()).Select(x => - { - return x.Name; - }) - .Except(new[] { "ToString", - "Equals", - "GetHashCode", - "GetType"}); - await Context.Channel.SendConfirmAsync("Available functions in calc", string.Join(", ", selection)); + var selection = typeof(Math).GetTypeInfo() + .GetMethods() + .Distinct(new MethodInfoEqualityComparer()) + .Select(x => x.Name) + .Except(new[] + { + "ToString", + "Equals", + "GetHashCode", + "GetType" + }); + await Context.Channel.SendConfirmAsync(GetText("utility_calcops", Prefix), string.Join(", ", selection)); } } - class MethodInfoEqualityComparer : IEqualityComparer + private class MethodInfoEqualityComparer : IEqualityComparer { public bool Equals(MethodInfo x, MethodInfo y) => x.Name == y.Name; public int GetHashCode(MethodInfo obj) => obj.Name.GetHashCode(); } - - class ExpressionContext - { - public double Pi { get; set; } = Math.PI; - } - } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index 194ee455..45318177 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -3,8 +3,6 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NLog; -using System; using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; @@ -14,12 +12,11 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class CrossServerTextChannel : ModuleBase + public class CrossServerTextChannel : NadekoSubmodule { static CrossServerTextChannel() { - _log = LogManager.GetCurrentClassLogger(); - NadekoBot.Client.MessageReceived += async (imsg) => + NadekoBot.Client.MessageReceived += async imsg => { try { @@ -37,23 +34,32 @@ namespace NadekoBot.Modules.Utility var set = subscriber.Value; if (!set.Contains(channel)) continue; - foreach (var chan in set.Except(new[] { channel })) + foreach (var chan in set.Except(new[] {channel})) { - try { await chan.SendMessageAsync(GetText(channel.Guild, channel, (IGuildUser)msg.Author, msg)).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try + { + await chan.SendMessageAsync(GetMessage(channel, (IGuildUser) msg.Author, + msg)).ConfigureAwait(false); + } + catch + { + // ignored + } } } } - catch (Exception ex) { - _log.Warn(ex); + catch + { + // ignored } }; } - private static string GetText(IGuild server, ITextChannel channel, IGuildUser user, IUserMessage message) => - $"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions(); - - public static readonly ConcurrentDictionary> Subscribers = new ConcurrentDictionary>(); - private static Logger _log { get; } + private static string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) => + $"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions(); + + public static readonly ConcurrentDictionary> Subscribers = + new ConcurrentDictionary>(); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -64,8 +70,9 @@ namespace NadekoBot.Modules.Utility var set = new ConcurrentHashSet(); if (Subscribers.TryAdd(token, set)) { - set.Add((ITextChannel)Context.Channel); - await ((IGuildUser)Context.User).SendConfirmAsync("This is your CSC token", token.ToString()).ConfigureAwait(false); + set.Add((ITextChannel) Context.Channel); + await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString()) + .ConfigureAwait(false); } } @@ -77,8 +84,8 @@ namespace NadekoBot.Modules.Utility ConcurrentHashSet set; if (!Subscribers.TryGetValue(token, out set)) return; - set.Add((ITextChannel)Context.Channel); - await Context.Channel.SendConfirmAsync("Joined cross server channel.").ConfigureAwait(false); + set.Add((ITextChannel) Context.Channel); + await ReplyConfirmLocalized("csc_join").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -88,9 +95,9 @@ namespace NadekoBot.Modules.Utility { foreach (var subscriber in Subscribers) { - subscriber.Value.TryRemove((ITextChannel)Context.Channel); + subscriber.Value.TryRemove((ITextChannel) Context.Channel); } - await Context.Channel.SendMessageAsync("Left cross server channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("csc_leave").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index fefd0a01..96e06a4e 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class InfoCommands : ModuleBase + public class InfoCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -24,7 +24,7 @@ namespace NadekoBot.Modules.Utility if (string.IsNullOrWhiteSpace(guildName)) guild = channel.Guild; else - guild = NadekoBot.Client.GetGuilds().Where(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant()).FirstOrDefault(); + guild = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant()); if (guild == null) return; var ownername = await guild.GetUserAsync(guild.OwnerId); @@ -37,22 +37,22 @@ namespace NadekoBot.Modules.Utility if (string.IsNullOrWhiteSpace(features)) features = "-"; var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Server Info")) + .WithAuthor(eab => eab.WithName(GetText("server_info"))) .WithTitle(guild.Name) - .AddField(fb => fb.WithName("**ID**").WithValue(guild.Id.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Owner**").WithValue(ownername.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Members**").WithValue(users.Count.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Text Channels**").WithValue(textchn.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Features**").WithValue(features).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("id")).WithValue(guild.Id.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("owner")).WithValue(ownername.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("members")).WithValue(users.Count.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("text_channels")).WithValue(textchn.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("voice_channels")).WithValue(voicechn.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("created_at")).WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("region")).WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("roles")).WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true)) .WithImageUrl(guild.IconUrl) .WithColor(NadekoBot.OkColor); if (guild.Emojis.Any()) { - embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); + embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emojis.Count})").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -69,9 +69,9 @@ namespace NadekoBot.Modules.Utility var embed = new EmbedBuilder() .WithTitle(ch.Name) .WithDescription(ch.Topic?.SanitizeMentions()) - .AddField(fb => fb.WithName("**ID**").WithValue(ch.Id.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("id")).WithValue(ch.Id.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("created_at")).WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("users")).WithValue(usercount.ToString()).WithIsInline(true)) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -86,15 +86,15 @@ namespace NadekoBot.Modules.Utility return; var embed = new EmbedBuilder() - .AddField(fb => fb.WithName("**Name**").WithValue($"**{user.Username}**#{user.Discriminator}").WithIsInline(true)); + .AddField(fb => fb.WithName(GetText("name")).WithValue($"**{user.Username}**#{user.Discriminator}").WithIsInline(true)); if (!string.IsNullOrWhiteSpace(user.Nickname)) { - embed.AddField(fb => fb.WithName("**Nickname**").WithValue(user.Nickname).WithIsInline(true)); + embed.AddField(fb => fb.WithName(GetText("nickname")).WithValue(user.Nickname).WithIsInline(true)); } - embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "unavail."}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) + embed.AddField(fb => fb.WithName(GetText("id")).WithValue(user.Id.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("joined_server")).WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "?"}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("joined_discord")).WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("roles")).WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); if (user.AvatarId != null) @@ -119,12 +119,17 @@ namespace NadekoBot.Modules.Utility StringBuilder str = new StringBuilder(); foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage)) { - str.AppendLine($"`{++startCount}.` **{kvp.Key}** [{kvp.Value/NadekoBot.Stats.GetUptime().TotalSeconds:F2}/s] - {kvp.Value} total"); + str.AppendLine(GetText("activity_line", + ++startCount, + Format.Bold(kvp.Key.ToString()), + kvp.Value / NadekoBot.Stats.GetUptime().TotalSeconds, kvp.Value)); } - await Context.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}") + await Context.Channel.EmbedAsync(new EmbedBuilder() + .WithTitle(GetText("activity_page", page)) .WithOkColor() - .WithFooter(efb => efb.WithText($"{NadekoBot.CommandHandler.UserMessagesSent.Count} users total.")) + .WithFooter(efb => efb.WithText(GetText("activity_users_total", + NadekoBot.CommandHandler.UserMessagesSent.Count))) .WithDescription(str.ToString())); } } diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index e767bbcf..7cddce2c 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -5,12 +5,10 @@ using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; @@ -22,14 +20,16 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class RepeatCommands : ModuleBase + public class RepeatCommands : NadekoSubmodule { //guildid/RepeatRunners - public static ConcurrentDictionary> repeaters { get; } + public static ConcurrentDictionary> Repeaters { get; set; } + + private static bool _ready; public class RepeatRunner { - private Logger _log { get; } + private readonly Logger _log; private CancellationTokenSource source { get; set; } private CancellationToken token { get; set; } @@ -39,8 +39,16 @@ namespace NadekoBot.Modules.Utility public RepeatRunner(Repeater repeater, ITextChannel channel = null) { _log = LogManager.GetCurrentClassLogger(); - this.Repeater = repeater; - this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); + Repeater = repeater; + //if (channel == null) + //{ + // var guild = NadekoBot.Client.GetGuild(repeater.GuildId); + // Channel = guild.GetTextChannel(repeater.ChannelId); + //} + //else + // Channel = channel; + + Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); if (Channel == null) return; Task.Run(Run); @@ -101,22 +109,21 @@ namespace NadekoBot.Modules.Utility public override string ToString() { - return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}"; + return $"{Channel.Mention} | {(int)Repeater.Interval.TotalHours}:{Repeater.Interval:mm} | {Repeater.Message.TrimTo(33)}"; } } static RepeatCommands() { - var _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); - - repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs - .ToDictionary(gc => gc.GuildId, - gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) - .Where(gr => gr.Channel != null)))); - - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); + var _ = Task.Run(async () => + { + await Task.Delay(5000).ConfigureAwait(false); + Repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs + .ToDictionary(gc => gc.GuildId, + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) + .Where(gr => gr.Channel != null)))); + _ready = true; + }); } [NadekoCommand, Usage, Description, Aliases] @@ -124,11 +131,13 @@ namespace NadekoBot.Modules.Utility [RequireUserPermission(GuildPermission.ManageMessages)] public async Task RepeatInvoke(int index) { + if (!_ready) + return; index -= 1; ConcurrentQueue rep; - if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + if (!Repeaters.TryGetValue(Context.Guild.Id, out rep)) { - await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); + await ReplyErrorLocalized("repeat_invoke_none").ConfigureAwait(false); return; } @@ -136,7 +145,7 @@ namespace NadekoBot.Modules.Utility if (index >= repList.Count) { - await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + await ReplyErrorLocalized("index_out_of_range").ConfigureAwait(false); return; } var repeater = repList[index].Repeater; @@ -151,19 +160,21 @@ namespace NadekoBot.Modules.Utility [Priority(0)] public async Task RepeatRemove(int index) { + if (!_ready) + return; if (index < 1) return; index -= 1; ConcurrentQueue rep; - if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + if (!Repeaters.TryGetValue(Context.Guild.Id, out rep)) return; var repeaterList = rep.ToList(); if (index >= repeaterList.Count) { - await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + await ReplyErrorLocalized("index_out_of_range").ConfigureAwait(false); return; } @@ -179,8 +190,9 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync().ConfigureAwait(false); } - if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) - await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false); + if (Repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) + await Context.Channel.SendConfirmAsync(GetText("message_repeater"), + GetText("repeater_stopped" , index + 1) + $"\n\n{repeater}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -189,6 +201,8 @@ namespace NadekoBot.Modules.Utility [Priority(1)] public async Task Repeat(int minutes, [Remainder] string message) { + if (!_ready) + return; if (minutes < 1 || minutes > 10080) return; @@ -216,13 +230,18 @@ namespace NadekoBot.Modules.Utility var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); - repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => + Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => { old.Enqueue(rep); return old; }); - await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync( + "🔁 " + GetText("repeater", + Format.Bold(rep.Repeater.Message), + Format.Bold(rep.Repeater.Interval.Days.ToString()), + Format.Bold(rep.Repeater.Interval.Hours.ToString()), + Format.Bold(rep.Repeater.Interval.Minutes.ToString()))).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -230,27 +249,33 @@ namespace NadekoBot.Modules.Utility [RequireUserPermission(GuildPermission.ManageMessages)] public async Task RepeatList() { + if (!_ready) + return; ConcurrentQueue repRunners; - if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners)) + if (!Repeaters.TryGetValue(Context.Guild.Id, out repRunners)) { - await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("repeaters_none").ConfigureAwait(false); return; } var replist = repRunners.ToList(); var sb = new StringBuilder(); - for (int i = 0; i < replist.Count; i++) + for (var i = 0; i < replist.Count; i++) { var rep = replist[i]; - sb.AppendLine($"`{i + 1}.` {rep.ToString()}"); + sb.AppendLine($"`{i + 1}.` {rep}"); } + var desc = sb.ToString(); + + if (string.IsNullOrWhiteSpace(desc)) + desc = GetText("no_active_repeaters"); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("List Of Repeaters") - .WithDescription(sb.ToString())) - .ConfigureAwait(false); + .WithTitle(GetText("list_of_repeaters")) + .WithDescription(desc)) + .ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index d68b8c29..1a924b29 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -33,10 +33,11 @@ namespace NadekoBot.Modules.Utility } if (quotes.Any()) - await Context.Channel.SendConfirmAsync($"💬 **Page {page + 1} of quotes:**\n```xl\n" + String.Join("\n", quotes.Select((q) => $"{q.Keyword,-20} by {q.AuthorName}")) + "\n```") + await Context.Channel.SendConfirmAsync(GetText("quotes_page", page + 1), + string.Join("\n", quotes.Select(q => $"{q.Keyword,-20} by {q.AuthorName}"))) .ConfigureAwait(false); else - await Context.Channel.SendErrorAsync("No quotes on this page.").ConfigureAwait(false); + await ReplyErrorLocalized("quotes_page_none").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -72,11 +73,11 @@ namespace NadekoBot.Modules.Utility } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] + [RequireContext(ContextType.Guild)] public async Task SearchQuote(string keyword, [Remainder] string text) { - if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) - return; + if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) + return; keyword = keyword.ToUpperInvariant(); @@ -113,7 +114,7 @@ namespace NadekoBot.Modules.Utility }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("✅ Quote added.").ConfigureAwait(false); + await ReplyConfirmLocalized("quote_added").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -135,7 +136,7 @@ namespace NadekoBot.Modules.Utility if (qs == null || !qs.Any()) { sucess = false; - response = "No quotes found which you can remove."; + response = GetText("quotes_remove_none"); } else { @@ -144,7 +145,7 @@ namespace NadekoBot.Modules.Utility uow.Quotes.Remove(q); await uow.CompleteAsync().ConfigureAwait(false); sucess = true; - response = "🗑 **Deleted a random quote.**"; + response = GetText("deleted_quote"); } } if(sucess) @@ -172,7 +173,7 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync(); } - await Context.Channel.SendConfirmAsync($"🗑 **Deleted all quotes** with **{keyword}** keyword."); + await ReplyConfirmLocalized("quotes_deleted", Format.Bold(keyword)).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 10d43352..572a7afc 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -17,21 +17,21 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class RemindCommands : ModuleBase + public class RemindCommands : NadekoSubmodule { - - Regex regex = new Regex(@"^(?:(?\d)mo)?(?:(?\d)w)?(?:(?\d{1,2})d)?(?:(?\d{1,2})h)?(?:(?\d{1,2})m)?$", + readonly Regex _regex = new Regex(@"^(?:(?\d)mo)?(?:(?\d)w)?(?:(?\d{1,2})d)?(?:(?\d{1,2})h)?(?:(?\d{1,2})m)?$", RegexOptions.Compiled | RegexOptions.Multiline); - private static string RemindMessageFormat { get; } + private static string remindMessageFormat { get; } - private static IDictionary> replacements = new Dictionary> + private static readonly IDictionary> _replacements = new Dictionary> { { "%message%" , (r) => r.Message }, { "%user%", (r) => $"<@!{r.UserId}>" }, { "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"} }; - private static Logger _log { get; } + + private new static readonly Logger _log; static RemindCommands() { @@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Utility { reminders = uow.Reminders.GetAll().ToList(); } - RemindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat; + remindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat; foreach (var r in reminders) { @@ -58,10 +58,10 @@ namespace NadekoBot.Modules.Utility if (time.TotalMilliseconds > int.MaxValue) return; - await Task.Delay(time); + await Task.Delay(time).ConfigureAwait(false); try { - IMessageChannel ch = null; + IMessageChannel ch; if (r.IsPrivate) { ch = await NadekoBot.Client.GetDMChannelAsync(r.ChannelId).ConfigureAwait(false); @@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Utility return; await ch.SendMessageAsync( - replacements.Aggregate(RemindMessageFormat, + _replacements.Aggregate(remindMessageFormat, (cur, replace) => cur.Replace(replace.Key, replace.Value(r))) .SanitizeMentions() ).ConfigureAwait(false); //it works trust me @@ -119,27 +119,21 @@ namespace NadekoBot.Modules.Utility { var channel = (ITextChannel)Context.Channel; - if (ch == null) - { - await channel.SendErrorAsync($"{Context.User.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false); - return; - } - - var m = regex.Match(timeStr); + var m = _regex.Match(timeStr); if (m.Length == 0) { - await channel.SendErrorAsync("Not a valid time format. Type `-h .remind`").ConfigureAwait(false); + await ReplyErrorLocalized("remind_invalid_format").ConfigureAwait(false); return; } string output = ""; var namesAndValues = new Dictionary(); - foreach (var groupName in regex.GetGroupNames()) + foreach (var groupName in _regex.GetGroupNames()) { if (groupName == "0") continue; - int value = 0; + int value; int.TryParse(m.Groups[groupName].Value, out value); if (string.IsNullOrEmpty(m.Groups[groupName].Value)) @@ -147,7 +141,7 @@ namespace NadekoBot.Modules.Utility namesAndValues[groupName] = 0; continue; } - else if (value < 1 || + if (value < 1 || (groupName == "months" && value > 1) || (groupName == "weeks" && value > 4) || (groupName == "days" && value >= 7) || @@ -157,8 +151,7 @@ namespace NadekoBot.Modules.Utility await channel.SendErrorAsync($"Invalid {groupName} value.").ConfigureAwait(false); return; } - else - namesAndValues[groupName] = value; + namesAndValues[groupName] = value; output += m.Groups[groupName].Value + " " + groupName + " "; } var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] + @@ -184,17 +177,26 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync(); } - try { await channel.SendConfirmAsync($"⏰ I will remind **\"{(ch is ITextChannel ? ((ITextChannel)ch).Name : Context.User.Username)}\"** to **\"{message.SanitizeMentions()}\"** in **{output}** `({time:d.M.yyyy.} at {time:HH:mm})`").ConfigureAwait(false); } catch { } + try + { + await channel.SendConfirmAsync( + "⏰ " + GetText("remind", + Format.Bold(ch is ITextChannel ? ((ITextChannel) ch).Name : Context.User.Username), + Format.Bold(message.SanitizeMentions()), + Format.Bold(output), + time, time)).ConfigureAwait(false); + } + catch + { + // ignored + } await StartReminder(rem); } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] [OwnerOnly] public async Task RemindTemplate([Remainder] string arg) { - var channel = (ITextChannel)Context.Channel; - if (string.IsNullOrWhiteSpace(arg)) return; @@ -203,7 +205,8 @@ namespace NadekoBot.Modules.Utility uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim(); await uow.CompleteAsync().ConfigureAwait(false); } - await channel.SendConfirmAsync("🆗 New remind template set."); + + await ReplyConfirmLocalized("remind_template").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 41ca8133..8b6aede7 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -9,7 +9,6 @@ using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; @@ -21,12 +20,12 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class UnitConverterCommands : ModuleBase + public class UnitConverterCommands : NadekoSubmodule { public static List Units { get; set; } = new List(); - private static Logger _log { get; } + private new static readonly Logger _log; private static Timer _timer; - private static TimeSpan updateInterval = new TimeSpan(12, 0, 0); + private static readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0); static UnitConverterCommands() { @@ -55,7 +54,7 @@ namespace NadekoBot.Modules.Utility _log.Warn("Could not load units: " + e.Message); } - _timer = new Timer(async (obj) => await UpdateCurrency(), null, (int)updateInterval.TotalMilliseconds, (int)updateInterval.TotalMilliseconds); + _timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval); } public static async Task UpdateCurrency() @@ -93,7 +92,7 @@ namespace NadekoBot.Modules.Utility } catch { - _log.Warn("Failed updating currency."); + _log.Warn("Failed updating currency. Ignore this."); } } @@ -101,7 +100,7 @@ namespace NadekoBot.Modules.Utility public async Task ConvertList() { var res = Units.GroupBy(x => x.UnitType) - .Aggregate(new EmbedBuilder().WithTitle("__Units which can be used by the converter__") + .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) .WithColor(NadekoBot.OkColor), (embed, g) => embed.AddField(efb => efb.WithName(g.Key.ToTitleCase()) @@ -116,12 +115,12 @@ namespace NadekoBot.Modules.Utility var targetUnit = Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); if (originUnit == null || targetUnit == null) { - await Context.Channel.SendErrorAsync(string.Format("Cannot convert {0} to {1}: units not found", origin, target)); + await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); return; } if (originUnit.UnitType != targetUnit.UnitType) { - await Context.Channel.SendErrorAsync(string.Format("Cannot convert {0} to {1}: types of unit are not equal", originUnit.Triggers.First(), targetUnit.Triggers.First())); + await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); return; } decimal res; @@ -150,8 +149,6 @@ namespace NadekoBot.Modules.Utility case "F": res = res * (9m / 5m) - 459.67m; break; - default: - break; } } else @@ -165,7 +162,7 @@ namespace NadekoBot.Modules.Utility } res = Math.Round(res, 4); - await Context.Channel.SendConfirmAsync(string.Format("{0} {1} is equal to {2} {3}", value, (originUnit.Triggers.First() + "s").SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); + await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); } } diff --git a/src/NadekoBot/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings index 65ccbd58..146bab9a 100644 --- a/src/NadekoBot/NadekoBot.xproj.DotSettings +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -1,4 +1,5 @@  True True - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index d6423df6..c363367f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -3353,6 +3353,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Joined. + /// + public static string utiliity_joined { + get { + return ResourceManager.GetString("utiliity_joined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}.` {1} [{2:F2}/s] - {3} total. + /// + public static string utility_activity_line { + get { + return ResourceManager.GetString("utility_activity_line", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Activity Page #{0}. + /// + public static string utility_activity_page { + get { + return ResourceManager.GetString("utility_activity_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} users total.. + /// + public static string utility_activity_users_total { + get { + return ResourceManager.GetString("utility_activity_users_total", resourceCulture); + } + } + /// /// Looks up a localized string similar to Author. /// @@ -3371,6 +3407,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to List of functions in {0}calc command. + /// + public static string utility_calcops { + get { + return ResourceManager.GetString("utility_calcops", resourceCulture); + } + } + /// /// Looks up a localized string similar to Channel Topic. /// @@ -3398,6 +3443,123 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} {1} is equal to {2} {3}. + /// + public static string utility_convert { + get { + return ResourceManager.GetString("utility_convert", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot convert {0} to {1}: units not found. + /// + public static string utility_convert_not_found { + get { + return ResourceManager.GetString("utility_convert_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot convert {0} to {1}: types of unit are not equal. + /// + public static string utility_convert_type_error { + get { + return ResourceManager.GetString("utility_convert_type_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Units which can be used by the converter. + /// + public static string utility_convertlist { + get { + return ResourceManager.GetString("utility_convertlist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Created At. + /// + public static string utility_created_at { + get { + return ResourceManager.GetString("utility_created_at", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined cross server channel.. + /// + public static string utility_csc_join { + get { + return ResourceManager.GetString("utility_csc_join", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Left cross server channel.. + /// + public static string utility_csc_leave { + get { + return ResourceManager.GetString("utility_csc_leave", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is your CSC token. + /// + public static string utility_csc_token { + get { + return ResourceManager.GetString("utility_csc_token", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Emojis. + /// + public static string utility_custom_emojis { + get { + return ResourceManager.GetString("utility_custom_emojis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error. + /// + public static string utility_error { + get { + return ResourceManager.GetString("utility_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Features. + /// + public static string utility_features { + get { + return ResourceManager.GetString("utility_features", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ID. + /// + public static string utility_id { + get { + return ResourceManager.GetString("utility_id", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Index out of range.. + /// + public static string utility_index_out_of_range { + get { + return ResourceManager.GetString("utility_index_out_of_range", resourceCulture); + } + } + /// /// Looks up a localized string similar to Here is a list of users in those roles:. /// @@ -3416,6 +3578,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Invalid {0} value.. + /// + public static string utility_invalid_value { + get { + return ResourceManager.GetString("utility_invalid_value", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined Discord. + /// + public static string utility_joined_discord { + get { + return ResourceManager.GetString("utility_joined_discord", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined Server. + /// + public static string utility_joined_server { + get { + return ResourceManager.GetString("utility_joined_server", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of Repeaters. + /// + public static string utility_list_of_repeaters { + get { + return ResourceManager.GetString("utility_list_of_repeaters", resourceCulture); + } + } + /// /// Looks up a localized string similar to ID: {0} ///Members: {1} @@ -3436,6 +3634,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Members. + /// + public static string utility_members { + get { + return ResourceManager.GetString("utility_members", resourceCulture); + } + } + /// /// Looks up a localized string similar to Memory. /// @@ -3445,6 +3652,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Message Repeater. + /// + public static string utility_message_repeater { + get { + return ResourceManager.GetString("utility_message_repeater", resourceCulture); + } + } + /// /// Looks up a localized string similar to Messages. /// @@ -3454,6 +3670,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Name. + /// + public static string utility_name { + get { + return ResourceManager.GetString("utility_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nickname. + /// + public static string utility_nickname { + get { + return ResourceManager.GetString("utility_nickname", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No active repeaters.. + /// + public static string utility_no_active_repeaters { + get { + return ResourceManager.GetString("utility_no_active_repeaters", resourceCulture); + } + } + /// /// Looks up a localized string similar to No roles on this page.. /// @@ -3490,6 +3733,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Owner. + /// + public static string utility_owner { + get { + return ResourceManager.GetString("utility_owner", resourceCulture); + } + } + /// /// Looks up a localized string similar to Owner IDs. /// @@ -3519,6 +3771,168 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Quote Added. + /// + public static string utility_quote_added { + get { + return ResourceManager.GetString("utility_quote_added", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deleted a random quote.. + /// + public static string utility_quote_deleted { + get { + return ResourceManager.GetString("utility_quote_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deleted all quotes with {0} keyword.. + /// + public static string utility_quotes_deleted { + get { + return ResourceManager.GetString("utility_quotes_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page {0} of quotes. + /// + public static string utility_quotes_page { + get { + return ResourceManager.GetString("utility_quotes_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No quotes on this page.. + /// + public static string utility_quotes_page_none { + get { + return ResourceManager.GetString("utility_quotes_page_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No quotes found which you can remove.. + /// + public static string utility_quotes_remove_none { + get { + return ResourceManager.GetString("utility_quotes_remove_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Region. + /// + public static string utility_region { + get { + return ResourceManager.GetString("utility_region", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Registered On. + /// + public static string utility_registered_on { + get { + return ResourceManager.GetString("utility_registered_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`. + /// + public static string utility_remind { + get { + return ResourceManager.GetString("utility_remind", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not a valid time format. Check the commandlist.. + /// + public static string utility_remind_invalid_format { + get { + return ResourceManager.GetString("utility_remind_invalid_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New remind template set.. + /// + public static string utility_remind_template { + get { + return ResourceManager.GetString("utility_remind_template", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No repeating messages found on this server.. + /// + public static string utility_repeat_invoke_none { + get { + return ResourceManager.GetString("utility_repeat_invoke_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeating {0} every {1} day(s), {2} hour(s) and {3} minute(s).. + /// + public static string utility_repeater { + get { + return ResourceManager.GetString("utility_repeater", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #{0} stopped.. + /// + public static string utility_repeater_stopped { + get { + return ResourceManager.GetString("utility_repeater_stopped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Of Repeaters. + /// + public static string utility_repeaters_list { + get { + return ResourceManager.GetString("utility_repeaters_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No repeaters running on this server.. + /// + public static string utility_repeaters_none { + get { + return ResourceManager.GetString("utility_repeaters_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Result. + /// + public static string utility_result { + get { + return ResourceManager.GetString("utility_result", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Roles. + /// + public static string utility_roles { + get { + return ResourceManager.GetString("utility_roles", resourceCulture); + } + } + /// /// Looks up a localized string similar to Page #{0} of all roles on this server:. /// @@ -3564,6 +3978,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Server Info. + /// + public static string utility_server_info { + get { + return ResourceManager.GetString("utility_server_info", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} of this server is {1}. /// @@ -3627,6 +4050,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Text Channels. + /// + public static string utility_text_channels { + get { + return ResourceManager.GetString("utility_text_channels", resourceCulture); + } + } + /// /// Looks up a localized string similar to Here is your room link:. /// @@ -3653,5 +4085,23 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("utility_userid", resourceCulture); } } + + /// + /// Looks up a localized string similar to Users. + /// + public static string utility_users { + get { + return ResourceManager.GetString("utility_users", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voice Channels. + /// + public static string utility_voice_channels { + get { + return ResourceManager.GetString("utility_voice_channels", resourceCulture); + } + } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 95396e70..f69a2577 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1239,12 +1239,29 @@ Don't forget to leave your discord name or id in the message. List of "{0}hangman" term types: + + Joined + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Activity Page #{0} + + + {0} users total. + Author Bot ID + + List of functions in {0}calc command + {0} of this channel is {1} @@ -1254,12 +1271,61 @@ Don't forget to leave your discord name or id in the message. Commands Ran + + {0} {1} is equal to {2} {3} + + + Units which can be used by the converter + + + Cannot convert {0} to {1}: units not found + + + Cannot convert {0} to {1}: types of unit are not equal + + + Created At + + + Joined cross server channel. + + + Left cross server channel. + + + This is your CSC token + + + Custom Emojis + + + Error + + + Features + + + ID + + + Index out of range. + Here is a list of users in those roles: you are not allowed to use this command on roles with a lot of users in them to prevent abuse. + + Invalid {0} value. + Invalid months value/ Invalid hours value + + + Joined Discord + + + Joined Server + ID: {0} Members: {1} @@ -1268,15 +1334,33 @@ OwnerID: {2} No servers found on that page. + + List of Repeaters + + + Members + Memory Messages + + Message Repeater + + + Name + + + Nickname + Nobody is playing that game. + + No active repeaters. + No roles on this page. @@ -1286,6 +1370,9 @@ OwnerID: {2} No topic set. + + Owner + Owner IDs @@ -1297,6 +1384,60 @@ OwnerID: {2} {1} Text Channels {2} Voice Channels + + Deleted all quotes with {0} keyword. + + + Page {0} of quotes + + + No quotes on this page. + + + No quotes found which you can remove. + + + Quote Added + + + Deleted a random quote. + + + Region + + + Registered On + + + I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})` + + + Not a valid time format. Check the commandlist. + + + New remind template set. + + + Repeating {0} every {1} day(s), {2} hour(s) and {3} minute(s). + + + List Of Repeaters + + + No repeaters running on this server. + + + #{0} stopped. + + + No repeating messages found on this server. + + + Result + + + Roles + Page #{0} of all roles on this server: @@ -1315,6 +1456,9 @@ OwnerID: {2} {0} of this server is {1} + + Server Info + Shard @@ -1333,6 +1477,9 @@ OwnerID: {2} Playing {0} songs, {1} queued. + + Text Channels + Here is your room link: @@ -1343,4 +1490,10 @@ OwnerID: {2} {0} of the user {1} is {2} Id of the user kwoth#1234 is 123123123123 + + Users + + + Voice Channels + \ No newline at end of file