Текст и переводы 26.1.2
Подробная документация по работе Minecraft с форматированным текстом и переводами.
Всякий раз, когда Minecraft отображает текст в игре, он, вероятно, определяется с помощью объекта Component. Этот пользовательский тип используется вместо String для обеспечения более сложного форматирования, включая цвета, выделение жирным шрифтом, обфускации и событий нажатия (click). Они также обеспечивают легкий доступ в систему перевода, что упрощает перевод любого элемента пользовательского интерфейса в разные языки.
Если вы раньше работали с пакетами данных (датапаками) или функциями, вы можете увидеть параллели с текстовым форматом json, используемым для отображения названий, книг, табличек и другого. Как вы, скорее всего, догадались, это просто JSON-представление объекта Component, и для взаимного преобразования между ними можно использовать Component.Serializer.
При создании мода, предпочтительнее конструировать объекты Component прямо в коде, используя перевод, когда это возможно.
Компоненты текстовых литералов
Самый простой способ создать объект Component — это сделать литерал (простой текст). По сути это строка которая будет отображена как есть, без форматирования по умолчанию.
Они создаются с помощью методов Component.nullToEmpty и Component.literal, которые действуют немного по-разному. Component.nullToEmpty принимает значения null и возвращает экземпляр класса Component. Component.literal же наоборот не сможет принять значение null, и вернёт MutableComponent, являющийся наследуемым классом от Component, который можно легко стилизовать и соединять с другими. Подробнее об этом будет сказано позже.
java
Component literal = Component.nullToEmpty("Hello, world!");
MutableComponent mutable = Component.literal("Hello, world!");
// Keep in mind that a MutableComponent can be used as a Component, making this valid:
Component mutableAsText = mutable;1
2
3
4
2
3
4
Компоненты переводимого текста
Если вы хотите предоставить несколько вариантов перевода для одной и той же строки текста, вы можете использовать метод Component.translatable, чтобы сослаться на ключ перевода в любом языковом файле. Если ключ не существует, ключ перевода конвертируется в литерал.
java
Component translatable = Component.translatable("example-mod.text.hello");
// Similarly to literals, translatable text can be easily made mutable.
MutableComponent mutable = Component.translatable("example-mod.text.bye");1
2
3
4
2
3
4
Файл языка, en_us.json, выглядит как то так:
json
{
"example-mod.text.hello": "Hello!",
"example-mod.text.bye": "Goodbye :("
}1
2
3
4
2
3
4
Если вы хотите иметь возможность использовать переменные в переводе, подобно тому, как сообщения о смерти позволяют вам использовать задействованных игроков и предметы в переводе, вы можете добавить указанные переменные в качестве параметров. Вы можете добавить сколько угодно параметров.
java
Component translatable = Component.translatable("example-mod.text.hello", player.getDisplayName());1
Вы можете ссылаться на эти переменные в переводе следующим образом:
json
{
"example-mod.text.hello": "%1$s said hello!"
}1
2
3
2
3
В игре %1$s будет заменено на имя игрока, на которого вы сослались в коде. Использование player.getDisplayName() приведет к тому, что дополнительная информация об объекте появится во всплывающей подсказке при наведении курсора на имя в сообщении чата, в отличие от использования player.getName(), которое все равно получит имя; однако дополнительные детали не отображаются. Аналогичное можно сделать с itemStacks, используя stack.getDisplayName().
Что касается того, что вообще означает %1$s, всё, что вам действительно нужно знать, это то, что это число соответствует переменной, которую вы пытаетесь использовать. Допустим, у вас есть три переменные, которые вы используете.
java
Component translatable = Component.translatable("example-mod.text.whack.item", victim.getDisplayName(), attacker.getDisplayName(), itemStack.toHoverableText());1
Если вы хотите сослаться на то, что в нашем случае является атакующим (attacker), вам нужно использовать %2$s, так как это вторая переданная нами переменная. Точно так же %3$s ссылается на itemStack. Перевод с таким количеством дополнительных параметров может выглядеть так:
json
{
"example-mod.text.whack.item": "%1$s was whacked by %2$s using %3$s"
}1
2
3
2
3
Десериализация Текста
Как было упомянуто выше, вы можете сериализовать текст в JSON используя текстовый кодек. Для большей информации об кодеках, посмотрите страницу Codec.
java
Gson gson = new Gson();
MutableComponent mutable = Component.translatable("example-mod.text.bye");
String json = gson.toJson(ComponentSerialization.CODEC.encodeStart(JsonOps.INSTANCE, mutable).getOrThrow());1
2
3
2
3
В результате получается JSON, который можно использовать в датапаках, командах и других местах которые принимают JSON формат текста вместо буквального или переводимого текста.
Сериализация Текста
Кроме того, чтобы десериализовать текстовый объект в реальный класс Component, опять же, используйте кодек.
java
String jsonString = "...";
Component deserialized = ComponentSerialization.CODEC
.decode(JsonOps.INSTANCE, gson.fromJson(jsonString, JsonElement.class))
.getOrThrow()
.getFirst();1
2
3
4
5
2
3
4
5
Форматирование Текста
Вы можете быть знакомы со стандартом форматирования в Minecraft:
Вы можете применить эти стили форматирования, используя перечисление ChatFormatting в классе MutableComponent:
java
MutableComponent result = Component.literal("Hello World!")
.withStyle(ChatFormatting.AQUA, ChatFormatting.BOLD, ChatFormatting.UNDERLINE);1
2
2
| Цвет | Название | Код в чате | Код для MOTD | HEX-код |
|---|---|---|---|---|
| Чёрный (black) | §0 | \u00A70 | #000000 | |
| Тёмно-синий (dark_blue) | §1 | \u00A71 | #0000AA | |
| Тёмно-зелёный (dark_green) | §2 | \u00A72 | #00AA00 | |
| Тёмно-голубой (dark_aqua) | §3 | \u00A73 | #00AAAA | |
| Тёмно-красный (dark_red) | §4 | \u00A74 | #AA0000 | |
| Тёмно-фиолетовый (dark_purple) | §5 | \u00A75 | #AA00AA | |
| Золотой (gold) | §6 | \u00A76 | #FFAA00 | |
| Серый (gray) | §7 | \u00A77 | #AAAAAA | |
| Тёмно-серый (dark_gray) | §8 | \u00A78 | #555555 | |
| Синий (blue) | §9 | \u00A79 | #5555FF | |
| Зелёный (green) | §a | \u00A7a | #55FF55 | |
Акваaqua | §b | \u00A7b | #55FFFF | |
| Красный (red) | §c | \u00A7c | #FF5555 | |
| Фиолетовый (light_purple) | §d | \u00A7d | #FF55FF | |
| Жёлтый (yellow) | §e | \u00A7e | #FFFF55 | |
| Белый (white) | §f | \u00A7f | #FFFFFF | |
| Сброс форматирования | §r | |||
| Жирный | §l | |||
| §m | ||||
| Подчёркнутый | §n | |||
| курсив | §o | |||
| Зашифрованный | §k |


