Add localization support. Fixes #230

This is less flexible, but it is an Adventure-native solution and doesn't require an onerous amount of work to maintain.
This commit is contained in:
Andrew Steinborn
2021-04-17 08:30:31 -04:00
parent 5d07c29cf6
commit c0b6f461cb
15 changed files with 247 additions and 196 deletions

View File

@@ -78,6 +78,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@@ -90,7 +91,11 @@ import java.util.function.IntFunction;
import java.util.stream.Collectors;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.translation.GlobalTranslator;
import net.kyori.adventure.translation.TranslationRegistry;
import net.kyori.adventure.util.UTF8ResourceBundleControl;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.asynchttpclient.AsyncHttpClient;
@@ -193,6 +198,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
logger.info("Booting up {} {}...", version().getName(), version().getVersion());
console.setupStreams();
registerTranslations();
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
cm.logChannelInformation();
@@ -236,6 +243,15 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
Metrics.VelocityMetrics.startMetrics(this, configuration.getMetrics());
}
private void registerTranslations() {
final TranslationRegistry translationRegistry = TranslationRegistry
.create(Key.key("velocity", "translations"));
translationRegistry.registerAll(Locale.US,
ResourceBundle.getBundle("com/velocitypowered/proxy/messages", Locale.US,
UTF8ResourceBundleControl.get()), false);
GlobalTranslator.get().addSource(translationRegistry);
}
@SuppressFBWarnings("DM_EXIT")
private void doStartupConfigLoad() {
try {

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.velocitypowered.proxy.command.builtin;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.NamedTextColor;
public class CommandMessages {
public static final TranslatableComponent PLAYERS_ONLY = Component.translatable(
"velocity.command.players-only", NamedTextColor.RED);
public static final TranslatableComponent SERVER_DOES_NOT_EXIST = Component.translatable(
"velocity.command.server-does-not-exist", NamedTextColor.RED);
}

View File

@@ -78,11 +78,7 @@ public class GlistCommand {
final CommandSource source = context.getSource();
sendTotalProxyCount(source);
source.sendMessage(Identity.nil(),
Component.text().content("To view all players on servers, use ")
.color(NamedTextColor.YELLOW)
.append(Component.text("/glist all", NamedTextColor.DARK_AQUA))
.append(Component.text(".", NamedTextColor.YELLOW))
.build());
Component.translatable("velocity.command.glist-view-all", NamedTextColor.YELLOW));
return 1;
}
@@ -98,7 +94,7 @@ public class GlistCommand {
Optional<RegisteredServer> registeredServer = server.server(serverName);
if (!registeredServer.isPresent()) {
source.sendMessage(Identity.nil(),
Component.text("Server " + serverName + " doesn't exist.", NamedTextColor.RED));
CommandMessages.SERVER_DOES_NOT_EXIST.args(Component.text(serverName)));
return -1;
}
sendServerPlayers(source, registeredServer.get(), false);
@@ -107,10 +103,19 @@ public class GlistCommand {
}
private void sendTotalProxyCount(CommandSource target) {
int online = server.countConnectedPlayers();
target.sendMessage(Identity.nil(), Component.text()
.content("There are ").color(NamedTextColor.YELLOW)
.append(Component.text(server.connectedPlayers().size(), NamedTextColor.GREEN))
.append(Component.text(" player(s) online.", NamedTextColor.YELLOW))
.append(Component.text(Integer.toString(online), NamedTextColor.GREEN))
.append(Component.space())
.append(Component.translatable(
online == 1
? "velocity.command.glist-player-singular"
: "velocity.command.glist-player-plural",
NamedTextColor.YELLOW
))
.append(Component.space())
.append(Component.translatable("velocity.command.glist-total-suffix",
NamedTextColor.YELLOW))
.build());
}

View File

@@ -35,6 +35,7 @@ import java.util.stream.Stream;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
@@ -53,8 +54,7 @@ public class ServerCommand implements SimpleCommand {
final String[] args = invocation.arguments();
if (!(source instanceof Player)) {
source.sendMessage(Identity.nil(), Component.text("Only players may run this command.",
NamedTextColor.RED));
source.sendMessage(Identity.nil(), CommandMessages.PLAYERS_ONLY);
return;
}
@@ -64,8 +64,8 @@ public class ServerCommand implements SimpleCommand {
String serverName = args[0];
Optional<RegisteredServer> toConnect = server.server(serverName);
if (!toConnect.isPresent()) {
player.sendMessage(Identity.nil(),
Component.text("Server " + serverName + " doesn't exist.", NamedTextColor.RED));
player.sendMessage(Identity.nil(), CommandMessages.SERVER_DOES_NOT_EXIST
.args(Component.text(serverName)));
return;
}
@@ -78,19 +78,23 @@ public class ServerCommand implements SimpleCommand {
private void outputServerInformation(Player executor) {
String currentServer = executor.connectedServer().map(ServerConnection::serverInfo)
.map(ServerInfo::name).orElse("<unknown>");
executor.sendMessage(Identity.nil(), Component.text(
"You are currently connected to " + currentServer + ".", NamedTextColor.YELLOW));
executor.sendMessage(Identity.nil(), Component.translatable(
"velocity.command.server-current-server",
NamedTextColor.YELLOW,
Component.text(currentServer)));
List<RegisteredServer> servers = BuiltinCommandUtil.sortedServerList(server);
if (servers.size() > MAX_SERVERS_TO_LIST) {
executor.sendMessage(Identity.nil(), Component.text(
"Too many servers to list. Tab-complete to show all servers.", NamedTextColor.RED));
executor.sendMessage(Identity.nil(), Component.translatable(
"velocity.command.server-too-many", NamedTextColor.RED));
return;
}
// Assemble the list of servers as components
TextComponent.Builder serverListBuilder = Component.text().content("Available servers: ")
.color(NamedTextColor.YELLOW);
TextComponent.Builder serverListBuilder = Component.text()
.append(Component.translatable("velocity.command.server-available",
NamedTextColor.YELLOW))
.append(Component.space());
for (int i = 0; i < servers.size(); i++) {
RegisteredServer rs = servers.get(i);
serverListBuilder.append(formatServerComponent(currentServer, rs));
@@ -106,17 +110,31 @@ public class ServerCommand implements SimpleCommand {
ServerInfo serverInfo = server.serverInfo();
TextComponent serverTextComponent = Component.text(serverInfo.name());
String playersText = server.connectedPlayers().size() + " player(s) online";
int connectedPlayers = server.connectedPlayers().size();
TranslatableComponent playersTextComponent;
if (connectedPlayers == 1) {
playersTextComponent = Component.translatable("velocity.command.server-tooltip-player-online");
} else {
playersTextComponent = Component.translatable("velocity.command.server-tooltip-players-online");
}
playersTextComponent = playersTextComponent.args(Component.text(connectedPlayers));
if (serverInfo.name().equals(currentPlayerServer)) {
serverTextComponent = serverTextComponent.color(NamedTextColor.GREEN)
.hoverEvent(
showText(Component.text("Currently connected to this server\n" + playersText))
showText(
Component.translatable("velocity.command.server-tooltip-current-server")
.append(Component.newline())
.append(playersTextComponent))
);
} else {
serverTextComponent = serverTextComponent.color(NamedTextColor.GRAY)
.clickEvent(ClickEvent.runCommand("/server " + serverInfo.name()))
.hoverEvent(
showText(Component.text("Click to connect to this server\n" + playersText))
showText(
Component.translatable("velocity.command.server-tooltip-offer-connect-server")
.append(Component.newline())
.append(playersTextComponent))
);
}
return serverTextComponent;

View File

@@ -17,7 +17,6 @@
package com.velocitypowered.proxy.command.builtin;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -49,6 +48,7 @@ import java.util.stream.Collectors;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
@@ -180,17 +180,15 @@ public class VelocityCommand implements SimpleCommand {
public void execute(CommandSource source, String @NonNull [] args) {
try {
if (server.reloadConfiguration()) {
source.sendMessage(Identity.nil(), Component.text(
"Configuration reloaded.", NamedTextColor.GREEN));
source.sendMessage(Component.translatable("velocity.command.reload-success",
NamedTextColor.GREEN));
} else {
source.sendMessage(Identity.nil(), Component.text(
"Unable to reload your configuration. Check the console for more details.",
source.sendMessage(Component.translatable("velocity.command.reload-failure",
NamedTextColor.RED));
}
} catch (Exception e) {
logger.error("Unable to reload configuration", e);
source.sendMessage(Identity.nil(), Component.text(
"Unable to reload your configuration. Check the console for more details.",
source.sendMessage(Component.translatable("velocity.command.reload-failure",
NamedTextColor.RED));
}
}
@@ -219,33 +217,35 @@ public class VelocityCommand implements SimpleCommand {
ProxyVersion version = server.version();
TextComponent velocity = Component.text().content(version.getName() + " ")
Component velocity = Component.text().content(version.getName() + " ")
.decoration(TextDecoration.BOLD, true)
.color(VELOCITY_COLOR)
.append(Component.text(version.getVersion()).decoration(TextDecoration.BOLD, false))
.build();
TextComponent copyright = Component
.text("Copyright 2018-2020 " + version.getVendor() + ". " + version.getName()
+ " is licensed under the terms of the GNU General Public License v3.");
Component copyright = Component
.translatable("velocity.command.version-copyright",
Component.text(version.getVendor()),
Component.text(version.getName()));
source.sendMessage(Identity.nil(), velocity);
source.sendMessage(Identity.nil(), copyright);
if (version.getName().equals("Velocity")) {
TextComponent velocityWebsite = Component.text()
.content("Visit the ")
.append(Component.text().content("Velocity website")
TextComponent embellishment = Component.text()
.append(Component.text().content("velocitypowered.com")
.color(NamedTextColor.GREEN)
.decoration(TextDecoration.UNDERLINED, true)
.clickEvent(
ClickEvent.openUrl("https://www.velocitypowered.com"))
.build())
.append(Component.text(" or the "))
.append(Component.text().content("Velocity GitHub")
.append(Component.text(" - "))
.append(Component.text().content("GitHub")
.color(NamedTextColor.GREEN)
.decoration(TextDecoration.UNDERLINED, true)
.clickEvent(ClickEvent.openUrl(
"https://github.com/VelocityPowered/Velocity"))
.build())
.build();
source.sendMessage(Identity.nil(), velocityWebsite);
source.sendMessage(Identity.nil(), embellishment);
}
}
@@ -274,12 +274,13 @@ public class VelocityCommand implements SimpleCommand {
int pluginCount = plugins.size();
if (pluginCount == 0) {
source.sendMessage(Identity.nil(), Component.text(
"No plugins installed.", NamedTextColor.YELLOW));
source.sendMessage(Component.translatable("velocity.command.no-plugins",
NamedTextColor.YELLOW));
return;
}
TextComponent.Builder output = Component.text().content("Plugins: ")
TranslatableComponent.Builder output = Component.translatable()
.key("velocity.command.plugins-list")
.color(NamedTextColor.YELLOW);
for (int i = 0; i < pluginCount; i++) {
PluginContainer plugin = plugins.get(i);
@@ -300,15 +301,21 @@ public class VelocityCommand implements SimpleCommand {
description.url().ifPresent(url -> {
hoverText.append(Component.newline());
hoverText.append(Component.text("Website: " + url));
hoverText.append(Component.translatable(
"velocity.command.plugin-tooltip-website",
Component.text(url)));
});
if (!description.authors().isEmpty()) {
hoverText.append(Component.newline());
if (description.authors().size() == 1) {
hoverText.append(Component.text("Author: " + description.authors().get(0)));
hoverText.append(Component.translatable("velocity.command.plugin-tooltip-author",
Component.text(description.authors().get(0))));
} else {
hoverText.append(Component.text("Authors: " + Joiner.on(", ")
.join(description.authors())));
hoverText.append(
Component.translatable("velocity.command.plugin-tooltip-author",
Component.text(String.join(", ", description.authors()))
)
);
}
}
description.description().ifPresent(pdesc -> {
@@ -352,8 +359,8 @@ public class VelocityCommand implements SimpleCommand {
JsonArray connectOrder = new JsonArray();
List<String> attemptedConnectionOrder = ImmutableList.copyOf(
server.configuration().getAttemptConnectionOrder());
for (int i = 0; i < attemptedConnectionOrder.size(); i++) {
connectOrder.add(attemptedConnectionOrder.get(i));
for (String s : attemptedConnectionOrder) {
connectOrder.add(s);
}
JsonObject proxyConfig = InformationUtils.collectProxyConfig(server.configuration());
@@ -446,7 +453,7 @@ public class VelocityCommand implements SimpleCommand {
e.getCause().printStackTrace();
} catch (JsonParseException e) {
source.sendMessage(Component.text()
.content("An error occurred on the Velocity-servers and the dump could not "
.content("An error occurred on the Velocity servers and the dump could not "
+ "be completed. Please contact the Velocity staff about this problem. "
+ "If you do, provide the details about this error from the Velocity "
+ "console or server log.")

View File

@@ -45,7 +45,6 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.apache.logging.log4j.LogManager;
@@ -72,25 +71,23 @@ public class VelocityConfiguration implements ProxyConfig {
@Expose private final Advanced advanced;
@Expose private final Query query;
private final Metrics metrics;
private final Messages messages;
private net.kyori.adventure.text.@MonotonicNonNull Component motdAsComponent;
private @Nullable Favicon favicon;
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
Query query, Metrics metrics, Messages messages) {
Query query, Metrics metrics) {
this.servers = servers;
this.forcedHosts = forcedHosts;
this.advanced = advanced;
this.query = query;
this.metrics = metrics;
this.messages = messages;
}
private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
boolean preventClientProxyConnections, boolean announceForge,
PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough, Servers servers,
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics, Messages messages) {
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics) {
this.bind = bind;
this.motd = motd;
this.showMaxPlayers = showMaxPlayers;
@@ -106,7 +103,6 @@ public class VelocityConfiguration implements ProxyConfig {
this.advanced = advanced;
this.query = query;
this.metrics = metrics;
this.messages = messages;
}
/**
@@ -373,10 +369,6 @@ public class VelocityConfiguration implements ProxyConfig {
return advanced.isLogCommandExecutions();
}
public Messages getMessages() {
return messages;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
@@ -450,7 +442,6 @@ public class VelocityConfiguration implements ProxyConfig {
CommentedConfig advancedConfig = config.get("advanced");
CommentedConfig queryConfig = config.get("query");
CommentedConfig metricsConfig = config.get("metrics");
CommentedConfig messagesConfig = config.get("messages");
PlayerInfoForwarding forwardingMode = config.getEnumOrElse("player-info-forwarding-mode",
PlayerInfoForwarding.NONE);
PingPassthroughMode pingPassthroughMode = config.getEnumOrElse("ping-passthrough",
@@ -480,8 +471,7 @@ public class VelocityConfiguration implements ProxyConfig {
new ForcedHosts(forcedHostsConfig),
new Advanced(advancedConfig),
new Query(queryConfig),
new Metrics(metricsConfig),
new Messages(messagesConfig, defaultConfig.get("messages"))
new Metrics(metricsConfig)
);
}
@@ -793,73 +783,4 @@ public class VelocityConfiguration implements ProxyConfig {
return enabled;
}
}
public static class Messages {
private final CommentedConfig toml;
private final CommentedConfig defaultToml;
private final String kickPrefix;
private final String disconnectPrefix;
private final String onlineModeOnly;
private final String noAvailableServers;
private final String alreadyConnected;
private final String movedToNewServerPrefix;
private final String genericConnectionError;
private Messages(CommentedConfig toml, CommentedConfig defaultToml) {
this.toml = toml;
this.defaultToml = defaultToml;
this.kickPrefix = getString("kick-prefix");
this.disconnectPrefix = getString("disconnect-prefix");
this.onlineModeOnly = getString("online-mode-only");
this.noAvailableServers = getString("no-available-servers");
this.alreadyConnected = getString("already-connected");
this.movedToNewServerPrefix = getString("moved-to-new-server-prefix");
this.genericConnectionError = getString("generic-connection-error");
}
private String getString(String path) {
String def = defaultToml.getOrElse(path, "");
if (toml == null) {
return def;
}
return toml.getOrElse(path, def);
}
public Component getKickPrefix(String server) {
return deserialize(String.format(kickPrefix, server));
}
public Component getDisconnectPrefix(String server) {
return deserialize(String.format(disconnectPrefix, server));
}
public Component getOnlineModeOnly() {
return deserialize(onlineModeOnly);
}
public Component getNoAvailableServers() {
return deserialize(noAvailableServers);
}
public Component getAlreadyConnected() {
return deserialize(alreadyConnected);
}
public Component getMovedToNewServerPrefix() {
return deserialize(movedToNewServerPrefix);
}
public Component getGenericConnectionError() {
return deserialize(genericConnectionError);
}
private Component deserialize(String str) {
if (str.startsWith("{")) {
return GsonComponentSerializer.gson().deserialize(str);
}
return LegacyComponentSerializer.legacyAmpersand().deserialize(str);
}
}
}

View File

@@ -50,8 +50,8 @@ import net.kyori.adventure.text.TextComponent;
public class LoginSessionHandler implements MinecraftSessionHandler {
private static final TextComponent MODERN_IP_FORWARDING_FAILURE = Component
.text("Your server did not send a forwarding request to the proxy. Is it set up correctly?");
private static final Component MODERN_IP_FORWARDING_FAILURE = Component
.translatable("velocity.error.modern-forwarding-failed");
private final VelocityServer server;
private final VelocityServerConnection serverConn;

View File

@@ -168,9 +168,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
.exceptionally(e -> {
logger.info("Exception occurred while running command for {}",
player.username(), e);
player.sendMessage(Identity.nil(),
Component.text("An error occurred while running this command.",
NamedTextColor.RED));
player.sendMessage(Component.translatable("velocity.command.generic-error",
NamedTextColor.RED));
return null;
});
} else {
@@ -335,7 +334,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
@Override
public void exception(Throwable throwable) {
player.disconnect(server.configuration().getMessages().getGenericConnectionError());
player.disconnect(Component.translatable("velocity.error.player-connection-error",
NamedTextColor.RED));
}
@Override

View File

@@ -446,18 +446,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
wrapped = cause;
}
}
String userMessage;
Component friendlyError;
if (connectedServer != null && connectedServer.serverInfo().equals(server.serverInfo())) {
userMessage = "Your connection to " + server.serverInfo().name() + " encountered an "
+ "error.";
friendlyError = Component.translatable("velocity.error.connected-server-error",
Component.text(server.serverInfo().name()));
} else {
logger.error("{}: unable to connect to server {}", this, server.serverInfo().name(),
wrapped);
userMessage = "Unable to connect to " + server.serverInfo().name() + ". Try again "
+ "later.";
friendlyError = Component.translatable("velocity.error.connecting-server-error",
Component.text(server.serverInfo().name()));
}
handleConnectionException(server, null, Component.text(userMessage,
NamedTextColor.RED), safe);
handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe);
}
/**
@@ -473,26 +473,22 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
return;
}
VelocityConfiguration.Messages messages = this.server.configuration().getMessages();
Component disconnectReason = GsonComponentSerializer.gson().deserialize(disconnect.getReason());
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
if (connectedServer != null && connectedServer.serverInfo().equals(server.serverInfo())) {
logger.error("{}: kicked from server {}: {}", this, server.serverInfo().name(),
plainTextReason);
handleConnectionException(server, disconnectReason, Component.text()
.append(messages.getKickPrefix(server.serverInfo().name())
.colorIfAbsent(NamedTextColor.RED))
.color(NamedTextColor.RED)
.append(disconnectReason)
.build(), safe);
handleConnectionException(server, disconnectReason,
Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED,
Component.text(server.serverInfo().name()),
disconnectReason), safe);
} else {
logger.error("{}: disconnected while connecting to {}: {}", this,
server.serverInfo().name(), plainTextReason);
handleConnectionException(server, disconnectReason, Component.text()
.append(messages.getDisconnectPrefix(server.serverInfo().name())
.colorIfAbsent(NamedTextColor.RED))
.append(disconnectReason)
.build(), safe);
handleConnectionException(server, disconnectReason,
Component.translatable("velocity.error.cant-connect", NamedTextColor.RED,
Component.text(server.serverInfo().name()),
disconnectReason), safe);
}
}
@@ -576,8 +572,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
protocolVersion()), ((Impl) status).isSafe());
break;
case SUCCESS:
sendMessage(Identity.nil(), server.configuration().getMessages()
.getMovedToNewServerPrefix().append(friendlyReason));
sendMessage(Component.translatable("velocity.error.moved-to-new-server",
NamedTextColor.RED,
Component.text(originalEvent.server().serverInfo().name()),
friendlyReason));
break;
default:
// The only remaining value is successful (no need to do anything!)

View File

@@ -70,7 +70,10 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
@Override
public boolean handle(LegacyHandshakePacket packet) {
connection.closeWith(LegacyDisconnectPacket
.from(Component.text("Your client is old, please upgrade!", NamedTextColor.RED)));
.from(Component.text(
"Your client is extremely old. Please update to a newer version of Minecraft.",
NamedTextColor.RED)
));
return true;
}
@@ -122,7 +125,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
InetAddress address = ((InetSocketAddress) connection.getRemoteAddress()).getAddress();
if (!server.getIpAttemptLimiter().attempt(address)) {
ic.disconnectQuietly(Component.text("You are logging in too fast, try again later."));
ic.disconnectQuietly(Component.translatable("velocity.error.logging-in-too-fast"));
return;
}
@@ -132,7 +135,8 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
// and lower, otherwise IP information will never get forwarded.
if (server.configuration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
&& handshake.getProtocolVersion().lt(ProtocolVersion.MINECRAFT_1_13)) {
ic.disconnectQuietly(Component.text("This server is only compatible with 1.13 and above."));
ic.disconnectQuietly(Component.translatable(
"velocity.error.modern-forwarding-needs-new-client"));
return;
}

View File

@@ -65,6 +65,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.translation.GlobalTranslator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -152,7 +153,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
GameProfile.class), true);
} else if (profileResponse.getStatusCode() == 204) {
// Apparently an offline-mode user logged onto this online-mode proxy.
inbound.disconnect(server.configuration().getMessages().getOnlineModeOnly());
inbound.disconnect(Component.translatable("velocity.error.online-mode-only",
NamedTextColor.RED));
} else {
// Something else went wrong
logger.error(
@@ -192,9 +194,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
Optional<Component> disconnectReason = result.denialReason();
if (disconnectReason.isPresent()) {
// The component is guaranteed to be provided if the connection was denied.
Component disconnectReasonTranslated = GlobalTranslator.render(disconnectReason.get(),
Locale.getDefault());
inbound.disconnect(disconnectReasonTranslated);
inbound.disconnect(disconnectReason.get());
return;
}
@@ -243,7 +243,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
mcConnection, inbound.connectedHost().orElse(null), onlineMode);
this.connectedPlayer = player;
if (!server.canRegisterConnection(player)) {
player.disconnect0(server.configuration().getMessages().getAlreadyConnected(), true);
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy",
NamedTextColor.RED), true);
return CompletableFuture.completedFuture(null);
}
@@ -304,8 +305,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
player.disconnect0(reason.get(), true);
} else {
if (!server.registerConnection(player)) {
player.disconnect0(server.configuration().getMessages()
.getAlreadyConnected(), true);
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"),
true);
return;
}
@@ -333,8 +334,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
.thenRunAsync(() -> {
Optional<RegisteredServer> toTry = event.initialServer();
if (!toTry.isPresent()) {
player.disconnect0(server.configuration().getMessages()
.getNoAvailableServers(), true);
player.disconnect0(Component.translatable("velocity.error.no-available-servers",
NamedTextColor.RED), true);
return;
}
player.createConnectionRequest(toTry.get()).fireAndForget();

View File

@@ -19,16 +19,17 @@ package com.velocitypowered.proxy.connection.util;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.NamedTextColor;
public class ConnectionMessages {
public static final TextComponent ALREADY_CONNECTED = Component
.text("You are already connected to this server!", NamedTextColor.RED);
public static final TextComponent IN_PROGRESS = Component
.text("You are already connecting to a server!", NamedTextColor.RED);
public static final TextComponent INTERNAL_SERVER_CONNECTION_ERROR = Component
.text("An internal server connection error occurred.", NamedTextColor.RED);
public static final TranslatableComponent ALREADY_CONNECTED = Component
.translatable("velocity.error.already-connected", NamedTextColor.RED);
public static final TranslatableComponent IN_PROGRESS = Component
.translatable("velocity.error.already-connecting", NamedTextColor.RED);
public static final TranslatableComponent INTERNAL_SERVER_CONNECTION_ERROR = Component
.translatable("velocity.error.internal-server-connection-error", NamedTextColor.RED);
private ConnectionMessages() {
throw new AssertionError();

View File

@@ -26,9 +26,12 @@ import com.velocitypowered.api.permission.PermissionFunction;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.proxy.VelocityServer;
import java.util.List;
import java.util.Locale;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import net.minecrell.terminalconsole.SimpleTerminalConsole;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
@@ -52,8 +55,8 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
@Override
public void sendMessage(@NonNull Identity identity, @NonNull Component message) {
logger.info(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()
.serialize(message));
Component translated = GlobalTranslator.render(message, Locale.getDefault());
logger.info(LegacyComponentSerializer.legacySection().serialize(translated));
}
@Override
@@ -114,7 +117,8 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
protected void runCommand(String command) {
try {
if (!this.server.commandManager().execute(this, command).join()) {
sendMessage(Component.text("Command not found.", NamedTextColor.RED));
sendMessage(Component.translatable("velocity.command.command-does-not-exist",
NamedTextColor.RED));
}
} catch (Exception e) {
logger.error("An error occurred while running this command.", e);

View File

@@ -0,0 +1,62 @@
#
# Copyright (C) 2018 Velocity Contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
velocity.error.already-connected=You are already connected to this server!
velocity.error.already-connected-proxy=You are already connected to this proxy!
velocity.error.already-connecting=You are already trying to connect to a server!
velocity.error.cant-connect=Unable to connect to {0}: {1}
velocity.error.connecting-server-error=Unable to connect you to {0}. Please try again later.
velocity.error.connected-server-error=Your connection to {0} encountered a problem.
velocity.error.internal-server-connection-error=An internal server connection error occurred.
velocity.error.logging-in-too-fast=You are logging in too fast, try again later.
velocity.error.online-mode-only=You are not logged into your Minecraft account. If you are logged into your Minecraft account, try restarting your Minecraft client.
velocity.error.player-connection-error=An internal error occurred in your connection.
velocity.error.modern-forwarding-needs-new-client=This server is only compatible with Minecraft 1.13 and above.
velocity.error.modern-forwarding-failed=Your server did not send a forwarding request to the proxy. Make sure the server is configured for Velocity forwarding.
velocity.error.moved-to-new-server=YOu were kicked from {0}: {1}
velocity.error.no-available-servers=There are no available servers to connect you to. Try again later or contact an admin.
# Commands
velocity.command.generic-error=An error occurred while running this command.
velocity.command.command-does-not-exist=This command does not exist.
velocity.command.players-only=Only players can run this command.
velocity.command.server-does-not-exist=The specified server {0} does not exist.
velocity.command.server-current-server=You are currently connected to {0}.
velocity.command.server-too-many=There are too many servers set up. Use tab completion to get individual server counts.
velocity.command.server-available=Available servers:
velocity.command.server-tooltip-player-online={0} player online
velocity.command.server-tooltip-players-online={0} players online
velocity.command.server-tooltip-current-server=Currently connected to this server
velocity.command.server-tooltip-offer-connect-server=Click to connect to this server
velocity.command.glist-player-singular=player
velocity.command.glist-player-plural=players
velocity.command.glist-total-suffix= are currently connected to the proxy.
velocity.command.glist-view-all=To view all players on servers, use /glist all.
velocity.command.reload-success=Velocity configuration successfully reloaded.
velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details.
velocity.command.version-copyright=Copyright 2018-2021 {0}. {1} is licensed under the terms of the GNU General Public License v3.
velocity.command.no-plugins=There are no plugins currently installed.
velocity.command.plugins-list=Plugins: {0}
velocity.command.plugin-tooltip-website=Website: {0}
velocity.command.plugin-tooltip-author=Author: {0}
velocity.command.plugin-tooltip-authors=Authors: {0}

View File

@@ -141,20 +141,4 @@ port = 25577
map = "Velocity"
# Whether plugins should be shown in query response by default or not
show-plugins = false
# Legacy color codes and JSON are accepted in all messages.
[messages]
# Prefix when the player gets kicked from a server.
# First argument '%s': the server name
kick-prefix = "&cKicked from %s: "
# Prefix when the player is disconnected from a server.
# First argument '%s': the server name
disconnect-prefix = "&cCan't connect to %s: "
online-mode-only = "&cThis server only accepts connections from online-mode clients.\n\n&7Did you change your username? Sign out of Minecraft, sign back in, and try again."
no-available-servers = "&cThere are no available servers."
already-connected = "&cYou are already connected to this proxy!"
moved-to-new-server-prefix = "&cThe server you were on kicked you: "
generic-connection-error = "&cAn internal error occurred in your connection."
show-plugins = false