diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 6290f8acb..d5adf258d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -55,6 +55,7 @@ import com.velocitypowered.proxy.protocol.util.GameProfileSerializer; import com.velocitypowered.proxy.scheduler.VelocityScheduler; import com.velocitypowered.proxy.server.ServerMap; import com.velocitypowered.proxy.util.AddressUtil; +import com.velocitypowered.proxy.util.ClosestLocaleMatcher; import com.velocitypowered.proxy.util.EncryptionUtils; import com.velocitypowered.proxy.util.FileSystemUtils; import com.velocitypowered.proxy.util.VelocityChannelRegistrar; @@ -272,6 +273,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { translationRegistry.registerAll(locale, ResourceBundle.getBundle("com/velocitypowered/proxy/l10n/messages", locale, UTF8ResourceBundleControl.get()), false); + ClosestLocaleMatcher.INSTANCE.registerKnown(locale); }); } catch (IOException e) { logger.error("Encountered an I/O error whilst loading translations", e); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index ca15b0bdd..8384f23ff 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -68,6 +68,7 @@ import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.server.VelocityRegisteredServer; import com.velocitypowered.proxy.tablist.VelocityTabList; import com.velocitypowered.proxy.tablist.VelocityTabListLegacy; +import com.velocitypowered.proxy.util.ClosestLocaleMatcher; import com.velocitypowered.proxy.util.DurationUtils; import com.velocitypowered.proxy.util.collect.CappedSet; import io.netty.buffer.ByteBufUtil; @@ -268,7 +269,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } public Component translateMessage(Component message) { - Locale locale = this.settings == null ? Locale.getDefault() : this.settings.getLocale(); + Locale locale = ClosestLocaleMatcher.INSTANCE + .lookupClosest(this.settings == null ? Locale.getDefault() : this.settings.getLocale()); return GlobalTranslator.render(message, locale); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialInboundConnection.java index 1c7656f0f..c094cc90a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialInboundConnection.java @@ -23,6 +23,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.Handshake; +import com.velocitypowered.proxy.util.ClosestLocaleMatcher; import java.net.InetSocketAddress; import java.util.Locale; import java.util.Optional; @@ -78,7 +79,8 @@ public final class InitialInboundConnection implements InboundConnection, * @param reason the reason for disconnecting */ public void disconnect(Component reason) { - Component translated = GlobalTranslator.render(reason, Locale.getDefault()); + Component translated = GlobalTranslator.render(reason, ClosestLocaleMatcher.INSTANCE + .lookupClosest(Locale.getDefault())); logger.info("{} has disconnected: {}", this, LegacyComponentSerializer.legacySection().serialize(translated)); @@ -90,7 +92,8 @@ public final class InitialInboundConnection implements InboundConnection, * @param reason the reason for disconnecting */ public void disconnectQuietly(Component reason) { - Component translated = GlobalTranslator.render(reason, Locale.getDefault()); + Component translated = GlobalTranslator.render(reason, ClosestLocaleMatcher.INSTANCE + .lookupClosest(Locale.getDefault())); connection.closeWith(Disconnect.create(translated, getProtocolVersion())); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java index 727ff1e92..fe38209d3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java @@ -24,6 +24,7 @@ import com.velocitypowered.api.permission.PermissionFunction; import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.util.ClosestLocaleMatcher; import java.util.List; import java.util.Locale; import net.kyori.adventure.identity.Identity; @@ -59,7 +60,8 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons @Override public void sendMessage(@NonNull Identity identity, @NonNull Component message) { - Component translated = GlobalTranslator.render(message, Locale.getDefault()); + Component translated = GlobalTranslator.render(message, ClosestLocaleMatcher.INSTANCE + .lookupClosest(Locale.getDefault())); logger.info(LegacyComponentSerializer.legacySection().serialize(translated)); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/ClosestLocaleMatcher.java b/proxy/src/main/java/com/velocitypowered/proxy/util/ClosestLocaleMatcher.java new file mode 100644 index 000000000..da3bc4e01 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/ClosestLocaleMatcher.java @@ -0,0 +1,35 @@ +package com.velocitypowered.proxy.util; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ClosestLocaleMatcher { + public static final ClosestLocaleMatcher INSTANCE = new ClosestLocaleMatcher(); + + private final Map byLanguage; + private final LoadingCache closest; + + private ClosestLocaleMatcher() { + this.byLanguage = new ConcurrentHashMap<>(); + this.closest = Caffeine.newBuilder() + .build(sublocale -> { + final String tag = sublocale.getLanguage(); + return byLanguage.getOrDefault(tag, sublocale); + }); + } + + public void registerKnown(final Locale locale) { + if (locale.getLanguage().equals(new Locale("zh").getLanguage())) { + return; + } + + this.byLanguage.put(locale.getLanguage(), locale); + } + + public Locale lookupClosest(final Locale locale) { + return closest.get(locale); + } +}