package dev.m7mqd.speedprison.translations; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.TranslationArgument; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.translation.Argument; import net.kyori.adventure.translation.Translator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; public abstract class MiniMessageTranslator implements Translator { final static int TRANSLATION_DEPTH = 128; //Maximum depth of inner components to translate final net.kyori.adventure.text.minimessage.translation.MiniMessageTranslator nativeMMT; final MiniMessage miniMessage; protected MiniMessageTranslator() { this(MiniMessage.miniMessage()); } protected MiniMessageTranslator(final @NotNull MiniMessage miniMessage) { this.miniMessage = Objects.requireNonNull(miniMessage, "miniMessage"); this.nativeMMT = new net.kyori.adventure.text.minimessage.translation.MiniMessageTranslator() { @Override protected @Nullable String getMiniMessageString(@NotNull final String key, @NotNull final Locale locale) { return MiniMessageTranslator.this.getMiniMessageString(key, locale); } @Override public @NotNull Key name() { return MiniMessageTranslator.this.name(); } }; } protected abstract @Nullable String getMiniMessageString(final @NotNull String key, final @NotNull Locale locale); @Override public final @Nullable MessageFormat translate(final @NotNull String key, final @NotNull Locale locale) { return null; } @Override public @Nullable Component translate(@NotNull TranslatableComponent component, final @NotNull Locale locale) { if (this.getMiniMessageString(component.key(), locale) == null) { return null; } // From now on the component will be manipulated component = this.translateArgs(component, locale); return this.translate(component, locale, 0); } private TranslatableComponent translateArgs(final TranslatableComponent component, final Locale locale) { final List arguments = component.arguments(); if (arguments.isEmpty()) { return component.arguments(Argument.tagResolver(new TranslatorTag(this))); } final List newArguments = new ArrayList<>(arguments.size()); for (final TranslationArgument argument : arguments) { if (!(argument.value() instanceof final TranslatableComponent translatableArgComp)) { newArguments.add(argument); continue; } final Component translatedComp = this.translate(translatableArgComp, locale);//Translate in-depth if (translatedComp == null) { newArguments.add(argument); continue; } newArguments.add(TranslationArgument.component(translatedComp)); } newArguments.add(TranslationArgument.component(Argument.tagResolver(new TranslatorTag(this)))); return component.arguments(newArguments); } private Component translate(@NotNull final TranslatableComponent component, @NotNull final Locale locale, final int depth) { if (depth >= TRANSLATION_DEPTH) { return null; } // First: if this is a translatable component, translate it Component translated = this.nativeMMT.translate(component, locale); if (translated == null) { return null; } final List children = translated.children(); if (translated instanceof final TranslatableComponent translatableTranslated) { //Not likely to be the case, need to check if needed later. translated = this.translate(translatableTranslated, locale, depth + 1); } if (translated == null) { return null; } final List newChildren = new ArrayList<>(children.size()); // Now recursively translate all children for (final Component child : children) { if (child instanceof final TranslatableComponent translatableChild) { final Component translatedChild = this.translate(translatableChild, locale, depth + 1); newChildren.add(translatedChild == null ? child : translatedChild); } else { newChildren.add(child); } } return translated.children(newChildren); } }