1
0
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:
BugTeaON
2025-06-08 07:54:08 +08:00
committed by GitHub
parent 0237579ad3
commit bf53c54e6f
4 changed files with 32 additions and 15 deletions

View File

@@ -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();
}
}
}

View File

@@ -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++) + "}");

View File

@@ -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");

View File

@@ -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();
}