mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-23 08:49:23 +00:00
Escape curly braces correctly in translation strings; remove default empty translation fallback in the text component (#5559)
* Escape curly braces correctly in translation strings * Default translation fallback should not appear in the text component * Only left braces need to be escaped * Some adjustments * Move the escapeBraces method to the MessageTranslator class * Improve code readability * Use complied static Pattern instead of Pattern.matches * Improve some code comments * Use regular expression complelety to escape braces instead of the inefficient, low-readablity escapeBraces method * Add some tests about escaping curly braces in translatable strings * Check instance availability to avoid exception during testing
This commit is contained in:
@@ -47,15 +47,20 @@ public class MinecraftLocale {
|
||||
|
||||
public static final Map<String, Map<String, String>> LOCALE_MAPPINGS = new HashMap<>();
|
||||
|
||||
private static final Path LOCALE_FOLDER = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("locales");
|
||||
// Check instance availability to avoid exception during testing
|
||||
private static final boolean IN_INSTANCE = GeyserImpl.getInstance() != null;
|
||||
|
||||
private static final Path LOCALE_FOLDER = (IN_INSTANCE) ? GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("locales") : null;
|
||||
|
||||
static {
|
||||
try {
|
||||
// Create the locales folder
|
||||
Files.createDirectories(LOCALE_FOLDER);
|
||||
Files.createDirectories(LOCALE_FOLDER.resolve("overrides"));
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Unable to create locale folders! " + exception.getMessage());
|
||||
if (IN_INSTANCE) {
|
||||
try {
|
||||
// Create the locales folder
|
||||
Files.createDirectories(LOCALE_FOLDER);
|
||||
Files.createDirectories(LOCALE_FOLDER.resolve("overrides"));
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Unable to create locale folders! " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,4 +271,4 @@ public class MinecraftLocale {
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.util.regex.Pattern;
|
||||
public class MinecraftTranslationRegistry extends TranslatableComponentRenderer<String> {
|
||||
private final Pattern stringReplacement = Pattern.compile("%s");
|
||||
private final Pattern positionalStringReplacement = Pattern.compile("%([0-9]+)\\$s");
|
||||
private final Pattern escapeBraces = Pattern.compile("\\{+['{]+\\{+|\\{+");
|
||||
|
||||
// Exists to maintain compatibility with Velocity's older Adventure version
|
||||
@Override
|
||||
@@ -66,14 +67,19 @@ public class MinecraftTranslationRegistry extends TranslatableComponentRenderer<
|
||||
// replace single quote instances which get lost in MessageFormat otherwise
|
||||
localeString = localeString.replace("'", "''");
|
||||
|
||||
// Wrap all curly brackets with single quote inserts - fixes https://github.com/GeyserMC/Geyser/issues/4662
|
||||
localeString = localeString.replace("{", "'{")
|
||||
.replace("}", "'}");
|
||||
|
||||
// Replace the `%s` with numbered inserts `{0}`
|
||||
Pattern p = stringReplacement;
|
||||
// Escape all left curly brackets with single quote - fixes https://github.com/GeyserMC/Geyser/issues/4662
|
||||
Pattern p = escapeBraces;
|
||||
Matcher m = p.matcher(localeString);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (m.find()) {
|
||||
m.appendReplacement(sb, "'" + m.group() + "'");
|
||||
}
|
||||
m.appendTail(sb);
|
||||
|
||||
// Replace the `%s` with numbered inserts `{0}`
|
||||
p = stringReplacement;
|
||||
m = p.matcher(sb.toString());
|
||||
sb = new StringBuilder();
|
||||
int i = 0;
|
||||
while (m.find()) {
|
||||
m.appendReplacement(sb, "{" + (i++) + "}");
|
||||
|
||||
@@ -500,7 +500,7 @@ public class MessageTranslator {
|
||||
} else {
|
||||
String translateKey = map.getString("translate", null);
|
||||
if (translateKey != null) {
|
||||
String fallback = map.getString("fallback", "");
|
||||
String fallback = map.getString("fallback", null);
|
||||
List<Component> args = new ArrayList<>();
|
||||
|
||||
Object with = map.get("with");
|
||||
|
||||
@@ -69,6 +69,12 @@ public class MessageTranslatorTest {
|
||||
"§e All participants will receive a reward\n" +
|
||||
"§e and the top 3 will get extra bonus prizes!");
|
||||
|
||||
// Escape curly braces in translatable strings (make MessageFormat ignore them)
|
||||
messages.put("{\"translate\":\"tt{tt%stt}tt\",\"with\":[\"AA\"]}", "tt{ttAAtt}tt");
|
||||
messages.put("{\"translate\":\"tt{'tt%stt'{tt\",\"with\":[\"AA\"]}", "tt{'ttAAtt'{tt");
|
||||
messages.put("{\"translate\":\"tt{''{tt\"}", "tt{''{tt");
|
||||
messages.put("{\"translate\":\"tt{{''}}tt\"}", "tt{{''}}tt");
|
||||
|
||||
MessageTranslator.init();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user