Makes language configurable

Changes the translator to load translations from several files
Moves strings.yml to en-US.yml and removes the "en" root node
Makes sure to use UTF-8 for custom languages
Improves some translator console messages and behavior when the selected language cannot be loaded
This commit is contained in:
2022-06-02 21:29:02 +02:00
parent a5484578f5
commit c4cdab8b7f
5 changed files with 50 additions and 45 deletions

View File

@@ -39,8 +39,8 @@ public class StargateCommand extends JavaPlugin {
this.saveDefaultConfig(); this.saveDefaultConfig();
configuration.options().copyDefaults(true); configuration.options().copyDefaults(true);
loadConfiguration(configuration); loadConfiguration(configuration);
saveConfig();
Translator.loadLanguages("en");
//Get the Stargate API //Get the Stargate API
ServicesManager servicesManager = this.getServer().getServicesManager(); ServicesManager servicesManager = this.getServer().getServicesManager();
RegisteredServiceProvider<StargateAPI> stargateProvider = servicesManager.getRegistration(StargateAPI.class); RegisteredServiceProvider<StargateAPI> stargateProvider = servicesManager.getRegistration(StargateAPI.class);
@@ -81,6 +81,7 @@ public class StargateCommand extends JavaPlugin {
* @param fileConfiguration <p>The configuration to load</p> * @param fileConfiguration <p>The configuration to load</p>
*/ */
private void loadConfiguration(FileConfiguration fileConfiguration) { private void loadConfiguration(FileConfiguration fileConfiguration) {
Translator.loadLanguages(fileConfiguration.getString("language"));
//Load all icons from config //Load all icons from config
for (Icon icon : Icon.values()) { for (Icon icon : Icon.values()) {
String iconString = fileConfiguration.getString(icon.getConfigNode()); String iconString = fileConfiguration.getString(icon.getConfigNode());

View File

@@ -9,6 +9,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
@@ -18,6 +19,7 @@ import java.util.logging.Level;
*/ */
public final class Translator { public final class Translator {
private static final String translationsFolder = "translations";
private static Map<TranslatableMessage, String> translatedMessages; private static Map<TranslatableMessage, String> translatedMessages;
private static Map<TranslatableMessage, String> backupTranslatedMessages; private static Map<TranslatableMessage, String> backupTranslatedMessages;
@@ -29,7 +31,7 @@ public final class Translator {
* Loads the languages used by this translator * Loads the languages used by this translator
*/ */
public static void loadLanguages(String selectedLanguage) { public static void loadLanguages(String selectedLanguage) {
backupTranslatedMessages = loadTranslatedMessages("en"); backupTranslatedMessages = loadTranslatedMessages("en-US");
translatedMessages = loadCustomTranslatedMessages(selectedLanguage); translatedMessages = loadCustomTranslatedMessages(selectedLanguage);
if (translatedMessages == null) { if (translatedMessages == null) {
translatedMessages = loadTranslatedMessages(selectedLanguage); translatedMessages = loadTranslatedMessages(selectedLanguage);
@@ -43,16 +45,13 @@ public final class Translator {
* @return <p>The translated message</p> * @return <p>The translated message</p>
*/ */
public static String getTranslatedMessage(TranslatableMessage translatableMessage) { public static String getTranslatedMessage(TranslatableMessage translatableMessage) {
if (translatedMessages == null) {
return "Translated strings not loaded";
}
String translatedMessage; String translatedMessage;
if (translatedMessages.containsKey(translatableMessage)) { if (translatedMessages != null && translatedMessages.containsKey(translatableMessage)) {
translatedMessage = translatedMessages.get(translatableMessage); translatedMessage = translatedMessages.get(translatableMessage);
} else if (backupTranslatedMessages.containsKey(translatableMessage)) { } else if (backupTranslatedMessages != null && backupTranslatedMessages.containsKey(translatableMessage)) {
translatedMessage = backupTranslatedMessages.get(translatableMessage); translatedMessage = backupTranslatedMessages.get(translatableMessage);
} else { } else {
translatedMessage = translatableMessage.toString(); return "Translated strings not loaded";
} }
return StringFormatter.translateAllColorCodes(translatedMessage); return StringFormatter.translateAllColorCodes(translatedMessage);
} }
@@ -65,32 +64,37 @@ public final class Translator {
*/ */
public static Map<TranslatableMessage, String> loadTranslatedMessages(String language) { public static Map<TranslatableMessage, String> loadTranslatedMessages(String language) {
try { try {
BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/strings.yml"); BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/" + translationsFolder + "/" +
return loadTranslatableMessages(language, reader); language + ".yml");
return loadTranslatableMessages(reader);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
StargateCommand.getInstance().getLogger().log(Level.SEVERE, "Unable to load translated messages"); StargateCommand.getInstance().getLogger().log(Level.SEVERE,
String.format("Unable to load translated messages from %s.yml", language));
return null; return null;
} }
} }
/** /**
* Tries to load translated messages from a custom strings.yml file * Tries to load translated messages from a custom en-US.yml file
* *
* @param language <p>The selected language</p> * @param language <p>The selected language</p>
* @return <p>The loaded translated strings, or null if no custom language file exists</p> * @return <p>The loaded translated strings, or null if no custom language file exists</p>
*/ */
public static Map<TranslatableMessage, String> loadCustomTranslatedMessages(String language) { public static Map<TranslatableMessage, String> loadCustomTranslatedMessages(String language) {
File strings = new File(StargateCommand.getInstance().getDataFolder(), "strings.yml"); File translationsFolderFile = new File(StargateCommand.getInstance().getDataFolder(), translationsFolder);
if (!strings.exists()) { File languageFile = new File(translationsFolderFile, language + ".yml");
StargateCommand.getInstance().getLogger().log(Level.FINEST, "Strings file not found"); if (!languageFile.exists()) {
return null; return null;
} }
try { try {
StargateCommand.getInstance().getLogger().log(Level.WARNING, "Loading custom strings..."); StargateCommand.getInstance().getLogger().log(Level.INFO,
return loadTranslatableMessages(language, new BufferedReader(new InputStreamReader(new FileInputStream(strings)))); String.format("Loading custom strings from %s.yml", language));
return loadTranslatableMessages(new BufferedReader(new InputStreamReader(new FileInputStream(languageFile),
StandardCharsets.UTF_8)));
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
StargateCommand.getInstance().getLogger().log(Level.WARNING, "Unable to load custom messages"); StargateCommand.getInstance().getLogger().log(Level.WARNING,
String.format("Unable to load custom messages from %s.yml", language));
return null; return null;
} }
} }
@@ -98,16 +102,15 @@ public final class Translator {
/** /**
* Loads translatable messages from the given reader * Loads translatable messages from the given reader
* *
* @param language <p>The selected language</p> * @param reader <p>The buffered reader to read from</p>
* @param reader <p>The buffered reader to read from</p>
* @return <p>The loaded translated strings</p> * @return <p>The loaded translated strings</p>
*/ */
private static Map<TranslatableMessage, String> loadTranslatableMessages(String language, BufferedReader reader) { private static Map<TranslatableMessage, String> loadTranslatableMessages(BufferedReader reader) {
Map<TranslatableMessage, String> translatedMessages = new HashMap<>(); Map<TranslatableMessage, String> translatedMessages = new HashMap<>();
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(reader); YamlConfiguration configuration = YamlConfiguration.loadConfiguration(reader);
for (TranslatableMessage message : TranslatableMessage.values()) { for (TranslatableMessage message : TranslatableMessage.values()) {
String translated = configuration.getString(language + "." + message.toString()); String translated = configuration.getString(message.toString());
if (translated != null) { if (translated != null) {
translatedMessages.put(message, translated); translatedMessages.put(message, translated);
} }

View File

@@ -1,3 +1,5 @@
# The language used for all text displayed to players
language: "en-US"
icon: icon:
# The "icon" used to mark a Stargate as hidden when visualizing the network # The "icon" used to mark a Stargate as hidden when visualizing the network
hiddenIcon: "⇒" hiddenIcon: "⇒"

View File

@@ -1,23 +0,0 @@
en:
PREFIX: "[StargateCommand]"
PERMISSION_DENIED: "Permission Denied"
INVALID_CONFIGURATION_OPTION: "Invalid configuration option specified"
INVALID_DATATYPE_GIVEN: "Invalid {datatype} given"
CONFIG_UPDATED: "Configuration updated"
POSITIVE_NUMBER_REQUIRED: "This config option cannot be negative"
INVALID_NUMBER_GIVEN: "Invalid number given"
CONFIG_OPTION_CURRENT_VALUE: "&aCurrent value: &6{value}"
CONFIG_VALUES_HEADER: "&aStargate &6Config values:"
CONFIG_OPTION_DESCRIPTION: "&6{name}&r - &a{description}&8 (Default: &7{value}&8)"
COMMAND_PLAYER_ONLY: "This command can only be used by players"
COMMAND_DIAL_ARGUMENTS: "You need to provide a network name and a Stargate name to dial"
INVALID_NETWORK_GIVEN: "Invalid network specified in input"
INVALID_PORTAL_GIVEN: "Invalid Stargate specified in input"
PORTAL_NO_ACCESS: "You don't have access to the selected Stargate"
NO_PORTAL_IN_SIGHT: "You need to look at a Stargate to use this command"
DIAL_SUCCESSFUL: "Your Stargate has been prepared"
COMMAND_VISUALIZER_ARGUMENTS: "A network must be provided to visualize"
COMMAND_VISUALIZER_FORMAT: "Symbol explanation: \n&6{icon_h}&r = hidden, &6{icon_nh}&r = not hidden\n&6{icon_a}&r = always open, &6{icon_na}&r = not always open\n&6{icon_r}&r = random destination, &6{icon_nr}&r = non-random destination\n&6{icon_arrow_right}&r = fixed Stargate going to the specified Stargate\n|\nAll Stargates in network &a{network}&r:"
COMMAND_VISUALIZER_PORTAL_FORMAT: "&6{icons} &a{portal}&r{fixed}"
COMMAND_VISUALIZER_FIXED_FORMAT: " {icon_arrow_right} &a{portal}"
COMMAND_INFO_FORMAT: "Stargate info:\n|- &6Name&r: &a{portal}&r\n|- &6Destination&r: &a{destination}&r\n|- &6Network&r: &a{network}&r\n|- &6Owner&r: &a{owner}&r\n|- &6Flags&r: &a{flags}&r"

View File

@@ -0,0 +1,22 @@
PREFIX: "[StargateCommand]"
PERMISSION_DENIED: "Permission Denied"
INVALID_CONFIGURATION_OPTION: "Invalid configuration option specified"
INVALID_DATATYPE_GIVEN: "Invalid {datatype} given"
CONFIG_UPDATED: "Configuration updated"
POSITIVE_NUMBER_REQUIRED: "This config option cannot be negative"
INVALID_NUMBER_GIVEN: "Invalid number given"
CONFIG_OPTION_CURRENT_VALUE: "&aCurrent value: &6{value}"
CONFIG_VALUES_HEADER: "&aStargate &6Config values:"
CONFIG_OPTION_DESCRIPTION: "&6{name}&r - &a{description}&8 (Default: &7{value}&8)"
COMMAND_PLAYER_ONLY: "This command can only be used by players"
COMMAND_DIAL_ARGUMENTS: "You need to provide a network name and a Stargate name to dial"
INVALID_NETWORK_GIVEN: "Invalid network specified in input"
INVALID_PORTAL_GIVEN: "Invalid Stargate specified in input"
PORTAL_NO_ACCESS: "You don't have access to the selected Stargate"
NO_PORTAL_IN_SIGHT: "You need to look at a Stargate to use this command"
DIAL_SUCCESSFUL: "Your Stargate has been prepared"
COMMAND_VISUALIZER_ARGUMENTS: "A network must be provided to visualize"
COMMAND_VISUALIZER_FORMAT: "Symbol explanation: \n&6{icon_h}&r = hidden, &6{icon_nh}&r = not hidden\n&6{icon_a}&r = always open, &6{icon_na}&r = not always open\n&6{icon_r}&r = random destination, &6{icon_nr}&r = non-random destination\n&6{icon_arrow_right}&r = fixed Stargate going to the specified Stargate\n|\nAll Stargates in network &a{network}&r:"
COMMAND_VISUALIZER_PORTAL_FORMAT: "&6{icons} &a{portal}&r{fixed}"
COMMAND_VISUALIZER_FIXED_FORMAT: " {icon_arrow_right} &a{portal}"
COMMAND_INFO_FORMAT: "Stargate info:\n|- &6Name&r: &a{portal}&r\n|- &6Destination&r: &a{destination}&r\n|- &6Network&r: &a{network}&r\n|- &6Owner&r: &a{owner}&r\n|- &6Flags&r: &a{flags}&r"