diff --git a/src/main/java/meteordevelopment/meteorclient/MeteorClient.java b/src/main/java/meteordevelopment/meteorclient/MeteorClient.java index 2670ade9cc..7fb667f368 100644 --- a/src/main/java/meteordevelopment/meteorclient/MeteorClient.java +++ b/src/main/java/meteordevelopment/meteorclient/MeteorClient.java @@ -27,6 +27,7 @@ import meteordevelopment.meteorclient.utils.misc.Version; import meteordevelopment.meteorclient.utils.misc.input.KeyAction; import meteordevelopment.meteorclient.utils.misc.input.KeyBinds; +import meteordevelopment.meteorclient.utils.misc.text.MeteorTranslatableTextComponent; import meteordevelopment.meteorclient.utils.network.OnlinePlayers; import meteordevelopment.orbit.EventBus; import meteordevelopment.orbit.EventHandler; @@ -37,6 +38,7 @@ import net.fabricmc.loader.api.metadata.ModMetadata; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.text.MutableText; import net.minecraft.util.Identifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -197,4 +199,12 @@ private void onOpenScreen(OpenScreenEvent event) { public static Identifier identifier(String path) { return Identifier.of(MeteorClient.MOD_ID, path); } + + public static MutableText translatable(String key, Object... args) { + return MutableText.of(new MeteorTranslatableTextComponent(key, args)); + } + + public static MutableText translatable(String key, String fallback, Object... args) { + return MutableText.of(new MeteorTranslatableTextComponent(key, fallback, args)); + } } diff --git a/src/main/java/meteordevelopment/meteorclient/addons/AddonManager.java b/src/main/java/meteordevelopment/meteorclient/addons/AddonManager.java index 54af1c4d00..2e1a10668e 100644 --- a/src/main/java/meteordevelopment/meteorclient/addons/AddonManager.java +++ b/src/main/java/meteordevelopment/meteorclient/addons/AddonManager.java @@ -48,6 +48,7 @@ public String getCommit() { ModMetadata metadata = FabricLoader.getInstance().getModContainer(MeteorClient.MOD_ID).get().getMetadata(); + MeteorClient.ADDON.id = metadata.getId(); MeteorClient.ADDON.name = metadata.getName(); MeteorClient.ADDON.authors = new String[metadata.getAuthors().size()]; if (metadata.containsCustomValue(MeteorClient.MOD_ID + ":color")) { @@ -72,6 +73,7 @@ public String getCommit() { throw new RuntimeException("Exception during addon init \"%s\".".formatted(metadata.getName()), throwable); } + addon.id = metadata.getId(); addon.name = metadata.getName(); if (metadata.getAuthors().isEmpty()) throw new RuntimeException("Addon \"%s\" requires at least 1 author to be defined in it's fabric.mod.json. See https://fabricmc.net/wiki/documentation:fabric_mod_json_spec".formatted(addon.name)); diff --git a/src/main/java/meteordevelopment/meteorclient/addons/MeteorAddon.java b/src/main/java/meteordevelopment/meteorclient/addons/MeteorAddon.java index 8499e60521..5c2eb55fff 100644 --- a/src/main/java/meteordevelopment/meteorclient/addons/MeteorAddon.java +++ b/src/main/java/meteordevelopment/meteorclient/addons/MeteorAddon.java @@ -8,6 +8,10 @@ import meteordevelopment.meteorclient.utils.render.color.Color; public abstract class MeteorAddon { + /** This field is automatically assigned from fabric.mod.json file. + * @since 1.21.11 */ // todo replace with exact version when released + public String id; + /** This field is automatically assigned from fabric.mod.json file. */ public String name; diff --git a/src/main/java/meteordevelopment/meteorclient/commands/Command.java b/src/main/java/meteordevelopment/meteorclient/commands/Command.java index 18fea76782..424502a0be 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/Command.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/Command.java @@ -12,12 +12,14 @@ import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.systems.config.Config; import meteordevelopment.meteorclient.utils.Utils; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; import meteordevelopment.meteorclient.utils.player.ChatUtils; import net.minecraft.client.MinecraftClient; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.command.CommandSource; import net.minecraft.registry.BuiltinRegistries; import net.minecraft.server.command.CommandManager; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; import java.util.List; @@ -29,14 +31,23 @@ public abstract class Command { private final String name; private final String title; - private final String description; private final List aliases; + public final String translationKey; + // todo remove the description parameter in the next minecraft version update + @Deprecated(forRemoval = true) public Command(String name, String description, String... aliases) { this.name = name; this.title = Utils.nameToTitle(name); - this.description = description; this.aliases = List.of(aliases); + this.translationKey = "meteor.command." + name; + } + + public Command(String name) { + this.name = name; + this.title = Utils.nameToTitle(name); + this.aliases = List.of(); + this.translationKey = "meteor.command." + name; } // Helper methods to painlessly infer the CommandSource generic type argument @@ -65,10 +76,6 @@ public String getName() { return name; } - public String getDescription() { - return description; - } - public List getAliases() { return aliases; } @@ -90,16 +97,24 @@ public void info(Text message) { public void info(String message, Object... args) { ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.infoPrefix(title, message, args); + ChatUtils.infoPrefix(title, MeteorTranslations.translate(translationKey + ".info." + message, message, args)); } public void warning(String message, Object... args) { ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.warningPrefix(title, message, args); + ChatUtils.warningPrefix(title, MeteorTranslations.translate(translationKey + ".warning." + message, message, args)); } public void error(String message, Object... args) { ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.errorPrefix(title, message, args); + ChatUtils.errorPrefix(title, MeteorTranslations.translate(translationKey + ".error." + message, message, args)); + } + + public MutableText translatable(String string, Object... args) { + return MeteorClient.translatable(translationKey + "." + string, args); + } + + public MutableText translatable(String string, String fallback, Object... args) { + return MeteorClient.translatable(translationKey + "." + string, fallback, args); } } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java index 3ef50aa80d..98302c02fd 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java @@ -14,7 +14,7 @@ public class BindCommand extends Command { public BindCommand() { - super("bind", "Binds a specified module to the next pressed key."); + super("bind"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java index 0bc90a5ea4..d21e6352d7 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java @@ -21,7 +21,7 @@ public class BindsCommand extends Command { public BindsCommand() { - super("binds", "List of all bound modules."); + super("binds"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java index e35078c472..7f63c4cd26 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java @@ -53,7 +53,7 @@ private MutableText getCommandText(Command command) { } tooltip.append(aliases.formatted(Formatting.GRAY)).append("\n\n"); - tooltip.append(Text.literal(command.getDescription()).formatted(Formatting.WHITE)); + tooltip.append(command.translatable("description")).formatted(Formatting.WHITE); // Text MutableText text = Text.literal(Utils.nameToTitle(command.getName())); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java index f43585276a..2ae2620ecf 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java @@ -21,7 +21,7 @@ public DisconnectCommand() { @Override public void build(LiteralArgumentBuilder builder) { builder.executes(context -> { - mc.player.networkHandler.onDisconnect(new DisconnectS2CPacket(Text.literal("%s[%sDisconnectCommand%s] Disconnected by user.".formatted(Formatting.GRAY, Formatting.BLUE, Formatting.GRAY)))); + mc.player.networkHandler.onDisconnect(new DisconnectS2CPacket(translatable("disconnection_message", Formatting.GRAY, Formatting.BLUE, Formatting.GRAY))); return SINGLE_SUCCESS; }); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/DismountCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/DismountCommand.java index 1cbdfb84cd..78253c2e8c 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/DismountCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/DismountCommand.java @@ -13,7 +13,7 @@ public class DismountCommand extends Command { public DismountCommand() { - super("dismount", "Dismounts you from entity you are riding."); + super("dismount"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java index 4816bedd09..e03c181216 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java @@ -10,6 +10,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.utils.player.InvUtils; import net.minecraft.client.network.ClientPlayerEntity; @@ -19,14 +20,13 @@ import net.minecraft.entity.EquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.text.Text; public class DropCommand extends Command { - private static final SimpleCommandExceptionType NOT_SPECTATOR = new SimpleCommandExceptionType(Text.literal("Can't drop items while in spectator.")); - private static final SimpleCommandExceptionType NO_SUCH_ITEM = new SimpleCommandExceptionType(Text.literal("Could not find an item with that name!")); + private static final SimpleCommandExceptionType NOT_SPECTATOR = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.drop.exception.not_spectator")); + private static final SimpleCommandExceptionType NO_SUCH_ITEM = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.drop.exception.no_such_item")); public DropCommand() { - super("drop", "Automatically drops specified items."); + super("drop"); } @Override @@ -70,9 +70,9 @@ public void build(LiteralArgumentBuilder builder) { // Specific item builder.then(argument("item", ItemStackArgumentType.itemStack(REGISTRY_ACCESS)) - .executes(context -> drop(player -> { - dropItem(player, context, Integer.MAX_VALUE); - })) + .executes(context -> drop(player -> + dropItem(player, context, Integer.MAX_VALUE) + )) .then(argument("amount", IntegerArgumentType.integer(1)) .executes(context -> drop(player -> { int amount = IntegerArgumentType.getInteger(context, "amount"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java index 7eb9e6b584..d9dc46cb3c 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java @@ -10,6 +10,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.commands.arguments.RegistryEntryReferenceArgumentType; import meteordevelopment.meteorclient.utils.Utils; @@ -19,16 +20,15 @@ import net.minecraft.item.ItemStack; import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.text.Text; import java.util.function.ToIntFunction; public class EnchantCommand extends Command { - private static final SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(Text.literal("You must be in creative mode to use this.")); - private static final SimpleCommandExceptionType NOT_HOLDING_ITEM = new SimpleCommandExceptionType(Text.literal("You need to hold some item to enchant.")); + private static final SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.enchant.exception.not_in_creative")); + private static final SimpleCommandExceptionType NOT_HOLDING_ITEM = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.enchant.exception.not_holding_item")); public EnchantCommand() { - super("enchant", "Enchants the item in your hand. REQUIRES Creative mode."); + super("enchant"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java index 5374e1f503..09dd5e3797 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java @@ -13,12 +13,11 @@ import meteordevelopment.meteorclient.systems.modules.player.FakePlayer; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerEntity; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerManager; -import meteordevelopment.meteorclient.utils.player.ChatUtils; import net.minecraft.command.CommandSource; public class FakePlayerCommand extends Command { public FakePlayerCommand() { - super("fake-player", "Manages fake players that you can use for testing."); + super("fake-player"); } @Override @@ -43,12 +42,12 @@ public void build(LiteralArgumentBuilder builder) { .executes(context -> { FakePlayerEntity fp = FakePlayerArgumentType.get(context); if (fp == null || !FakePlayerManager.contains(fp)) { - error("Couldn't find a Fake Player with that name."); + error("not_found"); return SINGLE_SUCCESS; } FakePlayerManager.remove(fp); - info("Removed Fake Player %s.".formatted(fp.getName().getString())); + info("removed", fp.getName().getString()); return SINGLE_SUCCESS; }) @@ -65,7 +64,7 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("list") .executes(context -> { info("--- Fake Players ((highlight)%s(default)) ---", FakePlayerManager.count()); - FakePlayerManager.forEach(fp -> ChatUtils.info("(highlight)%s".formatted(fp.getName().getString()))); + FakePlayerManager.forEach(fp -> info("(highlight)%s".formatted(fp.getName().getString()))); return SINGLE_SUCCESS; }) ); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/FovCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/FovCommand.java index dd612d030a..bf5aef1948 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/FovCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/FovCommand.java @@ -13,7 +13,7 @@ public class FovCommand extends Command { public FovCommand() { - super("fov", "Changes your fov."); + super("fov"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java index 23ae209cad..84d12f56c6 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java @@ -18,7 +18,7 @@ public class FriendsCommand extends Command { public FriendsCommand() { - super("friends", "Manages friends."); + super("friends"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java index 94150a58b7..83b4e8bc12 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java @@ -9,6 +9,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.utils.player.FindItemResult; import meteordevelopment.meteorclient.utils.player.InvUtils; @@ -16,14 +17,13 @@ import net.minecraft.command.argument.ItemStackArgumentType; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket; -import net.minecraft.text.Text; public class GiveCommand extends Command { - private final static SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(Text.literal("You must be in creative mode to use this.")); - private final static SimpleCommandExceptionType NO_SPACE = new SimpleCommandExceptionType(Text.literal("No space in hotbar.")); + private final static SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.give.exception.not_in_creative")); + private final static SimpleCommandExceptionType NO_SPACE = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.give.exception.no_space")); public GiveCommand() { - super("give", "Gives you any item."); + super("give"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/HClipCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/HClipCommand.java index 2af1daa8f3..11528ac7cf 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/HClipCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/HClipCommand.java @@ -14,7 +14,7 @@ public class HClipCommand extends Command { public HClipCommand() { - super("hclip", "Lets you clip through blocks horizontally."); + super("hclip"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java index e453767910..add4cdbd37 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java @@ -41,7 +41,7 @@ public class InputCommand extends Command { ); public InputCommand() { - super("input", "Keyboard input simulation."); + super("input"); } @Override @@ -76,9 +76,9 @@ public void build(LiteralArgumentBuilder builder) { } builder.then(literal("clear").executes(ctx -> { - if (activeHandlers.isEmpty()) warning("No active keypress handlers."); + if (activeHandlers.isEmpty()) warning("no_handlers"); else { - info("Cleared all keypress handlers."); + info("cleared_handlers"); activeHandlers.forEach(MeteorClient.EVENT_BUS::unsubscribe); activeHandlers.clear(); } @@ -86,12 +86,12 @@ public void build(LiteralArgumentBuilder builder) { })); builder.then(literal("list").executes(ctx -> { - if (activeHandlers.isEmpty()) warning("No active keypress handlers."); + if (activeHandlers.isEmpty()) warning("no_handlers"); else { - info("Active keypress handlers: "); + info(""); for (int i = 0; i < activeHandlers.size(); i++) { KeypressHandler handler = activeHandlers.get(i); - info("(highlight)%d(default) - (highlight)%s %d(default) ticks left out of (highlight)%d(default).", i, I18n.translate(handler.key.getId()), handler.ticks, handler.totalTicks); + info("keypress_handler", i, I18n.translate(handler.key.getId()), handler.ticks, handler.totalTicks); } } return SINGLE_SUCCESS; @@ -99,9 +99,9 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("remove").then(argument("index", IntegerArgumentType.integer(0)).executes(ctx -> { int index = IntegerArgumentType.getInteger(ctx, "index"); - if (index >= activeHandlers.size()) warning("Index out of range."); + if (index >= activeHandlers.size()) warning("out_of_range"); else { - info("Removed keypress handler."); + info("removed_handler"); MeteorClient.EVENT_BUS.unsubscribe(activeHandlers.get(index)); activeHandlers.remove(index); } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/MacroCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/MacroCommand.java index 074c9eae8d..566cfb43e1 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/MacroCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/MacroCommand.java @@ -21,7 +21,7 @@ public class MacroCommand extends Command { public MacroCommand() { - super("macro", "Allows you to execute macros."); + super("macro"); MeteorClient.EVENT_BUS.subscribe(this); } @@ -35,12 +35,12 @@ public void build(LiteralArgumentBuilder builder) { .then(literal("clear") .executes(context -> { if (scheduleQueue.isEmpty() && scheduledMacros.isEmpty()) { - error("No macros are currently scheduled."); + error("none_scheduled"); return SINGLE_SUCCESS; } clearAll(); - info("Cleared all scheduled macros."); + info("cleared_all"); return SINGLE_SUCCESS; }) @@ -49,12 +49,12 @@ public void build(LiteralArgumentBuilder builder) { Macro macro = MacroArgumentType.get(context); if (!isScheduled(macro)) { - error("This macro is not currently scheduled."); + error("not_scheduled"); return SINGLE_SUCCESS; } clear(macro); - info("Cleared scheduled macro."); + info("cleared"); return SINGLE_SUCCESS; }) ) diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java index db1a317183..3a646a477c 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java @@ -38,13 +38,13 @@ public void build(LiteralArgumentBuilder builder) { UUID uuid = lookUpTarget.getProfile().id(); NameHistory history = Http.get("https://laby.net/api/v2/user/" + uuid + "/get-profile") - .exceptionHandler(e -> error("There was an error fetching that users name history.")) + .exceptionHandler(e -> error("error_fetching_name")) .sendJson(NameHistory.class); if (history == null) { return; } else if (history.username_history == null || history.username_history.length == 0) { - error("There was an error fetching that users name history."); + error("error_fetching_name"); } String name = lookUpTarget.getProfile().name(); @@ -85,7 +85,7 @@ public void build(LiteralArgumentBuilder builder) { if (!entry.accurate) { MutableText text = Text.literal("*").formatted(Formatting.WHITE); - text.setStyle(text.getStyle().withHoverEvent(new HoverEvent.ShowText(Text.literal("This name history entry is not accurate according to laby.net")))); + text.setStyle(text.getStyle().withHoverEvent(new HoverEvent.ShowText(translatable("inaccurate")))); nameText.append(text); } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java index 1eea843b3a..667b28c421 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java @@ -51,7 +51,7 @@ public class NbtCommand extends Command { ))); public NbtCommand() { - super("nbt", "Modifies NBT data for an item, example: .nbt add {display:{Name:'{\"text\":\"$cRed Name\"}'}}"); + super("nbt"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java index ee791ce2fc..cf6822fb2e 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java @@ -41,7 +41,7 @@ public class NotebotCommand extends Command { private final Map> song = new HashMap<>(); // tick -> notes public NotebotCommand() { - super("notebot", "Allows you load notebot files"); + super("notebot"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java index 52e9761622..77d2ac6dcf 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java @@ -19,7 +19,7 @@ public class PeekCommand extends Command { private static final SimpleCommandExceptionType CANT_PEEK = new SimpleCommandExceptionType(Text.literal("You must be holding a storage block or looking at an item frame.")); public PeekCommand() { - super("peek", "Lets you see what's inside storage block items."); + super("peek"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java index 43c816f1c1..f8b0b7c25d 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java @@ -15,7 +15,7 @@ public class ProfilesCommand extends Command { public ProfilesCommand() { - super("profiles", "Loads and saves profiles."); + super("profiles"); } @Override @@ -25,7 +25,7 @@ public void build(LiteralArgumentBuilder builder) { if (profile != null) { profile.load(); - info("Loaded profile (highlight)%s(default).", profile.name.get()); + info("loaded", profile.name.get()); } return SINGLE_SUCCESS; @@ -36,7 +36,7 @@ public void build(LiteralArgumentBuilder builder) { if (profile != null) { profile.save(); - info("Saved profile (highlight)%s(default).", profile.name.get()); + info("saved", profile.name.get()); } return SINGLE_SUCCESS; @@ -47,7 +47,7 @@ public void build(LiteralArgumentBuilder builder) { if (profile != null) { Profiles.get().remove(profile); - info("Deleted profile (highlight)%s(default).", profile.name.get()); + info("deleted", profile.name.get()); } return SINGLE_SUCCESS; diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ReloadCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ReloadCommand.java index f299819854..4a66ff2272 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ReloadCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ReloadCommand.java @@ -17,13 +17,13 @@ public class ReloadCommand extends Command { public ReloadCommand() { - super("reload", "Reloads many systems."); + super("reload"); } @Override public void build(LiteralArgumentBuilder builder) { builder.executes(context -> { - warning("Reloading systems, this may take a while."); + warning("reloading"); Systems.load(); Capes.init(); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java index 3377b7d7e1..d5cd90994e 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java @@ -19,7 +19,7 @@ public class ResetCommand extends Command { public ResetCommand() { - super("reset", "Resets specified settings."); + super("reset"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/RotationCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/RotationCommand.java index d9b3be2622..ec0aa00d1b 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/RotationCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/RotationCommand.java @@ -15,7 +15,7 @@ public class RotationCommand extends Command { public RotationCommand() { - super("rotation", "Modifies your rotation."); + super("rotation"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java index e29c4f2f48..232ed70e9f 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java @@ -19,7 +19,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; -import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.lwjgl.BufferUtils; import org.lwjgl.PointerBuffer; @@ -33,8 +32,8 @@ import java.nio.ByteBuffer; public class SaveMapCommand extends Command { - private static final SimpleCommandExceptionType MAP_NOT_FOUND = new SimpleCommandExceptionType(Text.literal("You must be holding a filled map.")); - private static final SimpleCommandExceptionType OOPS = new SimpleCommandExceptionType(Text.literal("Something went wrong.")); + private static final SimpleCommandExceptionType MAP_NOT_FOUND = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.save-map.exception.map_not_found")); + private static final SimpleCommandExceptionType OOPS = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.save-map.exception.oops")); private final PointerBuffer filters; @@ -72,24 +71,25 @@ private void saveMap(int scale) throws CommandSyntaxException { if (path == null) throw OOPS.create(); MapTextureManagerAccessor textureManager = (MapTextureManagerAccessor) mc.gameRenderer.getClient().getMapTextureManager(); - MapTextureManager.MapTexture texture = textureManager.meteor$invokeGetMapTexture(map.get(DataComponentTypes.MAP_ID), state); - if (texture.texture.getImage() == null) throw OOPS.create(); - - try { - if (scale == 128) texture.texture.getImage().writeTo(path); - else { - int[] data = texture.texture.getImage().makePixelArray(); - BufferedImage image = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB); - image.setRGB(0, 0, image.getWidth(), image.getHeight(), data, 0, 128); - - BufferedImage scaledImage = new BufferedImage(scale, scale, 2); - scaledImage.createGraphics().drawImage(image, 0, 0, scale, scale, null); - - ImageIO.write(scaledImage, "png", path); + try (MapTextureManager.MapTexture texture = textureManager.meteor$invokeGetMapTexture(map.get(DataComponentTypes.MAP_ID), state)) { + if (texture.texture.getImage() == null) throw OOPS.create(); + + try { + if (scale == 128) texture.texture.getImage().writeTo(path); + else { + int[] data = texture.texture.getImage().makePixelArray(); + BufferedImage image = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB); + image.setRGB(0, 0, image.getWidth(), image.getHeight(), data, 0, 128); + + BufferedImage scaledImage = new BufferedImage(scale, scale, 2); + scaledImage.createGraphics().drawImage(image, 0, 0, scale, scale, null); + + ImageIO.write(scaledImage, "png", path); + } + } catch (IOException e) { + error("error_writing_texture"); + MeteorClient.LOG.error(e.toString()); } - } catch (IOException e) { - error("Error writing map texture"); - MeteorClient.LOG.error(e.toString()); } } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/SayCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/SayCommand.java index 102bc003fe..298a3512c0 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/SayCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/SayCommand.java @@ -23,7 +23,7 @@ public class SayCommand extends Command { public SayCommand() { - super("say", "Sends messages in chat."); + super("say"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java index c8441e85c0..969cdaa8b8 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java @@ -50,7 +50,7 @@ public class ServerCommand extends Command { public ServerCommand() { - super("server", "Prints server information"); + super("server"); MeteorClient.EVENT_BUS.subscribe(this); } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/SpectateCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/SpectateCommand.java index d54ed7cce9..deefaa9f60 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/SpectateCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/SpectateCommand.java @@ -21,7 +21,7 @@ public class SpectateCommand extends Command { private final StaticListener shiftListener = new StaticListener(); public SpectateCommand() { - super("spectate", "Allows you to spectate nearby players"); + super("spectate"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java index 555b73793d..1b39b2b3d9 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java @@ -43,7 +43,7 @@ public class SwarmCommand extends Command { private @Nullable ObjectIntPair pendingConnection; public SwarmCommand() { - super("swarm", "Sends commands to connected swarm workers."); + super("swarm"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/VClipCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/VClipCommand.java index 13124e5a54..d1ee18751c 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/VClipCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/VClipCommand.java @@ -14,7 +14,7 @@ public class VClipCommand extends Command { public VClipCommand() { - super("vclip", "Lets you clip through blocks vertically."); + super("vclip"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/WaspCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/WaspCommand.java index 1b3fb81e6a..0f57375d76 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/WaspCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/WaspCommand.java @@ -7,19 +7,19 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.commands.arguments.PlayerArgumentType; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.movement.AutoWasp; import net.minecraft.command.CommandSource; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.text.Text; public class WaspCommand extends Command { - private static final SimpleCommandExceptionType CANT_WASP_SELF = new SimpleCommandExceptionType(Text.literal("You cannot target yourself!")); + private static final SimpleCommandExceptionType CANT_WASP_SELF = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.wasp.exception.cant_wasp_self")); public WaspCommand() { - super("wasp", "Sets the auto wasp target."); + super("wasp"); } @Override @@ -38,7 +38,7 @@ public void build(LiteralArgumentBuilder builder) { wasp.target = player; if (!wasp.isActive()) wasp.toggle(); - info(player.getName().getString() + " set as target."); + info("target", player.getName().getString()); return SINGLE_SUCCESS; })); } diff --git a/src/main/java/meteordevelopment/meteorclient/gui/screens/ModulesScreen.java b/src/main/java/meteordevelopment/meteorclient/gui/screens/ModulesScreen.java index 02c9c0e33a..bd1f0bfbd3 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/screens/ModulesScreen.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/screens/ModulesScreen.java @@ -9,6 +9,7 @@ import meteordevelopment.meteorclient.gui.tabs.TabScreen; import meteordevelopment.meteorclient.gui.tabs.Tabs; import meteordevelopment.meteorclient.gui.utils.Cell; +import meteordevelopment.meteorclient.gui.widgets.WLabel; import meteordevelopment.meteorclient.gui.widgets.containers.WContainer; import meteordevelopment.meteorclient.gui.widgets.containers.WSection; import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList; @@ -18,13 +19,17 @@ import meteordevelopment.meteorclient.systems.modules.Category; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; import meteordevelopment.meteorclient.utils.misc.NbtUtils; +import meteordevelopment.meteorclient.utils.render.prompts.YesNoPrompt; import net.minecraft.item.Items; +import net.minecraft.util.Util; import java.util.ArrayList; import java.util.List; import java.util.Set; +import static meteordevelopment.meteorclient.MeteorClient.mc; import static meteordevelopment.meteorclient.utils.Utils.getWindowHeight; import static meteordevelopment.meteorclient.utils.Utils.getWindowWidth; @@ -43,6 +48,32 @@ public void initWidgets() { WVerticalList help = add(theme.verticalList()).pad(4).bottom().widget(); help.add(theme.label("Left click - Toggle module")); help.add(theme.label("Right click - Open module settings")); + + // Translation info + if (MeteorTranslations.isEnglish()) return; + double t = MeteorTranslations.percentLocalised(); + + WLabel translation = add(theme.label(String.format("%.1f%% translated", t))).pad(4).bottom().right().widget(); + translation.tooltip = "Open translation info"; + translation.instantTooltips = true; + translation.action = () -> { + // people who translate deserve their names recognised for it + String translators = MeteorTranslations.translate("meteor.lang.translators", ""); + // todo switch this to master before we merge + String url = "https://github.com/MeteorDevelopment/meteor-client/blob/translations/src/main/resources/assets/meteor-client/language/" + mc.options.language.toLowerCase() + ".json"; + + YesNoPrompt prompt = YesNoPrompt.create(theme, this) + .title("Translation Information") + .message("The current language (%s) is currently %.1f%% translated.", mc.options.language, t); + + if (!translators.isEmpty()) prompt.message("Translation work done by: " + translators); + + prompt.message("") + .message("Do you want to open the language file for the current language?") + .onYes(() -> Util.getOperatingSystem().open(url)) + .dontShowAgainCheckboxVisible(false) + .show(); + }; } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/widgets/WWidget.java b/src/main/java/meteordevelopment/meteorclient/gui/widgets/WWidget.java index c3286c2f36..a87b061696 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/widgets/WWidget.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/widgets/WWidget.java @@ -24,7 +24,7 @@ public abstract class WWidget implements BaseWidget { public String tooltip; public boolean mouseOver; - protected boolean instantTooltips; + public boolean instantTooltips; protected double mouseOverTimer; public void init() {} diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/AbstractSignEditScreenMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/AbstractSignEditScreenMixin.java deleted file mode 100644 index 68cb072b41..0000000000 --- a/src/main/java/meteordevelopment/meteorclient/mixin/AbstractSignEditScreenMixin.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). - * Copyright (c) Meteor Development. - */ - -package meteordevelopment.meteorclient.mixin; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen; -import net.minecraft.text.*; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; - -import java.util.stream.Stream; - -@Mixin(AbstractSignEditScreen.class) -public abstract class AbstractSignEditScreenMixin { - @ModifyExpressionValue(method = "(Lnet/minecraft/block/entity/SignBlockEntity;ZZLnet/minecraft/text/Text;)V", at = @At(value = "INVOKE", target = "Ljava/util/stream/IntStream;mapToObj(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;")) - private Stream modifyTranslatableText(Stream original) { - return original.map(this::modifyText); - } - - // based on https://github.com/JustAlittleWolf/ModDetectionPreventer - @Unique - private Text modifyText(Text message) { - MutableText modified = MutableText.of(message.getContent()); - - if (message.getContent() instanceof KeybindTextContent content) { - String key = content.getKey(); - - if (key.contains("meteor-client")) modified = MutableText.of(new PlainTextContent.Literal(key)); - } - if (message.getContent() instanceof TranslatableTextContent content) { - String key = content.getKey(); - - if (key.contains("meteor-client")) modified = MutableText.of(new PlainTextContent.Literal(key)); - } - - modified.setStyle(message.getStyle()); - for (Text sibling : message.getSiblings()) { - modified.append(modifyText(sibling)); - } - - return modified; - } -} diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/ControlListWidgetMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/ControlListWidgetMixin.java new file mode 100644 index 0000000000..40bcc25ae7 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/mixin/ControlListWidgetMixin.java @@ -0,0 +1,24 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.mixin; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.gui.screen.option.ControlsListWidget; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.text.MutableText; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ControlsListWidget.class) +public class ControlListWidgetMixin { + @ModifyExpressionValue(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/Text;translatable(Ljava/lang/String;)Lnet/minecraft/text/MutableText;")) + private MutableText modifyText(MutableText original, @Local KeyBinding binding) { + if (binding.getId().startsWith("meteor.key.")) return MeteorClient.translatable(binding.getId()); + return original; + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/DownloaderMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/DownloaderMixin.java index 85362f4815..1da0f0eb09 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/DownloaderMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/DownloaderMixin.java @@ -7,8 +7,8 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; -import meteordevelopment.meteorclient.MeteorClient; import net.minecraft.util.Downloader; +import net.minecraft.util.Uuids; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -36,10 +36,7 @@ public class DownloaderMixin { @ModifyExpressionValue(method = "method_55485", at = @At(value = "INVOKE", target = "Ljava/nio/file/Path;resolve(Ljava/lang/String;)Ljava/nio/file/Path;")) private Path hookResolve(Path original, @Local(argsOnly = true) UUID id) { UUID accountId = mc.getSession().getUuidOrNull(); - if (accountId == null) { - MeteorClient.LOG.warn("Failed to change resource pack download directory because the account id is null."); - return original; - } + if (accountId == null) accountId = Uuids.getOfflinePlayerUuid(mc.getSession().getUsername()); return directory.resolve(accountId.toString()).resolve(id.toString()); } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/KeyBindingCategoryMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/KeyBindingCategoryMixin.java new file mode 100644 index 0000000000..fcb1709e42 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/mixin/KeyBindingCategoryMixin.java @@ -0,0 +1,29 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.mixin; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(KeyBinding.Category.class) +public class KeyBindingCategoryMixin { + @Shadow + @Final + private Identifier id; + + @ModifyReturnValue(method = "getLabel", at = @At("RETURN")) + private Text modifyLabel(Text original) { + if (id.getNamespace().equals(MeteorClient.MOD_ID)) return MeteorClient.translatable(id.getPath()); + return original; + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LanguageManagerMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LanguageManagerMixin.java new file mode 100644 index 0000000000..4a1868909c --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LanguageManagerMixin.java @@ -0,0 +1,22 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.mixin; + +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; +import net.minecraft.client.resource.language.LanguageManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LanguageManager.class) +public class LanguageManagerMixin { + @Inject(method = "setLanguage", at = @At("TAIL")) + private void onSetLanguage(String languageCode, CallbackInfo ci) { + MeteorTranslations.loadLanguage(languageCode); + MeteorTranslations.clearUnusedLanguages(languageCode); + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java new file mode 100644 index 0000000000..c726bb5d4e --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java @@ -0,0 +1,179 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc; + +import com.google.gson.Gson; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.addons.AddonManager; +import meteordevelopment.meteorclient.addons.MeteorAddon; +import meteordevelopment.meteorclient.utils.PreInit; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.resource.language.LanguageDefinition; +import net.minecraft.client.resource.language.ReorderingUtil; +import net.minecraft.text.OrderedText; +import net.minecraft.text.StringVisitable; +import net.minecraft.util.Language; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +@SuppressWarnings("unused") +public class MeteorTranslations { + private static final String EN_US_CODE = "en_us"; + private static final Gson GSON = new Gson(); + private static final Map languages = new Object2ObjectOpenHashMap<>(); + private static MeteorLanguage defaultLanguage; + + @PreInit + public static void preInit() { + List toLoad = new ArrayList<>(2); + toLoad.add(EN_US_CODE); + if (!mc.options.language.equals(EN_US_CODE)) toLoad.add(mc.options.language); + + for (String language : toLoad) { + loadLanguage(language); + } + + defaultLanguage = getLanguage(EN_US_CODE); + } + + public static void loadLanguage(String languageCode) { + if (languages.containsKey(languageCode)) return; + + LanguageDefinition definition = MinecraftClient.getInstance().getLanguageManager().getLanguage(languageCode); + if (definition == null) return; + + Object2ObjectOpenHashMap languageMap = new Object2ObjectOpenHashMap<>(); + + try (InputStream stream = MeteorTranslations.class.getResourceAsStream("/assets/meteor-client/language/" + languageCode + ".json")) { + if (stream == null) { + if (languageCode.equals(EN_US_CODE)) throw new RuntimeException("Error loading the default language"); + else MeteorClient.LOG.info("No language file found for '{}'", languageCode); + } + else { + // noinspection unchecked + Object2ObjectOpenHashMap map = GSON.fromJson(new InputStreamReader(stream, StandardCharsets.UTF_8), Object2ObjectOpenHashMap.class); + languageMap.putAll(map); + + MeteorClient.LOG.info("Loaded language: {}", languageCode); + } + } catch (IOException e) { + if (languageCode.equals(EN_US_CODE)) throw new RuntimeException("Error loading default language", e); + else MeteorClient.LOG.error("Error loading language: {}", languageCode, e); + } + + for (MeteorAddon addon : AddonManager.ADDONS) { + if (addon == MeteorClient.ADDON) continue; + + try (InputStream stream = addon.getClass().getResourceAsStream("/assets/" + addon.id + "/language/" + languageCode + ".json")) { + if (stream == null) continue; + + // noinspection unchecked + Object2ObjectOpenHashMap map = GSON.fromJson(new InputStreamReader(stream, StandardCharsets.UTF_8), Object2ObjectOpenHashMap.class); + languageMap.putAll(map); + + MeteorClient.LOG.info("Loaded language {} from addon {}", languageCode, addon.name); + } catch (IOException e) { + MeteorClient.LOG.error("Error loading language {} from addon {}", languageCode, addon.name, e); + } + } + + if (!languageMap.isEmpty()) { + languages.put(languageCode, new MeteorLanguage(definition.rightToLeft(), languageMap)); + } + } + + public static void clearUnusedLanguages(String currentLanguageCode) { + languages.keySet().removeIf(languageCode -> !languageCode.equals(EN_US_CODE) && !languageCode.equals(currentLanguageCode)); + } + + public static String translate(String key, Object... args) { + MeteorLanguage currentLang = getCurrentLanguage(); + String translated = currentLang.get(key, getDefaultLanguage().get(key)); + + try { + return String.format(translated, args); + } catch (IllegalFormatException e) { + return key; + } + } + + public static String translate(String key, String fallback, Object... args) { + MeteorLanguage currentLang = getCurrentLanguage(); + String translated = currentLang.get(key, getDefaultLanguage().get(key, fallback)); + + try { + return String.format(translated, args); + } catch (IllegalFormatException e) { + return fallback; + } + } + + public static MeteorLanguage getLanguage(String lang) { + return languages.get(lang); + } + + public static MeteorLanguage getCurrentLanguage() { + return languages.getOrDefault(mc.options.language, getDefaultLanguage()); + } + + public static MeteorLanguage getDefaultLanguage() { + return defaultLanguage; + } + + /** + * @return what percentage of the current language has been localised compared to the default language + */ + public static double percentLocalised() { + // Right now there aren't enough differences between the english dialects to justify each having their own + // translation. Maybe that will change in the future. + if (isEnglish()) return 100; + + MeteorLanguage currentLang = languages.get(mc.options.language); + double currentLangSize = currentLang != null ? currentLang.translations.size() : 0; + return (currentLangSize / getDefaultLanguage().translations.size()) * 100; + } + + public static boolean isEnglish() { + return mc.options.language.startsWith("en"); + } + + public static class MeteorLanguage extends Language { + private final Map translations = new Object2ObjectOpenHashMap<>(); + private final boolean rightToLeft; + + public MeteorLanguage(boolean rightToLeft, Map translations) { + this.rightToLeft = rightToLeft; + this.translations.putAll(translations); + } + + @Override + public String get(String key, String fallback) { + return translations.getOrDefault(key, fallback); + } + + @Override + public boolean hasTranslation(String key) { + return translations.containsKey(key); + } + + @Override + public boolean isRightToLeft() { + return this.rightToLeft; + } + + @Override + public OrderedText reorder(StringVisitable text) { + return ReorderingUtil.reorder(text, this.rightToLeft); + } + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/input/KeyBinds.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/input/KeyBinds.java index 6830326c87..ca346284ad 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/misc/input/KeyBinds.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/input/KeyBinds.java @@ -11,16 +11,22 @@ import org.lwjgl.glfw.GLFW; public class KeyBinds { - private static final KeyBinding.Category CATEGORY = KeyBinding.Category.create(MeteorClient.identifier("meteor-client")); + /** + * see {@link meteordevelopment.meteorclient.mixin.KeyBindingCategoryMixin} + */ + private static final KeyBinding.Category CATEGORY = KeyBinding.Category.create(MeteorClient.identifier("meteor.key.category")); - public static KeyBinding OPEN_GUI = new KeyBinding("key.meteor-client.open-gui", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, CATEGORY); - public static KeyBinding OPEN_COMMANDS = new KeyBinding("key.meteor-client.open-commands", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_PERIOD, CATEGORY); + /** + * see {@link meteordevelopment.meteorclient.mixin.ControlListWidgetMixin} + */ + public static KeyBinding OPEN_GUI = new KeyBinding("meteor.key.open-gui", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, CATEGORY); + public static KeyBinding OPEN_COMMANDS = new KeyBinding("meteor.key.open-commands", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_PERIOD, CATEGORY); private KeyBinds() { } public static KeyBinding[] apply(KeyBinding[] binds) { - // Add key binding + // Add key bindings KeyBinding[] newBinds = new KeyBinding[binds.length + 2]; System.arraycopy(binds, 0, newBinds, 0, binds.length); diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextComponent.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextComponent.java new file mode 100644 index 0000000000..10f568660e --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextComponent.java @@ -0,0 +1,77 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +import com.mojang.serialization.MapCodec; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; +import net.minecraft.text.StringVisitable; +import net.minecraft.text.Style; +import net.minecraft.text.TextContent; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class MeteorTranslatableTextComponent implements TextContent { + private final String key; + @Nullable + private final String fallback; + private final Object[] args; + + private String translation; + private String cachedLanguage; + + public MeteorTranslatableTextComponent(String key, @Nullable String fallback, Object... args) { + this.key = key; + this.fallback = fallback; + this.args = args; + } + + public MeteorTranslatableTextComponent(String key, Object... args) { + this(key, null, args); + } + + private void updateTranslations() { + if (!mc.options.language.equals(this.cachedLanguage)) { + cachedLanguage = mc.options.language; + translation = fallback == null ? MeteorTranslations.translate(key, args) : MeteorTranslations.translate(key, fallback, args); + } + } + + @Override + public Optional visit(StringVisitable.StyledVisitor visitor, Style style) { + updateTranslations(); + + return visitor.accept(style, translation); + } + + @Override + public Optional visit(StringVisitable.Visitor visitor) { + updateTranslations(); + + return visitor.accept(translation); + } + + @Override + public MapCodec getCodec() { + return null; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (!(o instanceof MeteorTranslatableTextComponent component)) return false; + return Objects.equals(this.key, component.key) && Objects.equals(this.fallback, component.fallback) && Arrays.equals(this.args, component.args); + } + + @Override + public String toString() { + return "MeteorTranslatableTextComponent[key=" + key + ", fallback=" + fallback + ", args=" + Arrays.toString(args) + "]"; + } +} diff --git a/src/main/resources/assets/meteor-client/lang/en_gb.json b/src/main/resources/assets/meteor-client/lang/en_gb.json deleted file mode 100644 index 7b02207810..0000000000 --- a/src/main/resources/assets/meteor-client/lang/en_gb.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "key.meteor-client.open-gui": "Open GUI", - "key.meteor-client.open-commands": "Open Commands", - "key.category.meteor-client.meteor-client": "Meteor Client" -} diff --git a/src/main/resources/assets/meteor-client/lang/en_us.json b/src/main/resources/assets/meteor-client/lang/en_us.json deleted file mode 100644 index 7b02207810..0000000000 --- a/src/main/resources/assets/meteor-client/lang/en_us.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "key.meteor-client.open-gui": "Open GUI", - "key.meteor-client.open-commands": "Open Commands", - "key.category.meteor-client.meteor-client": "Meteor Client" -} diff --git a/src/main/resources/assets/meteor-client/lang/hi_in.json b/src/main/resources/assets/meteor-client/lang/hi_in.json deleted file mode 100644 index 991dfbf4ee..0000000000 --- a/src/main/resources/assets/meteor-client/lang/hi_in.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key.meteor-client.open-gui": "GUI खोलें", - "key.meteor-client.open-commands": "कमांड खोलें" -} diff --git a/src/main/resources/assets/meteor-client/lang/pt_br.json b/src/main/resources/assets/meteor-client/lang/pt_br.json deleted file mode 100644 index 0056869be4..0000000000 --- a/src/main/resources/assets/meteor-client/lang/pt_br.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key.meteor-client.open-gui": "Abrir Menu", - "key.meteor-client.open-commands": "Abrir Comandos" -} diff --git a/src/main/resources/assets/meteor-client/lang/vi_vn.json b/src/main/resources/assets/meteor-client/lang/vi_vn.json deleted file mode 100644 index 86372f9041..0000000000 --- a/src/main/resources/assets/meteor-client/lang/vi_vn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key.meteor-client.open-gui": "Mở giao diện", - "key.meteor-client.open-commands": "Mở lệnh" -} diff --git a/src/main/resources/assets/meteor-client/lang/zh_cn.json b/src/main/resources/assets/meteor-client/lang/zh_cn.json deleted file mode 100644 index 4c1eaa1207..0000000000 --- a/src/main/resources/assets/meteor-client/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key.meteor-client.open-gui": "打开GUI", - "key.meteor-client.open-commands": "输入命令" -} diff --git a/src/main/resources/assets/meteor-client/language/en_gb.json b/src/main/resources/assets/meteor-client/language/en_gb.json new file mode 100644 index 0000000000..35aa0b8e0c --- /dev/null +++ b/src/main/resources/assets/meteor-client/language/en_gb.json @@ -0,0 +1,74 @@ +{ + "meteor.key.category": "Meteor Client", + "meteor.key.open-commands": "Open Commands", + "meteor.key.open-gui": "Open GUI", + + "meteor.command.bind.description": "Binds a specified module to the next pressed key.", + "meteor.command.binds.description": "List of all bound modules.", + "meteor.command.commands.description": "List of all commands.", + "meteor.command.damage.description": "Damages self.", + "meteor.command.disconnect.description": "Disconnect from the server", + "meteor.command.disconnect.disconnection_message": "%s[%sDisconnectCommand%s] Disconnected by user.", + "meteor.command.dismount.description": "Dismounts you from entity you are riding.", + "meteor.command.drop.description": "Automatically drops specified items.", + "meteor.command.drop.exception.no_such_item": "Could not find an item with that name!", + "meteor.command.drop.exception.not_spectator": "Can't drop items while in spectator.", + "meteor.command.enchant.description": "Enchants the item in your hand. REQUIRES Creative mode.", + "meteor.command.enchant.exception.not_holding_item": "You need to hold some item to enchant.", + "meteor.command.enchant.exception.not_in_creative": "You must be in creative mode to use this.", + "meteor.command.ender-chest.description": "Allows you to preview memory of your ender chest.", + "meteor.command.fake-player.description": "Manages fake players that you can use for testing.", + "meteor.command.fake-player.error.not_found": "Couldn't find a Fake Player with that name.", + "meteor.command.fake-player.info.removed": "Removed Fake Player %s.", + "meteor.command.fov.description": "Changes your fov.", + "meteor.command.friends.description": "Manages friends.", + "meteor.command.gamemode.description": "Changes your gamemode client-side.", + "meteor.command.give.description": "Gives you any item.", + "meteor.command.give.exception.not_in_creative": "You must be in creative mode to use this.", + "meteor.command.give.exception.no_space": "No space in hotbar.", + "meteor.command.hclip.description": "Lets you clip through blocks horizontally.", + "meteor.command.input.description": "Keyboard input simulation.", + "meteor.command.input.info.cleared_handlers": "Cleared all keypress handlers.", + "meteor.command.input.info.active_handlers": "Active keypress handlers: ", + "meteor.command.input.info.keypress_handler": "(highlight)%d(default) - (highlight)%s %d(default) ticks left out of (highlight)%d(default).", + "meteor.command.input.info.removed_handler": "Removed keypress handler.", + "meteor.command.input.warning.no_handlers": "No active keypress handlers.", + "meteor.command.input.warning.out_of_range": "Index out of range.", + "meteor.command.inventory.description": "Allows you to see parts of another player's inventory.", + "meteor.command.locate.description": "Locates structures", + "meteor.command.macro.description": "Allows you to execute macros.", + "meteor.command.macro.error.none_scheduled": "No macros are currently scheduled.", + "meteor.command.macro.error.not_scheduled": "This macro is not currently scheduled.", + "meteor.command.macro.info.cleared_all": "Cleared all scheduled macros.", + "meteor.command.macro.info.cleared": "Cleared scheduled macro.", + "meteor.command.modules.description": "Displays a list of all modules.", + "meteor.command.name-history.description": "Provides a list of a players previous names from the laby.net api", + "meteor.command.name-history.error.error_fetching_name": "There was an error fetching that users name history.", + "meteor.command.name-history.inaccurate": "This name history entry is not accurate according to laby.net", + "meteor.command.nbt.description": "Modifies NBT data for an item, example: .nbt add {display:{Name:'{\"text\":\"$cRed Name\"}'}}", + "meteor.command.notebot.description": "Allows you load notebot files", + "meteor.command.peek.description": "Lets you see what's inside storage block items.", + "meteor.command.profiles.description": "Loads and saves profiles.", + "meteor.command.profiles.info.loaded": "Loaded profile (highlight)%s(default).", + "meteor.command.profiles.info.saved": "Saved profile (highlight)%s(default).", + "meteor.command.profiles.info.deleted": "Deleted profile (highlight)%s(default).", + "meteor.command.reload.description": "Reloads many systems.", + "meteor.command.reload.warning.reloading": "Reloading systems, this may take a while.", + "meteor.command.reset.description": "Resets specified settings.", + "meteor.command.rotation.description": "Modifies your rotation.", + "meteor.command.save-map.description": "Saves a map to an image.", + "meteor.command.save-map.error.error_writing_texture": "Error writing map texture", + "meteor.command.save-map.exception.map_not_found": "You must be holding a filled map.", + "meteor.command.save-map.exception.oops": "Something went wrong.", + "meteor.command.say.description": "Sends messages in chat.", + "meteor.command.server.description": "Prints server information", + "meteor.command.settings.description": "Allows you to view and change module settings.", + "meteor.command.spectate.description": "Allows you to spectate nearby players", + "meteor.command.swarm.description": "Sends commands to connected swarm workers.", + "meteor.command.toggle.description": "Toggles a module.", + "meteor.command.vclip.description": "Lets you clip through blocks vertically.", + "meteor.command.wasp.description": "Sets the auto wasp target.", + "meteor.command.wasp.exception.cant_wasp_self": "You cannot target yourself!", + "meteor.command.wasp.info.target": "%d set as target.", + "meteor.command.waypoint.description": "Manages waypoints." +} diff --git a/src/main/resources/assets/meteor-client/language/en_us.json b/src/main/resources/assets/meteor-client/language/en_us.json new file mode 100644 index 0000000000..c27502e5fe --- /dev/null +++ b/src/main/resources/assets/meteor-client/language/en_us.json @@ -0,0 +1,74 @@ +{ + "meteor.key.category": "Meteor Client", + "meteor.key.open-commands": "Open Commands", + "meteor.key.open-gui": "Open GUI", + + "meteor.command.bind.description": "Binds a specified module to the next pressed key.", + "meteor.command.binds.description": "List of all bound modules.", + "meteor.command.commands.description": "List of all commands.", + "meteor.command.damage.description": "Damages self.", + "meteor.command.disconnect.description": "Disconnect from the server", + "meteor.command.disconnect.disconnection_message": "%s[%sDisconnectCommand%s] Disconnected by user.", + "meteor.command.dismount.description": "Dismounts you from entity you are riding.", + "meteor.command.drop.description": "Automatically drops specified items.", + "meteor.command.drop.exception.no_such_item": "Could not find an item with that name!", + "meteor.command.drop.exception.not_spectator": "Can't drop items while in spectator.", + "meteor.command.enchant.description": "Enchants the item in your hand. REQUIRES Creative mode.", + "meteor.command.enchant.exception.not_holding_item": "You need to hold some item to enchant.", + "meteor.command.enchant.exception.not_in_creative": "You must be in creative mode to use this.", + "meteor.command.ender-chest.description": "Allows you to preview memory of your ender chest.", + "meteor.command.fake-player.description": "Manages fake players that you can use for testing.", + "meteor.command.fake-player.error.not_found": "Couldn't find a Fake Player with that name.", + "meteor.command.fake-player.info.removed": "Removed Fake Player %s.", + "meteor.command.fov.description": "Changes your fov.", + "meteor.command.friends.description": "Manages friends.", + "meteor.command.gamemode.description": "Changes your gamemode client-side.", + "meteor.command.give.description": "Gives you any item.", + "meteor.command.give.exception.not_in_creative": "You must be in creative mode to use this.", + "meteor.command.give.exception.no_space": "No space in hotbar.", + "meteor.command.hclip.description": "Lets you clip through blocks horizontally.", + "meteor.command.input.description": "Keyboard input simulation.", + "meteor.command.input.info.cleared_handlers": "Cleared all keypress handlers.", + "meteor.command.input.info.active_handlers": "Active keypress handlers: ", + "meteor.command.input.info.keypress_handler": "(highlight)%d(default) - (highlight)%s %d(default) ticks left out of (highlight)%d(default).", + "meteor.command.input.info.removed_handler": "Removed keypress handler.", + "meteor.command.input.warning.no_handlers": "No active keypress handlers.", + "meteor.command.input.warning.out_of_range": "Index out of range.", + "meteor.command.inventory.description": "Allows you to see parts of another player's inventory.", + "meteor.command.locate.description": "Locates structures", + "meteor.command.macro.description": "Allows you to execute macros.", + "meteor.command.macro.error.none_scheduled": "No macros are currently scheduled.", + "meteor.command.macro.error.not_scheduled": "This macro is not currently scheduled.", + "meteor.command.macro.info.cleared_all": "Cleared all scheduled macros.", + "meteor.command.macro.info.cleared": "Cleared scheduled macro.", + "meteor.command.modules.description": "Displays a list of all modules.", + "meteor.command.name-history.description": "Provides a list of a players previous names from the laby.net api", + "meteor.command.name-history.error.error_fetching_name": "There was an error fetching that users name history.", + "meteor.command.name-history.inaccurate": "This name history entry is not accurate according to laby.net", + "meteor.command.nbt.description": "Modifies NBT data for an item, example: .nbt add {display:{Name:'{\"text\":\"$cRed Name\"}'}}", + "meteor.command.notebot.description": "Allows you load notebot files", + "meteor.command.peek.description": "Lets you see what's inside storage block items.", + "meteor.command.profiles.description": "Loads and saves profiles.", + "meteor.command.profiles.info.loaded": "Loaded profile (highlight)%s(default).", + "meteor.command.profiles.info.saved": "Saved profile (highlight)%s(default).", + "meteor.command.profiles.info.deleted": "Deleted profile (highlight)%s(default).", + "meteor.command.reload.description": "Reloads many systems.", + "meteor.command.reload.warning.reloading": "Reloading systems, this may take a while.", + "meteor.command.reset.description": "Resets specified settings.", + "meteor.command.rotation.description": "Modifies your rotation.", + "meteor.command.save-map.description": "Saves a map to an image.", + "meteor.command.save-map.error.error_writing_texture": "Error writing map texture", + "meteor.command.save-map.exception.map_not_found": "You must be holding a filled map.", + "meteor.command.save-map.exception.oops": "Something went wrong.", + "meteor.command.say.description": "Sends messages in chat.", + "meteor.command.server.description": "Prints server information", + "meteor.command.settings.description": "Allows you to view and change module settings.", + "meteor.command.spectate.description": "Allows you to spectate nearby players", + "meteor.command.swarm.description": "Sends commands to connected swarm workers.", + "meteor.command.toggle.description": "Toggles a module.", + "meteor.command.vclip.description": "Lets you clip through blocks vertically.", + "meteor.command.wasp.description": "Sets the auto wasp target.", + "meteor.command.wasp.exception.cant_wasp_self": "You cannot target yourself!", + "meteor.command.wasp.info.target": "%s set as target.", + "meteor.command.waypoint.description": "Manages waypoints." +} diff --git a/src/main/resources/assets/meteor-client/language/hi_in.json b/src/main/resources/assets/meteor-client/language/hi_in.json new file mode 100644 index 0000000000..47bce958f5 --- /dev/null +++ b/src/main/resources/assets/meteor-client/language/hi_in.json @@ -0,0 +1,6 @@ +{ + "meteor.lang.translators" : "devendrapoonia", + + "meteor.key.open-gui": "GUI खोलें", + "meteor.key.open-commands": "कमांड खोलें" +} diff --git a/src/main/resources/assets/meteor-client/language/pt_br.json b/src/main/resources/assets/meteor-client/language/pt_br.json new file mode 100644 index 0000000000..16cc5e0c1c --- /dev/null +++ b/src/main/resources/assets/meteor-client/language/pt_br.json @@ -0,0 +1,6 @@ +{ + "meteor.lang.translators": "Niix-Dan", + + "meteor.key.open-gui": "Abrir Menu", + "meteor.key.open-commands": "Abrir Comandos" +} diff --git a/src/main/resources/assets/meteor-client/language/vi_vn.json b/src/main/resources/assets/meteor-client/language/vi_vn.json new file mode 100644 index 0000000000..dfd1122663 --- /dev/null +++ b/src/main/resources/assets/meteor-client/language/vi_vn.json @@ -0,0 +1,6 @@ +{ + "meteor.lang.translators": "AnhNguyenlost13", + + "meteor.key.open-gui": "Mở giao diện", + "meteor.key.open-commands": "Mở lệnh" +} diff --git a/src/main/resources/assets/meteor-client/language/zh_cn.json b/src/main/resources/assets/meteor-client/language/zh_cn.json new file mode 100644 index 0000000000..1a3140f140 --- /dev/null +++ b/src/main/resources/assets/meteor-client/language/zh_cn.json @@ -0,0 +1,6 @@ +{ + "meteor.lang.translators": "Wuqibor, Enaium", + + "meteor.key.open-gui": "打开GUI", + "meteor.key.open-commands": "输入命令" +} diff --git a/src/main/resources/meteor-client.mixins.json b/src/main/resources/meteor-client.mixins.json index 039572d42c..991ca13042 100644 --- a/src/main/resources/meteor-client.mixins.json +++ b/src/main/resources/meteor-client.mixins.json @@ -14,7 +14,6 @@ "AbstractFurnaceScreenMixin", "AbstractSignBlockEntityRendererMixin", "AbstractSignEditScreenAccessor", - "AbstractSignEditScreenMixin", "ArmorFeatureRendererMixin", "BakedQuadMixin", "BannerBlockEntityRendererMixin", @@ -67,6 +66,7 @@ "ConnectScreenMixin", "ContainerComponentAccessor", "ContainerComponentMixin", + "ControlListWidgetMixin", "CrashReportMixin", "CreativeInventoryScreenAccessor", "CreativeSlotMixin", @@ -116,8 +116,10 @@ "ItemRenderStateAccessor", "ItemStackMixin", "KeyBindingAccessor", + "KeyBindingCategoryMixin", "KeyboardInputMixin", "KeyboardMixin", + "LanguageManagerMixin", "LayerRenderStateAccessor", "LightmapTextureManagerMixin", "LightningEntityRendererMixin",