Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions src/main/java/me/icegames/iglanguages/command/LangCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,36 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
}

if (args[0].equalsIgnoreCase("reload")) {
plugin.reloadConfig();
langManager.loadAll();
langManager.clearCache();
langManager.reload();
if (plugin.getProtocolLibHook() != null) {
plugin.getProtocolLibHook().clearCache();
}
String consolePrefix = "\u001B[1;30m[\u001B[0m\u001B[36mI\u001B[1;36mG\u001B[0m\u001B[1;37m" + "Languages" + "\u001B[1;30m]\u001B[0m ";
System.out.println(consolePrefix + "Reloaded " + langManager.getAvailableLangs().size() + " languages! " + langManager.getAvailableLangs());
System.out.println(consolePrefix + "Reloaded " + langManager.getTotalTranslationsCount() + " total translations!");
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(), "reload_success"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(), "reload_success", langManager.isUseLegacyFormat()));
return true;
}

if (args[0].equalsIgnoreCase("set")) {
if (args.length == 3) {
Player target = Bukkit.getPlayer(args[1]);
if (target == null) {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"player_not_found"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"player_not_found", langManager.isUseLegacyFormat()));
return true;
}
String lang = args[2];
List<String> availableLangs = langManager.getAvailableLangs();
if (!availableLangs.contains(lang)) {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"invalid_lang", "{lang}", lang, "{langs}", String.join(", ", availableLangs)));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"invalid_lang", langManager.isUseLegacyFormat(), "{lang}", lang, "{langs}", String.join(", ", availableLangs)));
return true;
}
langManager.setPlayerLang(target.getUniqueId(), lang);
langManager.savePlayerLang(target.getUniqueId());
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"set_success", "{player}", target.getName(), "{lang}", lang));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"set_success", langManager.isUseLegacyFormat(), "{player}", target.getName(), "{lang}", lang));
actionsManager.executeActionsOnSet(target, lang);
} else {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"set_usage"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"set_usage", langManager.isUseLegacyFormat()));
}
return true;
}
Expand All @@ -95,44 +93,44 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
if (args.length == 2) {
Player target = Bukkit.getPlayer(args[1]);
if (target == null) {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"player_not_found"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"player_not_found", langManager.isUseLegacyFormat()));
return true;
}
String lang = langManager.getPlayerLang(target.getUniqueId());
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"get_success", "{player}", target.getName(), "{lang}", lang));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"get_success", langManager.isUseLegacyFormat(), "{player}", target.getName(), "{lang}", lang));
} else {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"get_usage"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"get_usage", langManager.isUseLegacyFormat()));
}
return true;
}

if (args[0].equalsIgnoreCase("list")) {
List<String> langs = langManager.getAvailableLangs();
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"list_languages", "{langs}", String.join(", ", langs)));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"list_languages", langManager.isUseLegacyFormat(), "{langs}", String.join(", ", langs)));
return true;
}

if (args[0].equalsIgnoreCase("auto")) {
if (args.length == 2) {
Player target = Bukkit.getPlayer(args[1]);
if (target == null) {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"player_not_found"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"player_not_found", langManager.isUseLegacyFormat()));
return true;
}
String selectedLang = langManager.detectClientLanguage(target);
langManager.setPlayerLang(target.getUniqueId(), selectedLang);
langManager.savePlayerLang(target.getUniqueId());
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(), "set_success", "{player}", target.getName(), "{lang}", selectedLang));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(), "set_success", langManager.isUseLegacyFormat(), "{player}", target.getName(), "{lang}", selectedLang));
actionsManager.executeActionsOnSet(target, selectedLang);
return true;
}
else {
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"get_usage"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"get_usage", langManager.isUseLegacyFormat()));
}
return true;
}

sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"unknown_subcommand"));
sender.sendMessage(MessageUtil.getMessage(plugin.getMessagesConfig(),"unknown_subcommand", langManager.isUseLegacyFormat()));
return true;
}
}
15 changes: 11 additions & 4 deletions src/main/java/me/icegames/iglanguages/manager/LangManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class LangManager {
private final Cache<String, CachedTranslation> translationCache;
private final Cache<String, String> parsedMessageCache;
private final String defaultLang;
private boolean useLegacyFormat;

// Patterns for placeholder detection and parsing
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("%[^%]+%");
Expand Down Expand Up @@ -121,6 +122,7 @@ public LangManager(IGLanguages plugin, PlayerLangStorage storage) {
this.plugin = plugin;
this.playerLangStorage = storage;
this.defaultLang = plugin.getConfig().getString("defaultLang");
this.useLegacyFormat = plugin.getConfig().getBoolean("performance.useLegacyFormat", false);

int cacheSize = plugin.getConfig().getInt("performance.translationCacheSize", 500);
this.translationCache = Caffeine.newBuilder()
Expand Down Expand Up @@ -250,6 +252,7 @@ private void loadLangFilesRecursively(File rootDir, File currentDir, Map<String,

public void reload() {
plugin.reloadConfig();
this.useLegacyFormat = plugin.getConfig().getBoolean("performance.useLegacyFormat", false);
loadAll();
clearCache();
plugin.getLogger().info("Reloaded language manager.");
Expand Down Expand Up @@ -352,7 +355,7 @@ public String getTranslation(Player player, String keyWithArgs) {
CachedTranslation cached = getCachedTranslation(lang, parsed.key);

if (cached == null) {
return MessageUtil.getMessage(plugin.getMessagesConfig(), "translation_not_found", "{key}", parsed.key);
return MessageUtil.getMessage(plugin.getMessagesConfig(), "translation_not_found", useLegacyFormat, "{key}", parsed.key);
}

// Fast path: If no placeholders and no args, return pre-colorized content immediately
Expand Down Expand Up @@ -417,10 +420,10 @@ public String getLangTranslation(String lang, String keyWithArgs) {
String translation = langMap.getOrDefault(parsed.key.toLowerCase(), defaultMap.get(parsed.key.toLowerCase()));

if (translation == null) {
return MessageUtil.getMessage(plugin.getMessagesConfig(), "translation_not_found", "{key}", parsed.key);
return MessageUtil.getMessage(plugin.getMessagesConfig(), "translation_not_found", useLegacyFormat, "{key}", parsed.key);
}

return applyArgs(MessageUtil.colorize(translation), parsed.args);
return applyArgs(MessageUtil.colorize(translation, useLegacyFormat), parsed.args);
}

public String detectClientLanguage(Player player) {
Expand All @@ -436,6 +439,10 @@ public String detectClientLanguage(Player player) {
return defaultLang;
}

public boolean isUseLegacyFormat() {
return useLegacyFormat;
}

public void clearCache() {
translationCache.invalidateAll();
parsedMessageCache.invalidateAll();
Expand All @@ -458,7 +465,7 @@ private CachedTranslation getCachedTranslation(String lang, String key) {
String translation = langMap.getOrDefault(key.toLowerCase(), defaultMap.get(key.toLowerCase()));

if (translation != null) {
String colorized = MessageUtil.colorize(translation);
String colorized = MessageUtil.colorize(translation, useLegacyFormat);
boolean hasPlaceholders = containsPlaceholders(colorized);
cached = new CachedTranslation(colorized, hasPlaceholders);
translationCache.put(cacheKey, cached);
Expand Down
42 changes: 26 additions & 16 deletions src/main/java/me/icegames/iglanguages/util/MessageUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public class MessageUtil {
private static final Pattern HEX_PATTERN = Pattern.compile("(?:&\\{#|<#|\\{#|&#|#)([A-Fa-f0-9]{6})(?:\\}|>|)");

public static String getMessage(FileConfiguration messageConfig, String path, String... placeholders) {
return getMessage(messageConfig, path, false, placeholders);
}

public static String getMessage(FileConfiguration messageConfig, String path, boolean useLegacyFormat, String... placeholders) {
Object messageObj = messageConfig.get(path);
String message;
String prefix = messageConfig.getString("prefix", "");
Expand All @@ -34,7 +38,7 @@ public static String getMessage(FileConfiguration messageConfig, String path, St
message = String.join("\n", messageList);
} else {
message = "&cMessage '" + path + "' not found in messages.yml.";
return colorize(message);
return colorize(message, useLegacyFormat);
}

for (int i = 0; i < placeholders.length; i += 2) {
Expand All @@ -44,31 +48,37 @@ public static String getMessage(FileConfiguration messageConfig, String path, St
}

String finalMessage = prefix + message;
return colorize(finalMessage);
return colorize(finalMessage, useLegacyFormat);
}

public static String colorize(String message) {
return colorize(message, false);
}

public static String colorize(String message, boolean useLegacyFormat) {
if (message == null || message.isEmpty())
return message;

String miniMessageParsed = MiniMessageWrapper.tryParse(message);
if (miniMessageParsed != null) {
message = miniMessageParsed;
}
if (!useLegacyFormat) {
String miniMessageParsed = MiniMessageWrapper.tryParse(message);
if (miniMessageParsed != null) {
message = miniMessageParsed;
}

Matcher matcher = HEX_PATTERN.matcher(message);
StringBuffer buffer = new StringBuffer();
Matcher matcher = HEX_PATTERN.matcher(message);
StringBuffer buffer = new StringBuffer();

while (matcher.find()) {
String hexCode = matcher.group(1);
StringBuilder replacement = new StringBuilder("§x");
for (char c : hexCode.toCharArray()) {
replacement.append('§').append(c);
while (matcher.find()) {
String hexCode = matcher.group(1);
StringBuilder replacement = new StringBuilder("§x");
for (char c : hexCode.toCharArray()) {
replacement.append('§').append(c);
}
matcher.appendReplacement(buffer, replacement.toString());
}
matcher.appendReplacement(buffer, replacement.toString());
matcher.appendTail(buffer);
message = buffer.toString();
}
matcher.appendTail(buffer);
message = buffer.toString();

return ChatColor.translateAlternateColorCodes('&', message);
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ performance:
# This is the L1 cache for translation lookups
translationCacheSize: 500

# If true, color commands like gradients or hex codes are passed 1 to 1 (Legacy Format).
# If false, MiniMessage and Hex codes will be parsed immediately.
useLegacyFormat: false

# ProtocolLib packet interception
# Translates %lang_*% placeholders in outgoing packets (chat, titles, scoreboard, etc.)
# Requires ProtocolLib to be installed
Expand Down