HyCodeYourTale

Translations (i18n)

Translations (i18n)

Dokumentace k překladovému systému v Hytale.

---

Přehled

Hytale používá I18nModule pro správu překladů. Překlady jsou uloženy v .lang souborech a podporují:

  • Parametry ({name}, {count})

  • Formátování ({value, number}, {text, upper})

  • Pluralizaci ({count, plural, one {...} other {...}})

  • Fallback jazyky
  • ---

    Struktura Souborů

    Umístění

    Assets/
    └── Server/
    └── Languages/
    ├── fallback.lang # Mapování variant jazyků
    ├── en-US/ # Výchozí jazyk
    │ ├── server.lang
    │ ├── commands.lang
    │ └── subfolder/
    │ └── module.lang
    ├── cs-CZ/ # Čeština
    │ ├── server.lang
    │ └── ...
    └── de-DE/ # Němčina
    └── ...

    Formát .lang Souborů

    Komentáře začínají #

    Jednoduchý překlad


    server.welcome = Welcome to the server!

    S parametry


    server.commands.spawn.teleported = Teleported to {x}, {y}, {z}

    Víceřádkový (escaped)


    server.help.description = This is a long description \
    that spans multiple lines

    S formátováním


    server.stats.kills = You have {count, number, integer} kills

    Příklad z Assets/Server/Languages/en-US/server.lang

    === assetEditor ===


    assetEditor.messages.unknownItem = Unknown Item "{id}"
    assetEditor.messages.failedToDecodeAsset = Failed to decode asset: {message}

    === barter ===


    barter.customUI.barterPage.restocksToday = Restocks today at {restockTime}
    barter.customUI.barterPage.restocksInDays = Restocks in {days} {days, plural, one {day} other {days}}
    barter.customUI.barterPage.noStock = OUT OF STOCK
    barter.customUI.barterPage.inStock = Stock: {count}

    === benchCategories ===


    benchCategories.workbench.crafting = Crafting
    benchCategories.workbench.survival = Survival

    ---

    Fallback Systém

    fallback.lang

    Mapuje varianty jazyků na hlavní verze:

    fallback.lang


    en-GB = en-US
    en-CA = en-US
    en-AU = en-US

    cs-SK = cs-CZ

    de-AT = de-DE
    de-CH = de-DE

    es-MX = es-ES
    es-AR = es-ES

    Fallback Řetězec

    1. Hledá klíč v požadovaném jazyce (např. cs-CZ)
    2. Pokud nenalezen, hledá ve fallback jazyce z fallback.lang
    3. Pokud stále nenalezen, hledá v en-US (výchozí)

    ---

    Parametry

    Základní Parametry

    // Definice v .lang
    // server.greeting = Hello, {name}!

    Message msg = Message.translation("server.greeting")
    .param("name", playerName);

    Typy Parametrů

    // String
    .param("name", "Player")

    // Integer
    .param("count", 42)

    // Long
    .param("id", 123456789L)

    // Double/Float
    .param("ratio", 3.14)

    // Boolean
    .param("enabled", true)

    // Message (vnořená)
    .param("item", Message.translation("items.sword.name"))

    Z Dekompilovaného Kódu - ParamValue

    // Podporované typy (Message.java - ParamValueCodec)
    switch (bsonValue.getBsonType()) {
    case DOUBLE -> DoubleParamValue
    case STRING -> StringParamValue
    case BOOLEAN -> BoolParamValue
    case INT32 -> IntParamValue
    case INT64 -> LongParamValue
    }

    ---

    Formátování

    Číselné Formátování

    V .lang souboru


    server.stats.score = Score: {score, number}
    server.stats.kills = Kills: {kills, number, integer}
    server.stats.ratio = K/D: {ratio, number, decimal}

    Textové Formátování

    Uppercase


    server.alert = ALERT: {message, upper}

    Lowercase


    server.whisper = {sender, lower} whispers: {text}

    Z MessageUtil.java

    // Formátovací logika
    formattedReplacement = switch (format) {
    case "upper" -> {
    if (replacement instanceof StringParamValue s) {
    yield s.value.toUpperCase();
    }
    }
    case "lower" -> {
    if (replacement instanceof StringParamValue s) {
    yield s.value.toLowerCase();
    }
    }
    case "number" -> {
    // decimal nebo integer
    switch (options) {
    case "integer" -> Integer.toString((int)d.value);
    default -> Double.toString(d.value);
    }
    }
    // ...
    };

    ---

    Pluralizace

    Syntaxe

    V .lang souboru


    server.items.count = You have {count, plural, one {{count} item} other {{count} items}}
    barter.customUI.barterPage.restocksInDays = Restocks in {days} {days, plural, one {day} other {days}}

    Části

  • one {...} - singulár (count == 1)

  • other {...} - plurál (count != 1)

  • Vnořené {count} odkazuje na stejný parametr

Příklad Použití

Message msg = Message.translation("server.items.count")
.param("count", itemCount);
// count=1: "You have 1 item"
// count=5: "You have 5 items"

Z MessageUtil.java - Plural Logika

case "plural" -> {
if (options != null) {
String oneText = null;
String otherText = null;
int oneIdx = options.indexOf("one {");
int otherIdx = options.indexOf("other {");

// Parse one {...}
if (oneIdx >= 0) {
int oneStart = oneIdx + "one {".length();
int oneEnd = findMatchingBrace(options, oneStart - 1);
if (oneEnd > oneStart) {
oneText = options.substring(oneStart, oneEnd);
}
}

// Parse other {...}
if (otherIdx >= 0) {
int otherStart = otherIdx + "other {".length();
int otherEnd = findMatchingBrace(options, otherStart - 1);
if (otherEnd > otherStart) {
otherText = options.substring(otherStart, otherEnd);
}
}

int value = Integer.parseInt(replacement.toString());
String selected;
if (value == 1 && oneText != null) {
selected = oneText;
} else if (otherText != null) {
selected = otherText;
} else if (oneText != null) {
selected = oneText;
} else {
selected = "";
}

yield formatText(selected, params, messageParams);
}
}

---

I18nModule API

Získání Instance

I18nModule i18n = I18nModule.get();

Získání Překladu

// Získání textu překladu
String text = I18nModule.get().getMessage("en-US", "server.welcome");

// Všechny překlady pro jazyk
Map messages = I18nModule.get().getMessages("cs-CZ");

Odeslání Překladů Hráči

// Interně používáno při připojení hráče
I18nModule.get().sendTranslations(packetHandler, playerLanguage);

---

Automatické Překlady z Assets

I18nModule automaticky generuje překlady z některých assets:

BlockType Benches

// Z I18nModule.java
event.getLoadedAssets().values().forEach(item -> {
Bench bench = item.getBench();
if (bench != null) {
String id = item.getId();
if (bench instanceof CraftingBench craftingBench) {
for (CraftingBench.BenchCategory category : craftingBench.getCategories()) {
addedMessages.put(
"server.items." + id + ".bench.categories." + category.getId() + ".name",
category.getName()
);
}
}
}
});

FieldcraftCategory

event.getLoadedAssets().values().forEach(category -> {
if (category.getName() != null) {
addedMessages.put("fieldcraftCategories." + category.getId() + ".name", category.getName());
}
});

ResourceType

event.getLoadedAssets().values().forEach(resourceType -> {
if (resourceType.getName() != null) {
addedMessages.put("resourceTypes." + resourceType.getId() + ".name", resourceType.getName());
}
if (resourceType.getDescription() != null) {
addedMessages.put("resourceTypes." + resourceType.getId() + ".description", resourceType.getDescription());
}
});

---

Konvence Klíčů

Struktura

{namespace}.{category}.{subcategory}.{key}

Příklady

Server příkazy


server.commands.spawn.teleported
server.commands.errors.playerNotFound
server.commands.errors.invalidArgument

UI


server.customUI.respawnPointClaimed
server.customUI.portalDevice.timeLimit

Interakce


server.interactions.sleep.sleepAtTheseHours
server.interactions.didNotMount

Formátování


server.formatting.list.header
server.formatting.list.empty
server.formatting.list.itemSeparator

Obecné


server.general.enabled
server.general.disabled
server.general.assetstore.reloadAssets

---

Hot Reload

I18nModule podporuje hot reload .lang souborů:

// Z I18nModule.java - AssetMonitorHandler
if (assetMonitor != null && !pack.isImmutable()) {
assetMonitor.monitorDirectoryFiles(languagesPath, new I18nAssetMonitorHandler(languagesPath));
}

// Při změně souboru:
// 1. Načte změněné překlady
// 2. Odešle UpdateTranslations paket všem hráčům
// 3. Vyvolá MessagesUpdated event

---

MessagesUpdated Event

// Pro reakci na změny překladů
getEventRegistry().register(MessagesUpdated.class, event -> {
Map> changed = event.getChanged();
Map> removed = event.getRemoved();

// Reaguj na změny
});

---

Vytvoření Vlastních Překladů

1. Vytvoř .lang Soubor

YourPlugin/
└── assets/
└── Server/
└── Languages/
└── en-US/
└── yourplugin.lang

2. Definuj Překlady

yourplugin.lang


yourplugin.commands.hello.success = Hello, {name}!
yourplugin.commands.hello.error = Player {name} not found
yourplugin.messages.welcome = Welcome to our server!
yourplugin.messages.goodbye = Goodbye, {name}. See you soon!

3. Použij v Kódu

// Jednoduché
player.sendMessage(Message.translation("yourplugin.messages.welcome"));

// S parametry
player.sendMessage(
Message.translation("yourplugin.commands.hello.success")
.param("name", playerName)
);

---

Escape Sekvence

Nový řádek


server.multiline = First line\nSecond line

Tab


server.tabbed = Column1\tColumn2

Escaped braces


server.literal = Use {{param}} for parameters

Pokračování na další řádek


server.long = This is a very long message \
that continues on the next line

---

Shrnutí

| Funkce | Syntaxe |
|--------|---------|
| Parametr | {name} |
| Číslo | {count, number} |
| Integer | {value, number, integer} |
| Uppercase | {text, upper} |
| Lowercase | {text, lower} |
| Plurál | {count, plural, one {...} other {...}} |
| Escaped brace | {{ nebo }} |

| Soubor | Účel |
|--------|------|
| *.lang | Překlady |
| fallback.lang | Mapování variant jazyků |

| API | Použití |
|-----|---------|
| Message.translation(key) | Vytvoření zprávy s překladem |
| .param(key, value) | Přidání parametru |
| I18nModule.get().getMessage(lang, key) | Přímé získání textu |

Last updated: 20. ledna 2026