From 260089405a06271be5c1ebbb4d3ed77baf3d565b Mon Sep 17 00:00:00 2001 From: joe Date: Sat, 30 Nov 2024 22:05:09 +0000 Subject: [PATCH] Add test that translation files follow the rules --- .../assets/clientcommands/lang/en_us.json | 2 +- .../clientcommands/test/TranslationsTest.java | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/test/java/net/earthcomputer/clientcommands/test/TranslationsTest.java diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index 1f546123..a498c41a 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -182,7 +182,7 @@ "commands.crender.entities.success": "Entity rendering rules have been updated", "commands.creply.noTargetFound": "Could not find a target to reply to", - "commands.creply.messageTooLong": "Your reply was too long (maximum: %d, given: %d)", + "commands.creply.messageTooLong": "Your reply was too long (maximum: %s, given: %s)", "commands.csignsearch.starting": "Searching signs", diff --git a/src/test/java/net/earthcomputer/clientcommands/test/TranslationsTest.java b/src/test/java/net/earthcomputer/clientcommands/test/TranslationsTest.java new file mode 100644 index 00000000..8124ac5d --- /dev/null +++ b/src/test/java/net/earthcomputer/clientcommands/test/TranslationsTest.java @@ -0,0 +1,68 @@ +package net.earthcomputer.clientcommands.test; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import net.fabricmc.loader.api.FabricLoader; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +public final class TranslationsTest { + private static final Gson GSON = new Gson(); + + @TestFactory + public Iterable testTranslate() throws IOException { + Path langDir = FabricLoader.getInstance().getModContainer("clientcommands").orElseThrow() + .findPath("assets/clientcommands/lang").orElseThrow(); + + JsonObject enUs; + try (BufferedReader reader = Files.newBufferedReader(langDir.resolve("en_us.json"))) { + enUs = GSON.fromJson(reader, JsonObject.class); + } + + List tests = new ArrayList<>(); + + try (Stream langFiles = Files.list(langDir)) { + for (Path langFile : (Iterable) langFiles::iterator) { + tests.add(DynamicTest.dynamicTest("Check " + langFile.getFileName().toString(), () -> checkLangFile(enUs, langFile))); + } + } + + return tests; + } + + private static void checkLangFile(JsonObject enUs, Path langFile) throws IOException { + String langFileName = langFile.getFileName().toString(); + + JsonObject lang; + try (BufferedReader reader = Files.newBufferedReader(langFile)) { + lang = GSON.fromJson(reader, JsonObject.class); + } + + for (String key : lang.keySet()) { + assertTrue(enUs.has(key), () -> langFileName + " has key " + key + " not present in en_us.json"); + } + for (var entry : lang.entrySet()) { + assertTrue(entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString(), () -> langFileName + " has a non-string value associated with " + entry.getKey()); + } + for (var entry : lang.entrySet()) { + assertTrue(checkPercentS(entry.getValue().getAsString()), () -> langFileName + " has invalid formatting codes in " + entry.getKey() + ". Only %s, %n$s and %% are allowed"); + } + } + + private static final Pattern NON_PERCENT_S_REGEX = Pattern.compile("%(?!(?:\\d+\\$)?s)"); + + private static boolean checkPercentS(String value) { + return !NON_PERCENT_S_REGEX.matcher(value.replace("%%", "")).find(); + } +}