From ed5fbb00e38ed6a8cb1da62b96fa923c1fed22bb Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Fri, 7 Mar 2025 14:05:29 +0000 Subject: [PATCH 1/5] MiniMessage translator docs --- source/index.rst | 1 + source/localization.rst | 122 ++++++++++++++++++++++++++++++ source/minimessage/index.rst | 1 + source/minimessage/translator.rst | 55 ++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 source/localization.rst create mode 100644 source/minimessage/translator.rst diff --git a/source/index.rst b/source/index.rst index 5fe9bd97..37e97eb1 100644 --- a/source/index.rst +++ b/source/index.rst @@ -39,6 +39,7 @@ There are many community-supported libraries that extend the capabilities of Adv tablist resource-pack minimessage/index + localization platform/index diff --git a/source/localization.rst b/source/localization.rst new file mode 100644 index 00000000..8967f5b8 --- /dev/null +++ b/source/localization.rst @@ -0,0 +1,122 @@ +.. _localization: + +Localization +============ + +Adventure provides a way to utilize Minecraft's built-in localization system for client-side translations as well as an additional Adventure-specific system for translating text. + +Using Minecraft's localization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To send text to a player that will be translated in the language they have selected in their client settings, use a translatable component. +For example, :java:`Component.translatable("block.minecraft.diamond_block")` will render as "Block of Diamond" (or translated to another language) when viewed by the client. +Some translation keys have arguments which are inserted into the translated content. +For example, :java:`Component.translatable("block.minecraft.player_head.named", Component.text("Kezz101"))` will render as "Kezz101's Head". +Translatable components can have styling, hover/click events and children components just like any other component type. + +Resource pack language files +---------------------------- + +You can provide translation files in a resource pack in order to change existing translations or add new ones. +For a guide on how to do that, see the `Minecraft Wiki `_. + +Using Adventure's localization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Adventure also provides a way to handle localization in Adventure itself. +This can be useful in environments where you do not have access to resource packs, or wish to do translations yourself, without relying on Minecraft's translation system. + +Any component that is sent to a client is ran through the ``GlobalTranslator`` using the locale of the client. +This means that if you wish to have automatic translation of components using your own translation data, you can add a ``Translator`` to the ``GlobalTranslator``. +You can either provide your own implementation of ``Translator`` or use one of the implementations that Adventure provides. + +Once you have a ``Translator`` instance, you can register it to the ``GlobalTranslator`` using :java:`GlobalTranslator.translator().addSource(myTranslator)`. +This will then make it available for automatic translation across the platform. + +.. warning:: + + Some implementations may not use the ``GlobalTranslator`` in every area, or at all. + For example, Paper does not use it for items, and Minestom does not use it unless specifically enabled. + Please consult the documentation for your platform for any limitations. + +Using a custom ``Translator`` +----------------------------- + +A ``Translator`` is a simple interface that provides two ways of translating content. + +The first ``translate`` method provides the translation key and locale as an argument and expects a nullable ``MessageFormat`` in return. +This system is comparable to Minecraft's built-in localization system, using the standard Java `message format `_ for arguments. + +If the first ``translate`` method returns ``null`, the second method which provides the translatable component and locale as an argument can be used. +This method allows for much richer customization of the translation process as you can return an entire component. +This means you can, for example, customize the colour and styling of the translated component, rather than relying solely on strings for the message format system. + +.. warning:: + + If you are overriding the component ``translate`` method, you should be careful not to unintentionally lose the children of the translatable component. + See the Javadocs for the translate method for a code example of how to avoid this common error. + +Below is an example of how one might implement a custom ``Translator``. + +.. code:: java + + public class MyTranslator implements Translator { + + @Override + public @NotNull Key name() { + // Every translator has a name which is used to identify this specific translator instance. + return Key.key("mynamespace:mykey"); + } + + @Override + public @Nullable MessageFormat translate(final @NotNull String key, final @NotNull Locale locale) { + // You could retrieve a string from a properties file, a config file, or some other system. + // An an example, we will hard-code a check for a specific key here. + if (key.equals("mytranslation.key") && locale == Locale.US) { + return new MessageFormat("Hello %s!", locale); + } else { + // If you only want to use component translation, you can override this method and always return `null`. + return null; + } + } + + @Override + public @Nullable Component translate(@NotNull TranslatableComponent component, @NotNull Locale locale) { + // As above, we will hardcode a check here, but you should be reading this from elsewhere. + if (key.equals("mytranslation.colorful") && locale == Locale.US) { + return Component.text("Hello, ", NamedTextColor.GREEN) + .append(component.arguments().get(0).color(NamedTextColor.RED)) + .append(component.children()); // Always make sure to copy the children over! + } else { + return null; + } + } + } + +Using a ``TranslationRegistry`` +------------------------------- + +A ``TranslationRegistry`` is a collection of ``Translator`` instances. +It can provide a simpler way creating a ``Translator`` without having to implement the logic for determining translations yourself. +You can create a translation registry and then add or remove translations at will. +This allows you to retain the same functionality as a ``Translator`` without the overhead of writing your own logic for determining the translations. + +There are also methods on ``TranslationRegistry`` to bulk register from `resource bundles `_. +You may also want to use Adventure's ``UTF8ResourceBundleControl`` utility class to create your bundle. + +.. code:: java + + // As above, every translator needs an identifying key! + final TranslationRegistry myRegistry = TranslationRegistry.create(Key.key("mynamespace:mykey")); + + // You can add translations one-by-one, or in bulk. Consult the Javadocs for a full list of methods. + myRegistry.register("mytranslation.key", Locale.US, new MessageFormat("Hello %s!", Locale.US)); + + // You can then register this to the global translator so the translations are available there! + GlobalTranslator.translator().addSource(myRegistry); + +Using ``MiniMessageTranslator`` +------------------------------- + +Adventure also provides a translator that can use MiniMessage strings, with automatic support for placeholders and arguments. +For more information, see :ref:`minimessage-translator`. diff --git a/source/minimessage/index.rst b/source/minimessage/index.rst index b09a395e..6f2d58c3 100644 --- a/source/minimessage/index.rst +++ b/source/minimessage/index.rst @@ -16,3 +16,4 @@ If you're looking to write messages with MiniMessage, take a look at the :ref:`m format api dynamic-replacements + translator diff --git a/source/minimessage/translator.rst b/source/minimessage/translator.rst new file mode 100644 index 00000000..a086cbe1 --- /dev/null +++ b/source/minimessage/translator.rst @@ -0,0 +1,55 @@ +.. _minimessage-translator: + +MiniMessage Translator +====================== + +.. info:: + + For more information about both Minecraft and Adventure's localization systems, see :ref:`localization`. + +MiniMessage provides a ``Translator`` implementation that allows you to use MiniMessage as translation strings. +It also provides automatic support for argument placeholders, letting you use simple translatable components throughout your codebase. + +Creating a MiniMessage translator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To start, create an implementation of the ``MiniMessageTranslator`` and register it to the ``GlobalTranslator``. +This can be done using :java:`GlobalTranslator.translator().addSource(myMiniMessageTranslator)`. +For an example of how to create your own ``MiniMessageTranslator``, see the below code block. + +.. code:: java + + public class MyMiniMessageTranslator extends MiniMessageTranslator() { + + public MyMiniMessageTranslator() { + // By default, the standard MiniMessage instance will be used. + // You can specify a custom one in the super constructor. + super(MiniMessage.miniMessage()); + } + + @Override + public @Nullable String getMiniMessageString(final @NotNull String key, final @NotNull Locale locale) { + // Creating a custom MiniMessage translator is as simple as overriding this one method. + // All you need to do is return a MiniMessage string for the provided key and locale. + // In this example we will hardcode this, but you could pull it from a resource bundle, a properties file, a config file or something else entirely. + if (key.equals("mykey") && locale == Locale.US) { + return "Hello, ! Today is ." + } else { + // Returning null "ignores" this translation. + return null; + } + } + } + +Using a MiniMessage translator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The MiniMessage translator will automatically turn translatable component arguments into a custom tag. +This tag will be :mm:`` or :mm:`` where ``index`` is the zero indexed position of the argument. +For example, this component :java:`Component.translatable(key, Component.text("Kezz"))` with the MiniMessage string :mm:`Hello, !` will produce "Hello, Kezz!". + +You can also use the `Argument` class to create named tags for ease of use. +For example, this component :java:`Component.translatable(key, Argument.component("name", Component.text("Kezz"))` will produce the string "Hello, Kezz!" when used with either :mm:`Hello, !` or :mm:`Hello, !`. + +Finally, you can also add entirely custom tags or tag resolvers to the deserialization by using the rest of the methods on ``Argument``. +For a full list, please see the Javadocs for the ``Argument`` class. From c0c05d61fa24d6b04eb3a00c478dbbc407ce570c Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Fri, 7 Mar 2025 15:52:01 +0000 Subject: [PATCH 2/5] adjust to translation store changes --- source/localization.rst | 18 +++++++++++------- source/minimessage/translator.rst | 8 ++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/source/localization.rst b/source/localization.rst index 8967f5b8..d9d9d967 100644 --- a/source/localization.rst +++ b/source/localization.rst @@ -93,21 +93,22 @@ Below is an example of how one might implement a custom ``Translator``. } } -Using a ``TranslationRegistry`` +Using a ``TranslationStore`` ------------------------------- -A ``TranslationRegistry`` is a collection of ``Translator`` instances. +A ``TranslationStore`` is a store of ``Translator`` instances. It can provide a simpler way creating a ``Translator`` without having to implement the logic for determining translations yourself. You can create a translation registry and then add or remove translations at will. This allows you to retain the same functionality as a ``Translator`` without the overhead of writing your own logic for determining the translations. -There are also methods on ``TranslationRegistry`` to bulk register from `resource bundles `_. -You may also want to use Adventure's ``UTF8ResourceBundleControl`` utility class to create your bundle. +Adventure provides two translation stores, one for message format translating and one for component translating. +An example of how to use a translation store is below. .. code:: java - // As above, every translator needs an identifying key! - final TranslationRegistry myRegistry = TranslationRegistry.create(Key.key("mynamespace:mykey")); + // As above, every translator needs an identifying name! + // Could also use TranslationStore#component(Key) to work with components instead. + final TranslationStore myRegistry = TranslationStore.messageFormat(Key.key("mynamespace:mykey")); // You can add translations one-by-one, or in bulk. Consult the Javadocs for a full list of methods. myRegistry.register("mytranslation.key", Locale.US, new MessageFormat("Hello %s!", Locale.US)); @@ -115,7 +116,10 @@ You may also want to use Adventure's ``UTF8ResourceBundleControl`` utility class // You can then register this to the global translator so the translations are available there! GlobalTranslator.translator().addSource(myRegistry); -Using ``MiniMessageTranslator`` +There are additional methods on the message format translation store to bulk register from `resource bundles `_. +You may also want to use Adventure's ``UTF8ResourceBundleControl`` utility class to create your bundle. + +Using MiniMessage for translations ------------------------------- Adventure also provides a translator that can use MiniMessage strings, with automatic support for placeholders and arguments. diff --git a/source/minimessage/translator.rst b/source/minimessage/translator.rst index a086cbe1..12d31cec 100644 --- a/source/minimessage/translator.rst +++ b/source/minimessage/translator.rst @@ -41,6 +41,14 @@ For an example of how to create your own ``MiniMessageTranslator``, see the belo } } +MiniMessage translation store +----------------------------- + +In order to make managing a ``MiniMessageTranslator`` easier, we also provide a ``TranslationStore`` implementation using MiniMessage strings. +For documentation on how to use translation stores, see :ref:`localization`. + +Note that the ``MiniMessageTranslationStore`` contains the same methods as the message format translation store for populating a translation store using resource bundles. + Using a MiniMessage translator ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 293d29877ad915ff8bba83a2ad77126fd9b11d0f Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Fri, 7 Mar 2025 16:09:55 +0000 Subject: [PATCH 3/5] replace some wording --- source/localization.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/source/localization.rst b/source/localization.rst index d9d9d967..a6eb3b79 100644 --- a/source/localization.rst +++ b/source/localization.rst @@ -96,10 +96,9 @@ Below is an example of how one might implement a custom ``Translator``. Using a ``TranslationStore`` ------------------------------- -A ``TranslationStore`` is a store of ``Translator`` instances. -It can provide a simpler way creating a ``Translator`` without having to implement the logic for determining translations yourself. -You can create a translation registry and then add or remove translations at will. -This allows you to retain the same functionality as a ``Translator`` without the overhead of writing your own logic for determining the translations. +A ``TranslationStore`` is a store of translations. +It provides a simpler way creating a ``Translator`` without having to implement the logic for determining and storing translations yourself. +You can create a translation store and then add or remove translations at will, even after registering it to the global translator. Adventure provides two translation stores, one for message format translating and one for component translating. An example of how to use a translation store is below. @@ -108,13 +107,13 @@ An example of how to use a translation store is below. // As above, every translator needs an identifying name! // Could also use TranslationStore#component(Key) to work with components instead. - final TranslationStore myRegistry = TranslationStore.messageFormat(Key.key("mynamespace:mykey")); + final TranslationStore myStore = TranslationStore.messageFormat(Key.key("mynamespace:mykey")); // You can add translations one-by-one, or in bulk. Consult the Javadocs for a full list of methods. - myRegistry.register("mytranslation.key", Locale.US, new MessageFormat("Hello %s!", Locale.US)); + myStore.register("mytranslation.key", Locale.US, new MessageFormat("Hello %s!", Locale.US)); // You can then register this to the global translator so the translations are available there! - GlobalTranslator.translator().addSource(myRegistry); + GlobalTranslator.translator().addSource(myStore); There are additional methods on the message format translation store to bulk register from `resource bundles `_. You may also want to use Adventure's ``UTF8ResourceBundleControl`` utility class to create your bundle. From 888c092e52cb5412cf44794945c2a83b58f6d142 Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Fri, 7 Mar 2025 18:12:56 +0000 Subject: [PATCH 4/5] fix some spelling issues --- .config/spelling_wordlist.txt | 4 ++++ source/contributing.rst | 2 +- source/localization.rst | 8 ++++---- source/minimessage/format.rst | 2 +- source/minimessage/translator.rst | 2 +- source/platform/native.rst | 6 +++--- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.config/spelling_wordlist.txt b/.config/spelling_wordlist.txt index d6a7baef..3805c689 100644 --- a/.config/spelling_wordlist.txt +++ b/.config/spelling_wordlist.txt @@ -64,3 +64,7 @@ aro philly bigender demigender +Minestom +nullable +Javadocs +codebase diff --git a/source/contributing.rst b/source/contributing.rst index 876bd3af..442dc291 100644 --- a/source/contributing.rst +++ b/source/contributing.rst @@ -42,7 +42,7 @@ These instructions assume you are working from a terminal, either on Windows or 5. Open a browser to ``https://localhost:8000`` to view the just-built site. Pages will auto-refresh when changes are made. -Any text editor will work for editing the documentation, but we've had the best experience with Visual Studio Code or (neo)vim, each of which have mature reST plugins. +Any text editor will work for editing the documentation, but we've had the best experience with Visual Studio Code or :spelling:ignore:`(neo)vim`, each of which have mature reST plugins. A typical development environment has a text editor and web browser side-by-side, with the web browser viewing the locally served test site. Once you've written changes, they can be submitted for inclusion in the docs with a GitHub Pull Request. diff --git a/source/localization.rst b/source/localization.rst index a6eb3b79..ef55cad0 100644 --- a/source/localization.rst +++ b/source/localization.rst @@ -11,7 +11,7 @@ Using Minecraft's localization To send text to a player that will be translated in the language they have selected in their client settings, use a translatable component. For example, :java:`Component.translatable("block.minecraft.diamond_block")` will render as "Block of Diamond" (or translated to another language) when viewed by the client. Some translation keys have arguments which are inserted into the translated content. -For example, :java:`Component.translatable("block.minecraft.player_head.named", Component.text("Kezz101"))` will render as "Kezz101's Head". +For example, :java:`Component.translatable("block.minecraft.player_head.named", Component.text("Mark"))` will render as "Mark's Head". Translatable components can have styling, hover/click events and children components just like any other component type. Resource pack language files @@ -47,9 +47,9 @@ A ``Translator`` is a simple interface that provides two ways of translating con The first ``translate`` method provides the translation key and locale as an argument and expects a nullable ``MessageFormat`` in return. This system is comparable to Minecraft's built-in localization system, using the standard Java `message format `_ for arguments. -If the first ``translate`` method returns ``null`, the second method which provides the translatable component and locale as an argument can be used. +If the first ``translate`` method returns ``null``, the second method which provides the translatable component and locale as an argument can be used. This method allows for much richer customization of the translation process as you can return an entire component. -This means you can, for example, customize the colour and styling of the translated component, rather than relying solely on strings for the message format system. +This means you can, for example, customize the color and styling of the translated component, rather than relying solely on strings for the message format system. .. warning:: @@ -119,7 +119,7 @@ There are additional methods on the message format translation store to bulk reg You may also want to use Adventure's ``UTF8ResourceBundleControl`` utility class to create your bundle. Using MiniMessage for translations -------------------------------- +---------------------------------- Adventure also provides a translator that can use MiniMessage strings, with automatic support for placeholders and arguments. For more information, see :ref:`minimessage-translator`. diff --git a/source/minimessage/format.rst b/source/minimessage/format.rst index 03a5115f..d36f07fd 100644 --- a/source/minimessage/format.rst +++ b/source/minimessage/format.rst @@ -89,7 +89,7 @@ Color the shadow of the next parts Tag * :mm:`` - * :mm:`` as an alias to disable the shadow (equalivent to :mm:``) + * :mm:`` as an alias to disable the shadow (equivalent to :mm:``) Arguments * ``_colorNameOrHex_``, a named color or hex color string with the format ``#RRGGBB`` or ``#RRGGBBAA`` * ``[alpha_as_float]``, a float value between 0 and 1, representing the alpha value of the shadow. Optional, defaults to 0.25. Has no effect if an alpha value is already provided in the hex color string. diff --git a/source/minimessage/translator.rst b/source/minimessage/translator.rst index 12d31cec..e7f553ad 100644 --- a/source/minimessage/translator.rst +++ b/source/minimessage/translator.rst @@ -3,7 +3,7 @@ MiniMessage Translator ====================== -.. info:: +.. note:: For more information about both Minecraft and Adventure's localization systems, see :ref:`localization`. diff --git a/source/platform/native.rst b/source/platform/native.rst index 3877711f..e219b6fc 100644 --- a/source/platform/native.rst +++ b/source/platform/native.rst @@ -4,8 +4,8 @@ Native Support ============== -Native platforms integrate Adventure directly with their platform's provided API, and bundle Adventure automatically. -This allows them to more tightly integrate Adventure with the rest of the game, and avoids users having to handle distributing +Native platforms integrate Adventure directly with their platform's provided API, and bundle Adventure automatically. +This allows them to more tightly integrate Adventure with the rest of the game, and avoids users having to handle distributing Adventure and some platform adapter themselves. The following software provide native support for Adventure. @@ -19,7 +19,7 @@ The following software provide native support for Adventure. +------------------------------+--------------------------------------+-----------------------------------------------------------------------------+ | Paper | 1.16.5 build 473 | | +------------------------------+--------------------------------------+-----------------------------------------------------------------------------+ -| :spelling:ignore:`Minestom` | Build 7494725 | For more information, see the | +| Minestom | Build 7494725 | For more information, see the | | | | `Minestom Wiki `_. | +------------------------------+--------------------------------------+-----------------------------------------------------------------------------+ | Fabric | ``adventure-platform-fabric`` 5.3.0 | This is not strictly native, but injected interfaces provide a near-native | From f65cd511a6a4a627a4e40c6c30c3d54c69f0a0ae Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Fri, 7 Mar 2025 18:16:15 +0000 Subject: [PATCH 5/5] ensure the lawyers are earning their retainers --- source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/conf.py b/source/conf.py index 8869d006..324c5f26 100644 --- a/source/conf.py +++ b/source/conf.py @@ -22,7 +22,7 @@ from pathlib import Path project = 'Adventure' -copyright = '2020-2025 KyoriPowered' +copyright = '2020-2025 KyoriPowered. Not official Minecraft software. Not approved by or associated with Mojang or Microsoft.' author = 'KyoriPowered' # The short X.Y versions