Farmstead Mods
EN

Локализация

Выбор языка сервера, свои переводы и переопределение отдельных строк.

На этой странице

Команды 1#

КомандаСинтаксисАлиасыПравоОписание
/language/language <code> | /language set <code> | /language list | /language reload | /language stats | /language info | /language template <code> | /language exportmissing | /language clearmissing | /language validate <code> | /language regenerate <code> | /language override set <key> <value> | /language override get <key> | /language override remove <key> | /language override list | /language override clear | /language override reload—vanilla:op-level-4Manage custom language filesКорень требует ванильный OP 4 (`source.hasPermission(4)`), не узел neoessentials.language. В реестре прав у команды записано vanilla:op-level-4. Bare `/language <code>` — сокращение для set. <value> у override set — greedyString (остаток строки). Консоль проходит проверку OP.

Примеры#

Переключить сервер на русский#

Язык задаётся одним кодом; игрокам ничего ставить не нужно.

/language list
/language ru_ru
/language stats

list печатает коды из джарника. /language ru_ru то же, что /language set ru_ru, и пишет localization.language в конфиг. stats показывает, сколько ключей закрыто относительно en_us. Неизвестный код не ломает чат: недостающие строки берутся из en_us.

Поправить одну строку, не трогая jar#

Своя формулировка кита или бана, которая переживёт обновление мода.

/language override set commands.neoessentials.kits.claimed Вы получили кит {0}
/language override get commands.neoessentials.kits.claimed
/language override list

Override кладётся в DataStore (language_overrides), не в файл языка. get печатает текущий оверрайд или что ключа нет. Кавычку ' в значении с {0} удваивайте, иначе MessageFormat съест подстановку.

Свой полный перевод#

Начать файл в languages/custom/, а не копировать джарник руками.

/language template ru_ru
/language validate ru_ru
/language reload

template пишет каркас в languages/custom/. Это наложение: ключей, которых в файле нет, мод по-прежнему берёт из jar. validate проверяет плейсхолдеры и §-коды. После ручной правки файла — reload, не рестарт.

Тонкие места#

OP 4 и neoessentials.language — разные вещи#

Brigadier проверяет hasPermission(4). Узел из PermissionRegistry на эту команду не вешается. Игрок с neoessentials.language в LuckPerms, но без OP 4, команду не увидит.

Что делать: Либо выдайте OP 4 / консоль, либо поймите, что внешний провайдер эту команду по узлу не откроет.

reload команд не перерегистрирует#

/language reload перечитывает каталоги и оверрайды. Секция commands.language читается при старте: выключенная команда после reload не появится.

Что делать: Включение самой /language — рестарт сервера.

Известные проблемы#

Одиночная кавычка в строке с {0} печатает литерал {0}#

Это MessageFormat: ' начинает экранированный кусок и глотает плейсхолдер. В en_us/ru_ru это уже учтено удвоением; свой override легко сломать.

Что делать: Пишите '' вместо '. После правки — /language override reload или /language reload.

Подробное руководство#

Раздел ниже — исходная документация проекта (docs/Wiki/LocalizationSystem.md). Ссылки на другие страницы вики переписаны на этот сайт; текст самих руководств не редактируется, чтобы синк с апстримом не давал конфликтов.

Version: 1.0.4+build.16 · Last verified: 2026-07-23 Added / overhauled in build.62 · Language config setting added in build.187 (build numbers below build.16 predate the NeoForge 26.1 port's build-counter reset)


Overview#

NeoEssentials ships a fully featured, server-side localization system. Every in-game message is driven by translation keys stored in language JSON files. Server admins can:

  • Set the active language with one line in config.json — no file renaming needed.
  • Override individual messages without editing any bundled file.
  • Add or swap entire languages by dropping a .json file in the custom language directory.
  • Validate coverage of any language file against the English base.
  • Regenerate a language file from the JAR while preserving user edits.

All tooling is exposed through the /language in-game command (OP level 4).


Choosing the Active Language#

In-game (recommended): /language set <code> (or the bare shortcut /language <code>) validates the code against the currently deployed language files, writes it to config.json, and reloads translations immediately — no restart or separate reload step needed.

/language set fr_fr

Manually: Set the server language in config.json under the localization section:

"localization": {
  "language": "fr_fr"
}

Reload in-game after a manual edit: /neoessentials reload

Available built-in language codes:

Code Language
en_us English (US) — default
fr_fr French
de_de German
es_es Spanish
pt_br Portuguese (Brazil)
zh_cn Chinese (Simplified)
nl_nl Dutch
pl_pl Polish
ru_ru Russian

Fallback: Any key not present in the configured language file automatically falls back to en_us. You will never see a raw translation key in-game.


File Locations#

File Purpose
neoessentials/languages/custom/<language>.json Active language file — auto-deployed from JAR when first selected, auto-merged on updates (e.g. fr_fr.json when "language": "fr_fr")
neoessentials/languages/custom/en_us.json Fallback English file (always present)
neoessentials/languages/custom/<code>.json Any additional custom / community language files
neoessentials/languages/overrides.json Legacy admin message overrides file — only consulted for a one-time migration into the DataStore on first boot (see note below)
neoessentials/languages/templates/<code>_template.json Auto-generated templates for translators

How the System Works#

Startup / Boot#

  1. ConfigManager.getServerLanguage() reads localization.language from config.json (default: en_us).
  2. MessageUtil.loadTranslations() (private, called internally on startup) resolves the configured language code. MessageUtil.reloadTranslations() (public) is the equivalent used by /language reload / /language set / /neoessentials reload.
  3. The language file is looked for at neoessentials/languages/custom/<code>.json.
  4. If not found (first run), it is deployed from the JAR's bundled <code>.json.
  5. If the fr_fr (or other) JAR file does not cover 100% of keys, missing keys are filled from en_us as fallback.
  6. If the deployed file's _langVersion is older than the current JAR version, new keys are merged in without overwriting existing values.
  7. overrides.json is loaded. Overrides take top priority over all files.

Key Resolution Order (highest → lowest priority)#

1. Admin overrides  (overrides.json)
2. Configured language file  (e.g. fr_fr.json when "language": "fr_fr")
3. en_us fallback  (for keys not covered by the configured language)
4. Human-readable fallback  (generated from the key name)

Human-Readable Fallback#

If a key is not found in any file, instead of showing the raw key string (commands.neoessentials.home.not_found), the system strips common prefixes and converts dots/underscores to spaces:

commands.neoessentials.home.not_found → "Home not found"
neoessentials.moderation.player_only_command → "Moderation player only command"

This ensures players always see readable English even if a key is missing.


Version Tracking#

Each language file contains a _langVersion metadata key:

{
  "_langVersion": "23",
  ...
}

MessageUtil.java maintains a constant CURRENT_LANG_VERSION. On startup, if the deployed file's version is lower, new keys are merged automatically. The file version is then bumped to the current value and saved.

Current version: 23 (MessageUtil.CURRENT_LANG_VERSION, matches the shipped en_us.json's own _langVersion).

When you add new translation keys to en_us.json, increment _langVersion by 1 in both: - src/main/resources/data/lang/en_us.json (the _langVersion value) - MessageUtil.java → CURRENT_LANG_VERSION constant


/language Command Reference#

All subcommands require OP level 4.

Information & Management#

Command Description
/language list List all custom language files loaded
/language reload Reload all language files and overrides from disk
/language stats Show statistics (loaded languages, missing keys tracked, overrides)
/language info Show full command reference
/language set <code> Set the active server language and reload translations immediately
/language <code> Shortcut for /language set <code>

Templates & Missing Keys#

Command Description
/language template <code> Generate a translator-ready template for language <code>
/language exportmissing Export all runtime-tracked missing keys to a JSON template file
/language clearmissing Reset the missing-keys tracker

Validation & Regeneration#

Command Description
/language validate <code> Compare <code>.json against en_us.json; shows coverage %, missing keys, and extra keys
/language regenerate <code> Re-deploy <code>.json from JAR, merging user translations, auto-backup to .bak

/language validate example output:

═══ Language Validation: fr_fr ═══
Total base keys: 1058
Translated keys: 987
Coverage: §e93%
Missing keys: 71
Extra keys (not in base): 3
First 10 missing key(s):
  - commands.neoessentials.teleport.request.sent
  - commands.neoessentials.teleport.request.received
  ...
Run /language regenerate fr_fr to update the file from JAR.

Admin Overrides#

Override any message key permanently. Overrides are persisted through the active DataStore (see Storage Backend) as a single document — with the default json backend that's neoessentials/store/language_overrides.json; with sqlite/mysql it's a table in the configured database. Overrides survive reloads.

Storage note: neoessentials/languages/overrides.json (the old flat file) is now only read for a one-time legacy migration — if the DataStore has no override document yet and storage.autoMigrate is enabled, any overrides found in that file are imported once and the DataStore becomes authoritative from then on.

Command Description
/language override set <key> <value> Set a message override
/language override get <key> Show the current override for a key
/language override remove <key> Remove a single override
/language override list List all active overrides
/language override clear Remove all overrides
/language override reload Reload overrides from disk

Example — customize the server's welcome message:

/language override set neoessentials.server.welcome §aWelcome to MyServer! Type /help to get started.

Creating a Custom Language#

  1. Generate a template: /language template zh_tw This creates neoessentials/languages/templates/zh_tw_template.json.

  2. Translate all values in the template (replace [TRANSLATE] English text with your translation). Keep {0}, {1} placeholders exactly as-is — they are substituted at runtime with player names, counts, etc.

  3. Add metadata at the top of your file: json { "_nativeName": "繁體中文", "_englishName": "Traditional Chinese", "_languageCode": "zh_tw", "_author": "YourName", "_version": "1.0", ... }

  4. Save the file as neoessentials/languages/custom/zh_tw.json.

  5. Set it active in config.json: json "localization": { "language": "zh_tw" }

  6. Run /neoessentials reload.

  7. Verify coverage with /language validate zh_tw.


Bundled Language Files#

The following languages are bundled in the JAR and can be activated via config.json:

Code Language
en_us English (base)
fr_fr French
de_de German
es_es Spanish
pt_br Portuguese (Brazil)
zh_cn Chinese (Simplified)
nl_nl Dutch
pl_pl Polish
ru_ru Russian

Developer Notes#

Adding a New Translation Key#

  1. Add the key + English value to src/main/resources/data/lang/en_us.json.
  2. Use the key via MessageUtil.localize("your.new.key", arg0, arg1...) in Java.
  3. Increment _langVersion in en_us.json and CURRENT_LANG_VERSION in MessageUtil.java.
  4. On the next server start, the new key is automatically merged into all deployed language files.

Key Naming Convention#

commands.neoessentials.<category>.<action>    (command feedback messages)
neoessentials.<category>.<action>             (system / non-command messages)

Examples: - commands.neoessentials.teleport.home.not_found - commands.neoessentials.moderation.ban.success - neoessentials.moderation.ban_message - neoessentials.error.no_server

MessageUtil API#

// Simple lookup with args
String msg = MessageUtil.localize("commands.neoessentials.home.not_found", homeName);

// With explicit English fallback (use when you're certain of the English text)
String msg = MessageUtil.localize("commands.neoessentials.home.not_found", "Home ''{0}'' not found.", homeName);

// As a Component (for sendSuccess / sendFailure)
Component comp = MessageUtil.component("commands.neoessentials.home.not_found", homeName);

// Convenience coloured components
Component success = MessageUtil.success("commands.neoessentials.home.set", name);
Component error   = MessageUtil.error("commands.neoessentials.home.not_found", name);
Component warning = MessageUtil.warning("commands.neoessentials.home.limit_reached", max);
Component info    = MessageUtil.info("commands.neoessentials.home.list_header", count);

Troubleshooting#

Problem Fix
Language not changing after config edit Run /neoessentials reload — language is re-read on every reload.
Message shows raw key (e.g. commands.neoessentials.xyz) The key is missing from en_us.json. Add it and bump _langVersion.
Message shows human-readable fallback instead of proper text Same as above — key is missing. The humanizer is a safety net, not the final output.
Bundled language file not updating Run /language regenerate <code>.
Override not showing in-game Run /language override reload or /language reload. Overrides live in the DataStore now — use /language override set/get/remove rather than hand-editing overrides.json (which is legacy-import-only).
Language file corrupted Delete it and run /language regenerate <code> to redeploy from JAR.
Language falls back to English for some messages That key isn't translated in the language file yet. Run /language validate <code> to see missing keys.

Last updated: 1.0.4+build.16 — 2026-07-23