mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-22 07:37:55 -05:00
FabricLanguageProvider - Data Generation API (#2451)
Co-authored-by: modmuss50 <modmuss50@gmail.com> Co-authored-by: apple502j <33279053+apple502j@users.noreply.github.com>
This commit is contained in:
parent
a37366baa3
commit
0b73465810
5 changed files with 282 additions and 1 deletions
|
@ -5,7 +5,8 @@ moduleDependencies(project, [
|
|||
'fabric-api-base',
|
||||
'fabric-registry-sync-v0',
|
||||
'fabric-networking-api-v1',
|
||||
'fabric-resource-conditions-api-v1'
|
||||
'fabric-resource-conditions-api-v1',
|
||||
'fabric-item-groups-v0'
|
||||
])
|
||||
|
||||
dependencies {
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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.api.datagen.v1.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.DataWriter;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.effect.StatusEffect;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.stat.StatType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
|
||||
|
||||
/**
|
||||
* Extend this class and implement {@link FabricLanguageProvider#generateTranslations(TranslationBuilder)}.
|
||||
* Make sure to use {@link FabricLanguageProvider#FabricLanguageProvider(FabricDataGenerator, String)} FabricLanguageProvider} to declare what language code is being generated if it isn't {@code en_us}.
|
||||
*
|
||||
* <p>Register an instance of the class with {@link FabricDataGenerator#addProvider} in a {@link net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint}
|
||||
*/
|
||||
public abstract class FabricLanguageProvider implements DataProvider {
|
||||
protected final FabricDataGenerator dataGenerator;
|
||||
private final String languageCode;
|
||||
|
||||
protected FabricLanguageProvider(FabricDataGenerator dataGenerator) {
|
||||
this(dataGenerator, "en_us");
|
||||
}
|
||||
|
||||
protected FabricLanguageProvider(FabricDataGenerator dataGenerator, String languageCode) {
|
||||
this.dataGenerator = dataGenerator;
|
||||
this.languageCode = languageCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to register languages.
|
||||
*
|
||||
* <p>Call {@link TranslationBuilder#add(String, String)} to add a translation.
|
||||
*/
|
||||
public abstract void generateTranslations(TranslationBuilder translationBuilder);
|
||||
|
||||
@Override
|
||||
public void run(DataWriter writer) throws IOException {
|
||||
TreeMap<String, String> translationEntries = new TreeMap<>();
|
||||
|
||||
generateTranslations((String key, String value) -> {
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(value);
|
||||
|
||||
if (translationEntries.containsKey(key)) {
|
||||
throw new RuntimeException("Existing translation key found - " + key + " - Duplicate will be ignored.");
|
||||
}
|
||||
|
||||
translationEntries.put(key, value);
|
||||
});
|
||||
|
||||
JsonObject langEntryJson = new JsonObject();
|
||||
|
||||
for (Map.Entry<String, String> entry : translationEntries.entrySet()) {
|
||||
langEntryJson.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
DataProvider.writeToPath(writer, langEntryJson, getLangFilePath(this.languageCode));
|
||||
}
|
||||
|
||||
private Path getLangFilePath(String code) {
|
||||
return dataGenerator.getOutput().resolve("assets/%s/lang/%s.json".formatted(dataGenerator.getModId(), code));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Language";
|
||||
}
|
||||
|
||||
/**
|
||||
* A consumer used by {@link FabricLanguageProvider#generateTranslations(TranslationBuilder)}.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
@FunctionalInterface
|
||||
public interface TranslationBuilder {
|
||||
/**
|
||||
* Adds a translation.
|
||||
*
|
||||
* @param translationKey The key of the translation.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
void add(String translationKey, String value);
|
||||
|
||||
/**
|
||||
* Adds a translation for an {@link Item}.
|
||||
* @param item The {@link Item} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(Item item, String value) {
|
||||
add(item.getTranslationKey(), value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a translation for a {@link Block}.
|
||||
* @param block The {@link Block} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(Block block, String value) {
|
||||
add(block.getTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for an {@link ItemGroup}.
|
||||
* @param group The {@link ItemGroup} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(ItemGroup group, String value) {
|
||||
add("itemGroup." + group.getName(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for an {@link EntityType}.
|
||||
* @param entityType The {@link EntityType} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(EntityType<?> entityType, String value) {
|
||||
add(entityType.getTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for an {@link Enchantment}.
|
||||
* @param enchantment The {@link Enchantment} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(Enchantment enchantment, String value) {
|
||||
add(enchantment.getTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for an {@link EntityAttribute}.
|
||||
* @param entityAttribute The {@link EntityAttribute} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(EntityAttribute entityAttribute, String value) {
|
||||
add(entityAttribute.getTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for a {@link StatType}.
|
||||
* @param statType The {@link StatType} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(StatType<?> statType, String value) {
|
||||
add(statType.getTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for a {@link StatusEffect}.
|
||||
* @param statusEffect The {@link StatusEffect} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(StatusEffect statusEffect, String value) {
|
||||
add(statusEffect.getTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation for an {@link Identifier}.
|
||||
* @param identifier The {@link Identifier} to get the translation key from.
|
||||
* @param value The value of the entry.
|
||||
*/
|
||||
default void add(Identifier identifier, String value) {
|
||||
add(identifier.toTranslationKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges an existing language file into the generated language file.
|
||||
* @param existingLanguageFile The path to the existing language file.
|
||||
* @throws IOException If loading the language file failed.
|
||||
*/
|
||||
default void add(Path existingLanguageFile) throws IOException {
|
||||
try (Reader reader = Files.newBufferedReader(existingLanguageFile)) {
|
||||
JsonObject translations = JsonParser.parseReader(reader).getAsJsonObject();
|
||||
|
||||
for (String key : translations.keySet()) {
|
||||
add(key, translations.get(key).getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,10 +24,13 @@ import net.minecraft.block.Material;
|
|||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
|
||||
|
||||
public class DataGeneratorTestContent implements ModInitializer {
|
||||
public static final String MOD_ID = "fabric-data-gen-api-v1-testmod";
|
||||
|
@ -35,9 +38,11 @@ public class DataGeneratorTestContent implements ModInitializer {
|
|||
public static Block SIMPLE_BLOCK;
|
||||
public static Block BLOCK_WITHOUT_ITEM;
|
||||
public static Block BLOCK_WITHOUT_LOOT_TABLE;
|
||||
public static ItemGroup SIMPLE_ITEM_GROUP;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
SIMPLE_ITEM_GROUP = FabricItemGroupBuilder.build(new Identifier(MOD_ID, "default"), () -> new ItemStack(Items.BONE));
|
||||
SIMPLE_BLOCK = createBlock("simple_block", true);
|
||||
BLOCK_WITHOUT_ITEM = createBlock("block_without_item", false);
|
||||
BLOCK_WITHOUT_LOOT_TABLE = createBlock("block_without_loot_table", false);
|
||||
|
|
|
@ -20,10 +20,17 @@ import static net.fabricmc.fabric.test.datagen.DataGeneratorTestContent.BLOCK_WI
|
|||
import static net.fabricmc.fabric.test.datagen.DataGeneratorTestContent.BLOCK_WITHOUT_LOOT_TABLE;
|
||||
import static net.fabricmc.fabric.test.datagen.DataGeneratorTestContent.MOD_ID;
|
||||
import static net.fabricmc.fabric.test.datagen.DataGeneratorTestContent.SIMPLE_BLOCK;
|
||||
import static net.fabricmc.fabric.test.datagen.DataGeneratorTestContent.SIMPLE_ITEM_GROUP;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.advancement.Advancement;
|
||||
import net.minecraft.advancement.AdvancementFrame;
|
||||
import net.minecraft.advancement.criterion.OnKilledCriterion;
|
||||
|
@ -31,6 +38,8 @@ import net.minecraft.data.client.BlockStateModelGenerator;
|
|||
import net.minecraft.data.client.ItemModelGenerator;
|
||||
import net.minecraft.data.server.recipe.RecipeJsonProvider;
|
||||
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.loot.LootPool;
|
||||
import net.minecraft.loot.LootTable;
|
||||
|
@ -52,6 +61,7 @@ import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
|
|||
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
|
||||
|
@ -60,6 +70,7 @@ import net.fabricmc.fabric.api.resource.conditions.v1.ConditionJsonProvider;
|
|||
import net.fabricmc.fabric.api.resource.conditions.v1.DefaultResourceConditions;
|
||||
|
||||
public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DataGeneratorTestEntrypoint.class);
|
||||
private static final ConditionJsonProvider NEVER_LOADED = DefaultResourceConditions.allModsLoaded("a");
|
||||
private static final ConditionJsonProvider ALWAYS_LOADED = DefaultResourceConditions.not(NEVER_LOADED);
|
||||
|
||||
|
@ -71,6 +82,8 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
|
|||
dataGenerator.addProvider(TestAdvancementProvider::new);
|
||||
dataGenerator.addProvider(TestBlockLootTableProvider::new);
|
||||
dataGenerator.addProvider(TestBarterLootTableProvider::new);
|
||||
dataGenerator.addProvider(ExistingEnglishLangProvider::new);
|
||||
dataGenerator.addProvider(JapaneseLangProvider::new);
|
||||
|
||||
TestBlockTagProvider blockTagProvider = dataGenerator.addProvider(TestBlockTagProvider::new);
|
||||
dataGenerator.addProvider(new TestItemTagProvider(dataGenerator, blockTagProvider));
|
||||
|
@ -110,6 +123,51 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ExistingEnglishLangProvider extends FabricLanguageProvider {
|
||||
private ExistingEnglishLangProvider(FabricDataGenerator dataGenerator) {
|
||||
super(dataGenerator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateTranslations(TranslationBuilder translationBuilder) {
|
||||
translationBuilder.add(SIMPLE_BLOCK, "Simple Block");
|
||||
translationBuilder.add(new Identifier(MOD_ID, "identifier_test"), "Identifier Test");
|
||||
translationBuilder.add(EntityType.ALLAY, "Allay");
|
||||
translationBuilder.add(EntityAttributes.GENERIC_ARMOR, "Generic Armor");
|
||||
|
||||
try {
|
||||
Optional<Path> path = dataGenerator.getModContainer().findPath("assets/testmod/lang/en_us.base.json");
|
||||
|
||||
if (path.isPresent()) {
|
||||
translationBuilder.add(path.get());
|
||||
} else {
|
||||
throw new RuntimeException("The existing language file could not be found in the testmod assets!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
translationBuilder.add(EntityType.ALLAY, "Allay Duplicate Test");
|
||||
} catch (RuntimeException e) {
|
||||
LOGGER.info("Duplicate test passed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class JapaneseLangProvider extends FabricLanguageProvider {
|
||||
private JapaneseLangProvider(FabricDataGenerator dataGenerator) {
|
||||
super(dataGenerator, "ja_jp");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateTranslations(TranslationBuilder translationBuilder) {
|
||||
translationBuilder.add(SIMPLE_BLOCK, "シンプルブロック");
|
||||
translationBuilder.add(SIMPLE_ITEM_GROUP, "データ生成項目");
|
||||
translationBuilder.add("this.is.a.test", "こんにちは");
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestConditionalRecipeProvider extends FabricRecipeProvider {
|
||||
private TestConditionalRecipeProvider(FabricDataGenerator dataGenerator) {
|
||||
super(dataGenerator);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"itemGroup.fabric-data-gen-api-v1-testmod.default": "Datagen Itemgroup"
|
||||
}
|
Loading…
Reference in a new issue