diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index 7b9324d121d3..8eb7b3824973 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -3275,6 +3276,23 @@ default boolean hasResourcePack() { */ java.util.Locale locale(); // Paper end + + /** + * Returns the locale the server will use to send messages translated via the Adventure global translator. + * By default, the value of {@link Player#locale()} is used. + * + * @return the locale. + */ + Locale getEffectiveLocale(); + + /** + * Change the locale the server will be translating its messages to. + * If set, the effective locale overrides the client locale for server-side translations. + * + * @param locale the locale to translate to + */ + void setEffectiveLocale(@Nullable Locale locale); + /** * Gets the player's estimated ping in milliseconds. * diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index a19f70a2559d..2ce663b13e76 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -1,12 +1,14 @@ --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -235,7 +_,8 @@ +@@ -235,7 +_,10 @@ private int levitationStartTime; private boolean disconnected; private int requestedViewDistance = 2; - public String language = "en_us"; + public String language = null; // Paper - default to null + public java.util.Locale adventure$locale = java.util.Locale.US; // Paper ++ @Nullable ++ public java.util.Locale effectiveLocale = null; // Paper @Nullable private Vec3 startingToFallPosition; @Nullable diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index 2ff7ea70fa34..c10234487e99 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -42,7 +42,7 @@ @Override public void handleClientInformation(ServerboundClientInformationPacket packet) { this.clientInformation = packet.information(); -+ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper ++ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(player.effectiveLocale != null ? player.effectiveLocale : net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper } @Override diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 8d173d9bbd39..6be62c080696 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -2513,7 +2513,7 @@ + // Paper end - do not accept invalid information boolean isModelPartShown = this.player.isModelPartShown(PlayerModelPart.HAT); this.player.updateOptions(packet.information()); -+ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper ++ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(player.effectiveLocale != null ? player.effectiveLocale : net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper if (this.player.isModelPartShown(PlayerModelPart.HAT) != isModelPartShown) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index df6612a86f7b..ba3d491a22e7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -2996,6 +2996,25 @@ public java.util.Locale locale() { return getHandle().adventure$locale; } // Paper end + + + @Override + public java.util.Locale getEffectiveLocale() { + if (getHandle().effectiveLocale == null) { + return locale(); + } + return getHandle().effectiveLocale; + } + + @Override + public void setEffectiveLocale(final java.util.Locale locale) { + getHandle().effectiveLocale = locale; + + if (getHandle().connection != null) { + getHandle().connection.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(getEffectiveLocale()); + } + } + @Override public int getPing() { return this.getHandle().connection.latency();