Merge pull request #155 from Dreeam-qwq/feat/i18n

i18n messages sending support
This commit is contained in:
DGun Otto
2024-06-03 23:55:23 +08:00
committed by GitHub
46 changed files with 1852 additions and 1023 deletions
@@ -0,0 +1,36 @@
package fr.xephi.authme.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.util.message.I18NUtils;
import java.util.UUID;
class I18NGetLocalePacketAdapter extends PacketAdapter {
I18NGetLocalePacketAdapter(AuthMe plugin) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.SETTINGS);
}
@Override
public void onPacketReceiving(PacketEvent event) {
if (event.getPacketType() == PacketType.Play.Client.SETTINGS) {
String locale = event.getPacket().getStrings().read(0).toLowerCase();
UUID uuid = event.getPlayer().getUniqueId();
I18NUtils.addLocale(uuid, locale);
}
}
public void register() {
ProtocolLibrary.getProtocolManager().addPacketListener(this);
}
public void unregister() {
ProtocolLibrary.getProtocolManager().removePacketListener(this);
}
}
@@ -9,7 +9,9 @@ import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -22,10 +24,12 @@ public class ProtocolLibService implements SettingsDependent {
/* Packet Adapters */
private InventoryPacketAdapter inventoryPacketAdapter;
private TabCompletePacketAdapter tabCompletePacketAdapter;
private I18NGetLocalePacketAdapter i18nGetLocalePacketAdapter;
/* Settings */
private boolean protectInvBeforeLogin;
private boolean denyTabCompleteBeforeLogin;
private boolean i18nMessagesSending;
/* Service */
private boolean isEnabled;
@@ -58,6 +62,10 @@ public class ProtocolLibService implements SettingsDependent {
logger.warning("WARNING! The denyTabComplete feature requires ProtocolLib! Disabling it...");
}
if (i18nMessagesSending) {
logger.warning("WARNING! The i18n Messages feature requires ProtocolLib on lower version (< 1.15.2)! Disabling it...");
}
this.isEnabled = false;
return;
}
@@ -84,6 +92,16 @@ public class ProtocolLibService implements SettingsDependent {
tabCompletePacketAdapter = null;
}
if (i18nMessagesSending) {
if (i18nGetLocalePacketAdapter == null) {
i18nGetLocalePacketAdapter = new I18NGetLocalePacketAdapter(plugin);
i18nGetLocalePacketAdapter.register();
}
} else if (i18nGetLocalePacketAdapter != null) {
i18nGetLocalePacketAdapter.unregister();
i18nGetLocalePacketAdapter = null;
}
this.isEnabled = true;
}
@@ -101,6 +119,10 @@ public class ProtocolLibService implements SettingsDependent {
tabCompletePacketAdapter.unregister();
tabCompletePacketAdapter = null;
}
if (i18nGetLocalePacketAdapter != null) {
i18nGetLocalePacketAdapter.unregister();
i18nGetLocalePacketAdapter = null;
}
}
/**
@@ -120,6 +142,7 @@ public class ProtocolLibService implements SettingsDependent {
this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
this.i18nMessagesSending = settings.getProperty(PluginSettings.I18N_MESSAGES) && Utils.MAJOR_VERSION <= 15;
//it was true and will be deactivated now, so we need to restore the inventory for every player
if (oldProtectInventory && !protectInvBeforeLogin && inventoryPacketAdapter != null) {
@@ -8,12 +8,15 @@ import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.message.I18NUtils;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static fr.xephi.authme.message.MessagePathHelper.DEFAULT_LANGUAGE;
@@ -33,6 +36,7 @@ public abstract class AbstractMessageFileHandler implements Reloadable {
private String filename;
private FileConfiguration configuration;
private Map<String, FileConfiguration> i18nConfiguration;
private final String defaultFile;
protected AbstractMessageFileHandler() {
@@ -46,6 +50,7 @@ public abstract class AbstractMessageFileHandler implements Reloadable {
filename = createFilePath(language);
File messagesFile = initializeFile(filename);
configuration = YamlConfiguration.loadConfiguration(messagesFile);
i18nConfiguration = null;
}
protected String getLanguage() {
@@ -83,6 +88,24 @@ public abstract class AbstractMessageFileHandler implements Reloadable {
: message;
}
/**
* Returns the i18n message for the given key and given locale.
*
* @param key the key to retrieve the message for
* @param locale the locale that player client setting uses
* @return the message
*/
public String getMessageByLocale(String key, String locale) {
if (locale == null || !settings.getProperty(PluginSettings.I18N_MESSAGES)) {
return getMessage(key);
}
String message = getI18nConfiguration(locale).getString(key);
return message == null
? "Error retrieving message '" + key + "'"
: message;
}
/**
* Returns the message for the given key only if it exists,
* i.e. without falling back to the default file.
@@ -94,6 +117,27 @@ public abstract class AbstractMessageFileHandler implements Reloadable {
return configuration.getString(key);
}
public FileConfiguration getI18nConfiguration(String locale) {
if (i18nConfiguration == null) {
i18nConfiguration = new ConcurrentHashMap<>();
}
locale = I18NUtils.localeToCode(locale, settings);
if (i18nConfiguration.containsKey(locale)) {
return i18nConfiguration.get(locale);
} else {
// Sync with reload();
String i18nFilename = createFilePath(locale);
File i18nMessagesFile = initializeFile(i18nFilename);
FileConfiguration config = YamlConfiguration.loadConfiguration(i18nMessagesFile);
i18nConfiguration.put(locale, config);
return config;
}
}
/**
* Creates the path to the messages file for the given language code.
*
@@ -5,6 +5,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.mail.EmailService;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.util.expiring.Duration;
import fr.xephi.authme.util.message.I18NUtils;
import fr.xephi.authme.util.message.MiniMessageUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -121,7 +122,10 @@ public class Messages {
* @return The message from the file
*/
private String retrieveMessage(MessageKey key, CommandSender sender) {
String message = messagesFileHandler.getMessage(key.getKey());
String locale = sender instanceof Player
? I18NUtils.getLocale((Player) sender)
: null;
String message = messagesFileHandler.getMessageByLocale(key.getKey(), locale);
String displayName = sender.getName();
if (sender instanceof Player) {
displayName = ((Player) sender).getDisplayName();
@@ -5,6 +5,9 @@ import ch.jalu.configme.SettingsHolder;
import ch.jalu.configme.properties.Property;
import fr.xephi.authme.output.LogLevel;
import java.util.Set;
import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseStringSetProperty;
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
public final class PluginSettings implements SettingsHolder {
@@ -16,6 +19,26 @@ public final class PluginSettings implements SettingsHolder {
public static final Property<Boolean> MENU_UNREGISTER_COMPATIBILITY =
newProperty("3rdPartyFeature.compatibility.menuPlugins", false);
@Comment({
"Send i18n messages to player based on their client settings, this option will override `settings.messagesLanguage`",
"(Requires Protocollib or Packetevents)",
"This will not affect language of AuthMe help command."
})
public static final Property<Boolean> I18N_MESSAGES =
newProperty("3rdPartyFeature.features.i18nMessages.enabled", false);
@Comment({"Redirect locale code to certain AuthMe language code as you want",
"Minecraft locale list: https://minecraft.wiki/w/Language",
"AuthMe language code: https://github.com/HaHaWTH/AuthMeReReloaded/blob/master/docs/translations.md",
"For example, if you want to show Russian messages to player using language Tatar(tt_ru),",
"and show Chinese Simplified messages to player using language Classical Chinese(lzh), then:",
"locale-code-redirect:",
"- 'tt_ru:ru'",
"- 'lzh:zhcn'"})
public static final Property<Set<String>> I18N_CODE_REDIRECT =
newLowercaseStringSetProperty("3rdPartyFeature.features.i18nMessages.locale-code-redirect",
"tt_ru:ru", "lzh:zhcn");
@Comment({
"Do you want to enable the session feature?",
"If enabled, when a player authenticates successfully,",
@@ -2,6 +2,7 @@ package fr.xephi.authme.util;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
@@ -107,4 +108,12 @@ public final class Utils {
public static boolean isEmailEmpty(String email) {
return StringUtils.isBlank(email) || "your@email.com".equalsIgnoreCase(email);
}
private final static String[] serverVersion = Bukkit.getServer().getBukkitVersion()
.substring(0, Bukkit.getServer().getBukkitVersion().indexOf("-"))
.split("\\.");
private final static int FIRST_VERSION = Integer.parseInt(serverVersion[0]);
public final static int MAJOR_VERSION = Integer.parseInt(serverVersion[1]);
public final static int MINOR_VERSION = serverVersion.length == 3 ? Integer.parseInt(serverVersion[2]) : 0;
}
@@ -0,0 +1,98 @@
package fr.xephi.authme.util.message;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class I18NUtils {
private static Map<UUID, String> PLAYER_LOCALE = new ConcurrentHashMap<>();
private static final Map<String, String> LOCALE_MAP = new HashMap<>();
private static final List<String> LOCALE_LIST = Arrays.asList(
"en", "bg", "de", "eo", "es", "et", "eu", "fi", "fr", "gl", "hu", "id", "it", "ja", "ko", "lt", "nl", "pl",
"pt", "ro", "ru", "sk", "sr", "tr", "uk"
);
static {
LOCALE_MAP.put("pt_br", "br");
LOCALE_MAP.put("cs_cz", "cz");
LOCALE_MAP.put("nds_de", "de");
LOCALE_MAP.put("sxu", "de");
LOCALE_MAP.put("swg", "de");
LOCALE_MAP.put("rpr", "ru");
LOCALE_MAP.put("sl_si", "si");
LOCALE_MAP.put("vi_vn", "vn");
LOCALE_MAP.put("lzh", "zhcn");
LOCALE_MAP.put("zh_cn", "zhcn");
LOCALE_MAP.put("zh_hk", "zhhk");
LOCALE_MAP.put("zh_tw", "zhtw");
//LOCALE_MAP.put("zhmc", "zhmc");
}
/**
* Returns the locale that player uses.
*
* @param player The player
*/
public static String getLocale(Player player) {
if (Utils.MAJOR_VERSION > 15) {
return player.getLocale().toLowerCase();
} else if (PLAYER_LOCALE.containsKey(player.getUniqueId())) {
return PLAYER_LOCALE.get(player.getUniqueId());
}
return null;
}
public static void addLocale(UUID uuid, String locale) {
if (PLAYER_LOCALE == null) {
PLAYER_LOCALE = new ConcurrentHashMap<>();
}
PLAYER_LOCALE.put(uuid, locale);
}
/**
* Returns the AuthMe messages file language code, by given locale and settings.
* Dreeam - Hard mapping, based on mc1.20.6, 5/29/2024
*
* @param locale The locale that player client setting uses.
* @param settings The AuthMe settings, for default/fallback language usage.
*/
public static String localeToCode(String locale, Settings settings) {
// Certain locale code to AuthMe language code redirect
if (!settings.getProperty(PluginSettings.I18N_CODE_REDIRECT).isEmpty()) {
for (String raw : settings.getProperty(PluginSettings.I18N_CODE_REDIRECT)) {
String[] split = raw.split(":");
if (split.length == 2 && locale.equalsIgnoreCase(split[0])) {
return split[1];
}
}
}
// Match certain locale code
if (LOCALE_MAP.containsKey(locale)) {
return LOCALE_MAP.get(locale);
}
if (locale.contains("_")) {
locale = locale.substring(0, locale.indexOf("_"));
}
// Match locale code with "_"
if (LOCALE_LIST.contains(locale)) {
return locale;
}
return settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
}
}