Skip to content

Commit

Permalink
Allow translating items inside hover actions (fixes #202)
Browse files Browse the repository at this point in the history
  • Loading branch information
diogotcorreia committed Jun 26, 2022
1 parent 2b4535e commit df14b63
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
* @since 1.0.0
*/
public interface Language {
public interface Language extends Localized {

/**
* @return The name of the language.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.rexcantor64.triton.api.language;

/**
* Represents something that has a language.
* It can be a player or even a language itself.
*
* @since 3.8.0
*/
public interface Localized {

/**
* Get the string identifier of the language of this object.
* Depending on the underlying implementation, it can get it from a
* player's current language, a language object or even a string itself.
*
* @return The string identifier of the language of this object.
* @since 3.8.0
*/
default String getLanguageId() {
final Language language = this.getLanguage();
if (language == null) {
return null;
}
return this.getLanguage().getName();
}

/**
* Get the language of this object.
* Depending on the underlying implementation, it can get it from a
* player's current language, a language object or derive it from its string id.
*
* @return The language of this object.
* @since 3.8.0
*/
Language getLanguage();

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.rexcantor64.triton.api.players;

import com.rexcantor64.triton.api.language.Language;
import com.rexcantor64.triton.api.language.Localized;

import java.util.UUID;

Expand All @@ -10,7 +11,7 @@
*
* @since 1.0.0
*/
public interface LanguagePlayer {
public interface LanguagePlayer extends Localized {

/**
* Get the {@link Language language} of the player.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(name, minecraftCodes, rawDisplayName, displayName, banner, flagCode, cmds);
}

@Override
public Language getLanguage() {
return this;
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package com.rexcantor64.triton.language;

import com.rexcantor64.triton.SpigotMLP;
import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.api.language.Localized;
import com.rexcantor64.triton.api.language.SignLocation;
import com.rexcantor64.triton.api.players.LanguagePlayer;
import com.rexcantor64.triton.language.item.LanguageSign;
import com.rexcantor64.triton.language.item.LanguageText;
import com.rexcantor64.triton.language.localized.StringLocale;
import com.rexcantor64.triton.storage.LocalStorage;
import lombok.Getter;
import lombok.NonNull;
import lombok.val;
import lombok.var;
import net.md_5.bungee.api.ChatColor;

import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -34,6 +39,10 @@ public String matchPattern(String input, LanguagePlayer p) {
return matchPattern(input, p.getLang().getName());
}

public String matchPattern(String input, Localized localized) {
return matchPattern(input, localized.getLanguageId());
}

public String matchPattern(String input, String language) {
for (Map.Entry<Pattern, LanguageText> entry : matches.entrySet()) {
String replacement = entry.getValue().getMessageRegex(language);
Expand All @@ -56,16 +65,14 @@ public String getText(@NonNull LanguagePlayer p, String code, Object... args) {
}

public String getText(@NonNull String languageName, @NonNull String code, @NonNull Object... args) {
val language = getLanguageByName(languageName, true);

return getText(language, code, args);
return getText(new StringLocale(languageName), code, args);
}

public String getText(@NonNull com.rexcantor64.triton.api.language.Language language, @NonNull String code, @NonNull Object... args) {
val text = getTextForLanguage(language.getName(), code, args);
public String getText(@NonNull Localized localized, @NonNull String code, @NonNull Object... args) {
val text = getTextForLanguage(localized.getLanguageId(), code, args);
if (text.isPresent()) return text.get();

for (String fallbackLanguage : language.getFallbackLanguages()) {
for (String fallbackLanguage : localized.getLanguage().getFallbackLanguages()) {
val textFallback = getTextForLanguage(fallbackLanguage, code, args);
if (textFallback.isPresent()) return textFallback.get();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import com.rexcantor64.triton.SpigotMLP;
import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.api.config.FeatureSyntax;
import com.rexcantor64.triton.api.language.Localized;
import com.rexcantor64.triton.language.localized.StringLocale;
import com.rexcantor64.triton.language.parser.AdvancedComponent;
import com.rexcantor64.triton.player.LanguagePlayer;
import com.rexcantor64.triton.player.SpigotLanguagePlayer;
import com.rexcantor64.triton.utils.ComponentUtils;
import com.rexcantor64.triton.wrappers.legacy.HoverComponentWrapper;
import lombok.val;
import lombok.var;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
Expand Down Expand Up @@ -83,9 +83,9 @@ public String parseString(String language, FeatureSyntax syntax, String input) {
return replaceLanguages(input, language, syntax);
}

public String replaceLanguages(String input, LanguagePlayer p, FeatureSyntax syntax) {
public String replaceLanguages(String input, Localized p, FeatureSyntax syntax) {
if (input == null) return null;
val translated = replaceLanguages(input, p.getLang().getName(), syntax);
val translated = replaceLanguages(input, p.getLanguageId(), syntax);

if (translated != null && p instanceof SpigotLanguagePlayer && Triton.isSpigot() && Triton.asSpigot().isPapiEnabled()) {
SpigotLanguagePlayer slp = (SpigotLanguagePlayer) p;
Expand Down Expand Up @@ -171,26 +171,21 @@ private List<BaseComponent> removeTritonLinks(BaseComponent... baseComponents) {
return result;
}

public BaseComponent[] parseComponent(LanguagePlayer p, FeatureSyntax syntax, BaseComponent... text) {
return parseComponent(p.getLang().getName(), syntax, p, text);
}

public BaseComponent[] parseComponent(String language, FeatureSyntax syntax, BaseComponent... text) {
return parseComponent(language, syntax, null, text);
return parseComponent(new StringLocale(language), syntax, text);
}

public BaseComponent[] parseComponent(String language, FeatureSyntax syntax, LanguagePlayer contextPlayer, BaseComponent... text) {
public BaseComponent[] parseComponent(Localized language, FeatureSyntax syntax, BaseComponent... text) {
text = ComponentSerializer.parse(ComponentSerializer.toString(text));
text = removeTritonLinks(text).toArray(new BaseComponent[0]);
val advancedComponent = parseAdvancedComponent(language, syntax, AdvancedComponent.fromBaseComponent(text), contextPlayer);
val advancedComponent = parseAdvancedComponent(language, syntax, AdvancedComponent.fromBaseComponent(text));

if (advancedComponent == null) return null;
return advancedComponent.toBaseComponent();
}

private AdvancedComponent parseAdvancedComponent(String language, FeatureSyntax syntax,
AdvancedComponent advancedComponent,
LanguagePlayer contextPlayer) {
private AdvancedComponent parseAdvancedComponent(Localized language, FeatureSyntax syntax,
AdvancedComponent advancedComponent) {
String input = advancedComponent.getTextClean();
input = Triton.get().getLanguageManager().matchPattern(input, language);
Integer[] i;
Expand All @@ -214,7 +209,7 @@ private AdvancedComponent parseAdvancedComponent(String language, FeatureSyntax
if (!Triton.get().getConf().getDisabledLine().isEmpty() &&
code.equals(Triton.get().getConf().getDisabledLine()))
return null;
val result = parseTritonTranslation(Triton.get().getLanguageManager().getText(language, code), contextPlayer);
val result = parseTritonTranslation(Triton.get().getLanguageManager().getText(language, code), language);
advancedComponent.inheritSpecialComponents(result);
builder.append(result.getTextClean());
builder.append(input.substring(i[1]));
Expand All @@ -231,15 +226,15 @@ private AdvancedComponent parseAdvancedComponent(String language, FeatureSyntax
for (int k = 0; k < argIndexList.size(); k++) {
Integer[] argIndex = argIndexList.get(k);
AdvancedComponent argAdvancedComponent = AdvancedComponent.fromString(args.substring(argIndex[2], argIndex[3]));
argAdvancedComponent = parseAdvancedComponent(language, syntax, argAdvancedComponent, contextPlayer);
argAdvancedComponent = parseAdvancedComponent(language, syntax, argAdvancedComponent);
if (argAdvancedComponent == null) {
argList[k] = "";
continue;
}
argList[k] = argAdvancedComponent.getText();
advancedComponent.inheritSpecialComponents(argAdvancedComponent);
}
val result = parseTritonTranslation(SpigotMLP.get().getLanguageManager().getText(language, code, argList), contextPlayer);
val result = parseTritonTranslation(SpigotMLP.get().getLanguageManager().getText(language, code, argList), language);
advancedComponent.inheritSpecialComponents(result);
builder.append(result.getTextClean());
builder.append(input.substring(i[1]));
Expand All @@ -260,22 +255,24 @@ private AdvancedComponent parseAdvancedComponent(String language, FeatureSyntax
val replaced = replaceLanguages(Triton.get().getLanguageManager()
.matchPattern(string, language), language, syntax);
if (replaced == null) {
if (entry.getValue().getAction() != HoverEvent.Action.SHOW_ITEM)
if (entry.getValue().getAction() != HoverEvent.Action.SHOW_ITEM) {
entry.setValue(null);
}
continue;
}
entry.setValue(HoverComponentWrapper
.setValue(entry.getValue(), TextComponent.fromLegacyText(replaced)));
}
}

for (val entry : advancedComponent.getAllTranslatableArguments().entrySet())
for (val entry : advancedComponent.getAllTranslatableArguments().entrySet()) {
advancedComponent.getAllTranslatableArguments().put(entry.getKey(), entry.getValue().stream()
.map(comp -> parseAdvancedComponent(language, syntax, comp, contextPlayer)).collect(Collectors.toList()));
.map(comp -> parseAdvancedComponent(language, syntax, comp)).collect(Collectors.toList()));
}
return advancedComponent;
}

private AdvancedComponent parseTritonTranslation(String translatedResult, LanguagePlayer contextPlayer) {
private AdvancedComponent parseTritonTranslation(String translatedResult, Localized contextPlayer) {
if (contextPlayer instanceof SpigotLanguagePlayer && Triton.isSpigot() && Triton.asSpigot().isPapiEnabled()) {
SpigotLanguagePlayer slp = (SpigotLanguagePlayer) contextPlayer;
val bukkitPlayer = slp.toBukkit();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.rexcantor64.triton.language.localized;

import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.api.language.Language;
import com.rexcantor64.triton.api.language.Localized;
import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
public class StringLocale implements Localized {

private final String languageId;
private Language cachedLanguage;

@Override
public Language getLanguage() {
if (cachedLanguage == null) {
cachedLanguage = Triton.get().getLanguageManager().getLanguageByName(languageId, true);
}
return cachedLanguage;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.rexcantor64.triton.player;

import com.rexcantor64.triton.api.language.Language;

import java.util.UUID;

public interface LanguagePlayer extends com.rexcantor64.triton.api.players.LanguagePlayer {
Expand All @@ -16,4 +18,8 @@ public interface LanguagePlayer extends com.rexcantor64.triton.api.players.Langu

void waitForClientLocale();

@Override
default Language getLanguage() {
return this.getLang();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.rexcantor64.triton.utils;

import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.comphenix.protocol.wrappers.nbt.NbtList;
import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.api.language.Localized;
import com.rexcantor64.triton.config.MainConfig;
import com.rexcantor64.triton.player.LanguagePlayer;
import lombok.val;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
Expand All @@ -23,6 +27,15 @@

public class ItemStackTranslationUtils {

private static final MethodAccessor NBT_DESERIALIZER_METHOD;

static {
val mojangsonParserClass = MinecraftReflection.getMinecraftClass("nbt.MojangsonParser", "MojangsonParser");
FuzzyReflection fuzzy = FuzzyReflection.fromClass(mojangsonParserClass);
val method = fuzzy.getMethodByParameters("deserializeNbtCompound", MinecraftReflection.getNBTCompoundClass(), new Class<?>[]{String.class});
NBT_DESERIALIZER_METHOD = Accessors.getMethodAccessor(method);
}

/**
* Translates an item stack in one of two ways:
* - if the item has a CraftBukkit handler, the item is translated through its NBT tag;
Expand All @@ -36,7 +49,7 @@ public class ItemStackTranslationUtils {
* @param translateBooks Whether it should translate written books
* @return The translated item stack, which may or may not be the same as the given parameter
*/
public static ItemStack translateItemStack(ItemStack item, LanguagePlayer languagePlayer, boolean translateBooks) {
public static ItemStack translateItemStack(ItemStack item, Localized languagePlayer, boolean translateBooks) {
if (item == null || item.getType() == Material.AIR) {
return item;
}
Expand Down Expand Up @@ -133,7 +146,7 @@ public static ItemStack translateItemStack(ItemStack item, LanguagePlayer langua
* @param languagePlayer The language player to translate for
* @param translateLore Whether to attempt to translate the lore of the item
*/
public static void translateNbtItem(NbtCompound compound, LanguagePlayer languagePlayer, boolean translateLore) {
public static void translateNbtItem(NbtCompound compound, Localized languagePlayer, boolean translateLore) {
if (!compound.containsKey("display")) {
return;
}
Expand Down Expand Up @@ -197,13 +210,28 @@ public static void translateNbtItem(NbtCompound compound, LanguagePlayer languag
}
}

private static String translate(String string, LanguagePlayer languagePlayer, MainConfig.FeatureSyntax featureSyntax) {
public static String translateNbtString(String nbt, Localized localized) {
val compound = deserializeItemTagNbt(nbt);
translateNbtItem(compound, localized, true);
return serializeItemTagNbt(compound);
}

private static NbtCompound deserializeItemTagNbt(String nbt) {
val nmsCompound = NBT_DESERIALIZER_METHOD.invoke(null, nbt);
return NbtFactory.fromNMSCompound(nmsCompound);
}

private static String serializeItemTagNbt(NbtCompound nbt) {
return nbt.getHandle().toString();
}

private static String translate(String string, Localized localized, MainConfig.FeatureSyntax featureSyntax) {
if (string == null) {
return null;
}
return main().getLanguageParser().replaceLanguages(
main().getLanguageManager().matchPattern(string, languagePlayer),
languagePlayer,
main().getLanguageManager().matchPattern(string, localized),
localized,
featureSyntax
);
}
Expand Down
Loading

0 comments on commit df14b63

Please sign in to comment.