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>
(cherry picked from commit a10d22bd14)
This commit is contained in:
Teddy Li 2022-12-11 22:10:27 +08:00 committed by modmuss50
parent e4fecd81f0
commit 574a764801
6 changed files with 75 additions and 16 deletions

View file

@ -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()) {

View file

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

View file

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

View file

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

View file

@ -0,0 +1,3 @@
{
"text.fabric-resource-loader-v0-testmod.server.lang.test1": "Test from fabric-resource-loader-v0-testmod-test1"
}

View file

@ -0,0 +1,3 @@
{
"text.fabric-resource-loader-v0-testmod.server.lang.test0": "Test from fabric-resource-loader-v0-testmod"
}