Skip to content

Commit 4404082

Browse files
committed
Add ComponentBundle#components
1 parent 3d958a4 commit 4404082

6 files changed

Lines changed: 180 additions & 19 deletions

File tree

src/main/java/net/thenextlvl/i18n/ComponentBundle.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,112 @@ public sealed interface ComponentBundle permits ComponentBundleImpl {
303303
@Contract(value = "_, _, _ -> new", pure = true)
304304
Component component(@NonNls String translationKey, Locale locale, TagResolver... resolvers);
305305

306+
/**
307+
* Creates an array of {@link Component Components} based on the provided translation key and locale.
308+
* Each line separated by {@code <br>}, {@code <newline>}, or {@code \n} is returned as a separate component.
309+
* <p>
310+
* Opposed to {@link #translate(String, Audience)},
311+
* this method does not return null if the translation could not be resolved.
312+
* Instead, it returns an array containing a red text component with the translation key.
313+
*
314+
* @param translationKey the key used to retrieve the localized translation
315+
* @param audience the {@link Audience} to determine the locale used for the translation
316+
* @return an array containing one localized {@link Component} per line
317+
* @see #translate(String, Audience)
318+
* @since 1.3.0
319+
*/
320+
@Contract(value = "_, _ -> new", pure = true)
321+
Component[] components(@NonNls String translationKey, Audience audience);
322+
323+
/**
324+
* Translates a given translation key into an array of localized {@link Component Components} for the specified
325+
* {@link Audience}, with optional arguments for formatting arguments within the translation.
326+
* Each line separated by {@code <br>}, {@code <newline>}, or {@code \n} is returned as a separate component.
327+
* <p>
328+
* Opposed to {@link #translate(String, Audience, ComponentLike...)},
329+
* this method does not return null if the translation could not be resolved.
330+
* Instead, it returns an array containing a red text component with the translation key.
331+
*
332+
* @param translationKey the translation key representing the entry to be localized
333+
* @param audience the {@link Audience} to determine the locale used for the translation
334+
* @param arguments optional {@link ComponentLike} arguments used to replace arguments within the translation
335+
* @return an array containing one translated {@link Component} per line
336+
* @see #translate(String, Audience, ComponentLike...)
337+
* @since 1.3.0
338+
*/
339+
@Contract(value = "_, _, _ -> new", pure = true)
340+
Component[] components(@NonNls String translationKey, Audience audience, ComponentLike... arguments);
341+
342+
/**
343+
* Translates a given translation key into an array of localized {@link Component Components} for the specified
344+
* {@link Audience}, with optional tag resolvers for formatting arguments within the translation.
345+
* Each line separated by {@code <br>}, {@code <newline>}, or {@code \n} is returned as a separate component.
346+
* <p>
347+
* This method does not return null if the translation could not be resolved.
348+
* Instead, it returns an array containing a red text component with the translation key.
349+
*
350+
* @param translationKey the translation key representing the entry to be localized
351+
* @param audience the {@link Audience} to determine the locale used for the translation
352+
* @param resolvers optional {@link TagResolver} arguments used for resolving tags within the translation
353+
* @return an array containing one translated {@link Component} per line
354+
* @since 1.3.0
355+
*/
356+
@Contract(value = "_, _, _ -> new", pure = true)
357+
Component[] components(@NonNls String translationKey, Audience audience, TagResolver... resolvers);
358+
359+
/**
360+
* Creates an array of {@link Component Components} based on the provided translation key and locale.
361+
* Each line separated by {@code <br>}, {@code <newline>}, or {@code \n} is returned as a separate component.
362+
* <p>
363+
* Opposed to {@link #translate(String, Locale)},
364+
* this method does not return null if the translation could not be resolved.
365+
* Instead, it returns an array containing a red text component with the translation key.
366+
*
367+
* @param translationKey the key used to retrieve the localized translation
368+
* @param locale the locale that determines the language and formatting of the translation
369+
* @return an array containing one localized {@link Component} per line
370+
* @see #translate(String, Locale)
371+
* @since 1.3.0
372+
*/
373+
@Contract(value = "_, _ -> new", pure = true)
374+
Component[] components(@NonNls String translationKey, Locale locale);
375+
376+
/**
377+
* Translates a given translation key into an array of localized {@link Component Components},
378+
* with optional arguments for formatting arguments within the translation.
379+
* Each line separated by {@code <br>}, {@code <newline>}, or {@code \n} is returned as a separate component.
380+
* <p>
381+
* Opposed to {@link #translate(String, Locale, ComponentLike...)},
382+
* this method does not return null if the translation could not be resolved.
383+
* Instead, it returns an array containing a red text component with the translation key.
384+
*
385+
* @param translationKey the translation key representing the entry to be localized
386+
* @param locale the locale that determines the language and formatting of the translation
387+
* @param arguments optional {@link ComponentLike} arguments used to replace arguments within the translation
388+
* @return an array containing one translated {@link Component} per line
389+
* @see #translate(String, Locale, ComponentLike...)
390+
* @since 1.3.0
391+
*/
392+
@Contract(value = "_, _, _ -> new", pure = true)
393+
Component[] components(@NonNls String translationKey, Locale locale, ComponentLike... arguments);
394+
395+
/**
396+
* Translates a given translation key into an array of localized {@link Component Components},
397+
* with optional tag resolvers for formatting arguments within the translation.
398+
* Each line separated by {@code <br>}, {@code <newline>}, or {@code \n} is returned as a separate component.
399+
* <p>
400+
* This method does not return null if the translation could not be resolved.
401+
* Instead, it returns an array containing a red text component with the translation key.
402+
*
403+
* @param translationKey the translation key representing the entry to be localized
404+
* @param locale the locale that determines the language and formatting of the translation
405+
* @param resolvers optional {@link TagResolver} arguments used for resolving tags within the translation
406+
* @return an array containing one translated {@link Component} per line
407+
* @since 1.3.0
408+
*/
409+
@Contract(value = "_, _, _ -> new", pure = true)
410+
Component[] components(@NonNls String translationKey, Locale locale, TagResolver... resolvers);
411+
306412
/**
307413
* A builder interface for constructing a {@link ComponentBundle}.
308414
*/

src/main/java/net/thenextlvl/i18n/ComponentBundleImpl.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.nio.file.Files;
3030
import java.nio.file.Path;
3131
import java.util.ArrayList;
32+
import java.util.Arrays;
3233
import java.util.HashMap;
3334
import java.util.List;
3435
import java.util.Locale;
@@ -38,11 +39,13 @@
3839
final class ComponentBundleImpl implements ComponentBundle {
3940
private static final Logger LOGGER = LoggerFactory.getLogger("i18n");
4041
private final Locale fallback;
42+
private final MiniMessage miniMessage;
4143
private final Map<String, String> placeholders;
4244
private final MiniMessageTranslationStore translator;
4345

44-
private ComponentBundleImpl(Locale fallback, Map<String, String> placeholders, MiniMessageTranslationStore translator) {
46+
private ComponentBundleImpl(final Locale fallback, final Map<String, String> placeholders, final MiniMessageTranslationStore translator, final MiniMessage miniMessage) {
4547
this.fallback = fallback;
48+
this.miniMessage = miniMessage;
4649
this.placeholders = Map.copyOf(placeholders);
4750
this.translator = translator;
4851
}
@@ -177,6 +180,39 @@ public Component component(final String translationKey, final Locale locale, fin
177180
return component(translationKey, locale, Argument.tagResolver(resolvers));
178181
}
179182

183+
@Override
184+
public Component[] components(final String translationKey, final Audience audience) {
185+
return components(translationKey, audience, new Component[0]);
186+
}
187+
188+
@Override
189+
public Component[] components(final String translationKey, final Audience audience, final ComponentLike... arguments) {
190+
return components(translationKey, audience.get(Identity.LOCALE).orElse(fallback), arguments);
191+
}
192+
193+
@Override
194+
public Component[] components(final String translationKey, final Audience audience, final TagResolver... resolvers) {
195+
return components(translationKey, audience, Argument.tagResolver(resolvers));
196+
}
197+
198+
@Override
199+
public Component[] components(final String translationKey, final Locale locale) {
200+
return components(translationKey, locale, new Component[0]);
201+
}
202+
203+
@Override
204+
public Component[] components(final String translationKey, final Locale locale, final ComponentLike... arguments) {
205+
final var serialized = miniMessage.serialize(component(translationKey, locale, arguments));
206+
return Arrays.stream(serialized.split("<br>|<newline>|\n", -1))
207+
.map(miniMessage::deserialize)
208+
.toArray(Component[]::new);
209+
}
210+
211+
@Override
212+
public Component[] components(final String translationKey, final Locale locale, final TagResolver... resolvers) {
213+
return components(translationKey, locale, Argument.tagResolver(resolvers));
214+
}
215+
180216
public static final class Builder implements ComponentBundle.Builder {
181217
private final Map<String, Locale> files = new HashMap<>();
182218
private final Map<String, String> placeholders = new HashMap<>();

src/test/java/module-info.java

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package net.thenextlvl.i18n.test;
2+
3+
import net.kyori.adventure.key.Key;
4+
import net.kyori.adventure.text.Component;
5+
import net.kyori.adventure.text.format.NamedTextColor;
6+
import net.kyori.adventure.text.format.TextDecoration;
7+
import org.junit.jupiter.api.Assertions;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.util.Locale;
11+
12+
class ComponentsTest extends BaseTest {
13+
@Override
14+
public Key key() {
15+
return Key.key("test", "components");
16+
}
17+
18+
@Test
19+
void lineBreaksProduceSeparateComponents() {
20+
final var lines = bundle.components("lines", Locale.US);
21+
22+
Assertions.assertArrayEquals(new Component[]{
23+
Component.text("first").decorate(TextDecoration.ITALIC),
24+
Component.text("second").decoration(TextDecoration.ITALIC, false),
25+
Component.text("third").decoration(TextDecoration.ITALIC, false),
26+
Component.text("fourth"),
27+
Component.empty(),
28+
Component.text("hello", NamedTextColor.RED)
29+
}, lines);
30+
}
31+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@NullMarked
2+
package net.thenextlvl.i18n.test;
3+
4+
import org.jspecify.annotations.NullMarked;

src/test/resources/test.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ hello=Hey
33
resolved=Hello <world>!
44
prefix=PREFIX
55
prefix_test=<prefix> TEST
6-
colored=<rainbow>So many colors</rainbow>
6+
colored=<rainbow>So many colors</rainbow>
7+
lines=<i>first<br><!i>second</!i><newline><!i>third</!i>\nfourth\n\n<red>hello

0 commit comments

Comments
 (0)