1
0
mirror of https://github.com/sciwhiz12/Janitor.git synced 2024-09-19 21:04:02 +00:00

Externalize translation strings

This commit is contained in:
Arnold Alejo Nunag 2020-09-30 04:50:38 +08:00
parent b02f38c70f
commit 3c13b559e3
Signed by: sciwhiz12
GPG Key ID: 622CF446534317E1
15 changed files with 327 additions and 202 deletions

View File

@ -8,6 +8,8 @@ import net.dv8tion.jda.api.entities.PrivateChannel;
import net.dv8tion.jda.api.entities.User;
import sciwhiz12.janitor.commands.CommandRegistry;
import sciwhiz12.janitor.config.BotConfig;
import sciwhiz12.janitor.msg.Messages;
import sciwhiz12.janitor.msg.Translations;
import sciwhiz12.janitor.utils.Util;
import java.util.concurrent.CompletableFuture;
@ -18,14 +20,18 @@ import static sciwhiz12.janitor.Logging.STATUS;
public class JanitorBot {
private final JDA discord;
private final BotConfig config;
private final BotConsole console;
private final CommandRegistry cmdRegistry;
private final Messages messages;
private BotConsole console;
private CommandRegistry cmdRegistry;
private Translations translations;
public JanitorBot(JDA discord, BotConfig config) {
this.config = config;
this.console = new BotConsole(this, System.in);
this.cmdRegistry = new CommandRegistry(this, config.getCommandPrefix());
this.discord = discord;
this.translations = new Translations(this, config.getTranslationsFile());
this.messages = new Messages(this);
discord.addEventListener(cmdRegistry);
discord.getPresence().setPresence(OnlineStatus.ONLINE, Activity.playing(" n' sweeping n' testing!"));
discord.getGuilds().forEach(Guild::loadMembers);
@ -52,10 +58,16 @@ public class JanitorBot {
return this.config;
}
public Messages getMessages() { return this.messages; }
public CommandRegistry getCommandRegistry() {
return this.cmdRegistry;
}
public Translations getTranslations() {
return this.translations;
}
public void shutdown() {
JANITOR.info(STATUS, "Shutting down!");
console.stop();

View File

@ -8,6 +8,7 @@ import org.slf4j.MarkerFactory;
public class Logging {
public static final Marker STATUS = MarkerFactory.getMarker("STATUS");
public static final Marker COMMANDS = MarkerFactory.getMarker("COMMANDS");
public static final Marker TRANSLATIONS = MarkerFactory.getMarker("TRANSLATIONS");
public static final Logger JANITOR = LoggerFactory.getLogger("janitor");
public static final Logger CONSOLE = LoggerFactory.getLogger("janitor.console");

View File

@ -74,7 +74,8 @@ public class CommandRegistry implements EventListener {
}
JANITOR.debug(COMMANDS, "Executing command.");
dispatcher.execute(parseResults);
} catch (CommandSyntaxException ex) {
}
catch (CommandSyntaxException ex) {
JANITOR.error(COMMANDS, "Error while parsing message and executing command", ex);
}
}

View File

@ -4,6 +4,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
@ -12,11 +13,10 @@ import sciwhiz12.janitor.commands.BaseCommand;
import sciwhiz12.janitor.commands.CommandRegistry;
import sciwhiz12.janitor.commands.util.CommandHelper;
import sciwhiz12.janitor.commands.util.ModerationHelper;
import sciwhiz12.janitor.msg.General;
import sciwhiz12.janitor.msg.Moderation;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
@ -50,20 +50,37 @@ public class KickCommand extends BaseCommand {
private int runWithReason(CommandContext<MessageReceivedEvent> ctx, @Nullable String reason) throws CommandSyntaxException {
MessageChannel channel = ctx.getSource().getChannel();
if (!ctx.getSource().isFromGuild()) {
General.guildOnlyCommand(channel).queue();
getBot().getMessages().GENERAL.guildOnlyCommand(channel).queue();
return 1;
}
Member performer = ctx.getSource().getMember();
if (performer == null) return 1;
List<Member> members = getMembers("member", ctx).fromGuild(performer.getGuild());
Member target = members.get(0);
if (ModerationHelper.ensurePermissions(channel, performer, target, KICK_PERMISSION)) {
target.getUser().openPrivateChannel()
.flatMap(dm -> Moderation.kickedDM(dm, performer, target, reason))
.flatMap(v -> ModerationHelper.kickUser(target.getGuild(), performer, target, reason))
.flatMap(v -> Moderation.kickUser(ctx.getSource().getChannel(), performer, target, reason))
.queue();
final Guild guild = ctx.getSource().getGuild();
final Member performer = Objects.requireNonNull(ctx.getSource().getMember());
final List<Member> members = getMembers("member", ctx).fromGuild(performer.getGuild());
if (members.size() < 1) {
return 1;
}
final Member target = members.get(0);
if (!guild.getSelfMember().hasPermission(KICK_PERMISSION)) {
getBot().getMessages().GENERAL.insufficientPermissions(channel, KICK_PERMISSION).queue();
return 1;
}
if (!guild.getSelfMember().canInteract(target)) {
getBot().getMessages().GENERAL.cannotInteract(channel, target).queue();
return 1;
}
if (!performer.hasPermission(KICK_PERMISSION)) {
getBot().getMessages().MODERATION.performerInsufficientPermissions(channel, performer, KICK_PERMISSION).queue();
return 1;
}
if (!performer.canInteract(target)) {
getBot().getMessages().MODERATION.cannotModerate(channel, performer, target).queue();
return 1;
}
target.getUser().openPrivateChannel()
.flatMap(dm -> getBot().getMessages().MODERATION.kickedDM(dm, performer, target, reason))
.flatMap(v -> ModerationHelper.kickUser(target.getGuild(), performer, target, reason))
.flatMap(v -> getBot().getMessages().MODERATION.kickUser(channel, performer, target, reason))
.queue();
return 1;
}
}

View File

@ -3,37 +3,15 @@ package sciwhiz12.janitor.commands.util;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import sciwhiz12.janitor.msg.General;
import java.util.EnumSet;
public class CommandHelper {
public static LiteralArgumentBuilder<MessageReceivedEvent> literal(String command) {
return LiteralArgumentBuilder.literal(command);
}
public static <Arg> RequiredArgumentBuilder<MessageReceivedEvent, Arg> argument(String command, ArgumentType<Arg> argument) {
public static <Arg> RequiredArgumentBuilder<MessageReceivedEvent, Arg> argument(String command,
ArgumentType<Arg> argument) {
return RequiredArgumentBuilder.argument(command, argument);
}
public static boolean canInteract(MessageChannel response, Member target) {
if (!target.getGuild().getSelfMember().canInteract(target)) {
General.cannotInteract(response, target).queue();
return false;
}
return true;
}
public static boolean hasPermission(MessageChannel response, Guild guild, EnumSet<Permission> permissions) {
if (!guild.getSelfMember().hasPermission(permissions)) {
General.insufficientPermissions(response, permissions).queue();
return false;
}
return true;
}
}

View File

@ -1,36 +1,18 @@
package sciwhiz12.janitor.commands.util;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import org.checkerframework.checker.nullness.qual.Nullable;
import sciwhiz12.janitor.msg.General;
import sciwhiz12.janitor.msg.Moderation;
import java.util.EnumSet;
import static sciwhiz12.janitor.utils.Util.nameFor;
public class ModerationHelper {
public static AuditableRestAction<Void> kickUser(Guild guild, Member performer, Member target, @Nullable String reason) {
StringBuilder auditReason = new StringBuilder();
auditReason.append("Kicked by ").append(General.nameFor(performer.getUser()));
auditReason.append("Kicked by ").append(nameFor(performer.getUser()));
if (reason != null)
auditReason.append(" for reason: ").append(reason);
return guild.kick(target, auditReason.toString());
}
public static boolean ensurePermissions(MessageChannel channel, Member performer, Member target, EnumSet<Permission> permissions) {
if (!CommandHelper.hasPermission(channel, target.getGuild(), permissions)) return false;
if (!CommandHelper.canInteract(channel, target)) return false;
if (!performer.hasPermission(permissions)) {
Moderation.performerInsufficientPermissions(channel, performer, permissions).queue();
return false;
}
if (!performer.canInteract(target)) {
Moderation.cannotModerate(channel, performer, target).queue();
return false;
}
return true;
}
}

View File

@ -3,6 +3,7 @@ package sciwhiz12.janitor.config;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.file.FileWatcher;
import com.electronwill.nightconfig.toml.TomlFormat;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.IOException;
import java.nio.file.Path;
@ -15,6 +16,7 @@ public class BotConfig {
public static final Path DEFAULT_CONFIG_PATH = Path.of("config.toml");
public static final String CLIENT_TOKEN = "discord.client_token";
public static final String OWNER_ID = "discord.owner_id";
public static final String TRANSLATION_FILE_PATH = "messages.translation_file";
public static final String COMMAND_PREFIX = "commands.prefix";
private final BotOptions options;
@ -33,7 +35,8 @@ public class BotConfig {
config.load();
// TODO: config spec
FileWatcher.defaultInstance().addWatch(configPath, this::onFileChange);
} catch (IOException ex) {
}
catch (IOException ex) {
JANITOR.error("Error while building config from file {}", configPath, ex);
}
}
@ -42,6 +45,13 @@ public class BotConfig {
return config;
}
@Nullable
public Path getTranslationsFile() {
return options.getTranslationsFile().
or(() -> Optional.ofNullable(config.<String>get(TRANSLATION_FILE_PATH)).map(Path::of))
.orElse(null);
}
public Optional<String> getToken() {
return options.getToken().or(() -> config.getOptional(CLIENT_TOKEN));
}
@ -62,7 +72,8 @@ public class BotConfig {
try {
CONFIG.info("Reloading config due to file change {}", configPath);
config.load();
} catch (Exception ex) {
}
catch (Exception ex) {
CONFIG.error("Error while reloading config from {}", configPath, ex);
}
}

View File

@ -13,6 +13,7 @@ import static joptsimple.util.PathProperties.*;
public class BotOptions {
private final OptionSet options;
private final ArgumentAcceptingOptionSpec<Path> configPath;
private final ArgumentAcceptingOptionSpec<Path> translationsPath;
private final ArgumentAcceptingOptionSpec<String> token;
private final ArgumentAcceptingOptionSpec<String> prefix;
private final ArgumentAcceptingOptionSpec<Long> owner;
@ -23,6 +24,10 @@ public class BotOptions {
.accepts("config", "The path to the config file; defaults to 'config.toml'")
.withRequiredArg()
.withValuesConvertedBy(new PathConverter(FILE_EXISTING, READABLE, WRITABLE));
this.translationsPath = parser
.accepts("translations", "The path to the translations file")
.withRequiredArg()
.withValuesConvertedBy(new PathConverter(FILE_EXISTING, READABLE));
this.token = parser
.accepts("token", "The Discord token for the bot user")
.withRequiredArg();
@ -40,6 +45,10 @@ public class BotOptions {
return configPath.valueOptional(options);
}
public Optional<Path> getTranslationsFile() {
return translationsPath.valueOptional(options);
}
public Optional<String> getToken() {
return token.valueOptional(options);
}

View File

@ -1,67 +0,0 @@
package sciwhiz12.janitor.msg;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.EnumSet;
import java.util.stream.Collectors;
public final class General {
public static final int FAILURE_COLOR = 0xF73132;
private General() {
}
public static RestAction<Message> guildOnlyCommand(MessageChannel channel) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle("Guild only command!")
.setDescription("The previous command can only be run in a guild channel.")
.setColor(FAILURE_COLOR)
.build()
);
}
public static RestAction<Message> insufficientPermissions(MessageChannel channel, EnumSet<Permission> permissions) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle("I have insufficient permissions!")
.setDescription("I do not have sufficient permissions to carry out this action!\n" +
"Please contact your server admins if you believe this is in error.")
.addField(new MessageEmbed.Field(
"Required permissions",
permissions.stream().map(Permission::getName).collect(Collectors.joining(", ")),
false))
.setColor(FAILURE_COLOR)
.build()
);
}
public static RestAction<Message> ambiguousMember(MessageChannel channel) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle("Ambiguous member argument!")
.setDescription("The name you have specified is too ambiguous (leads to more than 1 member)!\n" +
"Please narrow down the specified name until it can uniquely identify a member of this guild.")
.setColor(FAILURE_COLOR)
.build()
);
}
public static RestAction<Message> cannotInteract(MessageChannel channel, Member target) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle("Member is higher than me!")
.setDescription("Cannot perform action on the given member, as they higher up in the hierarchy than me.")
.addField("Target", nameFor(target.getUser()), true)
.setColor(General.FAILURE_COLOR)
.build()
);
}
public static String nameFor(User user) {
return user.getName().concat("#").concat(user.getDiscriminator());
}
}

View File

@ -0,0 +1,142 @@
package sciwhiz12.janitor.msg;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.MessageAction;
import org.checkerframework.checker.nullness.qual.Nullable;
import sciwhiz12.janitor.JanitorBot;
import java.util.EnumSet;
import java.util.stream.Collectors;
import static sciwhiz12.janitor.utils.Util.nameFor;
public class Messages {
private final JanitorBot bot;
public final General GENERAL;
public final Moderation MODERATION;
public Messages(JanitorBot bot) {
this.bot = bot;
this.GENERAL = new General();
this.MODERATION = new Moderation();
}
public String translate(String key, Object... args) {
return bot.getTranslations().translate(key, args);
}
public final class General {
public static final int FAILURE_COLOR = 0xF73132;
private General() {}
public RestAction<Message> guildOnlyCommand(MessageChannel channel) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle(translate("general.guild_only_command.title"))
.setDescription(translate("general.guild_only_command.desc"))
.setColor(FAILURE_COLOR)
.build()
);
}
public RestAction<Message> insufficientPermissions(MessageChannel channel, EnumSet<Permission> permissions) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle(translate("general.insufficient_permissions.title"))
.setDescription(translate("general.insufficient_permissions.desc"))
.addField(new MessageEmbed.Field(
translate("general.insufficient_permissions.field.permissions"),
permissions.stream().map(Permission::getName).collect(Collectors.joining(", ")),
false))
.setColor(FAILURE_COLOR)
.build()
);
}
public RestAction<Message> ambiguousMember(MessageChannel channel) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle(translate("general.ambiguous_member.title"))
.setDescription(translate("general.ambiguous_member.desc"))
.setColor(FAILURE_COLOR)
.build()
);
}
public RestAction<Message> cannotInteract(MessageChannel channel, Member target) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle(translate("general.cannot_interact.title"))
.setDescription(translate("general.cannot_interact.desc"))
.addField(translate("general.cannot_interact.field.target"), nameFor(target.getUser()), true)
.setColor(General.FAILURE_COLOR)
.build()
);
}
}
public final class Moderation {
public static final int MODERATION_COLOR = 0xF1BD25;
public static final String GAVEL_ICON_URL = "https://cdn.discordapp.com/attachments/738478941760782526" +
"/760463743330549760/gavel.png";
private Moderation() {}
public MessageAction performerInsufficientPermissions(MessageChannel channel, Member performer,
EnumSet<Permission> permissions) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle(translate("moderation.insufficient_permissions.title"))
.setDescription(translate("moderation.insufficient_permissions.desc"))
.addField(translate("moderation.insufficient_permissions.field.performer"), nameFor(performer.getUser()),
true)
.addField(new MessageEmbed.Field(
translate("moderation.insufficient_permissions.field.permissions"),
permissions.stream().map(Permission::getName).collect(Collectors.joining(", ")),
true))
.setColor(General.FAILURE_COLOR)
.build()
);
}
public MessageAction cannotModerate(MessageChannel channel, Member performer, Member target) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle(translate("moderation.cannot_interact.title"))
.setDescription(translate("moderation.cannot_interact.desc"))
.addField(translate("moderation.cannot_interact.field.performer"), nameFor(performer.getUser()), true)
.addField(translate("moderation.cannot_interact.field.target"), nameFor(target.getUser()), true)
.setColor(General.FAILURE_COLOR)
.build()
);
}
public MessageAction kickUser(MessageChannel channel, Member performer, Member target, @Nullable String reason) {
final EmbedBuilder embed = new EmbedBuilder()
.setAuthor(translate("moderation.kick.info.author"), null, GAVEL_ICON_URL)
.addField(translate("moderation.kick.info.field.performer"), nameFor(performer.getUser()), true)
.addField(translate("moderation.kick.info.field.target"), nameFor(target.getUser()), true);
if (reason != null)
embed.addField(translate("moderation.kick.info.field.reason"), reason, false);
return channel.sendMessage(embed.setColor(MODERATION_COLOR).build());
}
public MessageAction kickedDM(MessageChannel channel, Member performer, Member target, @Nullable String reason) {
final EmbedBuilder embed = new EmbedBuilder()
.setAuthor(performer.getGuild().getName(), null, performer.getGuild().getIconUrl())
.setTitle(translate("moderation.kick.dm.title"))
.addField(translate("moderation.kick.dm.field.performer"), nameFor(performer.getUser()), true);
if (reason != null)
embed.addField(translate("moderation.kick.dm.field.reason"), reason, false);
return channel.sendMessage(embed.setColor(MODERATION_COLOR).build());
}
}
}

View File

@ -1,73 +0,0 @@
package sciwhiz12.janitor.msg;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.requests.restaction.MessageAction;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.EnumSet;
import java.util.stream.Collectors;
import static sciwhiz12.janitor.msg.General.nameFor;
public final class Moderation {
public static final int MODERATION_COLOR = 0xF1BD25;
public static final String GAVEL_ICON_URL = "https://cdn.discordapp.com/attachments/738478941760782526/760463743330549760/gavel.png";
private Moderation() {
}
public static MessageAction performerInsufficientPermissions(MessageChannel channel, Member performer, EnumSet<Permission> permissions) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle("Insufficient permissions.")
.setDescription("The performer of this command has insufficient permissions to use this command.")
.addField("Performer", nameFor(performer.getUser()), true)
.addField(new MessageEmbed.Field(
"Required permissions",
permissions.stream().map(Permission::getName).collect(Collectors.joining(", ")),
true))
.setColor(General.FAILURE_COLOR)
.build()
);
}
public static MessageAction cannotModerate(MessageChannel channel, Member performer, Member target) {
return channel.sendMessage(
new EmbedBuilder()
.setTitle("Cannot moderate Target.")
.setDescription("The performer of this command cannot moderate the target user, likely due to being lower in the role hierarchy.")
.addField("Performer", nameFor(performer.getUser()), true)
.addField("Target", nameFor(target.getUser()), true)
.setColor(General.FAILURE_COLOR)
.build()
);
}
public static MessageAction kickUser(MessageChannel channel, Member performer, Member target, @Nullable String reason) {
final EmbedBuilder embed = new EmbedBuilder()
.setAuthor("Kicked user from server.", null, GAVEL_ICON_URL)
.addField("Moderator", nameFor(performer.getUser()), true)
.addField("Target", nameFor(target.getUser()), true);
if (reason != null)
embed.addField("Reason", reason, false);
return channel.sendMessage(
embed.setColor(MODERATION_COLOR).build()
);
}
public static MessageAction kickedDM(MessageChannel channel, Member performer, Member target, @Nullable String reason) {
final EmbedBuilder embed = new EmbedBuilder()
.setAuthor(performer.getGuild().getName(), null, performer.getGuild().getIconUrl())
.setTitle("You were kicked from this server.")
.addField("Moderator", nameFor(performer.getUser()), true);
if (reason != null)
embed.addField("Reason", reason, false);
return channel.sendMessage(
embed.setColor(MODERATION_COLOR).build()
);
}
}

View File

@ -0,0 +1,77 @@
package sciwhiz12.janitor.msg;
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import sciwhiz12.janitor.JanitorBot;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static sciwhiz12.janitor.Logging.JANITOR;
import static sciwhiz12.janitor.Logging.TRANSLATIONS;
public class Translations {
private static final Gson GSON = new GsonBuilder().create();
private static final String DEFAULT_TRANSLATIONS_RESOURCE = "english.json";
private static final Type MAP_TYPE = new TypeToken<Map<String, String>>() {}.getType();
private final JanitorBot bot;
private final Path translationsFile;
private final Map<String, String> translations = new HashMap<>();
public Translations(JanitorBot bot, Path translationsFile) {
this.bot = bot;
this.translationsFile = translationsFile;
loadTranslations();
}
void loadTranslations() {
if (translationsFile == null) {
JANITOR.info(TRANSLATIONS, "No translation file given, using default english translations");
loadDefaultTranslations();
return;
}
try {
JANITOR.debug(TRANSLATIONS, "Loading translations from file {}", translationsFile);
Map<String, String> trans = GSON.fromJson(Files.newBufferedReader(translationsFile), MAP_TYPE);
translations.clear();
translations.putAll(trans);
JANITOR.info(TRANSLATIONS, "Loaded {} translations from file {}", translations.size(), translationsFile);
}
catch (Exception e) {
JANITOR.error(TRANSLATIONS, "Error while loading translations from file {}", translationsFile, e);
loadDefaultTranslations();
}
}
void loadDefaultTranslations() {
try {
JANITOR.debug(TRANSLATIONS, "Loading default english translations");
// noinspection UnstableApiUsage
Map<String, String> trans = GSON.fromJson(
new InputStreamReader(Resources.getResource(DEFAULT_TRANSLATIONS_RESOURCE).openStream()),
MAP_TYPE);
translations.clear();
translations.putAll(trans);
JANITOR.info(TRANSLATIONS, "Loaded {} default english translations", translations.size());
}
catch (Exception e) {
JANITOR.error(TRANSLATIONS, "Error while loading default english translations", e);
}
}
public Map<String, String> getTranslationMap() {
return Collections.unmodifiableMap(translations);
}
public String translate(String key, Object... args) {
return String.format(translations.getOrDefault(key, key), args);
}
}

View File

@ -47,6 +47,10 @@ public class Util {
return String.format("<%s%s>", prefix, entity.getId());
}
public static String nameFor(User user) {
return user.getName().concat("#").concat(user.getDiscriminator());
}
public static <Success, Error> BiConsumer<Success, Error> handle(final Consumer<Success> success,
final Consumer<Error> exceptionally) {
return (suc, ex) -> {

View File

@ -5,6 +5,10 @@ client_token = "NONE"
# The id of the bot owner; used for sending status messages and allowing bot admin commands
owner_id = 0
[messages]
# The file containing the translation keys
# translation_file = "english.json"
[commands]
# The prefix for commands
prefix = "!"

View File

@ -0,0 +1,27 @@
{
"general.guild_only_command.title": "Guild only command!",
"general.guild_only_command.desc": "The previous command can only be run in a guild channel.",
"general.insufficient_permissions.title": "I have insufficient permissions!",
"general.insufficient_permissions.desc": "I do not have sufficient permissions to carry out this action!\nPlease contact your server admins if you believe this is in error.",
"general.insufficient_permissions.field.permissions": "Required permissions",
"general.ambiguous_member.title": "Ambiguous member argument!",
"general.ambiguous_member.desc": "The name you have specified is too ambiguous (leads to more than 1 member)!\nPlease narrow down the specified name until it can uniquely identify a member of this guild.",
"general.cannot_interact.title": "Member is higher than me!",
"general.cannot_interact.desc": "Cannot perform action on the given member, likely due to me being lower in the role hierarchy.",
"general.cannot_interact.field.target": "Target",
"moderation.insufficient_permissions.title": "Insufficient permissions.",
"moderation.insufficient_permissions.desc": "The performer of this command has insufficient permissions to use this command.",
"moderation.insufficient_permissions.field.performer": "Performer",
"moderation.insufficient_permissions.field.permissions": "Required permissions",
"moderation.cannot_interact.title": "Cannot moderate Target.",
"moderation.cannot_interact.desc": "The performer of this command cannot moderate the target user, likely due to being lower in the role hierarchy.",
"moderation.cannot_interact.field.performer": "Performer",
"moderation.cannot_interact.field.target": "Target",
"moderation.kick.info.author": "Kicked user from server.",
"moderation.kick.info.field.performer": "Performer",
"moderation.kick.info.field.target": "Target",
"moderation.kick.info.field.reason": "Reason",
"moderation.kick.dm.title": "You were kicked from this server.",
"moderation.kick.dm.field.performer": "Moderator",
"moderation.kick.dm.field.reason": "Reason"
}