1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-16 10:09:55 +00:00
CC-Tweaked/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java
Jonathan Coates 08df68dcc0
Generate en_us.json via datagen
I was originally pretty sceptical about this, but it actually ends up
being useful for the same reason any other form of datagen is: we can
ensure that names are well formed, and that every string is actually
translated.

There's some future work here to go through all the custom translation
keys and move them into constants (maybe also do something with the
/computercraft command?), but that's a separate chunk of work.

The main motivation for this is to add translation keys to our config:
the Fabric version of Forge Config API provides a config UI, so it's
useful to provide user-friendly strings. Our generator also
automatically copies comments over, turning them into tooltips.

This also updates all of the other language files to match en_us.json
again: it's a very noisy diff as the file is now sorted alphabetically.
Hopefully this won't affect weblate though

[^1]: Amusing really that the Fabric port actually is more useful than
the original.
2022-11-20 13:00:43 +00:00

323 lines
21 KiB
Java

/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.data;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.google.common.base.Splitter;
import com.google.gson.JsonObject;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
import dan200.computercraft.api.upgrades.IUpgradeBase;
import dan200.computercraft.core.metrics.Metric;
import dan200.computercraft.core.metrics.Metrics;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.computer.metrics.basic.Aggregate;
import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric;
import dan200.computercraft.shared.config.ConfigSpec;
import dan200.computercraft.shared.platform.Registries;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.ForgeConfigSpec;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
public final class LanguageProvider implements DataProvider {
private final DataGenerator generator;
private final TurtleUpgradeDataProvider turtleUpgrades;
private final PocketUpgradeDataProvider pocketUpgrades;
private final Map<String, String> translations = new HashMap<>();
public LanguageProvider(DataGenerator generator, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
this.generator = generator;
this.turtleUpgrades = turtleUpgrades;
this.pocketUpgrades = pocketUpgrades;
}
@Override
public void run(CachedOutput cachedOutput) throws IOException {
addTranslations();
getExpectedKeys().forEach(x -> {
if (!translations.containsKey(x)) throw new IllegalStateException("No translation for " + x);
});
var json = new JsonObject();
for (var pair : translations.entrySet()) json.addProperty(pair.getKey(), pair.getValue());
DataProvider.saveStable(cachedOutput, json, generator.getOutputFolder().resolve("assets/" + ComputerCraftAPI.MOD_ID + "/lang/en_us.json"));
}
@Override
public String getName() {
return "Languages";
}
private void addTranslations() {
add("itemGroup.computercraft", "ComputerCraft");
// Blocks and items
add(ModRegistry.Items.COMPUTER_NORMAL.get(), "Computer");
add(ModRegistry.Items.COMPUTER_ADVANCED.get(), "Advanced Computer");
add(ModRegistry.Items.COMPUTER_COMMAND.get(), "Command Computer");
add(ModRegistry.Items.DISK_DRIVE.get(), "Disk Drive");
add(ModRegistry.Items.PRINTER.get(), "Printer");
add(ModRegistry.Items.SPEAKER.get(), "Speaker");
add(ModRegistry.Items.MONITOR_NORMAL.get(), "Monitor");
add(ModRegistry.Items.MONITOR_ADVANCED.get(), "Advanced Monitor");
add(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get(), "Wireless Modem");
add(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get(), "Ender Modem");
add(ModRegistry.Items.WIRED_MODEM.get(), "Wired Modem");
add(ModRegistry.Items.CABLE.get(), "Networking Cable");
add(ModRegistry.Items.WIRED_MODEM_FULL.get(), "Wired Modem");
add(ModRegistry.Items.TURTLE_NORMAL.get(), "Turtle");
add(ModRegistry.Blocks.TURTLE_NORMAL.get().getDescriptionId() + ".upgraded", "%s Turtle");
add(ModRegistry.Blocks.TURTLE_NORMAL.get().getDescriptionId() + ".upgraded_twice", "%s %s Turtle");
add(ModRegistry.Items.TURTLE_ADVANCED.get(), "Advanced Turtle");
add(ModRegistry.Blocks.TURTLE_ADVANCED.get().getDescriptionId() + ".upgraded", "Advanced %s Turtle");
add(ModRegistry.Blocks.TURTLE_ADVANCED.get().getDescriptionId() + ".upgraded_twice", "Advanced %s %s Turtle");
add(ModRegistry.Items.DISK.get(), "Floppy Disk");
add(ModRegistry.Items.TREASURE_DISK.get(), "Floppy Disk");
add(ModRegistry.Items.PRINTED_PAGE.get(), "Printed Page");
add(ModRegistry.Items.PRINTED_PAGES.get(), "Printed Pages");
add(ModRegistry.Items.PRINTED_BOOK.get(), "Printed Book");
add(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), "Pocket Computer");
add(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get().getDescriptionId() + ".upgraded", "%s Pocket Computer");
add(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get(), "Advanced Pocket Computer");
add(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get().getDescriptionId() + ".upgraded", "Advanced %s Pocket Computer");
// Turtle/pocket upgrades
add("upgrade.minecraft.diamond_sword.adjective", "Melee");
add("upgrade.minecraft.diamond_shovel.adjective", "Digging");
add("upgrade.minecraft.diamond_pickaxe.adjective", "Mining");
add("upgrade.minecraft.diamond_axe.adjective", "Felling");
add("upgrade.minecraft.diamond_hoe.adjective", "Farming");
add("upgrade.minecraft.crafting_table.adjective", "Crafty");
add("upgrade.computercraft.wireless_modem_normal.adjective", "Wireless");
add("upgrade.computercraft.wireless_modem_advanced.adjective", "Ender");
add("upgrade.computercraft.speaker.adjective", "Noisy");
add("chat.computercraft.wired_modem.peripheral_connected", "Peripheral \"%s\" connected to network");
add("chat.computercraft.wired_modem.peripheral_disconnected", "Peripheral \"%s\" disconnected from network");
// Commands
add("commands.computercraft.synopsis", "Various commands for controlling computers.");
add("commands.computercraft.desc", "The /computercraft command provides various debugging and administrator tools for controlling and interacting with computers.");
add("commands.computercraft.help.synopsis", "Provide help for a specific command");
add("commands.computercraft.help.desc", "Displays this help message");
add("commands.computercraft.help.no_children", "%s has no sub-commands");
add("commands.computercraft.help.no_command", "No such command '%s'");
add("commands.computercraft.dump.synopsis", "Display the status of computers.");
add("commands.computercraft.dump.desc", "Display the status of all computers or specific information about one computer. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").");
add("commands.computercraft.dump.action", "View more info about this computer");
add("commands.computercraft.dump.open_path", "View this computer's files");
add("commands.computercraft.shutdown.synopsis", "Shutdown computers remotely.");
add("commands.computercraft.shutdown.desc", "Shutdown the listed computers or all if none are specified. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").");
add("commands.computercraft.shutdown.done", "Shutdown %s/%s computers");
add("commands.computercraft.turn_on.synopsis", "Turn computers on remotely.");
add("commands.computercraft.turn_on.desc", "Turn on the listed computers. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").");
add("commands.computercraft.turn_on.done", "Turned on %s/%s computers");
add("commands.computercraft.tp.synopsis", "Teleport to a specific computer.");
add("commands.computercraft.tp.desc", "Teleport to the location of a computer. You can either specify the computer's instance id (e.g. 123) or computer id (e.g #123).");
add("commands.computercraft.tp.action", "Teleport to this computer");
add("commands.computercraft.tp.not_player", "Cannot open terminal for non-player");
add("commands.computercraft.tp.not_there", "Cannot locate computer in the world");
add("commands.computercraft.view.synopsis", "View the terminal of a computer.");
add("commands.computercraft.view.desc", "Open the terminal of a computer, allowing remote control of a computer. This does not provide access to turtle's inventories. You can either specify the computer's instance id (e.g. 123) or computer id (e.g #123).");
add("commands.computercraft.view.action", "View this computer");
add("commands.computercraft.view.not_player", "Cannot open terminal for non-player");
add("commands.computercraft.track.synopsis", "Track execution times for computers.");
add("commands.computercraft.track.desc", "Track how long computers execute for, as well as how many events they handle. This presents information in a similar way to /forge track and can be useful for diagnosing lag.");
add("commands.computercraft.track.start.synopsis", "Start tracking all computers");
add("commands.computercraft.track.start.desc", "Start tracking all computers' execution times and event counts. This will discard the results of previous runs.");
add("commands.computercraft.track.start.stop", "Run %s to stop tracking and view the results");
add("commands.computercraft.track.stop.synopsis", "Stop tracking all computers");
add("commands.computercraft.track.stop.desc", "Stop tracking all computers' events and execution times");
add("commands.computercraft.track.stop.action", "Click to stop tracking");
add("commands.computercraft.track.stop.not_enabled", "Not currently tracking computers");
add("commands.computercraft.track.dump.synopsis", "Dump the latest track results");
add("commands.computercraft.track.dump.desc", "Dump the latest results of computer tracking.");
add("commands.computercraft.track.dump.no_timings", "No timings available");
add("commands.computercraft.track.dump.computer", "Computer");
add("commands.computercraft.reload.synopsis", "Reload the ComputerCraft config file");
add("commands.computercraft.reload.desc", "Reload the ComputerCraft config file");
add("commands.computercraft.reload.done", "Reloaded config");
add("commands.computercraft.queue.synopsis", "Send a computer_command event to a command computer");
add("commands.computercraft.queue.desc", "Send a computer_command event to a command computer, passing through the additional arguments. This is mostly designed for map makers, acting as a more computer-friendly version of /trigger. Any player can run the command, which would most likely be done through a text component's click event.");
add("commands.computercraft.generic.no_position", "<no pos>");
add("commands.computercraft.generic.position", "%s, %s, %s");
add("commands.computercraft.generic.yes", "Y");
add("commands.computercraft.generic.no", "N");
add("commands.computercraft.generic.exception", "Unhandled exception (%s)");
add("commands.computercraft.generic.additional_rows", "%d additional rows…");
add("argument.computercraft.computer.no_matching", "No computers matching '%s'");
add("argument.computercraft.computer.many_matching", "Multiple computers matching '%s' (instances %s)");
add("argument.computercraft.tracking_field.no_field", "Unknown field '%s'");
add("argument.computercraft.argument_expected", "Argument expected");
// Metrics
add(Metrics.COMPUTER_TASKS, "Tasks");
add(Metrics.SERVER_TASKS, "Server tasks");
add(Metrics.PERIPHERAL_OPS, "Peripheral calls");
add(Metrics.FS_OPS, "Filesystem operations");
add(Metrics.HTTP_REQUESTS, "HTTP requests");
add(Metrics.HTTP_UPLOAD, "HTTP upload");
add(Metrics.HTTP_DOWNLOAD, "HTTP download");
add(Metrics.WEBSOCKET_INCOMING, "Websocket incoming");
add(Metrics.WEBSOCKET_OUTGOING, "Websocket outgoing");
add(Metrics.COROUTINES_CREATED, "Coroutines created");
add(Metrics.COROUTINES_DISPOSED, "Coroutines disposed");
add(Metrics.TURTLE_OPS, "Turtle operations");
add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.MAX.id(), "%s (max)");
add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.AVG.id(), "%s (avg)");
add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.COUNT.id(), "%s (count)");
// Additional UI elements
add("gui.computercraft.tooltip.copy", "Copy to clipboard");
add("gui.computercraft.tooltip.computer_id", "Computer ID: %s");
add("gui.computercraft.tooltip.disk_id", "Disk ID: %s");
add("gui.computercraft.tooltip.turn_on", "Turn this computer on");
add("gui.computercraft.tooltip.turn_off", "Turn this computer off");
add("gui.computercraft.tooltip.turn_off.key", "Hold Ctrl+S");
add("gui.computercraft.tooltip.terminate", "Stop the currently running code");
add("gui.computercraft.tooltip.terminate.key", "Hold Ctrl+T");
add("gui.computercraft.upload.failed", "Upload Failed");
add("gui.computercraft.upload.failed.computer_off", "You must turn the computer on before uploading files.");
add("gui.computercraft.upload.failed.too_much", "Your files are too large to be uploaded.");
add("gui.computercraft.upload.failed.name_too_long", "File names are too long to be uploaded.");
add("gui.computercraft.upload.failed.too_many_files", "Cannot upload this many files.");
add("gui.computercraft.upload.failed.generic", "Uploading files failed (%s)");
add("gui.computercraft.upload.failed.corrupted", "Files corrupted when uploading. Please try again.");
add("gui.computercraft.upload.no_response", "Transferring Files");
add("gui.computercraft.upload.no_response.msg", "Your computer has not used your transferred files. You may need to run the %s program and try again.");
add("gui.computercraft.pocket_computer_overlay", "Pocket computer open. Press ESC to close.");
// Config options
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.computerSpaceLimit, "Computer space limit (bytes)");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.floppySpaceLimit, "Floppy Disk space limit (bytes)");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.maximumFilesOpen, "Maximum files open per computer");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.disableLua51Features, "Disable Lua 5.1 features");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.defaultComputerSettings, "Default Computer settings");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.logComputerErrors, "Log computer errors");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.commandRequireCreative, "Command computers require creative");
addConfigGroup(ConfigSpec.serverSpec, "execution", "Execution");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.computerThreads, "Computer threads");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.maxMainGlobalTime, "Server tick global time limit");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.maxMainComputerTime, "Server tick computer time limit");
addConfigGroup(ConfigSpec.serverSpec, "http", "HTTP");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpEnabled, "Enable the HTTP API");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpWebsocketEnabled, "Enable websockets");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpRules, "Allow/deny rules");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpMaxRequests, "Maximum concurrent requests");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpMaxWebsockets, "Maximum concurrent websockets");
addConfigGroup(ConfigSpec.serverSpec, "http.bandwidth", "Bandwidth");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpDownloadBandwidth, "Global download limit");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.httpUploadBandwidth, "Global upload limit");
addConfigGroup(ConfigSpec.serverSpec, "peripheral", "Peripherals");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.commandBlockEnabled, "Enable command block peripheral");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.modemRange, "Modem range (default)");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.modemHighAltitudeRange, "Modem range (high-altitude)");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.modemRangeDuringStorm, "Modem range (bad weather)");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.modemHighAltitudeRangeDuringStorm, "Modem range (high-altitude, bad weather)");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.maxNotesPerTick, "Maximum notes that a computer can play at once");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.monitorBandwidth, "Monitor bandwidth");
addConfigGroup(ConfigSpec.serverSpec, "turtle", "Turtles");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.turtlesNeedFuel, "Enable fuel");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.turtleFuelLimit, "Turtle fuel limit");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.advancedTurtleFuelLimit, "Advanced Turtle fuel limit");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.turtlesCanPush, "Turtles can push entities");
addConfigGroup(ConfigSpec.serverSpec, "term_sizes", "Terminal sizes");
addConfigGroup(ConfigSpec.serverSpec, "term_sizes.computer", "Computer");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.computerTermWidth, "Terminal width");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.computerTermHeight, "Terminal height");
addConfigGroup(ConfigSpec.serverSpec, "term_sizes.pocket_computer", "Pocket Computer");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.pocketTermWidth, "Terminal width");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.pocketTermHeight, "Terminal height");
addConfigGroup(ConfigSpec.serverSpec, "term_sizes.monitor", "Monitor");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.monitorWidth, "Max monitor width");
addConfigValue(ConfigSpec.serverSpec, ConfigSpec.monitorHeight, "Max monitor height");
addConfigValue(ConfigSpec.clientSpec, ConfigSpec.monitorRenderer, "Monitor renderer");
addConfigValue(ConfigSpec.clientSpec, ConfigSpec.monitorDistance, "Monitor distance");
addConfigValue(ConfigSpec.clientSpec, ConfigSpec.uploadNagDelay, "Upload nag delay");
}
private Stream<String> getExpectedKeys() {
return Stream.of(
Registries.BLOCKS.stream()
.filter(x -> Registries.BLOCKS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
.map(Block::getDescriptionId),
Registries.ITEMS.stream()
.filter(x -> Registries.ITEMS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
.map(Item::getDescriptionId),
turtleUpgrades.getGeneratedUpgrades().stream().map(IUpgradeBase::getUnlocalisedAdjective),
pocketUpgrades.getGeneratedUpgrades().stream().map(IUpgradeBase::getUnlocalisedAdjective),
Metric.metrics().values().stream().map(x -> AggregatedMetric.TRANSLATION_PREFIX + x.name() + ".name"),
getConfigKeys(ConfigSpec.serverSpec),
getConfigKeys(ConfigSpec.clientSpec)
).flatMap(x -> x);
}
private Stream<String> getConfigKeys(UnmodifiableConfig spec) {
return spec.entrySet().stream().flatMap(x -> {
if (x.getValue() instanceof ForgeConfigSpec.ValueSpec valueSpec) {
return Stream.of(valueSpec.getTranslationKey());
} else if (x.getValue() instanceof UnmodifiableConfig config) {
return getConfigKeys(config);
} else {
return Stream.empty();
}
});
}
private void add(String id, String text) {
Objects.requireNonNull(id, "id cannot be null");
Objects.requireNonNull(text, "text cannot be null");
if (translations.containsKey(id)) throw new IllegalArgumentException("Duplicate translation " + id);
translations.put(id, text);
}
private void add(Item item, String text) {
add(item.getDescriptionId(), text);
}
private void add(Metric metric, String text) {
add(AggregatedMetric.TRANSLATION_PREFIX + metric.name() + ".name", text);
}
private void addConfigGroup(ForgeConfigSpec spec, String path, String text) {
var pathList = Splitter.on('.').splitToList(path);
add(spec.getLevelTranslationKey(pathList), text);
add(spec.getLevelTranslationKey(pathList) + ".tooltip", spec.getLevelComment(pathList));
}
private void addConfigValue(ForgeConfigSpec spec, ForgeConfigSpec.ConfigValue<?> value, String text) {
ForgeConfigSpec.ValueSpec valueSpec = spec.getSpec().get(value.getPath());
add(valueSpec.getTranslationKey(), text);
add(valueSpec.getTranslationKey() + ".tooltip", valueSpec.getComment());
}
}