This repository was archived by the owner on Oct 6, 2025. It is now read-only.
  
  
  - 
                Notifications
    You must be signed in to change notification settings 
- Fork 38
Localization and MiniMessage translator #205
          
     Merged
      
      
    
  
     Merged
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            6 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      ed5fbb0
              
                MiniMessage translator docs
              
              
                kezz c0c05d6
              
                adjust to translation store changes
              
              
                kezz 293d298
              
                replace some wording
              
              
                kezz 888c092
              
                fix some spelling issues
              
              
                kezz f65cd51
              
                ensure the lawyers are earning their retainers
              
              
                kezz 132f2d9
              
                Merge branch 'main/4' into feature/mmt
              
              
                zml2008 File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -64,3 +64,7 @@ aro | |
| philly | ||
| bigender | ||
| demigender | ||
| Minestom | ||
| nullable | ||
| Javadocs | ||
| codebase | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| .. _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("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 | ||
| ---------------------------- | ||
|  | ||
| 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 <https://minecraft.wiki/w/Resource_pack#Language>`_. | ||
|  | ||
| 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 <https://docs.oracle.com/javase/8/docs/api/java/text/MessageFormat.html>`_ 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 color 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 ``TranslationStore`` | ||
| ------------------------------- | ||
|  | ||
| 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. | ||
|  | ||
| .. code:: java | ||
|  | ||
| // As above, every translator needs an identifying name! | ||
| // Could also use TranslationStore#component(Key) to work with components instead. | ||
| 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. | ||
| 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(myStore); | ||
|  | ||
| There are additional methods on the message format translation store to bulk register from `resource bundles <https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html>`_. | ||
| 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`. | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| .. _minimessage-translator: | ||
|  | ||
| MiniMessage Translator | ||
| ====================== | ||
|  | ||
| .. note:: | ||
|  | ||
| 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 "<red>Hello, <name>! Today is <day_of_week>." | ||
| } else { | ||
| // Returning null "ignores" this translation. | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
|  | ||
| 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 | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|  | ||
| The MiniMessage translator will automatically turn translatable component arguments into a custom tag. | ||
| This tag will be :mm:`<arg:index>` or :mm:`<argument:index>` 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, <arg:0>!` 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, <arg:0>!` or :mm:`Hello, <name>!`. | ||
|  | ||
| 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. | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.