/* * 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 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", ""); 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 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 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()); } }