#293 Translatable help messages: basic structure

(work in progress)
- Create service that provides localized messages when available for HelpProvider
This commit is contained in:
ljacqu
2016-10-01 14:40:08 +02:00
parent 113a3f346c
commit f6a2b2b34b
7 changed files with 256 additions and 57 deletions
@@ -9,7 +9,7 @@ import java.util.List;
/**
* Helper class for displaying the syntax of a command properly to a user.
*/
class CommandSyntaxHelper {
final class CommandSyntaxHelper {
private CommandSyntaxHelper() {
}
@@ -0,0 +1,49 @@
package fr.xephi.authme.command.help;
/**
* Common, non-generic keys for messages used when showing command help.
* All keys are prefixed with {@code common}.
*/
public enum HelpMessageKey {
SHORT_DESCRIPTION("description.short", "Short description"),
DETAILED_DESCRIPTION("description.detailed", "Detailed description"),
USAGE("usage", "Usage"),
ARGUMENTS("arguments", "Arguments"),
OPTIONAL("optional", "(Optional)"),
HAS_PERMISSION("hasPermission", "You have permission"),
NO_PERMISSION("noPermission", "No permission"),
ALTERNATIVES("alternatives", "Alternatives"),
DEFAULT("default", "Default"),
RESULT("result", "Result"),
PERMISSIONS("permissions", "Permissions"),
COMMANDS("commands", "Commands");
private final String key;
private final String fallback;
HelpMessageKey(String key, String fallback) {
this.key = "common." + key;
this.fallback = fallback;
}
public String getKey() {
return key;
}
public String getFallback() {
return fallback;
}
}
@@ -0,0 +1,113 @@
package fr.xephi.authme.command.help;
import com.google.common.base.CaseFormat;
import fr.xephi.authme.command.CommandArgumentDescription;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.util.FileUtils;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.inject.Inject;
import java.io.File;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* Manages translatable help messages.
*/
public class HelpMessagesService implements Reloadable {
private static final String COMMAND_PREFIX = "command.";
private static final String DESCRIPTION_SUFFIX = ".description";
private static final String DETAILED_DESCRIPTION_SUFFIX = ".detailedDescription";
private static final String DEFAULT_PERMISSIONS_PATH = "common.defaultPermissions.";
private final File dataFolder;
// FIXME: Make configurable
private String file = "messages/help_en.yml";
private FileConfiguration fileConfiguration;
@Inject
HelpMessagesService(@DataFolder File dataFolder) {
File messagesFile = new File(dataFolder, "messages/help_en.yml");
if (!FileUtils.copyFileFromResource(messagesFile, file)) {
throw new IllegalStateException("Could not copy help message");
}
this.dataFolder = dataFolder;
fileConfiguration = YamlConfiguration.loadConfiguration(messagesFile);
}
/**
* Creates a copy of the supplied command description with localized messages where present.
*
* @param command the command to build a localized version of
* @return the localized description
*/
public CommandDescription buildLocalizedDescription(CommandDescription command) {
final String path = getCommandPath(command);
if (fileConfiguration.get(path) == null) {
// Messages file does not have a section for this command - return the provided command
return command;
}
CommandDescription.CommandBuilder builder = CommandDescription.builder()
.description(getText(path + DESCRIPTION_SUFFIX, command::getDescription))
.detailedDescription(getText(path + DETAILED_DESCRIPTION_SUFFIX, command::getDetailedDescription))
.executableCommand(command.getExecutableCommand())
.parent(command.getParent())
.labels(command.getLabels())
.permission(command.getPermission());
int i = 1;
for (CommandArgumentDescription argument : command.getArguments()) {
String argPath = path + ".arg" + i;
String label = getText(argPath + ".label", argument::getName);
String description = getText(argPath + ".description", argument::getDescription);
builder.withArgument(label, description, argument.isOptional());
++i;
}
return builder.build();
}
public String getMessage(HelpMessageKey key) {
String message = fileConfiguration.getString(key.getKey());
return message == null
? key.getFallback()
: message;
}
public String getMessage(DefaultPermission defaultPermission) {
// e.g. {default_permissions_path}.opOnly for DefaultPermission.OP_ONLY
String path = DEFAULT_PERMISSIONS_PATH +
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, defaultPermission.name());
String message = fileConfiguration.getString(path);
if (message != null) {
return message;
}
return defaultPermission.name(); // FIXME: Default message
}
@Override
public void reload() {
fileConfiguration = YamlConfiguration.loadConfiguration(new File(dataFolder, "messages/help_en.yml"));
}
private String getText(String path, Supplier<String> defaultTextGetter) {
String message = fileConfiguration.getString(path);
return message == null
? defaultTextGetter.get()
: message;
}
private static String getCommandPath(CommandDescription command) {
return COMMAND_PREFIX + CommandUtils.constructParentList(command)
.stream()
.map(cmd -> cmd.getLabels().get(0))
.collect(Collectors.joining("."));
}
}
@@ -19,6 +19,8 @@ import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import static fr.xephi.authme.command.help.HelpMessageKey.DETAILED_DESCRIPTION;
import static fr.xephi.authme.command.help.HelpMessageKey.SHORT_DESCRIPTION;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -45,11 +47,13 @@ public class HelpProvider implements SettingsDependent {
public static final int ALL_OPTIONS = ~HIDE_COMMAND;
private final PermissionsManager permissionsManager;
private final HelpMessagesService helpMessagesService;
private String helpHeader;
@Inject
HelpProvider(PermissionsManager permissionsManager, Settings settings) {
HelpProvider(PermissionsManager permissionsManager, HelpMessagesService helpMessagesService, Settings settings) {
this.permissionsManager = permissionsManager;
this.helpMessagesService = helpMessagesService;
reload(settings);
}
@@ -61,7 +65,7 @@ public class HelpProvider implements SettingsDependent {
List<String> lines = new ArrayList<>();
lines.add(ChatColor.GOLD + "==========[ " + helpHeader + " HELP ]==========");
CommandDescription command = result.getCommandDescription();
CommandDescription command = helpMessagesService.buildLocalizedDescription(result.getCommandDescription());
List<String> labels = ImmutableList.copyOf(result.getLabels());
List<String> correctLabels = ImmutableList.copyOf(filterCorrectLabels(command, labels));
@@ -75,7 +79,7 @@ public class HelpProvider implements SettingsDependent {
printArguments(command, lines);
}
if (hasFlag(SHOW_PERMISSIONS, options) && sender != null) {
printPermissions(command, sender, permissionsManager, lines);
printPermissions(command, sender, lines);
}
if (hasFlag(SHOW_ALTERNATIVES, options)) {
printAlternatives(command, correctLabels, lines);
@@ -106,37 +110,40 @@ public class HelpProvider implements SettingsDependent {
helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
}
private static void printDetailedDescription(CommandDescription command, List<String> lines) {
lines.add(ChatColor.GOLD + "Short description: " + ChatColor.WHITE + command.getDescription());
lines.add(ChatColor.GOLD + "Detailed description:");
private void printDetailedDescription(CommandDescription command, List<String> lines) {
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(SHORT_DESCRIPTION) + ": "
+ ChatColor.WHITE + command.getDescription());
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(DETAILED_DESCRIPTION) + ":");
lines.add(ChatColor.WHITE + " " + command.getDetailedDescription());
}
private static void printArguments(CommandDescription command, List<String> lines) {
private void printArguments(CommandDescription command, List<String> lines) {
if (command.getArguments().isEmpty()) {
return;
}
lines.add(ChatColor.GOLD + "Arguments:");
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpMessageKey.ARGUMENTS) + ":");
StringBuilder argString = new StringBuilder();
String optionalText = " (" + helpMessagesService.getMessage(HelpMessageKey.OPTIONAL) + ")";
for (CommandArgumentDescription argument : command.getArguments()) {
argString.setLength(0);
argString.append(" ").append(ChatColor.YELLOW).append(ChatColor.ITALIC).append(argument.getName())
.append(": ").append(ChatColor.WHITE).append(argument.getDescription());
if (argument.isOptional()) {
argString.append(ChatColor.GRAY).append(ChatColor.ITALIC).append(" (Optional)");
argString.append(ChatColor.GRAY).append(ChatColor.ITALIC).append(optionalText);
}
lines.add(argString.toString());
}
}
private static void printAlternatives(CommandDescription command, List<String> correctLabels, List<String> lines) {
private void printAlternatives(CommandDescription command, List<String> correctLabels, List<String> lines) {
if (command.getLabels().size() <= 1 || correctLabels.size() <= 1) {
return;
}
lines.add(ChatColor.GOLD + "Alternatives:");
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpMessageKey.ALTERNATIVES) + ":");
// Get the label used
final String parentLabel = correctLabels.get(0);
final String childLabel = correctLabels.get(1);
@@ -149,44 +156,53 @@ public class HelpProvider implements SettingsDependent {
}
}
private static void printPermissions(CommandDescription command, CommandSender sender,
PermissionsManager permissionsManager, List<String> lines) {
private void printPermissions(CommandDescription command, CommandSender sender, List<String> lines) {
PermissionNode permission = command.getPermission();
if (permission == null) {
return;
}
lines.add(ChatColor.GOLD + "Permissions:");
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpMessageKey.PERMISSIONS) + ":");
boolean hasPermission = permissionsManager.hasPermission(sender, permission);
final String nodePermsString = "" + ChatColor.GRAY + ChatColor.ITALIC
+ (hasPermission ? " (You have permission)" : " (No permission)");
lines.add(" " + ChatColor.YELLOW + ChatColor.ITALIC + permission.getNode() + nodePermsString);
lines.add(String.format(" " + ChatColor.YELLOW + ChatColor.ITALIC + "%s" + ChatColor.GRAY + " (%s)",
permission.getNode(), getLocalPermissionText(hasPermission)));
// Addendum to the line to specify whether the sender has permission or not when default is OP_ONLY
final DefaultPermission defaultPermission = permission.getDefaultPermission();
String addendum = "";
if (DefaultPermission.OP_ONLY.equals(defaultPermission)) {
addendum = defaultPermission.evaluate(sender)
? " (You have permission)"
: " (No permission)";
addendum = " (" + getLocalPermissionText(defaultPermission.evaluate(sender)) + ")";
}
lines.add(ChatColor.GOLD + "Default: " + ChatColor.GRAY + ChatColor.ITALIC
+ defaultPermission.getTitle() + addendum);
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpMessageKey.DEFAULT) + ": "
+ ChatColor.GRAY + ChatColor.ITALIC + helpMessagesService.getMessage(defaultPermission) + addendum);
// Evaluate if the sender has permission to the command
ChatColor permissionColor;
String permissionText;
if (permissionsManager.hasPermission(sender, command.getPermission())) {
lines.add(ChatColor.GOLD + " Result: " + ChatColor.GREEN + ChatColor.ITALIC + "You have permission");
permissionColor = ChatColor.GREEN;
permissionText = getLocalPermissionText(true);
} else {
lines.add(ChatColor.GOLD + " Result: " + ChatColor.DARK_RED + ChatColor.ITALIC + "No permission");
permissionColor = ChatColor.DARK_RED;
permissionText = getLocalPermissionText(false);
}
lines.add(String.format(ChatColor.GOLD + " %s: %s" + ChatColor.ITALIC + "%s",
helpMessagesService.getMessage(HelpMessageKey.RESULT), permissionColor, permissionText));
}
private static void printChildren(CommandDescription command, List<String> parentLabels, List<String> lines) {
private String getLocalPermissionText(boolean hasPermission) {
if (hasPermission) {
return helpMessagesService.getMessage(HelpMessageKey.HAS_PERMISSION);
}
return helpMessagesService.getMessage(HelpMessageKey.NO_PERMISSION);
}
private void printChildren(CommandDescription command, List<String> parentLabels, List<String> lines) {
if (command.getChildren().isEmpty()) {
return;
}
lines.add(ChatColor.GOLD + "Commands:");
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpMessageKey.COMMANDS) + ":");
String parentCommandPath = CommandUtils.labelsToString(parentLabels);
for (CommandDescription child : command.getChildren()) {
lines.add(" /" + parentCommandPath + " " + child.getLabels().get(0)