package io.gitlab.jfronny.googlechat; import io.gitlab.jfronny.commons.log.Logger; import io.gitlab.jfronny.libjf.translate.api.*; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.text.*; import java.util.Arrays; import java.util.Optional; public class GoogleChat { public static final String MOD_ID = "google-chat"; public static final Logger LOGGER = Logger.forName(MOD_ID); public static final TranslateService TRANSLATE_SERVICE = TranslateService.getConfigured(); public static Text translateIfNeeded(Text source, Direction direction, boolean respectRegex) { if (shouldSkipOutright(direction)) return source; String sourceString = toString(source); if (respectRegex && failsRegex(sourceString, direction)) return source; MutableText translated; if (GoogleChatConfig.desugar) { translated = Text.literal(translateIfNeeded(sourceString, direction, true)); } else { translated = MutableText.of(translateIfNeeded(source.getContent(), direction, false)) .setStyle(source.getStyle()); for (Text sibling : source.getSiblings()) { translated.append(translateIfNeeded(sibling, direction, false)); } } if (GoogleChatConfig.debugLogs) LOGGER.info("Translated " + sourceString + " to " + toString(translated)); if (GoogleChatConfig.translationTooltip) { return source.copy().styled(style -> addHover(style, Text.literal("Translated: ").append(translated))); } else if (translated.getStyle().getHoverEvent() == null) { return translated.styled(style -> addHover(style, Text.literal("Original: ").append(source))); } else { return translated; } } private static String toString(Text text) { StringBuilder sb = new StringBuilder(); text.asOrderedText().accept((index, style, codePoint) -> { sb.append((char)codePoint); return true; }); return sb.toString(); } public static TextContent translateIfNeeded(TextContent source, Direction direction, boolean respectRegex) { if (shouldSkipOutright(direction)) return source; String sourceString = toString(source); if (respectRegex && failsRegex(sourceString, direction)) return source; //TODO This method (and the check for translatable args) should be converted to a switch pattern when available if (source instanceof TranslatableTextContent tx) { Object[] args = tx.getArgs(); args = Arrays.copyOf(args, args.length); // We're not translating TranslatableText, but are translating arguments for (int i = 0; i < args.length; i++) { if (args[i] instanceof Text tx1) args[i] = translateIfNeeded(tx1, direction, false); else if (args[i] instanceof TextContent tx1) args[i] = translateIfNeeded(tx1, direction, false); else if (args[i] instanceof String tx1) args[i] = translateIfNeeded(tx1, direction, false); else args[i] = args[i]; } return new TranslatableTextContent(tx.getKey(), translateIfNeeded(tx.getFallback(), direction, false), args); } else if (source instanceof LiteralTextContent tx) { return new LiteralTextContent(translateIfNeeded(tx.string(), direction, false)); } else { // LOGGER.info("Unhandled text type: " + source.getClass() + " (" + source + ")"); return source; } } private static String toString(TextContent text) { StringBuilder sb = new StringBuilder(); text.visit(asString -> { sb.append(asString); return Optional.empty(); }); return sb.toString(); } private static Style addHover(Style style, Text hoverText) { return style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText)); } public static String translateIfNeeded(String source, Direction direction, boolean respectRegex) { if (shouldSkipOutright(direction)) return source; if (respectRegex && failsRegex(source, direction)) return source; // Ignore generics since this is apparently not something java supports @SuppressWarnings("rawtypes") TranslateService svc = GoogleChat.TRANSLATE_SERVICE; Language sourceLang = svc.parseLang(direction.source()); Language targetLang = svc.parseLang(direction.target()); try { //noinspection unchecked return svc.translate(source, sourceLang, targetLang); } catch (TranslateException e) { LOGGER.error("Could not translate text: " + source, e); return source; } } private static boolean failsRegex(String text, Direction direction) { boolean isSender = (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) == (direction == Direction.C2S); if (isSender) return text.matches(GoogleChatConfig.sendingRegex) == GoogleChatConfig.sendingRegexIsBlacklist; else return text.matches(GoogleChatConfig.receivingRegex) == GoogleChatConfig.receivingRegexIsBlacklist; } private static boolean shouldSkipOutright(Direction direction) { return !GoogleChatConfig.enabled || !hasTarget(direction); } public static boolean hasTarget(Direction direction) { return direction.target().equals("auto"); } public enum Direction { C2S, S2C; public String source() { return switch (this) { case C2S -> GoogleChatConfig.clientLanguage; case S2C -> GoogleChatConfig.serverLanguage; }; } public String target() { return switch (this) { case C2S -> GoogleChatConfig.serverLanguage; case S2C -> GoogleChatConfig.clientLanguage; }; } } }