From ce79da12293f711c16d04cb734e26d11814a96f7 Mon Sep 17 00:00:00 2001
From: wangzhizhou <824219521@qq.com>
Date: Sun, 9 Aug 2026 10:03:17 +0800
Subject: [PATCH 1/3] fix(messages): remove duplicate YAML keys across message
files
Merge duplicated shop.common blocks in messages_zh.yml and messages_nl.yml
(8 keys were silently dropped, falling back to English), remove a stray
duplicate player-shops.messages key in messages_es.yml, and relocate the
Dutch player-shop message keys from the malformed hooks block to
player-shops.messages. Add a strict SnakeYAML regression test that fails on
any duplicate key in the bundled messages_*.yml files.
---
src/main/resources/messages/messages_es.yml | 1 -
src/main/resources/messages/messages_nl.yml | 104 +++++++++---------
src/main/resources/messages/messages_zh.yml | 4 +-
.../config/MessageFilesDuplicateKeyTest.java | 46 ++++++++
4 files changed, 98 insertions(+), 57 deletions(-)
create mode 100644 src/test/java/com/skyblockexp/ezshops/config/MessageFilesDuplicateKeyTest.java
diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml
index 91c49cd..b285676 100644
--- a/src/main/resources/messages/messages_es.yml
+++ b/src/main/resources/messages/messages_es.yml
@@ -227,7 +227,6 @@ player-shops:
price-prefix: "&6"
price-suffix: " &7por &6{price}"
out-of-stock-line: "&cAgotado"
- messages:
messages:
menu:
inventory-title: "&2Configuración de Player Shop"
diff --git a/src/main/resources/messages/messages_nl.yml b/src/main/resources/messages/messages_nl.yml
index 08eda17..4bb3b80 100644
--- a/src/main/resources/messages/messages_nl.yml
+++ b/src/main/resources/messages/messages_nl.yml
@@ -248,6 +248,56 @@ player-shops:
unknown-item:
singular: "&bItem"
plural: "&bItems"
+ # Player shop message keys (Dutch)
+ no-permission-create: "&cJe hebt geen toestemming om winkels te maken."
+ sign-requires-chest: "&cWinkelschilden moeten aan een kist bevestigd zijn."
+ enter-quantity: "&cVoer de hoeveelheid in op de tweede regel."
+ quantity-prompt: "&cAantal?"
+ enter-price: "&cVoer de prijs in op de derde regel."
+ price-prompt: "&cPrijs?"
+ using-saved-settings: "&aGebruikt je opgeslagen /playershop instellingen."
+ chest-access-denied: "&cJe kunt de kist van een andere speler niet openen."
+ break-denied: "&cJe kunt de winkel van iemand anders niet slopen."
+ shop-removed: "&eWinkel verwijderd."
+ creation-invalid-configuration: "&cOngeldige winkelconfiguratie."
+ creation-quantity-positive: "&cHoeveelheid moet groter zijn dan nul."
+ creation-quantity-min: "&cHoeveelheid moet minimaal &b{min}&c zijn."
+ creation-quantity-max: "&cHoeveelheid mag niet meer zijn dan &b{max}&c."
+ creation-price-positive: "&cPrijs moet groter zijn dan nul."
+ creation-price-min: "&cPrijs moet minimaal &6{min}&c zijn."
+ creation-price-max: "&cPrijs mag niet meer zijn dan &6{max}&c."
+ creation-sign-in-use: "&cEr is al een winkel op dit bord."
+ creation-chest-unresolved: "&cWinkelkisten konden niet worden gevonden."
+ creation-chest-in-use: "&cEen winkel gebruikt die kist al."
+ creation-chest-inaccessible: "&cKan geen toegang krijgen tot de kist."
+ creation-selected-item-missing: "&cDe kist bevat het geselecteerde item uit /playershop niet."
+ creation-item-missing: "&cPlaats het item dat je wilt verkopen in de kist."
+ creation-insufficient-stock: "&cDe kist bevat niet genoeg items om de winkel te starten."
+ creation-success: "&aWinkel succesvol aangemaakt!"
+ purchase-invalid: "&cOngeldige winkel aankoop poging."
+ purchase-no-permission: "&cJe hebt geen toestemming om bij winkels te kopen."
+ purchase-no-economy: "&cDe winkel is momenteel niet beschikbaar omdat er geen economyleverancier is geconfigureerd."
+ purchase-own-shop: "&cJe kunt niet bij je eigen winkel kopen."
+ purchase-missing-chest: "&cDe winkelkist ontbreekt. De aanbieding is verwijderd."
+ purchase-out-of-stock: "&cDeze winkel is momenteel uitverkocht."
+ purchase-no-space: "&cJe hebt niet genoeg ruimte in je inventaris."
+ purchase-transaction-failed: "&cTransactie mislukt: {error}"
+ purchase-owner-notify: "&b{buyer} &aheeft &b{item}&a gekocht voor &6{price}&a."
+ purchase-buyer-success: "&a{item}&a gekocht van &b{seller}&a voor &6{price}&a."
+ unknown-seller-name: "de verkoper"
+ setup-open: "&aConfigureer je spelerswinkel instellingen en bevestig om op te slaan."
+ setup-item-selected: "&aGeselecteerd &b{item}&a om te verkopen."
+ setup-item-cleared: "&eGeselecteerd item gewist. De inhoud van de kist bepaalt wat de winkel verkoopt."
+ setup-select-item: "&eKlik op een item in je inventaris om te kiezen wat je wilt verkopen."
+ setup-saved: "&aSpelerswinkel instellingen opgeslagen. Plaats een [playershop] bord op een kist om ze te gebruiken."
+ setup-quantity-chat-prompt: "&eTyp de hoeveelheid om te verkopen in de chat, of typ cancel om te stoppen."
+ setup-price-chat-prompt: "&eTyp de prijs in de chat, of typ cancel om te stoppen."
+ setup-chat-cancelled: "&eInvoer geannuleerd. Vorige waarde behouden."
+ setup-chat-invalid-number: "&cVoer een geldig nummer in."
+ setup-quantity-updated: "&aHoeveelheid ingesteld op &b{amount}&a."
+ setup-price-updated: "&aPrijs ingesteld op &6{price}&a."
+ command-players-only: "&cAlleen spelers kunnen dit commando gebruiken."
+ command-disabled: "&cSpelerswinkels zijn momenteel uitgeschakeld."
# English fallback keys added from messages_en.yml to ensure full key coverage
# (keep existing translations above; these are used when a translation is missing)
@@ -262,6 +312,7 @@ shop:
cannot-sell-line: "&7This item cannot be sold."
buy-only-shift-line: "&7Shift-click {bulk_amount}: &a{buy_bulk_total}"
spawner-display-name: "&f{spawner}"
+ prices-may-change: "&7Prices may change over time."
categories:
building:
name: "&eBuilding Blocks"
@@ -353,9 +404,6 @@ shop:
menu:
title: "&aWood & Nature"
- common:
- prices-may-change: "&7Prices may change over time."
-
menu:
main:
title: "&aServer Shop"
@@ -439,53 +487,3 @@ shop:
note: "&7Treat yourself or resell at a premium."
hooks:
player-lacking-permission-message: "&cJe hebt geen toestemming om winkelhook-commando's uit te voeren."
- # Player shop message keys (Dutch)
- no-permission-create: "&cJe hebt geen toestemming om winkels te maken."
- sign-requires-chest: "&cWinkelschilden moeten aan een kist bevestigd zijn."
- enter-quantity: "&cVoer de hoeveelheid in op de tweede regel."
- quantity-prompt: "&cAantal?"
- enter-price: "&cVoer de prijs in op de derde regel."
- price-prompt: "&cPrijs?"
- using-saved-settings: "&aGebruikt je opgeslagen /playershop instellingen."
- chest-access-denied: "&cJe kunt de kist van een andere speler niet openen."
- break-denied: "&cJe kunt de winkel van iemand anders niet slopen."
- shop-removed: "&eWinkel verwijderd."
- creation-invalid-configuration: "&cOngeldige winkelconfiguratie."
- creation-quantity-positive: "&cHoeveelheid moet groter zijn dan nul."
- creation-quantity-min: "&cHoeveelheid moet minimaal &b{min}&c zijn."
- creation-quantity-max: "&cHoeveelheid mag niet meer zijn dan &b{max}&c."
- creation-price-positive: "&cPrijs moet groter zijn dan nul."
- creation-price-min: "&cPrijs moet minimaal &6{min}&c zijn."
- creation-price-max: "&cPrijs mag niet meer zijn dan &6{max}&c."
- creation-sign-in-use: "&cEr is al een winkel op dit bord."
- creation-chest-unresolved: "&cWinkelkisten konden niet worden gevonden."
- creation-chest-in-use: "&cEen winkel gebruikt die kist al."
- creation-chest-inaccessible: "&cKan geen toegang krijgen tot de kist."
- creation-selected-item-missing: "&cDe kist bevat het geselecteerde item uit /playershop niet."
- creation-item-missing: "&cPlaats het item dat je wilt verkopen in de kist."
- creation-insufficient-stock: "&cDe kist bevat niet genoeg items om de winkel te starten."
- creation-success: "&aWinkel succesvol aangemaakt!"
- purchase-invalid: "&cOngeldige winkel aankoop poging."
- purchase-no-permission: "&cJe hebt geen toestemming om bij winkels te kopen."
- purchase-no-economy: "&cDe winkel is momenteel niet beschikbaar omdat er geen economyleverancier is geconfigureerd."
- purchase-own-shop: "&cJe kunt niet bij je eigen winkel kopen."
- purchase-missing-chest: "&cDe winkelkist ontbreekt. De aanbieding is verwijderd."
- purchase-out-of-stock: "&cDeze winkel is momenteel uitverkocht."
- purchase-no-space: "&cJe hebt niet genoeg ruimte in je inventaris."
- purchase-transaction-failed: "&cTransactie mislukt: {error}"
- purchase-owner-notify: "&b{buyer} &aheeft &b{item}&a gekocht voor &6{price}&a."
- purchase-buyer-success: "&a{item}&a gekocht van &b{seller}&a voor &6{price}&a."
- unknown-seller-name: "de verkoper"
- setup-open: "&aConfigureer je spelerswinkel instellingen en bevestig om op te slaan."
- setup-item-selected: "&aGeselecteerd &b{item}&a om te verkopen."
- setup-item-cleared: "&eGeselecteerd item gewist. De inhoud van de kist bepaalt wat de winkel verkoopt."
- setup-select-item: "&eKlik op een item in je inventaris om te kiezen wat je wilt verkopen."
- setup-saved: "&aSpelerswinkel instellingen opgeslagen. Plaats een [playershop] bord op een kist om ze te gebruiken."
- setup-quantity-chat-prompt: "&eTyp de hoeveelheid om te verkopen in de chat, of typ cancel om te stoppen."
- setup-price-chat-prompt: "&eTyp de prijs in de chat, of typ cancel om te stoppen."
- setup-chat-cancelled: "&eInvoer geannuleerd. Vorige waarde behouden."
- setup-chat-invalid-number: "&cVoer een geldig nummer in."
- setup-quantity-updated: "&aHoeveelheid ingesteld op &b{amount}&a."
- setup-price-updated: "&aPrijs ingesteld op &6{price}&a."
- command-players-only: "&cAlleen spelers kunnen dit commando gebruiken."
- command-disabled: "&cSpelerswinkels zijn momenteel uitgeschakeld."
diff --git a/src/main/resources/messages/messages_zh.yml b/src/main/resources/messages/messages_zh.yml
index c4f148a..d9263b9 100644
--- a/src/main/resources/messages/messages_zh.yml
+++ b/src/main/resources/messages/messages_zh.yml
@@ -262,6 +262,7 @@ shop:
cannot-sell-line: "&7This item cannot be sold."
buy-only-shift-line: "&7Shift-click {bulk_amount}: &a{buy_bulk_total}"
spawner-display-name: "&f{spawner}"
+ prices-may-change: "&7Prices may change over time."
categories:
building:
name: "&eBuilding Blocks"
@@ -353,9 +354,6 @@ shop:
menu:
title: "&aWood & Nature"
- common:
- prices-may-change: "&7Prices may change over time."
-
menu:
main:
title: "&aServer Shop"
diff --git a/src/test/java/com/skyblockexp/ezshops/config/MessageFilesDuplicateKeyTest.java b/src/test/java/com/skyblockexp/ezshops/config/MessageFilesDuplicateKeyTest.java
new file mode 100644
index 0000000..16c7a4f
--- /dev/null
+++ b/src/test/java/com/skyblockexp/ezshops/config/MessageFilesDuplicateKeyTest.java
@@ -0,0 +1,46 @@
+package com.skyblockexp.ezshops.config;
+
+import org.junit.jupiter.api.Test;
+import org.yaml.snakeyaml.LoaderOptions;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Guards the bundled {@code messages/*.yml} files against duplicate YAML keys.
+ *
+ *
SnakeYAML (and therefore Bukkit's YamlConfiguration) silently keeps the last
+ * duplicate mapping key and discards the first, which once silently dropped the
+ * {@code shop.common} sub-keys in {@code messages_zh.yml} / {@code messages_nl.yml}
+ * and logged {@code duplicate keys found : common} at startup.
+ *
+ * Parsing in strict mode ({@code allowDuplicateKeys = false}) makes any duplicate
+ * key throw, so a regression re-introduced by an upstream merge fails this test.
+ */
+class MessageFilesDuplicateKeyTest {
+
+ private static final List MESSAGE_FILES = List.of(
+ "messages_en.yml", "messages_es.yml", "messages_nl.yml", "messages_zh.yml");
+
+ @Test
+ void messageFilesContainNoDuplicateKeys() throws IOException {
+ for (String file : MESSAGE_FILES) {
+ LoaderOptions options = new LoaderOptions();
+ options.setAllowDuplicateKeys(false);
+ Yaml yaml = new Yaml(options);
+
+ try (InputStream in = getClass().getResourceAsStream("/messages/" + file)) {
+ if (in == null) {
+ fail("Missing bundled resource /messages/" + file);
+ }
+ assertDoesNotThrow(() -> yaml.load(in),
+ "Duplicate (or invalid) YAML keys in " + file);
+ }
+ }
+ }
+}
From 32e4f07b3e9e5f27b098edc508c5404b5fce7674 Mon Sep 17 00:00:00 2001
From: wangzhizhou <824219521@qq.com>
Date: Sun, 9 Aug 2026 11:25:41 +0800
Subject: [PATCH 2/3] fix(messages): fully localize messages_zh.yml
Translate ~130 live keys from English to Chinese across shop UI, stock
GUI, daily rotations and commands; add missing live keys (stock-admin,
reload messages, food.item-note, valuables.experience-bottle-display-name)
and fix two upstream structural bugs in the zh file:
- shop.shop.rotations double-nesting -> shop.rotations
- see-all.lore defined as a list, but stock-gui.yml references
see-all.lore.line1/line2 -> convert to a line1/line2 map
zh now covers 327 keys; only inert sections remain untranslated
(player-shops chat messages and setup-shops GUI are Java defaults).
---
src/main/resources/messages/messages_zh.yml | 339 +++++++++++---------
1 file changed, 182 insertions(+), 157 deletions(-)
diff --git a/src/main/resources/messages/messages_zh.yml b/src/main/resources/messages/messages_zh.yml
index d9263b9..fef2dbf 100644
--- a/src/main/resources/messages/messages_zh.yml
+++ b/src/main/resources/messages/messages_zh.yml
@@ -10,6 +10,9 @@ commands:
invalid-amount: "&c数量无效:{amount}"
amount-positive: "&c数量必须为正数。"
unknown-category: "&c未知的商店分类:{category}"
+ reload-no-permission: "&c你没有权限重载 EzShops。"
+ reload-success: "&aEzShops 配置已成功重载。"
+ reload-failed: "&c重载 EzShops 失败:{error}"
sell-hand:
players-only: "&c只有玩家可以出售物品。"
must-hold-item: "&c你必须拿着一个物品才能使用此指令。"
@@ -47,6 +50,16 @@ commands:
list-header: "&6价格列表 - 第 {page}/{total} 页"
list-entry: "&e{key} &7- 购买: {buy} 出售: {sell}"
+ stock-admin:
+ usage: "&e用法:/stockadmin ..."
+ no-permission: "&c你没有权限使用此命令。"
+ lack-permission: "&c你缺少权限:{perm}"
+ set-success: "&a已将 {item} 的价格设置为 {price}"
+ reset-success: "&a已将 {item} 的价格重置为基础价格"
+ freeze-success: "&a已由 {by} 在 {when} 冻结 {item}"
+ unfreeze-success: "&a已解冻 {item}"
+ reload-success: "&a已从磁盘重新加载冻结状态。"
+
sign-shop-scan:
players-only: "&c只有玩家可以扫描商店告示牌。"
no-permission: "&c你没有权限扫描商店告示牌。"
@@ -192,47 +205,47 @@ signs:
buy-label: "&a购买"
sell-label: "&c出售"
display:
- header: "&2[Shop]"
- buy-prefix: "&aBuy &7x"
- buy-suffix: " &7for &6{price}"
- sell-prefix: "&cSell &7x"
- sell-suffix: " &7for &6{price}"
+ header: "&2[商店]"
+ buy-prefix: "&a购买 &7x"
+ buy-suffix: " &7价格 &6{price}"
+ sell-prefix: "&c出售 &7x"
+ sell-suffix: " &7价格 &6{price}"
item-format: "&b{item}"
price-format: "&6{price}"
- unavailable-format: "&cUnavailable"
+ unavailable-format: "&c不可用"
player-shops:
sign-format:
- available-header: "&2[PlayerShop]"
- out-of-stock-header: "&c[PlayerShop]"
+ available-header: "&2[玩家商店]"
+ out-of-stock-header: "&c[玩家商店]"
owner-prefix: "&7"
- owner-suffix: "'s"
- unknown-owner-name: "Owner"
+ owner-suffix: "&7的"
+ unknown-owner-name: "未知店主"
item-prefix: "&b"
item-middle: "&7x &b"
item-suffix: " -"
price-prefix: "&6"
- price-suffix: " &7for &6{price}"
- out-of-stock-line: "&cOut of Stock"
+ price-suffix: " &7价格 &6{price}"
+ out-of-stock-line: "&c缺货"
messages:
menu:
- inventory-title: "&2Player Shop Setup"
+ inventory-title: "&2玩家商店设置"
confirm-button:
- name: "&aSave Settings"
+ name: "&a保存设置"
lore:
- - "&7Apply these values to your next shop."
+ - "&7将这些值应用到你的下一个商店。"
select-item:
- name: "&eSelect Item"
+ name: "&e选择物品"
lore:
- - "&7Click an item in your inventory to choose it."
- - "&7Current: None"
- - "&7Click this slot to clear the selection."
- item-selected-clear-hint: "&7Click to clear this selection."
+ - "&7点击背包中的物品来选择它。"
+ - "&7当前:无"
+ - "&7点击此槽位以清除选择。"
+ item-selected-clear-hint: "&7点击清除此选择。"
quantity-display:
- name: "&bQuantity"
+ name: "&b数量"
value-format: "&ex{amount}"
price-display:
- name: "&6Price"
+ name: "&6价格"
value-format: "&e{price}"
quantity-adjust:
minus-one: "&c-1"
@@ -246,195 +259,207 @@ player-shops:
plus-one: "&a+1"
item-description-format: "&b{amount}&7x {item}"
unknown-item:
- singular: "&bItem"
- plural: "&bItems"
+ singular: "&b物品"
+ plural: "&b物品"
-# English fallback keys added from messages_en.yml to ensure full key coverage
-# (keep existing translations above; these are used when a translation is missing)
+# ================= 商店界面 =================
+# 分类 / 主菜单 / 股票市场 / 每日特惠 的展示文本。
shop:
common:
menu:
fill-display-name: "&7 "
item-display-name: "&f{material}"
- buy-line: "&7Buy {amount}: &a{buy_total}"
- sell-line: "&7Sell {amount}: &c{sell_total}"
- shift-click-line: "&7Shift-click {bulk_amount}: &a{buy_bulk_total} &7/ &c{sell_bulk_total}"
- cannot-sell-line: "&7This item cannot be sold."
- buy-only-shift-line: "&7Shift-click {bulk_amount}: &a{buy_bulk_total}"
+ buy-line: "&7购买 {amount} 个:&a{buy_total}"
+ sell-line: "&7出售 {amount} 个:&c{sell_total}"
+ shift-click-line: "&7潜行点击 {bulk_amount} 个:&a{buy_bulk_total} &7/ &c{sell_bulk_total}"
+ cannot-sell-line: "&7该物品无法出售。"
+ buy-only-shift-line: "&7潜行点击 {bulk_amount} 个:&a{buy_bulk_total}"
spawner-display-name: "&f{spawner}"
- prices-may-change: "&7Prices may change over time."
+ prices-may-change: "&7价格可能会随时间变化。"
categories:
building:
- name: "&eBuilding Blocks"
- icon-display-name: "&eBuilding Blocks"
- icon-lore: "&7Blocks for construction projects."
+ name: "&e建筑方块"
+ icon-display-name: "&e建筑方块"
+ icon-lore: "&7用于建筑工程的方块。"
menu:
- title: "&eBuilding Blocks"
+ title: "&e建筑方块"
farming:
- name: "&aFarming Supplies"
- icon-display-name: "&aFarming Supplies"
- icon-lore: "&7Common crops and farming goods."
+ name: "&a农业用品"
+ icon-display-name: "&a农业用品"
+ icon-lore: "&7常见农作物与农业用品。"
menu:
- title: "&aFarming Supplies"
+ title: "&a农业用品"
food:
- name: "&eFood & Meals"
- icon-display-name: "&eFood & Meals"
- icon-lore: "&7Everyday meals and snacks."
+ name: "&e食物与餐点"
+ icon-display-name: "&e食物与餐点"
+ icon-lore: "&7日常餐点和零食。"
menu:
- title: "&eFood & Meals"
+ title: "&e食物与餐点"
+ item-note: "&7美味餐点与易腐食品。"
daily_specials:
- name: "&dDaily Specials"
- icon-display-name: "&dDaily Specials"
- icon-lore: "&7Hand-picked deals that change throughout the day."
+ name: "&d每日特惠"
+ icon-display-name: "&d每日特惠"
+ icon-lore: "&7全天轮换的精选商品。"
menu:
- title: "&dDaily Specials"
+ title: "&d每日特惠"
rotation-defaults:
- visit-lore: "&7Visit often to catch the featured option."
- admin-hint: "&7Admins can swap options manually by editing shop-rotations.yml."
- item-note: "&7Limited-time special - grab it while it lasts!"
+ visit-lore: "&7常来看看,抓住精选特惠。"
+ admin-hint: "&7管理员可通过编辑 shop-rotations.yml 手动更换选项。"
+ item-note: "&7限时特惠——机不可失!"
decorations:
- name: "&dDecorations & Lighting"
- icon-display-name: "&dDecorations & Lighting"
- icon-lore: "&7Ornamental blocks and lighting."
+ name: "&d装饰与照明"
+ icon-display-name: "&d装饰与照明"
+ icon-lore: "&7装饰性方块和照明。"
menu:
- title: "&dDecorations & Lighting"
+ title: "&d装饰与照明"
enchantments:
- name: "&5Enchantment Books"
- icon-display-name: "&5Enchantment Books"
- icon-lore: "&7Powerful books for upgrading your gear."
+ name: "&5附魔书"
+ icon-display-name: "&5附魔书"
+ icon-lore: "&7升级装备的强力书籍。"
menu:
- title: "&5Enchantment Books"
- item-display-name: "&d{enchantments} Book"
- contains-line: "&7Contains: &b{enchantments}"
+ title: "&5附魔书"
+ item-display-name: "&d{enchantments} 附魔书"
+ contains-line: "&7包含:&b{enchantments}"
fishing:
- name: "&bFishing Gear"
- icon-display-name: "&bFishing Gear"
- icon-lore: "&7Fishing essentials and bait."
+ name: "&b钓鱼装备"
+ icon-display-name: "&b钓鱼装备"
+ icon-lore: "&7钓鱼必备品和鱼饵。"
menu:
- title: "&bFishing Gear"
- item-note: "&7Freshly stocked for anglers."
+ title: "&b钓鱼装备"
+ item-note: "&7为垂钓者新鲜上架。"
mining:
- name: "&bMining Resources"
- icon-display-name: "&bMining Resources"
- icon-lore: "&7Ores, ingots, and stone."
+ name: "&b采矿资源"
+ icon-display-name: "&b采矿资源"
+ icon-lore: "&7矿石、锭和石头。"
menu:
- title: "&bMining Resources"
- item-note: "&7Trusted by miners everywhere."
+ title: "&b采矿资源"
+ item-note: "&7备受矿工信赖。"
mob_drops:
- name: "&cMob Drops & Combat"
- icon-display-name: "&cMob Drops & Combat"
- icon-lore: "&7Mob drops and combat gear."
+ name: "&c生物掉落与战斗"
+ icon-display-name: "&c生物掉落与战斗"
+ icon-lore: "&7生物掉落物和战斗装备。"
menu:
- title: "&cMob Drops & Combat"
- item-note: "&7Favored by hunters and warriors."
+ title: "&c生物掉落与战斗"
+ item-note: "&7深受猎人和战士的青睐。"
redstone:
- name: "&cRedstone & Utility"
- icon-display-name: "&cRedstone & Utility"
- icon-lore: "&7Automation components and wiring."
+ name: "&c红石与机关"
+ icon-display-name: "&c红石与机关"
+ icon-lore: "&7自动化组件和线路。"
menu:
- title: "&cRedstone & Utility"
+ title: "&c红石与机关"
spawners:
- name: "&6Mob Spawners"
- icon-display-name: "&6Mob Spawners"
- icon-lore: "&7Purchase mob spawners to power your island grinders."
+ name: "&6生物刷怪笼"
+ icon-display-name: "&6生物刷怪笼"
+ icon-lore: "&7购买刷怪笼来给你的岛屿刷怪塔供能。"
menu:
- title: "&6Mob Spawners"
- spawns-line: "&7Spawns: &b{spawner_name}"
+ title: "&6生物刷怪笼"
+ spawns-line: "&7生成:&b{spawner_name}"
valuables:
- name: "&bValuables & Rares"
- icon-display-name: "&bValuables & Rares"
- icon-lore: "&7Rare and valuable items."
+ name: "&b贵重品与稀有物"
+ icon-display-name: "&b贵重品与稀有物"
+ icon-lore: "&7稀有且有价值的物品。"
menu:
- title: "&bValuables & Rares"
- item-note: "&7Guaranteed by the shopkeeper."
+ title: "&b贵重品与稀有物"
+ item-note: "&7由店主保证。"
+ experience-bottle-display-name: "&b经验瓶"
wood:
- name: "&aWood & Nature"
- icon-display-name: "&aWood & Nature"
- icon-lore: "&7Raw lumber and forestry goods."
+ name: "&a木材与自然"
+ icon-display-name: "&a木材与自然"
+ icon-lore: "&7原木和林业产品。"
menu:
- title: "&aWood & Nature"
+ title: "&a木材与自然"
menu:
main:
- title: "&aServer Shop"
+ title: "&a服务器商店"
category:
- back-display-name: "&eBack"
- back-lore: "&7Return to the main shop menu."
+ back-display-name: "&e返回"
+ back-lore: "&7返回商店主菜单。"
stock:
gui:
overview:
- title: "&6Stock Market Overview"
+ title: "&6股市总览"
filter:
- all: "All Stocks"
- category: "By Category"
- price: "By Price"
+ all: "全部股票"
+ category: "按分类"
+ price: "按价格"
localization:
- next-page: "&aNext Page"
- prev-page: "&cPrevious Page"
- filter-label: "&eFilter: {filter}"
- no-stocks: "&cNo tradable stocks found."
+ next-page: "&a下一页"
+ prev-page: "&c上一页"
+ filter-label: "&e筛选:{filter}"
+ no-stocks: "&c未找到可交易的股票。"
item-format: "&e{item} &7- &6{price}"
+ item-price-format: "&7当前价格:&6{price}"
+ item-blocked: "&c已封锁"
+ item-frozen: "&b已冻结"
+ no-items: "&c没有匹配当前筛选的物品。"
+ filters:
+ all: "全部物品"
+ blocks: "方块"
+ items: "物品"
+ pagination:
+ previous: "&a上一页"
+ next: "&a下一页"
see-all:
- display-name: "&bSee All Stocks"
+ display-name: "&b查看全部股票"
lore:
- - "&7View all available stocks in the market."
- - "&eClick to browse everything!"
+ line1: "&7查看市场中所有可用的股票。"
+ line2: "&e点击浏览全部!"
all-stocks:
- title: "&bAll Stocks"
- back-display-name: "&cBack to My Stocks"
- back-lore: "&7Return to your stock overview"
- filter-button-display: "&aFilter: {filter}"
+ title: "&b全部股票"
+ back-display-name: "&c返回我的股票"
+ back-lore: "&7返回你的股票总览"
+ filter-button-display: "&a筛选:{filter}"
filter-button:
lore:
- click: "&7Click to cycle filters"
- current: "&eCurrent: {filter}"
+ click: "&7点击切换筛选条件"
+ current: "&e当前:{filter}"
filters:
- all: "All Items"
- blocks: "Blocks"
- items: "Items"
+ all: "全部物品"
+ blocks: "方块"
+ items: "物品"
pagination:
- previous: "&aPrevious Page"
- next: "&aNext Page"
+ previous: "&a上一页"
+ next: "&a下一页"
localization:
- item-price-format: "&7Current Price: &6{price}"
- item-blocked: "&cBlocked"
- item-frozen: "&bFrozen"
- no-items: "&cNo items match the current filter."
+ item-price-format: "&7当前价格:&6{price}"
+ item-blocked: "&c已封锁"
+ item-frozen: "&b已冻结"
+ no-items: "&c没有匹配当前筛选的物品。"
- shop:
- rotations:
- daily_specials:
- farming_frenzy:
- display-name: "&aDaily Special: Farming Frenzy"
- lore: "&7Staple crops on sale for islands stocking up."
- menu-title: "&aDaily Special: Farming Frenzy"
- monster_madness:
- display-name: "&cDaily Special: Monster Madness"
- lore: "&7Overstocked mob drops priced to move."
- menu-title: "&cDaily Special: Monster Madness"
- harvest_bundle:
- display-name: "&cRotten Flesh Bundle"
- note: "&7Fresh from tonight's mob farm cleanup."
- seasonal_treats:
- display-name: "&cExplosive Care Package"
- note: "&7Perfect for crafting rockets or TNT."
- premium_pick:
- display-name: "&cBlaze Rod Stash"
- note: "&7Stockpile rods for brewing stands and fuel."
- miner_mania:
- display-name: "&bDaily Special: Miner Mania"
- lore: "&7Premium ore shipments delivered overnight."
- menu-title: "&bDaily Special: Miner Mania"
- harvest_bundle:
- display-name: "&bBulk Iron Ingot Shipment"
- note: "&7Perfect for hoppers, anvils, and tools."
- seasonal_treats:
- display-name: "&bRefined Gold Ingot Batch"
- note: "&7Ideal for beacons, apples, and rails."
- premium_pick:
- display-name: "&bShimmering Diamond Parcel"
- note: "&7Treat yourself or resell at a premium."
+ rotations:
+ daily_specials:
+ farming_frenzy:
+ display-name: "&a每日特惠:丰收狂潮"
+ lore: "&7为囤货的岛屿准备的常规作物特卖。"
+ menu-title: "&a每日特惠:丰收狂潮"
+ monster_madness:
+ display-name: "&c每日特惠:怪物狂欢"
+ lore: "&7积压的生物掉落物,降价促销。"
+ menu-title: "&c每日特惠:怪物狂欢"
+ harvest_bundle:
+ display-name: "&c腐肉礼包"
+ note: "&7今晚刷怪场清理的新鲜产物。"
+ seasonal_treats:
+ display-name: "&c爆炸补给包"
+ note: "&7适合制作烟花或 TNT。"
+ premium_pick:
+ display-name: "&c烈焰棒囤货"
+ note: "&7囤积烈焰棒用于酿造台和燃料。"
+ miner_mania:
+ display-name: "&b每日特惠:矿工狂热"
+ lore: "&7隔夜送达的优质矿石运输。"
+ menu-title: "&b每日特惠:矿工狂热"
+ harvest_bundle:
+ display-name: "&b大捆铁锭装运"
+ note: "&7非常适合漏斗、铁砧和工具。"
+ seasonal_treats:
+ display-name: "&b精炼金锭批次"
+ note: "&7适合信标、金苹果和铁轨。"
+ premium_pick:
+ display-name: "&b闪烁钻石包裹"
+ note: "&7犒劳自己或高价转售。"
hooks:
- player-lacking-permission-message: "&cYou do not have permission to run shop hook commands."
+ player-lacking-permission-message: "&c你没有权限执行商店相关的钩子命令。"
From 6e33868939ed1c00f081651d39b5589109903671 Mon Sep 17 00:00:00 2001
From: wangzhizhou <824219521@qq.com>
Date: Sun, 9 Aug 2026 11:36:04 +0800
Subject: [PATCH 3/3] fix(messages): align messages_nl.yml with en structure
messages_nl.yml had the same two structural bugs as messages_zh.yml
previously, plus missing live keys referenced by stock-gui.yml translate
macros (which would render empty in Dutch):
- shop.shop.rotations double-nesting -> shop.rotations
- see-all.lore defined as a list, but stock-gui.yml references
see-all.lore.line1/line2 -> convert to line1/line2 map
- add missing shop.stock.gui keys: localization.item-price-format /
item-blocked / item-frozen / no-items, filters.*, pagination.*
en/es were already correct; this brings nl to full live-key coverage.
---
src/main/resources/messages/messages_nl.yml | 80 ++++++++++++---------
1 file changed, 45 insertions(+), 35 deletions(-)
diff --git a/src/main/resources/messages/messages_nl.yml b/src/main/resources/messages/messages_nl.yml
index 4bb3b80..014c42b 100644
--- a/src/main/resources/messages/messages_nl.yml
+++ b/src/main/resources/messages/messages_nl.yml
@@ -425,11 +425,22 @@ shop:
filter-label: "&eFilter: {filter}"
no-stocks: "&cNo tradable stocks found."
item-format: "&e{item} &7- &6{price}"
+ item-price-format: "&7Current Price: &6{price}"
+ item-blocked: "&cBlocked"
+ item-frozen: "&bFrozen"
+ no-items: "&cNo items match the current filter."
+ filters:
+ all: "All Items"
+ blocks: "Blocks"
+ items: "Items"
+ pagination:
+ previous: "&aPrevious Page"
+ next: "&aNext Page"
see-all:
display-name: "&bSee All Stocks"
lore:
- - "&7View all available stocks in the market."
- - "&eClick to browse everything!"
+ line1: "&7View all available stocks in the market."
+ line2: "&eClick to browse everything!"
all-stocks:
title: "&bAll Stocks"
back-display-name: "&cBack to My Stocks"
@@ -452,38 +463,37 @@ shop:
item-frozen: "&bFrozen"
no-items: "&cNo items match the current filter."
- shop:
- rotations:
- daily_specials:
- farming_frenzy:
- display-name: "&aDaily Special: Farming Frenzy"
- lore: "&7Staple crops on sale for islands stocking up."
- menu-title: "&aDaily Special: Farming Frenzy"
- monster_madness:
- display-name: "&cDaily Special: Monster Madness"
- lore: "&7Overstocked mob drops priced to move."
- menu-title: "&cDaily Special: Monster Madness"
- harvest_bundle:
- display-name: "&cRotten Flesh Bundle"
- note: "&7Fresh from tonight's mob farm cleanup."
- seasonal_treats:
- display-name: "&cExplosive Care Package"
- note: "&7Perfect for crafting rockets or TNT."
- premium_pick:
- display-name: "&cBlaze Rod Stash"
- note: "&7Stockpile rods for brewing stands and fuel."
- miner_mania:
- display-name: "&bDaily Special: Miner Mania"
- lore: "&7Premium ore shipments delivered overnight."
- menu-title: "&bDaily Special: Miner Mania"
- harvest_bundle:
- display-name: "&bBulk Iron Ingot Shipment"
- note: "&7Perfect for hoppers, anvils, and tools."
- seasonal_treats:
- display-name: "&bRefined Gold Ingot Batch"
- note: "&7Ideal for beacons, apples, and rails."
- premium_pick:
- display-name: "&bShimmering Diamond Parcel"
- note: "&7Treat yourself or resell at a premium."
+ rotations:
+ daily_specials:
+ farming_frenzy:
+ display-name: "&aDaily Special: Farming Frenzy"
+ lore: "&7Staple crops on sale for islands stocking up."
+ menu-title: "&aDaily Special: Farming Frenzy"
+ monster_madness:
+ display-name: "&cDaily Special: Monster Madness"
+ lore: "&7Overstocked mob drops priced to move."
+ menu-title: "&cDaily Special: Monster Madness"
+ harvest_bundle:
+ display-name: "&cRotten Flesh Bundle"
+ note: "&7Fresh from tonight's mob farm cleanup."
+ seasonal_treats:
+ display-name: "&cExplosive Care Package"
+ note: "&7Perfect for crafting rockets or TNT."
+ premium_pick:
+ display-name: "&cBlaze Rod Stash"
+ note: "&7Stockpile rods for brewing stands and fuel."
+ miner_mania:
+ display-name: "&bDaily Special: Miner Mania"
+ lore: "&7Premium ore shipments delivered overnight."
+ menu-title: "&bDaily Special: Miner Mania"
+ harvest_bundle:
+ display-name: "&bBulk Iron Ingot Shipment"
+ note: "&7Perfect for hoppers, anvils, and tools."
+ seasonal_treats:
+ display-name: "&bRefined Gold Ingot Batch"
+ note: "&7Ideal for beacons, apples, and rails."
+ premium_pick:
+ display-name: "&bShimmering Diamond Parcel"
+ note: "&7Treat yourself or resell at a premium."
hooks:
player-lacking-permission-message: "&cJe hebt geen toestemming om winkelhook-commando's uit te voeren."