refactor: language rework

This commit is contained in:
aro 2023-01-11 17:00:44 +01:00
parent b838bc173a
commit 14b4916a67
12 changed files with 156 additions and 114 deletions

View file

@ -96,7 +96,7 @@
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.19</artifactId>
<version>2.143.0</version>
<version>2.29.0</version>
<scope>test</scope>
</dependency>
<!-- MariaDB JDBC Driver -->

View file

@ -9,7 +9,8 @@ import net.artelnatif.nicko.config.NickoConfiguration;
import net.artelnatif.nicko.event.PlayerJoinListener;
import net.artelnatif.nicko.event.PlayerQuitListener;
import net.artelnatif.nicko.gui.items.main.ExitDoorItem;
import net.artelnatif.nicko.i18n.LocaleManager;
import net.artelnatif.nicko.i18n.Locale;
import net.artelnatif.nicko.i18n.LocaleFileManager;
import net.artelnatif.nicko.impl.Internals;
import net.artelnatif.nicko.impl.InternalsProvider;
import net.artelnatif.nicko.mojang.MojangAPI;
@ -34,7 +35,7 @@ public class NickoBukkit extends JavaPlugin {
private NickoConfiguration config;
private MojangAPI mojangAPI;
private PlayerDataStore dataStore;
private LocaleManager localeManager;
private LocaleFileManager localeFileManager;
public NickoBukkit() { this.unitTesting = false; }
@ -70,7 +71,7 @@ public class NickoBukkit extends JavaPlugin {
dataStore.getStorage().setError(false);
}
if (config.isBungeecordEnabled()) {
if (config.isBungeecordSupport()) {
getServer().getMessenger().unregisterIncomingPluginChannel(this);
getServer().getMessenger().unregisterOutgoingPluginChannel(this);
}
@ -103,9 +104,14 @@ public class NickoBukkit extends JavaPlugin {
saveDefaultConfig();
config = new NickoConfiguration(this);
localeManager = new LocaleManager(this);
localeManager.findFallbackLocale();
localeManager.installCustomLanguageFile();
localeFileManager = new LocaleFileManager();
if (config.isCustomLocale()) {
if (localeFileManager.dumpFromLocale(Locale.ENGLISH)) {
getLogger().info("Successfully dumped English locale to lang.yml!");
} else {
getLogger().warning("Failed to dump English locale to lang.yml! Custom Locale usage will be disabled.");
}
}
final PluginCommand command = getCommand("nicko");
if (command != null) {
@ -131,7 +137,7 @@ public class NickoBukkit extends JavaPlugin {
final ServerUtils serverUtils = new ServerUtils(this);
serverUtils.checkSpigotBungeeCordHook();
if (config.isBungeecordEnabled()) {
if (config.isBungeecordSupport()) {
if (serverUtils.checkBungeeCordHook()) {
getLogger().info("Enabling BungeeCord support...");
getServer().getMessenger().registerIncomingPluginChannel(this, NickoBungee.NICKO_PLUGIN_CHANNEL_UPDATE, new PluginMessageHandler());
@ -154,8 +160,8 @@ public class NickoBukkit extends JavaPlugin {
public PlayerDataStore getDataStore() { return dataStore; }
public LocaleManager getLocaleManager() {
return localeManager;
public LocaleFileManager getLocaleFileManager() {
return localeFileManager;
}
public boolean isUnitTesting() {

View file

@ -62,7 +62,7 @@ public class AnvilManager {
if (!actionResult.isError()) {
player.sendMessage(I18N.translate(player, I18NDict.Event.DISGUISE_SUCCESS));
} else {
player.sendMessage(I18N.translate(player, I18NDict.Event.DISGUISE_FAIL, I18N.translateFlat(player, actionResult.getErrorMessage())));
player.sendMessage(I18N.translate(player, I18NDict.Event.DISGUISE_FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
}
return AnvilGUI.Response.close();
}
@ -83,7 +83,7 @@ public class AnvilManager {
if (!actionResult.isError()) {
player.sendMessage(I18N.translate(player, I18NDict.Event.DISGUISE_SUCCESS));
} else {
player.sendMessage(I18N.translate(player, I18NDict.Event.DISGUISE_FAIL, I18N.translateFlat(player, actionResult.getErrorMessage())));
player.sendMessage(I18N.translate(player, I18NDict.Event.DISGUISE_FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
}
return AnvilGUI.Response.close();
}

View file

@ -7,7 +7,6 @@ import org.bukkit.configuration.file.FileConfiguration;
public class NickoConfiguration {
private final NickoBukkit nicko;
private String prefix;
private String fallbackLocale;
private Boolean bungeecordSupport;
private Boolean localStorage;
@ -19,13 +18,22 @@ public class NickoConfiguration {
this.nicko = nicko;
}
//.............
// SECTION ACCESSORS
//.............
public ConfigurationSection getBungeecordSection() { return getConfig().getConfigurationSection("bungeecord"); }
public ConfigurationSection getStorageSection() { return getConfig().getConfigurationSection("storage"); }
// Unused for now
public ConfigurationSection getRedisSection() { return getBungeecordSection().getConfigurationSection("redis"); }
public ConfigurationSection getLocaleSection() { return getConfig().getConfigurationSection("locale"); }
public ConfigurationSection getRedisSection() { return getBungeecordSection().getConfigurationSection("redis"); }
public ConfigurationSection getStorageSection() { return getConfig().getConfigurationSection("storage"); }
//.............
// GLOBAL
//.............
public String getPrefix() {
if (prefix == null) {
@ -34,33 +42,11 @@ public class NickoConfiguration {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
//.............
// BUNGEECORD
//.............
public String getFallbackLocale() {
if (fallbackLocale == null) {
return fallbackLocale = getLocaleSection().getString("fallback");
}
return fallbackLocale;
}
public void setFallbackLocale(String fallbackLocale) {
this.fallbackLocale = fallbackLocale;
}
public boolean isCustomLocaleEnabled() {
if (customLocale == null) {
return customLocale = getStorageSection().getBoolean("local");
}
return customLocale;
}
public void setCustomLocaleEnabled(Boolean localStorage) {
this.localStorage = localStorage;
}
public boolean isBungeecordEnabled() {
public boolean isBungeecordSupport() {
if (bungeecordSupport == null) {
return bungeecordSupport = getBungeecordSection().getBoolean("enabled");
}
@ -71,6 +57,25 @@ public class NickoConfiguration {
this.bungeecordSupport = bungeecordSupport;
}
//.............
// LOCALE
//.............
public boolean isCustomLocale() {
if (customLocale == null) {
return customLocale = getLocaleSection().getBoolean("use_custom_locale");
}
return customLocale;
}
public void setCustomLocale(boolean customLocale) {
this.customLocale = customLocale;
}
//.............
// STORAGE
//.............
public boolean isLocalStorage() {
if (localStorage == null) {
return localStorage = getStorageSection().getBoolean("local");
@ -78,7 +83,7 @@ public class NickoConfiguration {
return localStorage;
}
public void setLocalStorage(Boolean localStorage) {
public void setLocalStorage(boolean localStorage) {
this.localStorage = localStorage;
}

View file

@ -2,35 +2,28 @@ package net.artelnatif.nicko.i18n;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.NickoProfile;
import org.apache.commons.lang3.LocaleUtils;
import org.bukkit.entity.Player;
import org.yaml.snakeyaml.Yaml;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Optional;
import java.util.ResourceBundle;
public class I18N {
private final static MessageFormat formatter = new MessageFormat("");
private static final Yaml yaml = new Yaml();
private static Locale getLocale(Player player) {
final NickoBukkit instance = NickoBukkit.getInstance();
try {
final Optional<NickoProfile> profile = instance.getDataStore().getData(player.getUniqueId());
if (profile.isEmpty()) {
return Locale.ENGLISH;
} else {
return profile.get().getLocale();
}
return profile.isEmpty() ? Locale.FALLBACK_LOCALE : profile.get().getLocale();
} catch (IllegalArgumentException exception) {
instance.getLogger().severe("Invalid locale provided by " + player.getName() + ", defaulting to " + LocaleManager.getFallback().getCode() + ".");
return LocaleManager.getFallback();
instance.getLogger().severe("Invalid locale provided by " + player.getName() + ", defaulting to " + Locale.FALLBACK_LOCALE.getCode() + ".");
return Locale.FALLBACK_LOCALE;
}
}
private static ResourceBundle getBundle(java.util.Locale locale) {
return ResourceBundle.getBundle("locale", locale);
}
public static String translate(Player player, I18NDict key, Object... arguments) {
final NickoBukkit instance = NickoBukkit.getInstance();
final String translation = findTranslation(player, key);
@ -43,7 +36,7 @@ public class I18N {
}
}
public static String translateFlat(Player player, I18NDict key, Object... arguments) {
public static String translateWithoutPrefix(Player player, I18NDict key, Object... arguments) {
final String translation = findTranslation(player, key);
try {
formatter.applyPattern(translation);
@ -53,15 +46,15 @@ public class I18N {
}
}
private static String findTranslation(Player player, I18NDict key) {
final NickoBukkit instance = NickoBukkit.getInstance();
final Locale locale = getLocale(player);
String translation;
if (locale == Locale.CUSTOM) {
translation = instance.getLocaleManager().getCustomLanguageFile().getProperty(key.key(), key.key());
translation = instance.getLocaleFileManager().getFromFile(key.key());
} else {
translation = getBundle(LocaleUtils.toLocale(locale.getCode())).getString(key.key());
final HashMap<String, String> values = yaml.load(I18N.class.getResourceAsStream(locale.getCode() + ".yml"));
translation = values.getOrDefault(key.key(), key.key());
}
return translation;

View file

@ -1,14 +1,13 @@
package net.artelnatif.nicko.i18n;
import java.io.Serializable;
import java.util.HashMap;
public enum Locale implements Serializable {
ENGLISH("en", "English"),
FRENCH("fr", "Français"),
CUSTOM("custom", "Server Custom");
private static HashMap<String, Locale> locales;
public static final Locale FALLBACK_LOCALE = ENGLISH;
private final String code;
private transient final String name;
@ -18,21 +17,6 @@ public enum Locale implements Serializable {
this.name = name;
}
public static HashMap<String, Locale> getLocales() {
if (locales == null) {
return locales = new HashMap<>() {{
for (Locale value : Locale.values()) {
put(value.getCode(), value);
}
}};
}
return locales;
}
public static Locale fromCode(String code) {
return getLocales().getOrDefault(code, LocaleManager.getFallback());
}
public String getCode() {
return code;
}

View file

@ -0,0 +1,46 @@
package net.artelnatif.nicko.i18n;
import net.artelnatif.nicko.NickoBukkit;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.util.HashMap;
public class LocaleFileManager {
private final Yaml yaml = new Yaml();
private final File folder = new File(NickoBukkit.getInstance().getDataFolder() + "/lang/");
private final File file = new File(folder, "lang.yml");
private HashMap<String, String> data = new HashMap<>();
public boolean loadValues() {
if (!file.exists()) return false;
try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
data = yaml.load(inputStream);
return true;
} catch (IOException e) {
return false;
}
}
public String getFromFile(String key) {
if (!file.exists() || data.isEmpty()) return key;
return data.get(key);
}
public boolean dumpFromLocale(Locale locale) {
if (locale == Locale.CUSTOM) return true;
if (file.exists()) return true;
final HashMap<String, String> values = yaml.load(this.getClass().getResourceAsStream(locale.getCode() + ".yml"));
try {
if (file.createNewFile()) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
yaml.dump(values, writer);
}
}
return true;
} catch (IOException e) {
return false;
}
}
}

View file

@ -14,7 +14,7 @@ public class ServerUtils {
public void checkSpigotBungeeCordHook() {
final Server server = instance.getServer();
final YamlConfiguration config = server.spigot().getConfig();
if (config.getConfigurationSection("settings").getBoolean("bungeecord") && instance.getNickoConfig().isBungeecordEnabled()) {
if (config.getConfigurationSection("settings").getBoolean("bungeecord") && instance.getNickoConfig().isBungeecordSupport()) {
instance.getLogger().severe("Hummm. Your server is hooked to BungeeCord, but it seems");
instance.getLogger().severe("that BungeeCord support is not enabled inside Nicko.");
instance.getLogger().severe("If this is intentional, you can safely ignore this message.");

View file

@ -14,13 +14,9 @@ bungeecord:
# Localisation:
locale:
# By default, Nicko tries to get the locale from the player's preferences.
# If that fails, the locale fallback is the one provided by this option.
# Accepted values: fr (French), en (English), custom (Custom language file).
fallback: "en"
# Nicko will copy the English locale as "custom.yml"
# Nicko will copy the English locale as "lang.yml"
# and will use the translations in that file when "Server Custom"
# is selected as the player's locale/default locale.
# is selected as the player's locale.
use_custom_locale: false

View file

@ -1,15 +1,21 @@
event.previous_skin_applied.success=§aYour previous active disguise has been applied back.
event.previous_skin_applied.fail=§cFailed to apply your previous disguise back. §7§o({0})
event.disguise.success=§aDisguise applied!
event.disguise.fail=§cUnable to apply your disguise. §7§o({0})
event.undisguise.success=§aDisguise removed.
event.undisguise.fail=§cUnable to remove your disguise. It will be set back to default on your next login. Sorry!
event.undisguise.notactive=§cYou do not have an active disguise.
error.player_offline=§c{0} §fis offline, please try again.
error.generic=Unknown error
error.couldnt_get_name_from_mojang=Failed to get username from Mojang
error.couldnt_get_skin_from_mojang=Failed to get skin from Mojang
error.couldnt_get_skin_from_cache=Failed to get skin from cache
error.invalid_username=§cThe specified username is not a valid Minecraft username.
admin.custom_language_reload_success=§aReloaded custom language file.
admin.custom_language_reload_fail=§cFailed to reload the custom language file!
admin:
custom_language_reload_fail: "§cFailed to reload the custom language file!"
custom_language_reload_success: "§aReloaded custom language file."
error:
couldnt_get_name_from_mojang: "Failed to get username from Mojang"
couldnt_get_skin_from_cache: "Failed to get skin from cache"
couldnt_get_skin_from_mojang: "Failed to get skin from Mojang"
generic: "Unknown error"
invalid_username: "§cThe specified username is not a valid Minecraft username."
player_offline: "§c{0} §fis offline, please try again."
event:
disguise:
fail: "§cUnable to apply your disguise. §7§o({0})"
success: "§aDisguise applied!"
previous_skin_applied:
fail: "§cFailed to apply your previous disguise back. §7§o({0})"
success: "§aYour previous active disguise has been applied back."
undisguise:
fail: "§cUnable to remove your disguise. It will be set back to default on your next login. Sorry!"
notactive: "§cYou do not have an active disguise."
success: "§aDisguise removed."

View file

@ -1,15 +1,21 @@
event.previous_skin_applied.success=§aVotre précédent déguisement a été réappliqué.
event.previous_skin_applied.fail=§cImpossible d'appliquer votre déguisement précédent. §7§o({0})
event.disguise.success=§aDéguisement appliqué !
event.disguise.fail=§cImpossible d'appliquer votre déguisement. §7§o({0})
event.undisguise.success=§aDéguisement retiré.
event.undisguise.fail=§cImpossible de retier votre déguisement. Il sera remis par défaut à votre prochaine reconnexion. Désolé !
event.undisguise.notactive=§cVous n'avez pas de déguisement.
error.player_offline=§c{0} §fest hors-ligne, veuillez réessayer.
error.generic=Erreur inconnue
error.couldnt_get_name_from_mojang=Impossible de récupérer le nom d'utilisateur depuis Mojang
error.couldnt_get_skin_from_mojang=Impossible de récupérer le skin depuis Mojang
error.couldnt_get_skin_from_cache=Impossible de récupérer le skin depuis le cache
error.invalid_username=§cLe pseudo spécifié n'est pas un pseudo Minecraft valide.
admin.custom_language_reload_success=§aFichier de langue rechargé.
admin.custom_language_reload_fail=§cImpossible de recharger le fichier de langue !
admin:
custom_language_reload_fail: "§cImpossible de recharger le fichier de langue !"
custom_language_reload_success: "§aFichier de langue rechargé."
error:
couldnt_get_name_from_mojang: "Impossible de récupérer le nom d'utilisateur depuis Mojang"
couldnt_get_skin_from_cache: "Impossible de récupérer le skin depuis le cache"
couldnt_get_skin_from_mojang: "Impossible de récupérer le skin depuis Mojang"
generic: "Erreur inconnue"
invalid_username: "§cLe pseudo spécifié n'est pas un pseudo Minecraft valide."
player_offline: "§c{0} §fest hors-ligne, veuillez réessayer."
event:
disguise:
fail: "§cImpossible d'appliquer votre déguisement. §7§o({0})"
success: "§aDéguisement appliqué !"
previous_skin_applied:
fail: "§cImpossible d'appliquer votre déguisement précédent. §7§o({0})"
success: "§aVotre précédent déguisement a été réappliqué."
undisguise:
fail: "§cImpossible de retier votre déguisement. Il sera remis par défaut à votre prochaine reconnexion. Désolé !"
notactive: "§cVous n'avez pas de déguisement."
success: "§aDéguisement retiré."

View file

@ -31,7 +31,7 @@ public class SQLStorageTest {
@DisplayName("Create SQL Tables")
public void testSQLTables() {
final PlayerMock playerMock = server.addPlayer("Aro");
final PlayerMock playerMock = server.addPlayer();
final Optional<NickoProfile> data = plugin.getDataStore().getData(playerMock.getUniqueId());
Assertions.assertTrue(data.isPresent());
Assertions.assertNull(data.get().getSkin());