Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translation fallback #2543

Merged
merged 6 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.denizenscript.denizen.tags.core;

import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.objects.properties.bukkit.BukkitElementExtensions;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizen.utilities.FormattedTextHelper;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ColorTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.objects.core.MapTag;
import com.denizenscript.denizencore.tags.TagManager;
import com.denizenscript.denizencore.tags.core.EscapeTagUtil;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import org.bukkit.ChatColor;

public class TextTagBase {
Expand Down Expand Up @@ -180,41 +183,67 @@ public TextTagBase() {
});

// <--[tag]
// @attribute <&translate[<key>]>
// @attribute <&translate[key=<key>;(fallback=<fallback>);(with=<text>|...)]>
// @returns ElementTag
// @description
// Returns a special chat code that displays an autotranslated message.
// For example: - narrate "Reward: <&translate[item.minecraft.diamond_sword]>"
// Be warned that language keys change between Minecraft versions.
// Returns a special chat code that is read by the client to display an auto-translated message.
// "key" is the translation key.
// Optionally specify "fallback" as text to display when the client can't find a translation for the key.
// Optionally specify "with" as a list of input data for the translatable message (parts of the message that are dynamic).
// Be warned that language keys can change between Minecraft versions.
// Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>.
// You can use <@link tag ElementTag.strip_color> to convert the translated output to plain text (pre-translated).
// -->
TagManager.registerTagHandler(ElementTag.class, "&translate", (attribute) -> { // Cannot be static due to hacked sub-tag
if (!attribute.hasParam()) {
return null;
// @example
// Narrates a translatable of a diamond sword's name.
// - narrate "Reward: <&translate[key=item.minecraft.diamond_sword]>"
// @example
// Narrates a translatable with some input data.
// - narrate <&translate[key=commands.give.success.single;with=32|<&translate[key=item.minecraft.diamond_sword].escaped>|<player.name.escaped>]>
// @example
// Narrates a custom translatable (from something like a resource pack), with a fallback in case it can't be translated.
// - narrate <&translate[key=my.custom.translation;fallback=Please use the resource pack!]>
// -->
TagManager.registerTagHandler(ElementTag.class, ObjectTag.class, "&translate", (attribute, param) -> { // Cannot be static due to hacked sub-tag
String translateText;
ElementTag fallback = null;
ListTag with = null;
MapTag translateMap = param.asType(MapTag.class, CoreUtilities.noDebugContext);
if (translateMap != null) {
ElementTag translateElement = translateMap.getRequiredObjectAs("key", ElementTag.class, attribute);
if (translateElement == null) {
return null;
}
translateText = translateElement.asString();
fallback = translateMap.getElement("fallback");
with = translateMap.getObjectAs("with", ListTag.class, attribute.context);
}
String translateText = attribute.getParam();

// <--[tag]
// @attribute <&translate[<key>].with[<text>|...]>
// @returns ElementTag
// @description
// Returns a special chat code that displays an autotranslated message.
// Optionally, specify a list of escaped text values representing input data for the translatable message.
// Be aware that missing 'with' values will cause exceptions in your console.
// For example: - narrate "<&translate[commands.give.success.single].with[32|<&translate[item.minecraft.diamond_sword].escaped>|<player.name.escaped>]>"
// Be warned that language keys change between Minecraft versions.
// Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>.
// -->
StringBuilder with = new StringBuilder();
if (attribute.startsWith("with", 2)) {
ListTag withList = attribute.contextAsType(2, ListTag.class);
attribute.fulfill(1);
for (String str : withList) {
with.append(";").append(FormattedTextHelper.escape(EscapeTagUtil.unEscape(str)));
else {
BukkitImplDeprecations.translateLegacySyntax.warn(attribute.context);
translateText = param.toString();

// <--[tag]
// @attribute <&translate[<key>].with[<text>|...]>
// @returns ElementTag
// @deprecated Use '<&translate[key=<key>;with=<text>|...]>'.
// @description
// Deprecated in favor of <@link tag &translate>.
// -->
if (attribute.startsWith("with", 2)) {
with = attribute.contextAsType(2, ListTag.class);
attribute.fulfill(1);
}
}
StringBuilder output = new StringBuilder().append(ChatColor.COLOR_CHAR).append("[translate=").append(FormattedTextHelper.escape(translateText));
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && fallback != null) {
output.append(';').append(ChatColor.COLOR_CHAR).append("fallback=").append(FormattedTextHelper.escape(fallback.asString()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

injecting color_char inside of the block here is problematic

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to be a MapTag as discussed on Discord

}
if (with != null) {
for (String str : with) {
output.append(';').append(FormattedTextHelper.escape(EscapeTagUtil.unEscape(str)));
}
}
return new ElementTag(ChatColor.COLOR_CHAR + "[translate=" + FormattedTextHelper.escape(translateText) + with + "]");
output.append(']');
return new ElementTag(output.toString(), true);
});

// <--[tag]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ public class BukkitImplDeprecations {
// Added 2023/03/27, deprecate officially by 2026
public static Warning oldAgeLockedControls = new FutureWarning("oldAgeLockedControls", "Several old ways of controlling whether an entity's age is locked are deprecated in favor of the 'EntityTag.age_locked' tag/mech pair.");

// Added 2023/10/04, deprecate officially by 2027
public static Warning translateLegacySyntax = new FutureWarning("translateLegacySyntax", "<&translate[...].with[...]> is deprecated in favor of the modern <&translate[key=...;with=...]> syntax.");

// ==================== PAST deprecations of things that are already gone but still have a warning left behind ====================

// Added on 2019/10/13
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.denizenscript.denizen.utilities;

import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.objects.properties.bukkit.BukkitElementExtensions;
import com.denizenscript.denizencore.objects.core.ColorTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
Expand Down Expand Up @@ -171,9 +172,12 @@ public static String stringifySub(BaseComponent component, ChatColor parentColor
if (component instanceof TextComponent) {
builder.append(((TextComponent) component).getText());
}
else if (component instanceof TranslatableComponent) {
builder.append(ChatColor.COLOR_CHAR).append("[translate=").append(escape(((TranslatableComponent) component).getTranslate()));
List<BaseComponent> with = ((TranslatableComponent) component).getWith();
else if (component instanceof TranslatableComponent translatableComponent) {
builder.append(ChatColor.COLOR_CHAR).append("[translate=").append(escape(translatableComponent.getTranslate()));
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && translatableComponent.getFallback() != null) {
builder.append(';').append(ChatColor.COLOR_CHAR).append("fallback=").append(escape(translatableComponent.getFallback()));
}
List<BaseComponent> with = translatableComponent.getWith();
if (with != null) {
for (BaseComponent withComponent : with) {
builder.append(";").append(escape(stringify(withComponent)));
Expand Down Expand Up @@ -466,6 +470,9 @@ public static BaseComponent[] parseInternal(String str, ChatColor baseColor, boo
TranslatableComponent component = new TranslatableComponent();
List<String> innardParts = CoreUtilities.split(translatable, ';');
component.setTranslate(unescape(innardParts.get(0)));
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && innardParts.size() > 1 && innardParts.get(1).startsWith(ChatColor.COLOR_CHAR + "fallback=")) {
component.setFallback(unescape(innardParts.remove(1).substring("&fallback=".length())));
}
for (int i = 1; i < innardParts.size(); i++) {
for (BaseComponent subComponent : parseInternal(unescape(innardParts.get(i)), baseColor, false, optimize)) {
component.addWith(subComponent);
Expand Down Expand Up @@ -537,6 +544,9 @@ else if (innardType.equals("selector")) {
else if (innardType.equals("translate")) {
TranslatableComponent component = new TranslatableComponent();
component.setTranslate(unescape(innardBase.get(1)));
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && !innardParts.isEmpty() && innardParts.get(0).startsWith(ChatColor.COLOR_CHAR + "fallback=")) {
component.setFallback(unescape(innardParts.remove(0).substring("&fallback=".length())));
}
for (String extra : innardParts) {
for (BaseComponent subComponent : parseInternal(unescape(extra), baseColor, false, optimize)) {
component.addWith(subComponent);
Expand Down