CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-net-kyori--adventure-api

A serverside user interface library for Minecraft: Java Edition

Pending
Overview
Eval results
Files

translation-system.mddocs/

Translation System

Internationalization support with locale-based rendering, translation registries, and global translation management. Adventure's translation system enables multi-language support for text components.

Capabilities

Translatable Components

Components that display translated text based on the client's locale and registered translations.

/**
 * Component that displays translated text
 */
interface TranslatableComponent extends BuildableComponent<TranslatableComponent, TranslatableComponent.Builder> {
    /**
     * Gets the translation key
     * @return the translation key
     */
    String key();
    
    /**
     * Gets the translation arguments
     * @return list of translation arguments
     */
    List<TranslationArgument> arguments();
    
    /**
     * Gets the fallback string used when translation is not available
     * @return the fallback string or null
     */
    @Nullable String fallback();
    
    /**
     * Sets the translation key
     * @param key the translation key
     * @return component with new key
     */
    TranslatableComponent key(String key);
    
    /**
     * Sets the translation arguments
     * @param arguments the arguments
     * @return component with new arguments
     */
    TranslatableComponent arguments(List<? extends TranslationArgumentLike> arguments);
    TranslatableComponent arguments(TranslationArgumentLike... arguments);
    
    /**
     * Sets the fallback string
     * @param fallback the fallback string
     * @return component with new fallback
     */
    TranslatableComponent fallback(@Nullable String fallback);
}

Translation Arguments

Arguments that can be passed to translatable components for parameter substitution.

/**
 * Argument for translatable components
 */
interface TranslationArgument {
    /**
     * Converts this argument to a component
     * @return the component representation
     */
    Component asComponent();
    
    /**
     * Converts this argument to a string
     * @return the string representation
     */
    String asString();
    
    /**
     * Creates a component argument
     * @param component the component
     * @return translation argument
     */
    static TranslationArgument component(ComponentLike component);
    
    /**
     * Creates a string argument
     * @param string the string
     * @return translation argument
     */
    static TranslationArgument string(String string);
    
    /**
     * Creates a numeric argument
     * @param number the number
     * @return translation argument
     */
    static TranslationArgument numeric(Number number);
    
    /**
     * Creates a boolean argument
     * @param bool the boolean value
     * @return translation argument
     */
    static TranslationArgument bool(boolean bool);
}

/**
 * Objects that can be used as translation arguments
 */
interface TranslationArgumentLike {
    /**
     * Converts to a translation argument
     * @return the translation argument
     */
    TranslationArgument asTranslationArgument();
}

Translator Interface

Core interface for translating keys to formatted messages based on locale.

/**
 * Interface for translating keys to messages
 */
interface Translator {
    /**
     * Translates a key to a message format
     * @param key the translation key
     * @param locale the target locale
     * @return the message format or null if not found
     */
    @Nullable MessageFormat translate(String key, Locale locale);
    
    /**
     * Creates an empty translator
     * @return empty translator
     */
    static Translator empty();
    
    /**
     * Creates a translator from a resource bundle
     * @param bundle the resource bundle
     * @return new translator
     */
    static Translator translator(ResourceBundle bundle);
    
    /**
     * Creates a translator from a map of translations
     * @param translations the translation map (key -> message)
     * @return new translator
     */
    static Translator translator(Map<String, String> translations);
}

Global Translator

Global translation service that manages multiple translation sources.

/**
 * Global translation service for the entire application
 */
interface GlobalTranslator extends Translator {
    /**
     * Adds a translation source
     * @param translator the translator to add
     */
    void addSource(Translator translator);
    
    /**
     * Removes a translation source
     * @param translator the translator to remove
     */
    void removeSource(Translator translator);
    
    /**
     * Gets the default global translator instance
     * @return the global translator
     */
    static GlobalTranslator translator();
}

Translation Registry

Registry interface for managing translations with locale support.

/**
 * Registry for translation keys and their translations
 */
interface TranslationRegistry extends Translator {
    /**
     * Registers a translation
     * @param key the translation key
     * @param locale the locale
     * @param format the message format
     */
    void register(String key, Locale locale, MessageFormat format);
    
    /**
     * Registers a simple string translation
     * @param key the translation key
     * @param locale the locale
     * @param message the message string
     */
    void register(String key, Locale locale, String message);
    
    /**
     * Unregisters a translation
     * @param key the translation key
     */
    void unregister(String key);
    
    /**
     * Gets all registered keys
     * @return set of translation keys
     */
    Set<String> keys();
    
    /**
     * Creates a new translation registry
     * @return new registry
     */
    static TranslationRegistry create();
}

Translation Store

Storage system for translations with hierarchy support.

/**
 * Storage system for translations
 */
interface TranslationStore extends Translator {
    /**
     * Gets all available locales
     * @return set of locales
     */
    Set<Locale> locales();
    
    /**
     * Gets all translation keys
     * @return set of keys
     */
    Set<String> keys();
    
    /**
     * Checks if a translation exists
     * @param key the translation key
     * @param locale the locale
     * @return true if translation exists
     */
    boolean contains(String key, Locale locale);
}

/**
 * Abstract base for translation storage implementations
 */
abstract class AbstractTranslationStore implements TranslationStore {
    /**
     * Template method for loading translations
     * @param key the translation key
     * @param locale the locale
     * @return the message format or null
     */
    protected abstract @Nullable MessageFormat loadTranslation(String key, Locale locale);
}

Usage Examples:

import net.kyori.adventure.text.Component;
import net.kyori.adventure.translation.*;
import java.util.Locale;
import java.text.MessageFormat;

// Basic translatable component
Component welcome = Component.translatable("welcome.message");

// Translatable with arguments
Component playerJoined = Component.translatable("player.joined", 
    Component.text("PlayerName").color(NamedTextColor.YELLOW));

// With fallback for missing translations
Component customMessage = Component.translatable()
    .key("custom.greeting")
    .fallback("Hello, {0}!")
    .arguments(TranslationArgument.string("World"))
    .build();

// Register translations globally
GlobalTranslator global = GlobalTranslator.translator();
TranslationRegistry registry = TranslationRegistry.create();

registry.register("welcome.message", Locale.ENGLISH, "Welcome to the server!");
registry.register("welcome.message", Locale.FRENCH, "Bienvenue sur le serveur!");
registry.register("player.joined", Locale.ENGLISH, "{0} joined the game");
registry.register("player.joined", Locale.FRENCH, "{0} a rejoint la partie");

global.addSource(registry);

Translation Patterns

Resource Bundle Integration

public class ResourceBundleTranslations {
    public static void loadTranslations(String baseName) {
        GlobalTranslator global = GlobalTranslator.translator();
        
        // Load translations for different locales
        for (Locale locale : getSupportedLocales()) {
            try {
                ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale);
                Translator translator = Translator.translator(bundle);
                global.addSource(translator);
            } catch (MissingResourceException e) {
                // Handle missing resource bundle
                logger.warn("Missing resource bundle for locale: " + locale);
            }
        }
    }
    
    private static Set<Locale> getSupportedLocales() {
        return Set.of(
            Locale.ENGLISH,
            Locale.FRENCH, 
            Locale.GERMAN,
            Locale.SPANISH,
            new Locale("es", "MX") // Mexican Spanish
        );
    }
}

Dynamic Translation Management

public class DynamicTranslations {
    private final TranslationRegistry registry = TranslationRegistry.create();
    
    public void addTranslation(String key, Locale locale, String message) {
        registry.register(key, locale, message);
    }
    
    public void addFormattedTranslation(String key, Locale locale, String pattern) {
        MessageFormat format = new MessageFormat(pattern, locale);
        registry.register(key, locale, format);
    }
    
    public void loadFromProperties(String propertyFile, Locale locale) {
        Properties props = loadProperties(propertyFile);
        for (String key : props.stringPropertyNames()) {
            registry.register(key, locale, props.getProperty(key));
        }
    }
    
    public Component createTranslatable(String key, Object... args) {
        TranslationArgument[] arguments = Arrays.stream(args)
            .map(this::toTranslationArgument)
            .toArray(TranslationArgument[]::new);
        
        return Component.translatable(key, arguments);
    }
    
    private TranslationArgument toTranslationArgument(Object obj) {
        if (obj instanceof Component) return TranslationArgument.component((Component) obj);
        if (obj instanceof Number) return TranslationArgument.numeric((Number) obj);
        if (obj instanceof Boolean) return TranslationArgument.bool((Boolean) obj);
        return TranslationArgument.string(String.valueOf(obj));
    }
}

Locale-Aware Messaging

public class LocalizedMessaging {
    private final GlobalTranslator translator = GlobalTranslator.translator();
    
    public void sendLocalizedMessage(Audience audience, String key, Object... args) {
        // Get player's locale (implementation-specific)
        Locale playerLocale = getPlayerLocale(audience);
        
        // Create translatable component
        Component message = Component.translatable(key, 
            Arrays.stream(args)
                .map(TranslationArgument::string)
                .toArray(TranslationArgument[]::new));
        
        // Send with locale context
        audience.sendMessage(message);
    }
    
    public void broadcastLocalized(Collection<? extends Audience> audiences, String key, Object... args) {
        Component message = Component.translatable(key,
            Arrays.stream(args)
                .map(TranslationArgument::string)
                .toArray(TranslationArgument[]::new));
        
        for (Audience audience : audiences) {
            audience.sendMessage(message);
        }
    }
    
    public Component formatNumber(Number number, Locale locale) {
        NumberFormat formatter = NumberFormat.getInstance(locale);
        return Component.text(formatter.format(number));
    }
    
    public Component formatTime(long timestamp, Locale locale) {
        DateFormat formatter = DateFormat.getDateTimeInstance(
            DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
        return Component.text(formatter.format(new Date(timestamp)));
    }
}

Translation Validation

public class TranslationValidator {
    public void validateTranslations(TranslationStore store) {
        Set<String> keys = store.keys();
        Set<Locale> locales = store.locales();
        
        for (String key : keys) {
            for (Locale locale : locales) {
                if (!store.contains(key, locale)) {
                    logger.warn("Missing translation: {} for locale: {}", key, locale);
                }
                
                // Validate message format
                MessageFormat format = store.translate(key, locale);
                if (format != null) {
                    validateMessageFormat(key, locale, format);
                }
            }
        }
    }
    
    private void validateMessageFormat(String key, Locale locale, MessageFormat format) {
        try {
            // Test with sample arguments
            format.format(new Object[]{"test", 123, true});
        } catch (IllegalArgumentException e) {
            logger.error("Invalid message format for {}: {} ({})", key, locale, e.getMessage());
        }
    }
    
    public Set<String> findMissingTranslations(Set<String> requiredKeys, TranslationStore store) {
        return requiredKeys.stream()
            .filter(key -> store.locales().stream()
                .noneMatch(locale -> store.contains(key, locale)))
            .collect(Collectors.toSet());
    }
}

Best Practices

Translation Key Conventions

  • Use hierarchical keys: menu.main.title, error.permission.denied
  • Keep keys descriptive and consistent
  • Use namespaces for different modules: plugin.feature.message

Argument Handling

  • Use typed arguments (numbers, booleans) when possible
  • Provide meaningful argument names in translation files
  • Consider argument order differences between languages

Fallback Strategies

  • Always provide fallback text for custom keys
  • Use English as the base language for fallbacks
  • Handle missing translations gracefully

Performance Considerations

  • Cache frequently used translations
  • Load translations at startup, not runtime
  • Use global translator efficiently to avoid duplicate lookups

Install with Tessl CLI

npx tessl i tessl/maven-net-kyori--adventure-api

docs

audience-system.md

books-and-inventory.md

boss-bars.md

events-and-interactivity.md

index.md

nbt-data-components.md

resource-packs.md

sound-system.md

text-components.md

text-formatting.md

titles-and-subtitles.md

translation-system.md

tile.json