feat(C-01): i18n SystemMessageManager — 83 translatable keys

Phase 1: Core system message migration to Component.translatable().
- Replace getMessageTemplate() hardcoded strings with getTranslationKey() key derivation
- All send methods now use Component.translatable() with positional args
- Add 83 keys to en_us.json (msg.tiedup.system.*)
- Add sendTranslatable() convenience for external callers with string args
- Migrate 3 external getTemplate() callers (PlayerShockCollar, CellRegistryV2)
- Add resistance_suffix key for sendWithResistance()
This commit is contained in:
NotEvil
2026-04-15 13:24:05 +02:00
parent ac72f6aae7
commit 0662739fe0
4 changed files with 173 additions and 160 deletions

View File

@@ -670,13 +670,7 @@ public class CellRegistryV2 extends SavedData {
if (server == null || ownerId == null) return; if (server == null || ownerId == null) return;
ServerPlayer owner = server.getPlayerList().getPlayer(ownerId); ServerPlayer owner = server.getPlayerList().getPlayer(ownerId);
if (owner != null) { if (owner != null) {
String template = SystemMessageManager.getTemplate(category); SystemMessageManager.sendTranslatable(owner, category, prisonerName);
String formattedMessage = String.format(template, prisonerName);
SystemMessageManager.sendToPlayer(
owner,
category,
formattedMessage
);
} }
} }

View File

@@ -138,120 +138,17 @@ public class SystemMessageManager {
ERROR, // Generic error ERROR, // Generic error
} }
// MESSAGE TEMPLATES // TRANSLATION KEYS
/** /**
* Get the raw message template for a category. * Get the translation key for a category.
* Use this when you need to customize the message. * Keys follow the pattern: msg.tiedup.system.<category_lowercase>
* *
* @param category The message category * @param category The message category
* @return The template string (may contain %s placeholders) * @return The translation key (for use with Component.translatable)
*/ */
public static String getTemplate(MessageCategory category) { public static String getTranslationKey(MessageCategory category) {
return getMessageTemplate(category); return "msg.tiedup.system." + category.name().toLowerCase();
}
/**
* Get message template for a category.
* Use %s for entity name placeholder.
*/
private static String getMessageTemplate(MessageCategory category) {
return switch (category) {
// Restraint actions
case BEING_TIED -> "%s is tying you up!";
case TIED_UP -> "%s tied you up, you can't move!";
case BEING_GAGGED -> "%s is gagging you!";
case GAGGED -> "%s gagged you, you can't speak!";
case BEING_BLINDFOLDED -> "%s is blindfolding you!";
case BLINDFOLDED -> "%s blindfolded you, you can't see!";
case BEING_COLLARED -> "%s is putting a collar on you!";
case COLLARED -> "%s collared you!";
case EARPLUGS_ON -> "%s put earplugs on you!";
case MITTENS_ON -> "%s put mittens on you!";
case ENSLAVED -> "You have been enslaved by %s!";
// Restraint actions (kidnapper's perspective)
case TYING_TARGET -> "You are tying %s...";
case TIED_TARGET -> "You tied %s!";
case GAGGING_TARGET -> "You are gagging %s...";
case GAGGED_TARGET -> "You gagged %s!";
case BLINDFOLDING_TARGET -> "You are blindfolding %s...";
case BLINDFOLDED_TARGET -> "You blindfolded %s!";
case COLLARING_TARGET -> "You are collaring %s...";
case COLLARED_TARGET -> "You collared %s!";
// Release actions
case UNTIED -> "%s untied you!";
case UNGAGGED -> "%s removed your gag!";
case UNBLINDFOLDED -> "%s removed your blindfold!";
case UNCOLLARED -> "%s removed your collar!";
case FREED -> "You have been freed!";
// Struggle
case STRUGGLE_SUCCESS -> "You feel the ropes loosening...";
case STRUGGLE_FAIL -> "You struggle against the ropes, but they hold tight.";
case STRUGGLE_BROKE_FREE -> "You broke free!";
case STRUGGLE_SHOCKED -> "You were shocked for struggling!";
case STRUGGLE_COLLAR_SUCCESS -> "You manage to damage the lock!";
case STRUGGLE_COLLAR_FAIL -> "You try to reach the lock, but can't get a good grip.";
// Restrictions (Tied)
case CANT_MOVE -> "You can't move while tied!";
case CANT_ATTACK_TIED -> "You can't attack while tied!";
case CANT_USE_ITEM_TIED -> "You can't use items while tied!";
case CANT_OPEN_INVENTORY -> "You can't open inventory while tied!";
case CANT_INTERACT_TIED -> "You can't interact while tied!";
case CANT_SPEAK -> "You can't speak while gagged!";
case CANT_SEE -> "You can't see while blindfolded!";
case CANT_BREAK_TIED -> "You can't break blocks while tied!";
case CANT_PLACE_TIED -> "You can't place blocks while tied!";
case NO_ELYTRA -> "You can't fly with elytra while tied!";
// Restrictions (Mittens)
case CANT_ATTACK_MITTENS -> "You can't attack with mittens on!";
case CANT_USE_ITEM_MITTENS -> "You can't use items with mittens on!";
case CANT_INTERACT_MITTENS -> "You can't interact with mittens on!";
case CANT_BREAK_MITTENS -> "You can't break blocks with mittens on!";
case CANT_PLACE_MITTENS -> "You can't place blocks with mittens on!";
// Slave system
case SLAVE_COMMAND -> "Your master commands: %s";
case SLAVE_SHOCK -> "You've been shocked!";
case GPS_ZONE_VIOLATION -> "You've been shocked! Return back to your allowed area!";
case GPS_OWNER_ALERT -> "ALERT: %s is outside the safe zone!";
case SLAVE_JOB_ASSIGNED -> "Job assigned: bring %s";
case SLAVE_JOB_COMPLETE -> "Job complete! You are free.";
case SLAVE_JOB_FAILED -> "Job failed!";
case SLAVE_JOB_LAST_CHANCE -> "LAST CHANCE! Next failure means death!";
case SLAVE_JOB_KILLED -> "You were executed for failing your task.";
// Tighten
case BINDS_TIGHTENED -> "%s tightened your binds!";
// Tools & Items
case KEY_CLAIMED -> "Key claimed and linked to %s!";
case KEY_NOT_OWNER -> "You don't own this key!";
case KEY_WRONG_TARGET -> "This key doesn't fit this collar!";
case LOCATOR_CLAIMED -> "Locator claimed!";
case LOCATOR_NOT_OWNER -> "You don't own this locator!";
case LOCATOR_DETECTED -> "Target detected: %s";
case SHOCKER_CLAIMED -> "Shocker claimed!";
case SHOCKER_NOT_OWNER -> "You don't own this shocker!";
case SHOCKER_MODE_SET -> "Shocker mode: %s";
case SHOCKER_TRIGGERED -> "Shocked %s!";
case RAG_DRY -> "The rag is dry - soak it first";
case RAG_SOAKED -> "You soaked the rag with chloroform";
case RAG_EVAPORATED -> "The chloroform has evaporated";
// Bounty
case BOUNTY_CREATED -> "Bounty created on %s!";
case BOUNTY_CLAIMED -> "You claimed the bounty on %s!";
case BOUNTY_EXPIRED -> "Bounty on %s expired";
// Cell System
case PRISONER_ARRIVED -> "%s has been placed in your cell";
case PRISONER_ESCAPED -> "%s has escaped from your cell!";
case PRISONER_RELEASED -> "%s has been released from your cell";
case CELL_BREACH -> "Your cell wall has been breached!";
case CELL_ASSIGNED -> "You have been assigned to %s's cell";
case CELL_CREATED -> "Cell created successfully";
case CELL_DELETED -> "Cell deleted";
case CELL_RENAMED -> "Cell renamed to: %s";
// Generic
case INFO -> "%s";
case WARNING -> "%s";
case ERROR -> "%s";
};
} }
/** /**
@@ -373,11 +270,11 @@ public class SystemMessageManager {
/** /**
* Send a system message to a player's action bar. * Send a system message to a player's action bar.
* Uses category template with entity name. * Uses translatable category with entity name as argument.
* *
* @param player The player to send to * @param player The player to send to
* @param category The message category * @param category The message category
* @param actor The entity performing the action (for %s replacement) * @param actor The entity performing the action (for %1$s replacement)
*/ */
public static void sendToPlayer( public static void sendToPlayer(
Player player, Player player,
@@ -387,14 +284,23 @@ public class SystemMessageManager {
if (player == null) return; if (player == null) return;
String actorName = actor != null ? getEntityName(actor) : "Someone"; String actorName = actor != null ? getEntityName(actor) : "Someone";
String message = String.format(getMessageTemplate(category), actorName); MutableComponent component = Component.translatable(
getTranslationKey(category), actorName
).withStyle(style -> style.withColor(getCategoryColor(category)));
sendToPlayer(player, message, getCategoryColor(category)); player.displayClientMessage(component, true);
TiedUpMod.LOGGER.debug(
"[SystemMessage] -> {}: {} ({})",
player.getName().getString(),
getTranslationKey(category),
actorName
);
} }
/** /**
* Send a system message to a player's action bar. * Send a system message to a player's action bar.
* Uses category template without entity (for messages that don't need one). * Uses translatable category without arguments.
* *
* @param player The player to send to * @param player The player to send to
* @param category The message category * @param category The message category
@@ -402,12 +308,22 @@ public class SystemMessageManager {
public static void sendToPlayer(Player player, MessageCategory category) { public static void sendToPlayer(Player player, MessageCategory category) {
if (player == null) return; if (player == null) return;
String message = getMessageTemplate(category); MutableComponent component = Component.translatable(
sendToPlayer(player, message, getCategoryColor(category)); getTranslationKey(category)
).withStyle(style -> style.withColor(getCategoryColor(category)));
player.displayClientMessage(component, true);
TiedUpMod.LOGGER.debug(
"[SystemMessage] -> {}: {}",
player.getName().getString(),
getTranslationKey(category)
);
} }
/** /**
* Send a custom system message to a player's action bar. * Send a custom system message to a player's action bar.
* Uses literal text (for dynamic/non-translatable messages).
* *
* @param player The player to send to * @param player The player to send to
* @param message The message to send * @param message The message to send
@@ -420,12 +336,10 @@ public class SystemMessageManager {
) { ) {
if (player == null || message == null) return; if (player == null || message == null) return;
// Works on both client and server
MutableComponent component = Component.literal(message).withStyle( MutableComponent component = Component.literal(message).withStyle(
style -> style.withColor(color) style -> style.withColor(color)
); );
// true = action bar (above hotbar), false = chat
player.displayClientMessage(component, true); player.displayClientMessage(component, true);
TiedUpMod.LOGGER.debug( TiedUpMod.LOGGER.debug(
@@ -437,6 +351,7 @@ public class SystemMessageManager {
/** /**
* Send a custom system message to a player's CHAT. * Send a custom system message to a player's CHAT.
* Uses literal text (for dynamic/non-translatable messages).
* *
* @param player The player to send to * @param player The player to send to
* @param message The message to send * @param message The message to send
@@ -453,7 +368,6 @@ public class SystemMessageManager {
style -> style.withColor(color) style -> style.withColor(color)
); );
// false = chat
player.displayClientMessage(component, false); player.displayClientMessage(component, false);
TiedUpMod.LOGGER.debug( TiedUpMod.LOGGER.debug(
@@ -464,19 +378,21 @@ public class SystemMessageManager {
} }
/** /**
* Send a system message to a player's CHAT using a category. * Send a system message to a player's CHAT using a translatable category.
*/ */
public static void sendChatToPlayer( public static void sendChatToPlayer(
Player player, Player player,
MessageCategory category MessageCategory category
) { ) {
if (player == null) return; if (player == null) return;
String message = getMessageTemplate(category); MutableComponent component = Component.translatable(
sendChatToPlayer(player, message, getCategoryColor(category)); getTranslationKey(category)
).withStyle(style -> style.withColor(getCategoryColor(category)));
player.displayClientMessage(component, false);
} }
/** /**
* Send a system message to a player's CHAT using a category and actor. * Send a system message to a player's CHAT using a translatable category and actor.
*/ */
public static void sendChatToPlayer( public static void sendChatToPlayer(
Player player, Player player,
@@ -485,8 +401,10 @@ public class SystemMessageManager {
) { ) {
if (player == null) return; if (player == null) return;
String actorName = actor != null ? getEntityName(actor) : "Someone"; String actorName = actor != null ? getEntityName(actor) : "Someone";
String message = String.format(getMessageTemplate(category), actorName); MutableComponent component = Component.translatable(
sendChatToPlayer(player, message, getCategoryColor(category)); getTranslationKey(category), actorName
).withStyle(style -> style.withColor(getCategoryColor(category)));
player.displayClientMessage(component, false);
} }
/** /**
@@ -494,7 +412,7 @@ public class SystemMessageManager {
* *
* @param player The player to send to * @param player The player to send to
* @param category The category (for color) * @param category The category (for color)
* @param customMessage The custom message text * @param customMessage The custom message text (literal, not translatable)
*/ */
public static void sendToPlayer( public static void sendToPlayer(
Player player, Player player,
@@ -505,7 +423,27 @@ public class SystemMessageManager {
} }
/** /**
* Send a message with resistance info appended. * Send a translatable message with string arguments.
* Uses the category's translation key and color.
*
* @param player The player to send to
* @param category The message category
* @param args Arguments for the translation (replaces %1$s, %2$s, etc.)
*/
public static void sendTranslatable(
Player player,
MessageCategory category,
Object... args
) {
if (player == null) return;
MutableComponent component = Component.translatable(
getTranslationKey(category), args
).withStyle(style -> style.withColor(getCategoryColor(category)));
player.displayClientMessage(component, true);
}
/**
* Send a translatable message with resistance info appended.
* *
* @param player The player to send to * @param player The player to send to
* @param category The message category * @param category The message category
@@ -518,9 +456,13 @@ public class SystemMessageManager {
) { ) {
if (player == null) return; if (player == null) return;
String message = MutableComponent component = Component.translatable(
getMessageTemplate(category) + " (Resistance: " + resistance + ")"; getTranslationKey(category)
sendToPlayer(player, message, getCategoryColor(category)); ).append(
Component.translatable("msg.tiedup.system.resistance_suffix", resistance)
).withStyle(style -> style.withColor(getCategoryColor(category)));
player.displayClientMessage(component, true);
} }
// SEND METHODS - TO NEARBY PLAYERS // SEND METHODS - TO NEARBY PLAYERS
@@ -695,15 +637,10 @@ public class SystemMessageManager {
*/ */
public static void sendJobAssigned(Player player, String itemName) { public static void sendJobAssigned(Player player, String itemName) {
if (player == null) return; if (player == null) return;
String message = String.format( MutableComponent component = Component.translatable(
getMessageTemplate(MessageCategory.SLAVE_JOB_ASSIGNED), getTranslationKey(MessageCategory.SLAVE_JOB_ASSIGNED), itemName
itemName ).withStyle(style -> style.withColor(getCategoryColor(MessageCategory.SLAVE_JOB_ASSIGNED)));
); player.displayClientMessage(component, true);
sendToPlayer(
player,
message,
getCategoryColor(MessageCategory.SLAVE_JOB_ASSIGNED)
);
} }
// UTILITY // UTILITY

View File

@@ -15,6 +15,8 @@ import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@@ -99,12 +101,11 @@ public class PlayerShockCollar {
// HUD Message via SystemMessageManager // HUD Message via SystemMessageManager
if (messageAddon != null) { if (messageAddon != null) {
// Custom message with addon (e.g., GPS violation) // Custom message with addon (e.g., GPS violation)
SystemMessageManager.sendToPlayer( MutableComponent msg = Component.translatable(
player, SystemMessageManager.getTranslationKey(MessageCategory.SLAVE_SHOCK)
MessageCategory.SLAVE_SHOCK, ).append(Component.literal(messageAddon));
SystemMessageManager.getTemplate(MessageCategory.SLAVE_SHOCK) + msg.withStyle(style -> style.withColor(ChatFormatting.RED));
messageAddon player.displayClientMessage(msg, true);
);
} else { } else {
SystemMessageManager.sendToPlayer( SystemMessageManager.sendToPlayer(
player, player,
@@ -239,11 +240,8 @@ public class PlayerShockCollar {
if (!CollarHelper.shouldWarnMasters(stack)) return; if (!CollarHelper.shouldWarnMasters(stack)) return;
// Format: "ALERT: <player name> is outside the safe zone!" // Translatable: "ALERT: <player name> is outside the safe zone!"
String alertMessage = String.format( String playerName = player.getName().getString();
SystemMessageManager.getTemplate(MessageCategory.GPS_OWNER_ALERT),
player.getName().getString()
);
for (UUID ownerId : CollarHelper.getOwners(stack)) { for (UUID ownerId : CollarHelper.getOwners(stack)) {
ServerPlayer owner = player ServerPlayer owner = player
@@ -253,8 +251,8 @@ public class PlayerShockCollar {
if (owner != null) { if (owner != null) {
SystemMessageManager.sendChatToPlayer( SystemMessageManager.sendChatToPlayer(
owner, owner,
alertMessage, MessageCategory.GPS_OWNER_ALERT,
ChatFormatting.RED player
); );
} }
} }

View File

@@ -687,5 +687,89 @@
"gui.tiedup.status.key_info": "Key: %s", "gui.tiedup.status.key_info": "Key: %s",
"gui.tiedup.status.no_key": "No key", "gui.tiedup.status.no_key": "No key",
"gui.tiedup.status.target_info": "Target: %s", "gui.tiedup.status.target_info": "Target: %s",
"gui.tiedup.status_bar": "Status bar" "gui.tiedup.status_bar": "Status bar",
"msg.tiedup.system.being_tied": "%1$s is tying you up!",
"msg.tiedup.system.tied_up": "%1$s tied you up, you can't move!",
"msg.tiedup.system.being_gagged": "%1$s is gagging you!",
"msg.tiedup.system.gagged": "%1$s gagged you, you can't speak!",
"msg.tiedup.system.being_blindfolded": "%1$s is blindfolding you!",
"msg.tiedup.system.blindfolded": "%1$s blindfolded you, you can't see!",
"msg.tiedup.system.being_collared": "%1$s is putting a collar on you!",
"msg.tiedup.system.collared": "%1$s collared you!",
"msg.tiedup.system.earplugs_on": "%1$s put earplugs on you!",
"msg.tiedup.system.mittens_on": "%1$s put mittens on you!",
"msg.tiedup.system.enslaved": "You have been enslaved by %1$s!",
"msg.tiedup.system.tying_target": "You are tying %1$s...",
"msg.tiedup.system.tied_target": "You tied %1$s!",
"msg.tiedup.system.gagging_target": "You are gagging %1$s...",
"msg.tiedup.system.gagged_target": "You gagged %1$s!",
"msg.tiedup.system.blindfolding_target": "You are blindfolding %1$s...",
"msg.tiedup.system.blindfolded_target": "You blindfolded %1$s!",
"msg.tiedup.system.collaring_target": "You are collaring %1$s...",
"msg.tiedup.system.collared_target": "You collared %1$s!",
"msg.tiedup.system.untied": "%1$s untied you!",
"msg.tiedup.system.ungagged": "%1$s removed your gag!",
"msg.tiedup.system.unblindfolded": "%1$s removed your blindfold!",
"msg.tiedup.system.uncollared": "%1$s removed your collar!",
"msg.tiedup.system.freed": "You have been freed!",
"msg.tiedup.system.struggle_success": "You feel the ropes loosening...",
"msg.tiedup.system.struggle_fail": "You struggle against the ropes, but they hold tight.",
"msg.tiedup.system.struggle_broke_free": "You broke free!",
"msg.tiedup.system.struggle_shocked": "You were shocked for struggling!",
"msg.tiedup.system.struggle_collar_success": "You manage to damage the lock!",
"msg.tiedup.system.struggle_collar_fail": "You try to reach the lock, but can't get a good grip.",
"msg.tiedup.system.cant_move": "You can't move while tied!",
"msg.tiedup.system.cant_attack_tied": "You can't attack while tied!",
"msg.tiedup.system.cant_use_item_tied": "You can't use items while tied!",
"msg.tiedup.system.cant_open_inventory": "You can't open inventory while tied!",
"msg.tiedup.system.cant_interact_tied": "You can't interact while tied!",
"msg.tiedup.system.cant_speak": "You can't speak while gagged!",
"msg.tiedup.system.cant_see": "You can't see while blindfolded!",
"msg.tiedup.system.cant_break_tied": "You can't break blocks while tied!",
"msg.tiedup.system.cant_place_tied": "You can't place blocks while tied!",
"msg.tiedup.system.no_elytra": "You can't fly with elytra while tied!",
"msg.tiedup.system.cant_attack_mittens": "You can't attack with mittens on!",
"msg.tiedup.system.cant_use_item_mittens": "You can't use items with mittens on!",
"msg.tiedup.system.cant_interact_mittens": "You can't interact with mittens on!",
"msg.tiedup.system.cant_break_mittens": "You can't break blocks with mittens on!",
"msg.tiedup.system.cant_place_mittens": "You can't place blocks with mittens on!",
"msg.tiedup.system.slave_command": "Your master commands: %1$s",
"msg.tiedup.system.slave_shock": "You've been shocked!",
"msg.tiedup.system.gps_zone_violation": "You've been shocked! Return back to your allowed area!",
"msg.tiedup.system.gps_owner_alert": "ALERT: %1$s is outside the safe zone!",
"msg.tiedup.system.slave_job_assigned": "Job assigned: bring %1$s",
"msg.tiedup.system.slave_job_complete": "Job complete! You are free.",
"msg.tiedup.system.slave_job_failed": "Job failed!",
"msg.tiedup.system.slave_job_last_chance": "LAST CHANCE! Next failure means death!",
"msg.tiedup.system.slave_job_killed": "You were executed for failing your task.",
"msg.tiedup.system.binds_tightened": "%1$s tightened your binds!",
"msg.tiedup.system.key_claimed": "Key claimed and linked to %1$s!",
"msg.tiedup.system.key_not_owner": "You don't own this key!",
"msg.tiedup.system.key_wrong_target": "This key doesn't fit this collar!",
"msg.tiedup.system.locator_claimed": "Locator claimed!",
"msg.tiedup.system.locator_not_owner": "You don't own this locator!",
"msg.tiedup.system.locator_detected": "Target detected: %1$s",
"msg.tiedup.system.shocker_claimed": "Shocker claimed!",
"msg.tiedup.system.shocker_not_owner": "You don't own this shocker!",
"msg.tiedup.system.shocker_mode_set": "Shocker mode: %1$s",
"msg.tiedup.system.shocker_triggered": "Shocked %1$s!",
"msg.tiedup.system.rag_dry": "The rag is dry - soak it first",
"msg.tiedup.system.rag_soaked": "You soaked the rag with chloroform",
"msg.tiedup.system.rag_evaporated": "The chloroform has evaporated",
"msg.tiedup.system.bounty_created": "Bounty created on %1$s!",
"msg.tiedup.system.bounty_claimed": "You claimed the bounty on %1$s!",
"msg.tiedup.system.bounty_expired": "Bounty on %1$s expired",
"msg.tiedup.system.prisoner_arrived": "%1$s has been placed in your cell",
"msg.tiedup.system.prisoner_escaped": "%1$s has escaped from your cell!",
"msg.tiedup.system.prisoner_released": "%1$s has been released from your cell",
"msg.tiedup.system.cell_breach": "Your cell wall has been breached!",
"msg.tiedup.system.cell_assigned": "You have been assigned to %1$s's cell",
"msg.tiedup.system.cell_created": "Cell created successfully",
"msg.tiedup.system.cell_deleted": "Cell deleted",
"msg.tiedup.system.cell_renamed": "Cell renamed to: %1$s",
"msg.tiedup.system.info": "%1$s",
"msg.tiedup.system.warning": "%1$s",
"msg.tiedup.system.error": "%1$s",
"msg.tiedup.system.resistance_suffix": " (Resistance: %1$s)"
} }