Skip to content

Commit

Permalink
feat(api): Support representing translation args losslessly
Browse files Browse the repository at this point in the history
  • Loading branch information
zml2008 committed Dec 8, 2023
1 parent ec7b524 commit 971381e
Show file tree
Hide file tree
Showing 12 changed files with 433 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ public interface ComponentIteratorType {
ComponentIteratorType DEPTH_FIRST = (component, deque, flags) -> {
if (flags.contains(ComponentIteratorFlag.INCLUDE_TRANSLATABLE_COMPONENT_ARGUMENTS) && component instanceof TranslatableComponent) {
final TranslatableComponent translatable = (TranslatableComponent) component;
final List<Component> args = translatable.args();
final List<? extends ComponentLike> args = translatable.arguments();

for (int i = args.size() - 1; i >= 0; i--) {
deque.addFirst(args.get(i));
deque.addFirst(args.get(i).asComponent());
}
}

Expand All @@ -79,7 +79,9 @@ public interface ComponentIteratorType {
*/
ComponentIteratorType BREADTH_FIRST = (component, deque, flags) -> {
if (flags.contains(ComponentIteratorFlag.INCLUDE_TRANSLATABLE_COMPONENT_ARGUMENTS) && component instanceof TranslatableComponent) {
deque.addAll(((TranslatableComponent) component).args());
for (final TranslationArgument argument : ((TranslatableComponent) component).arguments()) {
deque.add(argument.asComponent());
}
}

final HoverEvent<?> hoverEvent = component.hoverEvent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,12 @@ private TextReplacementRenderer() {
// otherwise, we haven't modified the component, so nothing to change
}
} else if (modified instanceof TranslatableComponent) { // get TranslatableComponent with() args
final List<Component> args = ((TranslatableComponent) modified).args();
List<Component> newArgs = null;
final List<TranslationArgument> args = ((TranslatableComponent) modified).arguments();
List<TranslationArgument> newArgs = null;
for (int i = 0, size = args.size(); i < size; i++) {
final Component original = args.get(i);
final Component replaced = this.render(original, state);
if (replaced != component) {
final TranslationArgument original = args.get(i);
final TranslationArgument replaced = original.value() instanceof Component ? TranslationArgument.component(this.render((Component) original.value(), state)) : original;
if (replaced != original) {
if (newArgs == null) {
newArgs = new ArrayList<>(size);
if (i > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,19 @@ public interface TranslatableComponent extends BuildableComponent<TranslatableCo
*
* @return the unmodifiable list of translation arguments
* @since 4.0.0
* @deprecated for removal since 4.15.0, use {@link #arguments()} instead.
*/
@Deprecated
@NotNull List<Component> args();

/**
* Sets the translation arguments for this component.
*
* <p>Non-{@link Component} arguments can be wrapped in {@link TranslationArgument}.</p>
*
* @param args the translation arguments
* @return a translatable component
* @see TranslationArgument
* @since 4.0.0
*/
@Contract(pure = true)
Expand All @@ -113,13 +118,23 @@ public interface TranslatableComponent extends BuildableComponent<TranslatableCo
/**
* Sets the translation arguments for this component.
*
* <p>Non-{@link Component} arguments can be wrapped in {@link TranslationArgument}.</p>
*
* @param args the translation arguments
* @return a translatable component
* @since 4.0.0
*/
@Contract(pure = true)
@NotNull TranslatableComponent args(final @NotNull List<? extends ComponentLike> args);

/**
* Gets the unmodifiable list of translation arguments.
*
* @return the unmodifiable list of translation arguments
* @since 4.0.0
*/
@NotNull List<TranslationArgument> arguments();

/**
* Gets the translation fallback text for this component.
* The fallback text will be shown when the client doesn't know the
Expand Down Expand Up @@ -149,7 +164,7 @@ public interface TranslatableComponent extends BuildableComponent<TranslatableCo
return Stream.concat(
Stream.of(
ExaminableProperty.of("key", this.key()),
ExaminableProperty.of("args", this.args()),
ExaminableProperty.of("arguments", this.arguments()),
ExaminableProperty.of("fallback", this.fallback())
),
BuildableComponent.super.examinableProperties()
Expand Down Expand Up @@ -218,6 +233,8 @@ interface Builder extends ComponentBuilder<TranslatableComponent, Builder> {
/**
* Sets the translation args.
*
* <p>Non-{@link Component} arguments can be wrapped in {@link TranslationArgument}.</p>
*
* @param args the translation args
* @return this builder
* @since 4.0.0
Expand All @@ -228,6 +245,8 @@ interface Builder extends ComponentBuilder<TranslatableComponent, Builder> {
/**
* Sets the translation args.
*
* <p>Non-{@link Component} arguments can be wrapped in {@link TranslationArgument}.</p>
*
* @param args the translation args
* @return this builder
* @since 4.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
package net.kyori.adventure.text;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand All @@ -48,15 +49,15 @@ static TranslatableComponent create(final @NotNull List<? extends ComponentLike>
requireNonNull(style, "style"),
requireNonNull(key, "key"),
fallback,
ComponentLike.asComponents(args) // Since translation arguments can be indexed, empty components are also included.
asArguments(args) // Since translation arguments can be indexed, empty components are also included.
);
}

private final String key;
private final @Nullable String fallback;
private final List<Component> args;
private final List<TranslationArgument> args;

TranslatableComponentImpl(final @NotNull List<Component> children, final @NotNull Style style, final @NotNull String key, final @Nullable String fallback, final @NotNull List<Component> args) {
TranslatableComponentImpl(final @NotNull List<Component> children, final @NotNull Style style, final @NotNull String key, final @Nullable String fallback, final @NotNull List<TranslationArgument> args) {
super(children, style);
this.key = key;
this.fallback = fallback;
Expand All @@ -75,7 +76,13 @@ static TranslatableComponent create(final @NotNull List<? extends ComponentLike>
}

@Override
@Deprecated
public @NotNull List<Component> args() {
return ComponentLike.asComponents(this.args); // eww
}

@Override
public @NotNull List<TranslationArgument> arguments() {
return this.args;
}

Expand Down Expand Up @@ -115,7 +122,7 @@ public boolean equals(final @Nullable Object other) {
if (!(other instanceof TranslatableComponent)) return false;
if (!super.equals(other)) return false;
final TranslatableComponent that = (TranslatableComponent) other;
return Objects.equals(this.key, that.key()) && Objects.equals(this.fallback, that.fallback()) && Objects.equals(this.args, that.args());
return Objects.equals(this.key, that.key()) && Objects.equals(this.fallback, that.fallback()) && Objects.equals(this.args, that.arguments());
}

@Override
Expand All @@ -140,15 +147,15 @@ public String toString() {
static final class BuilderImpl extends AbstractComponentBuilder<TranslatableComponent, Builder> implements TranslatableComponent.Builder {
private @Nullable String key;
private @Nullable String fallback;
private List<? extends Component> args = Collections.emptyList();
private List<TranslationArgument> args = Collections.emptyList();

BuilderImpl() {
}

BuilderImpl(final @NotNull TranslatableComponent component) {
super(component);
this.key = component.key();
this.args = component.args();
this.args = component.arguments();
this.fallback = component.fallback();
}

Expand Down Expand Up @@ -185,7 +192,7 @@ static final class BuilderImpl extends AbstractComponentBuilder<TranslatableComp

@Override
public @NotNull Builder args(final @NotNull List<? extends ComponentLike> args) {
this.args = ComponentLike.asComponents(requireNonNull(args, "args"));
this.args = asArguments(requireNonNull(args, "args"));
return this;
}

Expand All @@ -201,4 +208,25 @@ static final class BuilderImpl extends AbstractComponentBuilder<TranslatableComp
return create(this.children, this.buildStyle(), this.key, this.fallback, this.args);
}
}

static List<TranslationArgument> asArguments(final @NotNull List<? extends ComponentLike> likes) {
if (likes.isEmpty()) {
return Collections.emptyList();
}

final List<TranslationArgument> ret = new ArrayList<>(likes.size());
for (int i = 0; i < likes.size(); i++) {
final ComponentLike like = likes.get(i);
if (like == null) {
throw new NullPointerException("likes[" + i + "]");
}
if (like instanceof TranslationArgument) {
ret.add((TranslationArgument) like);
} else {
ret.add(TranslationArgument.component(like));
}
}

return Collections.unmodifiableList(ret);
}
}
130 changes: 130 additions & 0 deletions api/src/main/java/net/kyori/adventure/text/TranslationArgument.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* This file is part of adventure, licensed under the MIT License.
*
* Copyright (c) 2017-2023 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.kyori.adventure.text;

import net.kyori.examination.Examinable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

import static java.util.Objects.requireNonNull;

/**
* An argument that can be part of a {@link TranslatableComponent}.
*
* @since 4.15.0
*/
@ApiStatus.NonExtendable
public interface TranslationArgument extends ComponentLike, Examinable {

/**
* The argument's value.
*
* @return the argument value
* @since 4.15.0
*/
@NotNull Object value();

/**
* Create a boolean argument.
*
* @param value the value
* @return the argument
* @since 4.15.0
* @sinceMinecraft 1.20.3
*/
static @NotNull TranslationArgument bool(final boolean value) {
return new TranslationArgumentImpl.BooleanImpl(value);
}

/**
* Create a numeric argument.
*
* @param value the value
* @return the argument
* @since 4.15.0
* @sinceMinecraft 1.20.3
*/
static @NotNull TranslationArgument numeric(final @NotNull Number value) {
return new TranslationArgumentImpl.NumericImpl(requireNonNull(value, "value"));
}

/**
* Create a component argument.
*
* @param value the value
* @return the argument
* @since 4.15.0
* @sinceMinecraft 1.20.3
*/
static @NotNull TranslationArgument component(final @NotNull ComponentLike value) {
return new TranslationArgumentImpl.ComponentImpl(requireNonNull(requireNonNull(value, "value").asComponent(), "value.asComponent()"));
}

/**
* A boolean argument to translations.
*
* @since 4.15.0
* @sinceMinecraft 1.20.3
*/
interface Boolean extends TranslationArgument {
/**
* The value of the argument.
*
* @return the raw argument value
* @since 4.15.0
*/
java.lang.@NotNull Boolean value();
}

/**
* A numeric argument to translations.
*
* @since 4.15.0
* @sinceMinecraft 1.20.3
*/
interface Numeric extends TranslationArgument {
/**
* The value of the argument.
*
* @return the raw argument value
* @since 4.15.0
*/
@NotNull Number value();
}

/**
* A component argument to translations.
*
* @since 4.15.0
*/
interface Component extends TranslationArgument {
/**
* The value of the argument.
*
* @return the raw argument value
* @since 4.15.0
*/
net.kyori.adventure.text.@NotNull Component value();
}
}
Loading

0 comments on commit 971381e

Please sign in to comment.