From a10d22bd14c26bf1df7d74d3eafcda58c57666e1 Mon Sep 17 00:00:00 2001 From: Teddy Li <tedexe_work.top@foxmail.com> Date: Sun, 11 Dec 2022 22:10:27 +0800 Subject: [PATCH] Load default translations from all namespaces on the server (#2709) * Introduce fabric:server-language-namespaces custom meta to fabric-resource-loader-v0 (extension of FabricMC/fabric#2668) * Fix testmod assertion message * Automatically detect every en_us.json files in mod container Remove fabric:server-language-namespaces custom meta detection * Remove unused custom field in fabric.mod.json * Update license * Update style * cleanup format * Fix checkstyle, move constructor Co-authored-by: modmuss50 <modmuss50@gmail.com> --- .../resource/loader/ModNioResourcePack.java | 2 +- .../resource/loader/ServerLanguageUtil.java | 56 +++++++++++++++++++ .../resource/loader/server/LanguageMixin.java | 16 ++---- .../test/resource/loader/LanguageTestMod.java | 11 +++- .../lang/en_us.json | 3 + .../lang/en_us.json | 3 + 6 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ServerLanguageUtil.java create mode 100644 fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod-test1/lang/en_us.json create mode 100644 fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod/lang/en_us.json diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ModNioResourcePack.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ModNioResourcePack.java index bd5ba9713..ce2d60f2a 100644 --- a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ModNioResourcePack.java +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ModNioResourcePack.java @@ -107,7 +107,7 @@ public class ModNioResourcePack implements ResourcePack, ModResourcePack { this.namespaces = readNamespaces(paths, modInfo.getId()); } - private static Map<ResourceType, Set<String>> readNamespaces(List<Path> paths, String modId) { + static Map<ResourceType, Set<String>> readNamespaces(List<Path> paths, String modId) { Map<ResourceType, Set<String>> ret = new EnumMap<>(ResourceType.class); for (ResourceType type : ResourceType.values()) { diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ServerLanguageUtil.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ServerLanguageUtil.java new file mode 100644 index 000000000..a38a8efbe --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ServerLanguageUtil.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.resource.loader; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Language; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +public final class ServerLanguageUtil { + private static final String ASSETS_PREFIX = ResourceType.CLIENT_RESOURCES.getDirectory() + '/'; + + private ServerLanguageUtil() { + } + + public static Collection<Path> getModLanguageFiles() { + Set<Path> paths = new LinkedHashSet<>(); + + for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { + if (mod.getMetadata().getType().equals("builtin")) continue; + + final Map<ResourceType, Set<String>> map = ModNioResourcePack.readNamespaces(mod.getRootPaths(), mod.getMetadata().getId()); + + for (String ns : map.get(ResourceType.CLIENT_RESOURCES)) { + mod.findPath(ASSETS_PREFIX + ns + "/lang/" + Language.DEFAULT_LANGUAGE + ".json") + .filter(Files::isRegularFile) + .ifPresent(paths::add); + } + } + + return Collections.unmodifiableCollection(paths); + } +} diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/server/LanguageMixin.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/server/LanguageMixin.java index ca443ad69..b2008d5af 100644 --- a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/server/LanguageMixin.java +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/server/LanguageMixin.java @@ -35,8 +35,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; import net.minecraft.util.Language; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.fabric.impl.resource.loader.ServerLanguageUtil; @Mixin(Language.class) class LanguageMixin { @@ -44,25 +43,18 @@ class LanguageMixin { @Final private static Logger LOGGER; - @Shadow - @Final - public static String DEFAULT_LANGUAGE; - @Redirect(method = "create", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap$Builder;build()Lcom/google/common/collect/ImmutableMap;")) private static ImmutableMap<String, String> create(ImmutableMap.Builder<String, String> cir) { Map<String, String> map = new HashMap<>(cir.buildOrThrow()); - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if (!mod.getMetadata().getType().equals("builtin")) loadModLanguage(mod, map::put); + for (Path path : ServerLanguageUtil.getModLanguageFiles()) { + loadFromPath(path, map::put); } return ImmutableMap.copyOf(map); } - private static void loadModLanguage(ModContainer container, BiConsumer<String, String> entryConsumer) { - Path path = container.findPath("assets/" + container.getMetadata().getId() + "/lang/" + DEFAULT_LANGUAGE + ".json").orElse(null); - if (path == null || !Files.isRegularFile(path)) return; - + private static void loadFromPath(Path path, BiConsumer<String, String> entryConsumer) { try (InputStream stream = Files.newInputStream(path)) { LOGGER.debug("Loading translations from {}", path); load(stream, entryConsumer); diff --git a/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/LanguageTestMod.java b/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/LanguageTestMod.java index ae13bdfe1..ff59f36ad 100644 --- a/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/LanguageTestMod.java +++ b/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/LanguageTestMod.java @@ -27,11 +27,16 @@ public class LanguageTestMod implements DedicatedServerModInitializer { } private static void testTranslationLoaded() { - String expected = "Fabric mod"; - String actual = Text.translatable("pack.source.fabricmod").getString(); + testTranslationLoaded("pack.source.fabricmod", "Fabric mod"); + testTranslationLoaded("text.fabric-resource-loader-v0-testmod.server.lang.test0", "Test from fabric-resource-loader-v0-testmod"); + testTranslationLoaded("text.fabric-resource-loader-v0-testmod.server.lang.test1", "Test from fabric-resource-loader-v0-testmod-test1"); + } + + private static void testTranslationLoaded(String key, String expected) { + String actual = Text.translatable(key).getString(); if (!expected.equals(actual)) { - throw new AssertionError("Expected 'pack.source.fabricmod' to translate to " + expected + ", but translated to " + actual); + throw new AssertionError("Expected " + key + " to translate to " + expected + ", but translated to " + actual); } } } diff --git a/fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod-test1/lang/en_us.json b/fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod-test1/lang/en_us.json new file mode 100644 index 000000000..2b38e51f2 --- /dev/null +++ b/fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod-test1/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "text.fabric-resource-loader-v0-testmod.server.lang.test1": "Test from fabric-resource-loader-v0-testmod-test1" +} diff --git a/fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod/lang/en_us.json b/fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod/lang/en_us.json new file mode 100644 index 000000000..30fada154 --- /dev/null +++ b/fabric-resource-loader-v0/src/testmod/resources/assets/fabric-resource-loader-v0-testmod/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "text.fabric-resource-loader-v0-testmod.server.lang.test0": "Test from fabric-resource-loader-v0-testmod" +}