diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java
index f426d41af..8bdb3c207 100644
--- a/src/main/java/emu/grasscutter/Grasscutter.java
+++ b/src/main/java/emu/grasscutter/Grasscutter.java
@@ -206,6 +206,14 @@ public final class Grasscutter {
 		return language;
 	}
 
+	public static void setLanguage(Language language) {
+        Grasscutter.language = language;
+	}
+
+	public static Language getLanguage(String langCode) {
+        return Language.getLanguage(langCode);
+	}
+
 	public static Logger getLogger() {
 		return log;
 	}
diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java
index a16cc6480..2669ff8b9 100644
--- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java
@@ -17,12 +17,12 @@ public final class AccountCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (sender != null) {
-            CommandHandler.sendMessage(sender, translate("commands.generic.console_execute_error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.console_execute_error"));
             return;
         }
 
         if (args.size() < 2) {
-            CommandHandler.sendMessage(null, translate("commands.account.command_usage"));
+            CommandHandler.sendMessage(null, translate(sender, "commands.account.command_usage"));
             return;
         }
 
@@ -31,7 +31,7 @@ public final class AccountCommand implements CommandHandler {
 
         switch (action) {
             default:
-                CommandHandler.sendMessage(null, translate("commands.account.command_usage"));
+                CommandHandler.sendMessage(null, translate(sender, "commands.account.command_usage"));
                 return;
             case "create":
                 int uid = 0;
@@ -39,20 +39,20 @@ public final class AccountCommand implements CommandHandler {
                     try {
                         uid = Integer.parseInt(args.get(2));
                     } catch (NumberFormatException ignored) {
-                        CommandHandler.sendMessage(null, translate("commands.account.invalid"));
+                        CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid"));
                         return;
                     }
                 }
 
                 emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithId(username, uid);
                 if (account == null) {
-                    CommandHandler.sendMessage(null, translate("commands.account.exists"));
+                    CommandHandler.sendMessage(null, translate(sender, "commands.account.exists"));
                     return;
                 } else {
                     account.addPermission("*");
                     account.save(); // Save account to database.
 
-                    CommandHandler.sendMessage(null, translate("commands.account.create", Integer.toString(account.getPlayerUid())));
+                    CommandHandler.sendMessage(null, translate(sender, "commands.account.create", Integer.toString(account.getPlayerUid())));
                 }
                 return;
             case "delete":
@@ -60,7 +60,7 @@ public final class AccountCommand implements CommandHandler {
                 Account toDelete = DatabaseHelper.getAccountByName(username);
 
                 if (toDelete == null) {
-                    CommandHandler.sendMessage(null, translate("commands.account.no_account"));
+                    CommandHandler.sendMessage(null, translate(sender, "commands.account.no_account"));
                     return;
                 }
 
@@ -73,7 +73,7 @@ public final class AccountCommand implements CommandHandler {
 
                 // Finally, we do the actual deletion.
                 DatabaseHelper.deleteAccount(toDelete);
-                CommandHandler.sendMessage(null, translate("commands.account.delete"));
+                CommandHandler.sendMessage(null, translate(sender, "commands.account.delete"));
         }
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/BroadcastCommand.java b/src/main/java/emu/grasscutter/command/commands/BroadcastCommand.java
index 95f0c7c05..86080c822 100644
--- a/src/main/java/emu/grasscutter/command/commands/BroadcastCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/BroadcastCommand.java
@@ -15,7 +15,7 @@ public final class BroadcastCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (args.size() < 1) {
-            CommandHandler.sendMessage(sender, translate("commands.broadcast.command_usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.command_usage"));
             return;
         }
 
@@ -25,6 +25,6 @@ public final class BroadcastCommand implements CommandHandler {
             CommandHandler.sendMessage(p, message);
         }
 
-        CommandHandler.sendMessage(sender, translate("commands.broadcast.message_sent"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.message_sent"));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/ChangeSceneCommand.java b/src/main/java/emu/grasscutter/command/commands/ChangeSceneCommand.java
index 59706dd96..c653acee1 100644
--- a/src/main/java/emu/grasscutter/command/commands/ChangeSceneCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ChangeSceneCommand.java
@@ -14,31 +14,31 @@ public final class ChangeSceneCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (args.size() != 1) {
-            CommandHandler.sendMessage(sender, translate("commands.changescene.usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.usage"));
             return;
         }
 
         try {
             int sceneId = Integer.parseInt(args.get(0));
             if (sceneId == targetPlayer.getSceneId()) {
-            	CommandHandler.sendMessage(sender, translate("commands.changescene.already_in_scene"));
+            	CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.already_in_scene"));
             	return;
             }
             
             boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, targetPlayer.getPos());
             if (!result) {
-                CommandHandler.sendMessage(sender, translate("commands.changescene.exists_error"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.exists_error"));
                 return;
             }
 
-            CommandHandler.sendMessage(sender, translate("commands.changescene.success", Integer.toString(sceneId)));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.success", Integer.toString(sceneId)));
         } catch (Exception e) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
         }
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/ClearCommand.java b/src/main/java/emu/grasscutter/command/commands/ClearCommand.java
index ab0ff0eb1..7b50ee034 100644
--- a/src/main/java/emu/grasscutter/command/commands/ClearCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ClearCommand.java
@@ -21,11 +21,11 @@ public final class ClearCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         if (args.size() < 1) {
-            CommandHandler.sendMessage(sender, translate("commands.clear.command_usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.clear.command_usage"));
             return;
         }
         Inventory playerInventory = targetPlayer.getInventory();
@@ -37,7 +37,7 @@ public final class ClearCommand implements CommandHandler {
                         .filter(item -> item.getItemType() == ItemType.ITEM_WEAPON)
                         .filter(item -> !item.isLocked() && !item.isEquipped())
                         .toList();
-                CommandHandler.sendMessage(sender, translate("commands.clear.weapons", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.weapons", targetPlayer.getNickname()));
             }
             case "art" -> {
             	toDelete = playerInventory.getItems().values().stream()
@@ -45,7 +45,7 @@ public final class ClearCommand implements CommandHandler {
                         .filter(item -> item.getLevel() == 1 && item.getExp() == 0)
                         .filter(item -> !item.isLocked() && !item.isEquipped())
                         .toList();
-                CommandHandler.sendMessage(sender, translate("commands.clear.artifacts", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.artifacts", targetPlayer.getNickname()));
             }
             case "mat" -> {
             	toDelete = playerInventory.getItems().values().stream()
@@ -53,7 +53,7 @@ public final class ClearCommand implements CommandHandler {
                         .filter(item -> item.getLevel() == 1 && item.getExp() == 0)
                         .filter(item -> !item.isLocked() && !item.isEquipped())
                         .toList();
-                CommandHandler.sendMessage(sender, translate("commands.clear.materials", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.materials", targetPlayer.getNickname()));
             }
             case "all" -> {
             	toDelete = playerInventory.getItems().values().stream()
@@ -61,7 +61,7 @@ public final class ClearCommand implements CommandHandler {
                         .filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0)
                         .filter(item1 -> !item1.isLocked() && !item1.isEquipped())
                         .toList();
-                CommandHandler.sendMessage(sender, translate("commands.clear.artifacts", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.artifacts", targetPlayer.getNickname()));
                 playerInventory.removeItems(toDelete);
                 
                 toDelete = playerInventory.getItems().values().stream()
@@ -69,7 +69,7 @@ public final class ClearCommand implements CommandHandler {
                         .filter(item2 -> !item2.isLocked() && !item2.isEquipped())
                         .toList();
                 playerInventory.removeItems(toDelete);
-                CommandHandler.sendMessage(sender, translate("commands.clear.materials", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.materials", targetPlayer.getNickname()));
                 
                 toDelete = playerInventory.getItems().values().stream()
                         .filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON)
@@ -77,28 +77,28 @@ public final class ClearCommand implements CommandHandler {
                         .filter(item3 -> !item3.isLocked() && !item3.isEquipped())
                         .toList();
                 playerInventory.removeItems(toDelete);
-                CommandHandler.sendMessage(sender, translate("commands.clear.weapons", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.weapons", targetPlayer.getNickname()));
                 
                 toDelete = playerInventory.getItems().values().stream()
                         .filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE)
                         .filter(item4 -> !item4.isLocked() && !item4.isEquipped())
                         .toList();
                 playerInventory.removeItems(toDelete);
-                CommandHandler.sendMessage(sender, translate("commands.clear.furniture", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.furniture", targetPlayer.getNickname()));
                 
                 toDelete = playerInventory.getItems().values().stream()
                         .filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY)
                         .filter(item5 -> !item5.isLocked() && !item5.isEquipped())
                         .toList();
                 playerInventory.removeItems(toDelete);
-                CommandHandler.sendMessage(sender, translate("commands.clear.displays", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.displays", targetPlayer.getNickname()));
                 
                 toDelete = playerInventory.getItems().values().stream()
                         .filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL)
                         .filter(item6 -> !item6.isLocked() && !item6.isEquipped())
                         .toList();
-                CommandHandler.sendMessage(sender, translate("commands.clear.virtuals", targetPlayer.getNickname()));
-                CommandHandler.sendMessage(sender, translate("commands.clear.everything", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.virtuals", targetPlayer.getNickname()));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.clear.everything", targetPlayer.getNickname()));
             }
         }
         
diff --git a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java
index a86472978..509c554b7 100644
--- a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java
@@ -15,14 +15,14 @@ public final class CoopCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
 		if (targetPlayer == null) {
-			CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
 			return;
 		}
 
         Player host = sender;
         switch (args.size()) {
             case 0:  // Summon target to self
-                CommandHandler.sendMessage(sender, translate("commands.coop.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.coop.usage"));
                 if (sender == null) // Console doesn't have a self to summon to
                     return;
                 break;
@@ -31,16 +31,16 @@ public final class CoopCommand implements CommandHandler {
                     int hostId = Integer.parseInt(args.get(0));
                     host = Grasscutter.getGameServer().getPlayerByUid(hostId);
                     if (host == null) {
-                        CommandHandler.sendMessage(sender, translate("commands.execution.player_offline_error"));
+                        CommandHandler.sendMessage(sender, translate(sender, "commands.execution.player_offline_error"));
                         return;
                     }
                     break;
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.execution.uid_error"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.execution.uid_error"));
                     return;
                 }
             default:
-                CommandHandler.sendMessage(sender, translate("commands.coop.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.coop.usage"));
                 return;
         }
         
@@ -50,6 +50,6 @@ public final class CoopCommand implements CommandHandler {
         }
         host.getServer().getMultiplayerManager().applyEnterMp(targetPlayer, host.getUid());
         targetPlayer.getServer().getMultiplayerManager().applyEnterMpReply(host, targetPlayer.getUid(), true);
-        CommandHandler.sendMessage(sender, translate("commands.coop.success", targetPlayer.getNickname(), host.getNickname()));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.coop.success", targetPlayer.getNickname(), host.getNickname()));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/DropCommand.java b/src/main/java/emu/grasscutter/command/commands/DropCommand.java
index e2579a7be..eecec06e9 100644
--- a/src/main/java/emu/grasscutter/command/commands/DropCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/DropCommand.java
@@ -19,7 +19,7 @@ public final class DropCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(null, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(null, translate(sender, "commands.execution.need_target"));
             return;
         }
         
@@ -31,25 +31,25 @@ public final class DropCommand implements CommandHandler {
                 try {
                     amount = Integer.parseInt(args.get(1));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
                     return;
                 }  // Slightly cheeky here: no break, so it falls through to initialize the first argument too
             case 1:
                 try {
                     item = Integer.parseInt(args.get(0));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
                     return;
                 }
                 break;
             default:
-                CommandHandler.sendMessage(sender, translate("commands.drop.command_usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.drop.command_usage"));
                 return;
         }
 
         ItemData itemData = GameData.getItemDataMap().get(item);
         if (itemData == null) {
-            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
             return;
         }
         if (itemData.isEquip()) {
@@ -63,6 +63,6 @@ public final class DropCommand implements CommandHandler {
             EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, targetPlayer.getPos().clone().addY(3f), amount);
             targetPlayer.getScene().addEntity(entity);
         }
-        CommandHandler.sendMessage(sender, translate("commands.drop.success", Integer.toString(amount), Integer.toString(item)));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.drop.success", Integer.toString(amount), Integer.toString(item)));
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java b/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java
index c4e37a93e..b44952393 100644
--- a/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java
@@ -14,30 +14,30 @@ public final class EnterDungeonCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(null, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(null, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (args.size() < 1) {
-            CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage"));
             return;
         }
 
         try {
             int dungeonId = Integer.parseInt(args.get(0));
             if (dungeonId == targetPlayer.getSceneId()) {
-            	CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.in_dungeon_error"));
+            	CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.in_dungeon_error"));
             	return;
             }
             
             boolean result = targetPlayer.getServer().getDungeonManager().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId);
-            CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.changed", dungeonId));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.changed", dungeonId));
 
             if (!result) {
-                CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.not_found_error"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.not_found_error"));
             }
         } catch (Exception e) {
-            CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage"));
         }
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java
index 6b9104626..3a0dee111 100644
--- a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java
@@ -21,7 +21,7 @@ public final class GiveAllCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         int amount = 99999;
@@ -33,21 +33,21 @@ public final class GiveAllCommand implements CommandHandler {
                 try {
                     amount = Integer.parseInt(args.get(0));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
                     return;
                 }
                 break;
             default: // invalid
-                CommandHandler.sendMessage(sender, translate("commands.giveAll.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.giveAll.usage"));
                 return;
         }
 
         this.giveAllItems(targetPlayer, amount);
-        CommandHandler.sendMessage(sender, translate("commands.giveAll.success", targetPlayer.getNickname()));
+        CommandHandler.sendMessage(sender, translate(targetPlayer, "commands.giveAll.success", targetPlayer.getNickname()));
     }
 
     public void giveAllItems(Player player, int amount) {
-        CommandHandler.sendMessage(player, translate("commands.giveAll.started"));
+        CommandHandler.sendMessage(player, translate(player, "commands.giveAll.started"));
 
         for (AvatarData avatarData: GameData.getAvatarDataMap().values()) {
             //Exclude test avatar
diff --git a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java
index 25503dbd3..6f3a02a5e 100644
--- a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java
@@ -115,11 +115,11 @@ public final class GiveArtifactCommand implements CommandHandler {
 	public void execute(Player sender, Player targetPlayer, List<String> args) {
 		// Sanity checks
 		if (targetPlayer == null) {
-			CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
 			return;
 		}
 		if (args.size() < 2) {
-			CommandHandler.sendMessage(sender, translate("commands.giveArtifact.usage"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.usage"));
 			return;
 		}
 
@@ -128,13 +128,13 @@ public final class GiveArtifactCommand implements CommandHandler {
 		try {
 			itemId = Integer.parseInt(args.remove(0));
 		} catch (NumberFormatException ignored) {
-			CommandHandler.sendMessage(sender, translate("commands.giveArtifact.id_error"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
 			return;
 		}
 
 		ItemData itemData = GameData.getItemDataMap().get(itemId);
 		if (itemData.getItemType() != ItemType.ITEM_RELIQUARY) {
-			CommandHandler.sendMessage(sender, translate("commands.giveArtifact.id_error"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
 			return;
 		}
 
@@ -155,7 +155,7 @@ public final class GiveArtifactCommand implements CommandHandler {
 		}
 
 		if (mainPropId == -1) {
-			CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
 			return;
 		}
 
@@ -194,7 +194,7 @@ public final class GiveArtifactCommand implements CommandHandler {
 				appendPropIdList.addAll(Collections.nCopies(n, appendPropId));
 			});
 		} catch (Exception ignored) {
-			CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
+			CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
 			return;
 		}
 
@@ -206,7 +206,7 @@ public final class GiveArtifactCommand implements CommandHandler {
 		item.getAppendPropIdList().addAll(appendPropIdList);
 		targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop);
 
-		CommandHandler.sendMessage(sender, translate("commands.giveArtifact.success", Integer.toString(itemId), Integer.toString(targetPlayer.getUid())));
+		CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.success", Integer.toString(itemId), Integer.toString(targetPlayer.getUid())));
 	}
 }
 
diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCharCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCharCommand.java
index af789f394..2917c64c4 100644
--- a/src/main/java/emu/grasscutter/command/commands/GiveCharCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GiveCharCommand.java
@@ -18,7 +18,7 @@ public final class GiveCharCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -31,7 +31,7 @@ public final class GiveCharCommand implements CommandHandler {
                     level = Integer.parseInt(args.get(1));
                 } catch (NumberFormatException ignored) {
                     // TODO: Parse from avatar name using GM Handbook.
-                    CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarLevel"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.execution.invalid.avatarLevel"));
                     return;
                 }  // Cheeky fall-through to parse first argument too
             case 1:
@@ -39,24 +39,24 @@ public final class GiveCharCommand implements CommandHandler {
                     avatarId = Integer.parseInt(args.get(0));
                 } catch (NumberFormatException ignored) {
                     // TODO: Parse from avatar name using GM Handbook.
-                    CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarId"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.execution.invalid.avatarId"));
                     return;
                 }
                 break;
             default:
-                CommandHandler.sendMessage(sender, translate("commands.giveChar.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.usage"));
                 return;
         }
 
         AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
         if (avatarData == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarId"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.invalid.avatarId"));
             return;
         }
 
         // Check level.
         if (level > 90) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarLevel"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.invalid.avatarLevel"));
             return;
         }
 
@@ -76,6 +76,6 @@ public final class GiveCharCommand implements CommandHandler {
         avatar.recalcStats();
 
         targetPlayer.addAvatar(avatar);
-        CommandHandler.sendMessage(sender, translate("commands.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java
index a60991bad..9ce353419 100644
--- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java
@@ -34,7 +34,7 @@ public final class GiveCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         int item;
@@ -68,21 +68,21 @@ public final class GiveCommand implements CommandHandler {
                 try {
                     refinement = Integer.parseInt(args.get(3));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
                     return;
                 }  // Fallthrough
             case 3: // <itemId|itemName> [amount] [level]
                 try {
                     lvl = Integer.parseInt(args.get(2));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
                     return;
                 }  // Fallthrough
             case 2: // <itemId|itemName> [amount]
                 try {
                     amount = Integer.parseInt(args.get(1));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
                     return;
                 }  // Fallthrough
             case 1: // <itemId|itemName>
@@ -90,28 +90,28 @@ public final class GiveCommand implements CommandHandler {
                     item = Integer.parseInt(args.get(0));
                 } catch (NumberFormatException ignored) {
                     // TODO: Parse from item name using GM Handbook.
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
                     return;
                 }
                 break;
             default: // *No args*
-                CommandHandler.sendMessage(sender, translate("commands.give.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.give.usage"));
                 return;
         }
 
         ItemData itemData = GameData.getItemDataMap().get(item);
         if (itemData == null) {
-            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
             return;
         }
         if (refinement != 0) {
             if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
                 if (refinement < 1 || refinement > 5) {
-                    CommandHandler.sendMessage(sender, translate("commands.give.refinement_must_between_1_and_5"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.give.refinement_must_between_1_and_5"));
                     return;
                 }
             } else {
-                CommandHandler.sendMessage(sender, translate("commands.give.refinement_only_applicable_weapons"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.give.refinement_only_applicable_weapons"));
                 return;
             }
         }
@@ -119,11 +119,11 @@ public final class GiveCommand implements CommandHandler {
         this.item(targetPlayer, itemData, amount, lvl, refinement);
 
         if (!itemData.isEquip()) {
-            CommandHandler.sendMessage(sender, translate("commands.give.given", Integer.toString(amount), Integer.toString(item), Integer.toString(targetPlayer.getUid())));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.give.given", Integer.toString(amount), Integer.toString(item), Integer.toString(targetPlayer.getUid())));
         } else if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
-            CommandHandler.sendMessage(sender, translate("commands.give.given_with_level_and_refinement", Integer.toString(item), Integer.toString(lvl), Integer.toString(refinement), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.give.given_with_level_and_refinement", Integer.toString(item), Integer.toString(lvl), Integer.toString(refinement), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
         } else {
-            CommandHandler.sendMessage(sender, translate("commands.give.given_level", Integer.toString(item), Integer.toString(lvl), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.give.given_level", Integer.toString(item), Integer.toString(lvl), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
         }
     }
 
diff --git a/src/main/java/emu/grasscutter/command/commands/GodModeCommand.java b/src/main/java/emu/grasscutter/command/commands/GodModeCommand.java
index 98a375838..9b9160bcd 100644
--- a/src/main/java/emu/grasscutter/command/commands/GodModeCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GodModeCommand.java
@@ -14,7 +14,7 @@ public final class GodModeCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -35,6 +35,6 @@ public final class GodModeCommand implements CommandHandler {
         }
 
         targetPlayer.setGodmode(enabled);
-        CommandHandler.sendMessage(sender, translate("commands.godmode.success", (enabled ? translate("commands.status.enabled") : translate("commands.status.disabled")), targetPlayer.getNickname()));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.godmode.success", (enabled ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/HealCommand.java b/src/main/java/emu/grasscutter/command/commands/HealCommand.java
index 78ff14405..0eb92356f 100644
--- a/src/main/java/emu/grasscutter/command/commands/HealCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/HealCommand.java
@@ -17,7 +17,7 @@ public final class HealCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         
@@ -32,6 +32,6 @@ public final class HealCommand implements CommandHandler {
                 entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
             }
         });
-        CommandHandler.sendMessage(sender, translate("commands.heal.success"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.heal.success"));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/HelpCommand.java b/src/main/java/emu/grasscutter/command/commands/HelpCommand.java
index 8a222f7a6..fc94426d7 100644
--- a/src/main/java/emu/grasscutter/command/commands/HelpCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/HelpCommand.java
@@ -32,16 +32,16 @@ public final class HelpCommand implements CommandHandler {
         } else {
             String command = args.get(0);
             CommandHandler handler = CommandMap.getInstance().getHandler(command);
-            StringBuilder builder = new StringBuilder(player == null ? "\n" + translate("commands.status.help") + " - " : translate("commands.status.help") + " - ").append(command).append(": \n");
+            StringBuilder builder = new StringBuilder(player == null ? "\n" + translate(player, "commands.status.help") + " - " : translate(player, "commands.status.help") + " - ").append(command).append(": \n");
             if (handler == null) {
-                builder.append(translate("commands.generic.command_exist_error"));
+                builder.append(translate(player, "commands.generic.command_exist_error"));
             } else {
                 Command annotation = handler.getClass().getAnnotation(Command.class);
 
-                builder.append("   ").append(translate(annotation.description())).append("\n");
-                builder.append(translate("commands.help.usage")).append(annotation.usage());
+                builder.append("   ").append(translate(player, annotation.description())).append("\n");
+                builder.append(translate(player, "commands.help.usage")).append(annotation.usage());
                 if (annotation.aliases().length >= 1) {
-                    builder.append("\n").append(translate("commands.help.aliases"));
+                    builder.append("\n").append(translate(player, "commands.help.aliases"));
                     for (String alias : annotation.aliases()) {
                         builder.append(alias).append(" ");
                     }
@@ -57,13 +57,13 @@ public final class HelpCommand implements CommandHandler {
 
     void SendAllHelpMessage(Player player, List<Command> annotations) {
         if (player == null) {
-            StringBuilder builder = new StringBuilder("\n" + translate("commands.help.available_commands") + "\n");
+            StringBuilder builder = new StringBuilder("\n" + translate(player, "commands.help.available_commands") + "\n");
             annotations.forEach(annotation -> {
                 builder.append(annotation.label()).append("\n");
-                builder.append("   ").append(translate(annotation.description())).append("\n");
-                builder.append(translate("commands.help.usage")).append(annotation.usage());
+                builder.append("   ").append(translate(player, annotation.description())).append("\n");
+                builder.append(translate(player, "commands.help.usage")).append(annotation.usage());
                 if (annotation.aliases().length >= 1) {
-                    builder.append("\n").append(translate("commands.help.aliases"));
+                    builder.append("\n").append(translate(player, "commands.help.aliases"));
                     for (String alias : annotation.aliases()) {
                         builder.append(alias).append(" ");
                     }
@@ -74,13 +74,13 @@ public final class HelpCommand implements CommandHandler {
 
             CommandHandler.sendMessage(null, builder.toString());
         } else {
-            CommandHandler.sendMessage(player, translate("commands.help.available_commands"));
+            CommandHandler.sendMessage(player, translate(player, "commands.help.available_commands"));
             annotations.forEach(annotation -> {
                 StringBuilder builder = new StringBuilder(annotation.label()).append("\n");
-                builder.append("   ").append(translate(annotation.description())).append("\n");
-                builder.append(translate("commands.help.usage")).append(annotation.usage());
+                builder.append("   ").append(translate(player, annotation.description())).append("\n");
+                builder.append(translate(player, "commands.help.usage")).append(annotation.usage());
                 if (annotation.aliases().length >= 1) {
-                    builder.append("\n").append(translate("commands.help.aliases"));
+                    builder.append("\n").append(translate(player, "commands.help.aliases"));
                     for (String alias : annotation.aliases()) {
                         builder.append(alias).append(" ");
                     }
diff --git a/src/main/java/emu/grasscutter/command/commands/KickCommand.java b/src/main/java/emu/grasscutter/command/commands/KickCommand.java
index 9741226e7..57837666c 100644
--- a/src/main/java/emu/grasscutter/command/commands/KickCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/KickCommand.java
@@ -14,16 +14,16 @@ public final class KickCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (sender != null) {
-            CommandHandler.sendMessage(sender, translate("commands.kick.player_kick_player", 
+            CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player", 
                     Integer.toString(sender.getAccount().getPlayerUid()), sender.getAccount().getUsername(),
                     Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
         } else {
-            CommandHandler.sendMessage(null, translate("commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
+            CommandHandler.sendMessage(null, translate(sender, "commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
         }
 
         targetPlayer.getSession().close();
diff --git a/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java b/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java
index 853395fe6..a803f7d3a 100644
--- a/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java
@@ -18,7 +18,7 @@ public final class KillAllCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -31,14 +31,14 @@ public final class KillAllCommand implements CommandHandler {
                     scene = targetPlayer.getWorld().getSceneById(Integer.parseInt(args.get(0)));
                     break;
                 default:
-                    CommandHandler.sendMessage(sender, translate("commands.kill.usage"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.kill.usage"));
                     return;
             }
         } catch (NumberFormatException ignored) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
         }
         if (scene == null) {
-            CommandHandler.sendMessage(sender, translate("commands.kill.scene_not_found_in_player_world"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.kill.scene_not_found_in_player_world"));
             return;
         }
 
@@ -48,6 +48,6 @@ public final class KillAllCommand implements CommandHandler {
                 .filter(entity -> entity instanceof EntityMonster)
                 .toList();
         toKill.forEach(entity -> sceneF.killEntity(entity, 0));
-        CommandHandler.sendMessage(sender, translate("commands.kill.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.kill.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/KillCharacterCommand.java b/src/main/java/emu/grasscutter/command/commands/KillCharacterCommand.java
index 99a57e122..b0f5c3603 100644
--- a/src/main/java/emu/grasscutter/command/commands/KillCharacterCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/KillCharacterCommand.java
@@ -19,7 +19,7 @@ public final class KillCharacterCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -32,6 +32,6 @@ public final class KillCharacterCommand implements CommandHandler {
         targetPlayer.getScene().removeEntity(entity);
         entity.onDeath(0);
 
-        CommandHandler.sendMessage(sender, translate("commands.killCharacter.success", targetPlayer.getNickname()));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.killCharacter.success", targetPlayer.getNickname()));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/ListCommand.java b/src/main/java/emu/grasscutter/command/commands/ListCommand.java
index 53a274e52..5c35874cb 100644
--- a/src/main/java/emu/grasscutter/command/commands/ListCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ListCommand.java
@@ -22,7 +22,7 @@ public final class ListCommand implements CommandHandler {
             needUID = args.get(0).equals("uid");
         }
 
-        CommandHandler.sendMessage(sender, translate("commands.list.success", Integer.toString(playersMap.size())));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.list.success", Integer.toString(playersMap.size())));
 
         if (playersMap.size() != 0) {
             StringBuilder playerSet = new StringBuilder();
diff --git a/src/main/java/emu/grasscutter/command/commands/PermissionCommand.java b/src/main/java/emu/grasscutter/command/commands/PermissionCommand.java
index 4b945b3d1..fdcda5b95 100644
--- a/src/main/java/emu/grasscutter/command/commands/PermissionCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/PermissionCommand.java
@@ -16,12 +16,12 @@ public final class PermissionCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         
         if (args.size() != 2) {
-            CommandHandler.sendMessage(sender, translate("commands.permission.usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.permission.usage"));
             return;
         }
 
@@ -30,26 +30,26 @@ public final class PermissionCommand implements CommandHandler {
 
         Account account = targetPlayer.getAccount();
         if (account == null) {
-            CommandHandler.sendMessage(sender, translate("commands.permission.account_error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.permission.account_error"));
             return;
         }
 
         switch (action) {
             default:
-                CommandHandler.sendMessage(sender, translate("commands.permission.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.permission.usage"));
                 break;
             case "add":
                 if (account.addPermission(permission)) {
-                    CommandHandler.sendMessage(sender, translate("commands.permission.add"));
-                } else CommandHandler.sendMessage(sender, translate("commands.permission.has_error"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.permission.add"));
+                } else CommandHandler.sendMessage(sender, translate(sender, "commands.permission.has_error"));
                 break;
             case "remove":
                 if (account.removePermission(permission)) {
-                    CommandHandler.sendMessage(sender, translate("commands.permission.remove"));
-                } else CommandHandler.sendMessage(sender, translate("commands.permission.not_have_error"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.permission.remove"));
+                } else CommandHandler.sendMessage(sender, translate(sender, "commands.permission.not_have_error"));
                 break;
         }
 
         account.save();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/emu/grasscutter/command/commands/PositionCommand.java b/src/main/java/emu/grasscutter/command/commands/PositionCommand.java
index b5a250af6..530d44ae0 100644
--- a/src/main/java/emu/grasscutter/command/commands/PositionCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/PositionCommand.java
@@ -15,12 +15,12 @@ public final class PositionCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         Position pos = targetPlayer.getPos();
-        CommandHandler.sendMessage(sender, translate("commands.position.success",
+        CommandHandler.sendMessage(sender, translate(sender, "commands.position.success",
                 Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()),
                 Integer.toString(targetPlayer.getSceneId())));
     }
diff --git a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java
index 29eb93d0d..9414a89c4 100644
--- a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java
@@ -14,7 +14,7 @@ public final class ReloadCommand implements CommandHandler {
 
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
-        CommandHandler.sendMessage(sender, translate("commands.reload.reload_start"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_start"));
         
         Grasscutter.loadConfig();
         Grasscutter.loadLanguage();
@@ -23,6 +23,6 @@ public final class ReloadCommand implements CommandHandler {
         Grasscutter.getGameServer().getShopManager().load();
         Grasscutter.getDispatchServer().loadQueries();
         
-        CommandHandler.sendMessage(sender, translate("commands.reload.reload_done"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_done"));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/ResetConstCommand.java b/src/main/java/emu/grasscutter/command/commands/ResetConstCommand.java
index e8229eaf5..3c962b950 100644
--- a/src/main/java/emu/grasscutter/command/commands/ResetConstCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ResetConstCommand.java
@@ -17,13 +17,13 @@ public final class ResetConstCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
             targetPlayer.getAvatars().forEach(this::resetConstellation);
-            CommandHandler.sendMessage(sender, translate("commands.resetConst.reset_all"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.reset_all"));
         } else {
             EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
             if (entity == null) {
@@ -33,7 +33,7 @@ public final class ResetConstCommand implements CommandHandler {
             Avatar avatar = entity.getAvatar();
             this.resetConstellation(avatar);
 
-            CommandHandler.sendMessage(sender, translate("commands.resetConst.success", avatar.getAvatarData().getName()));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.success", avatar.getAvatarData().getName()));
         }
     }
 
@@ -43,4 +43,4 @@ public final class ResetConstCommand implements CommandHandler {
         avatar.recalcStats();
         avatar.save();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/emu/grasscutter/command/commands/ResetShopLimitCommand.java b/src/main/java/emu/grasscutter/command/commands/ResetShopLimitCommand.java
index bf5e2a4a6..d2b910811 100644
--- a/src/main/java/emu/grasscutter/command/commands/ResetShopLimitCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ResetShopLimitCommand.java
@@ -15,12 +15,12 @@ public final class ResetShopLimitCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0));
         targetPlayer.save();
-        CommandHandler.sendMessage(sender, translate("commands.status.success"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.status.success"));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
index 69aafa20b..21d9e64d9 100644
--- a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
@@ -39,7 +39,7 @@ public final class SendMailCommand implements CommandHandler {
                     MailBuilder mailBuilder;
                     switch (args.get(0).toLowerCase()) {
                         case "help" -> {
-                            CommandHandler.sendMessage(sender, translate(this.getClass().getAnnotation(Command.class).description()) + "\nUsage: " + this.getClass().getAnnotation(Command.class).usage());
+                            CommandHandler.sendMessage(sender, translate(sender, this.getClass().getAnnotation(Command.class).description()) + "\nUsage: " + this.getClass().getAnnotation(Command.class).usage());
                             return;
                         }
                         case "all" -> mailBuilder = new MailBuilder(true, new Mail());
@@ -47,16 +47,16 @@ public final class SendMailCommand implements CommandHandler {
                             if (DatabaseHelper.getPlayerById(Integer.parseInt(args.get(0))) != null) {
                                 mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail());
                             } else {
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.user_not_exist", args.get(0)));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.user_not_exist", args.get(0)));
                                 return;
                             }
                         }
                     }
                     mailBeingConstructed.put(senderId, mailBuilder);
-                    CommandHandler.sendMessage(sender, translate("commands.sendMail.start_composition"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.start_composition"));
                 }
-                case 2 -> CommandHandler.sendMessage(sender, translate("commands.sendMail.templates"));
-                default -> CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments"));
+                case 2 -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.templates"));
+                default -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments"));
             }
         } else {
             MailBuilder mailBuilder = mailBeingConstructed.get(senderId);
@@ -65,28 +65,28 @@ public final class SendMailCommand implements CommandHandler {
                 switch (args.get(0).toLowerCase()) {
                     case "stop" -> {
                         mailBeingConstructed.remove(senderId);
-                        CommandHandler.sendMessage(sender, translate("commands.sendMail.sendCancel"));
+                        CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.sendCancel"));
                         return;
                     }
                     case "finish" -> {
                         if (mailBuilder.constructionStage == 3) {
                             if (!mailBuilder.sendToAll) {
                                 Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail);
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.send_done", Integer.toString(mailBuilder.recipient)));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", Integer.toString(mailBuilder.recipient)));
                             } else {
                                 for (Player player : DatabaseHelper.getAllPlayers()) {
                                     Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail);
                                 }
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.send_all_done"));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_all_done"));
                             }
                             mailBeingConstructed.remove(senderId);
                         } else {
-                            CommandHandler.sendMessage(sender, translate("commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage)));
+                            CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage, sender)));
                         }
                         return;
                     }
                     case "help" -> {
-                        CommandHandler.sendMessage(sender, translate("commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage)));
+                        CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage, sender)));
                         return;
                     }
                     default -> {
@@ -94,19 +94,19 @@ public final class SendMailCommand implements CommandHandler {
                             case 0 -> {
                                 String title = String.join(" ", args.subList(0, args.size()));
                                 mailBuilder.mail.mailContent.title = title;
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.set_title", title));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_title", title));
                                 mailBuilder.constructionStage++;
                             }
                             case 1 -> {
                                 String contents = String.join(" ", args.subList(0, args.size()));
                                 mailBuilder.mail.mailContent.content = contents;
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.set_contents", contents));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_contents", contents));
                                 mailBuilder.constructionStage++;
                             }
                             case 2 -> {
                                 String msgSender = String.join(" ", args.subList(0, args.size()));
                                 mailBuilder.mail.mailContent.sender = msgSender;
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.set_message_sender", msgSender));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_message_sender", msgSender));
                                 mailBuilder.constructionStage++;
                             }
                             case 3 -> {
@@ -119,21 +119,21 @@ public final class SendMailCommand implements CommandHandler {
                                         try {
                                             refinement = Integer.parseInt(args.get(3));
                                         } catch (NumberFormatException ignored) {
-                                            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement"));
+                                            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
                                             return;
                                         }  // Fallthrough
                                     case 3: // <itemId|itemName> [amount] [level]
                                         try {
                                             lvl = Integer.parseInt(args.get(2));
                                         } catch (NumberFormatException ignored) {
-                                            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel"));
+                                            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
                                             return;
                                         }  // Fallthrough
                                     case 2: // <itemId|itemName> [amount]
                                         try {
                                             amount = Integer.parseInt(args.get(1));
                                         } catch (NumberFormatException ignored) {
-                                            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
+                                            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
                                             return;
                                         }  // Fallthrough
                                     case 1: // <itemId|itemName>
@@ -141,33 +141,33 @@ public final class SendMailCommand implements CommandHandler {
                                             item = Integer.parseInt(args.get(0));
                                         } catch (NumberFormatException ignored) {
                                             // TODO: Parse from item name using GM Handbook.
-                                            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
+                                            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
                                             return;
                                         }
                                         break;
                                     default: // *No args*
-                                        CommandHandler.sendMessage(sender, translate("commands.give.usage"));
+                                        CommandHandler.sendMessage(sender, translate(sender, "commands.give.usage"));
                                         return;
                                 }
                                 mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl));
-                                CommandHandler.sendMessage(sender, translate("commands.sendMail.send", Integer.toString(amount), Integer.toString(item), Integer.toString(lvl)));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send", Integer.toString(amount), Integer.toString(item), Integer.toString(lvl)));
                             }
                         }
                     }
                 }
             } else {
-                CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments_please_use", getConstructionArgs(mailBuilder.constructionStage)));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments_please_use", getConstructionArgs(mailBuilder.constructionStage, sender)));
             }
         }
     }
 
-    private String getConstructionArgs(int stage) {
+    private String getConstructionArgs(int stage, Player sender) {
         return switch(stage) {
-            case 0 -> translate("commands.sendMail.title");
-            case 1 -> translate("commands.sendMail.message");
-            case 2 -> translate("commands.sendMail.sender");
-            case 3 -> translate("commands.sendMail.arguments");
-            default -> translate("commands.sendMail.error", Integer.toString(stage));
+            case 0 -> translate(sender, "commands.sendMail.title");
+            case 1 -> translate(sender, "commands.sendMail.message");
+            case 2 -> translate(sender, "commands.sendMail.sender");
+            case 3 -> translate(sender, "commands.sendMail.arguments");
+            default -> translate(sender, "commands.sendMail.error", Integer.toString(stage));
         };
     }
 
diff --git a/src/main/java/emu/grasscutter/command/commands/SendMessageCommand.java b/src/main/java/emu/grasscutter/command/commands/SendMessageCommand.java
index befbf4f00..2e6feb96d 100644
--- a/src/main/java/emu/grasscutter/command/commands/SendMessageCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SendMessageCommand.java
@@ -15,16 +15,16 @@ public final class SendMessageCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         if (args.size() == 0) {
-            CommandHandler.sendMessage(null, translate("commands.sendMessage.usage"));
+            CommandHandler.sendMessage(null, translate(sender, "commands.sendMessage.usage"));
             return;
         }
 
         String message = String.join(" ", args);
         CommandHandler.sendMessage(targetPlayer, message);
-        CommandHandler.sendMessage(sender, translate("commands.sendMessage.success"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.sendMessage.success"));
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java b/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java
index cf356d06b..2f838fb1a 100644
--- a/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java
@@ -18,19 +18,19 @@ public final class SetFetterLevelCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (args.size() != 1) {
-            CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.usage"));
             return;
         }
 
         try {
             int fetterLevel = Integer.parseInt(args.get(0));
             if (fetterLevel < 0 || fetterLevel > 10) {
-                CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.range_error"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.range_error"));
                 return;
             }
             Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
@@ -42,9 +42,9 @@ public final class SetFetterLevelCommand implements CommandHandler {
 		    avatar.save();
 		
 		    targetPlayer.sendPacket(new PacketAvatarFetterDataNotify(avatar));
-            CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.success", fetterLevel));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.success", fetterLevel));
         } catch (NumberFormatException ignored) {
-            CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.level_error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.level_error"));
         }
     }
     
diff --git a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java
index a0572d2c2..b51b09197 100644
--- a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java
@@ -175,13 +175,13 @@ public final class SetStatsCommand implements CommandHandler {
 
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
-        String syntax = sender == null ? translate("commands.setStats.usage_console") : translate("commands.setStats.usage_ingame");
-        String usage = syntax + translate("commands.setStats.help_message");
+        String syntax = sender == null ? translate(sender, "commands.setStats.usage_console") : translate(sender, "commands.setStats.usage_ingame");
+        String usage = syntax + translate(sender, "commands.setStats.help_message");
         String statStr;
         String valueStr;
 
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -203,7 +203,7 @@ public final class SetStatsCommand implements CommandHandler {
                 value = Float.parseFloat(valueStr);
             }
         } catch (NumberFormatException ignored) {
-            CommandHandler.sendMessage(sender, translate("commands.setStats.value_error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.value_error"));
             return;
         }
 
@@ -217,10 +217,10 @@ public final class SetStatsCommand implements CommandHandler {
                 valueStr = String.format("%.0f", value);
             }
             if (targetPlayer == sender) {
-                CommandHandler.sendMessage(sender, translate("commands.setStats.set_self", stat.name, valueStr));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.set_self", stat.name, valueStr));
             } else {
                 String uidStr = targetPlayer.getAccount().getId();
-                CommandHandler.sendMessage(sender, translate("commands.setStats.set_self", stat.name, uidStr, valueStr));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.set_self", stat.name, uidStr, valueStr));
             }
         } else {
             CommandHandler.sendMessage(sender, usage);
diff --git a/src/main/java/emu/grasscutter/command/commands/SetWorldLevelCommand.java b/src/main/java/emu/grasscutter/command/commands/SetWorldLevelCommand.java
index aa773159e..d09c00a91 100644
--- a/src/main/java/emu/grasscutter/command/commands/SetWorldLevelCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SetWorldLevelCommand.java
@@ -16,19 +16,19 @@ public final class SetWorldLevelCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (args.size() < 1) {
-            CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.usage"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage"));
             return;
         }
 
         try {
             int level = Integer.parseInt(args.get(0));
             if (level > 8 || level < 0) {
-                CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.value_error"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.value_error"));
                 return;
             }
 
@@ -36,9 +36,9 @@ public final class SetWorldLevelCommand implements CommandHandler {
             targetPlayer.getWorld().setWorldLevel(level);
             targetPlayer.setWorldLevel(level);
 
-            CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.success", Integer.toString(level)));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.success", Integer.toString(level)));
         } catch (NumberFormatException ignored) {
-            CommandHandler.sendMessage(null, translate("commands.setWorldLevel.invalid_world_level"));
+            CommandHandler.sendMessage(null, translate(sender, "commands.setWorldLevel.invalid_world_level"));
         }
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java
index e3193c638..24a6bc174 100644
--- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java
@@ -28,7 +28,7 @@ public final class SpawnCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -40,23 +40,23 @@ public final class SpawnCommand implements CommandHandler {
                 try {
                     level = Integer.parseInt(args.get(2));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
                 }  // Fallthrough
             case 2:
                 try {
                     amount = Integer.parseInt(args.get(1));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
                 }  // Fallthrough
             case 1:
                 try {
                     id = Integer.parseInt(args.get(0));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.generic.invalid.entityId"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId"));
                 }
                 break;
             default:
-                CommandHandler.sendMessage(sender, translate("commands.spawn.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.usage"));
                 return;
         }
 
@@ -64,7 +64,7 @@ public final class SpawnCommand implements CommandHandler {
         GadgetData gadgetData = GameData.getGadgetDataMap().get(id);
         ItemData itemData = GameData.getItemDataMap().get(id);
         if (monsterData == null && gadgetData == null && itemData == null) {
-            CommandHandler.sendMessage(sender, translate("commands.generic.invalid.entityId"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId"));
             return;
         }
         Scene scene = targetPlayer.getScene();
@@ -100,7 +100,7 @@ public final class SpawnCommand implements CommandHandler {
 
             scene.addEntity(entity);
         }
-        CommandHandler.sendMessage(sender, translate("commands.spawn.success", Integer.toString(amount), Integer.toString(id)));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", Integer.toString(amount), Integer.toString(id)));
     }
 
     private Position GetRandomPositionInCircle(Position origin, double radius){
diff --git a/src/main/java/emu/grasscutter/command/commands/StopCommand.java b/src/main/java/emu/grasscutter/command/commands/StopCommand.java
index 129b27b24..d1fa0fe75 100644
--- a/src/main/java/emu/grasscutter/command/commands/StopCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/StopCommand.java
@@ -14,9 +14,9 @@ public final class StopCommand implements CommandHandler {
 
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
-        CommandHandler.sendMessage(null, translate("commands.stop.success"));
+        CommandHandler.sendMessage(null, translate(sender, "commands.stop.success"));
         for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
-            CommandHandler.sendMessage(p, translate("commands.stop.success"));
+            CommandHandler.sendMessage(p, translate(sender, "commands.stop.success"));
         }
 
         System.exit(1000);
diff --git a/src/main/java/emu/grasscutter/command/commands/TalentCommand.java b/src/main/java/emu/grasscutter/command/commands/TalentCommand.java
index 40ac11b50..6cb687efe 100644
--- a/src/main/java/emu/grasscutter/command/commands/TalentCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/TalentCommand.java
@@ -19,7 +19,7 @@ public final class TalentCommand implements CommandHandler {
     private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) {
         int oldLevel = avatar.getSkillLevelMap().get(talentId);
         if (talentLevel < 0 || talentLevel > 15) {
-            CommandHandler.sendMessage(sender, translate("commands.talent.lower_16"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.talent.lower_16"));
             return;
         }
 
@@ -40,20 +40,20 @@ public final class TalentCommand implements CommandHandler {
         } else if (talentId == depot.getEnergySkill()) {
             successMessage = "commands.talent.set_q";
         }
-        CommandHandler.sendMessage(sender, translate(successMessage, talentLevel));
+        CommandHandler.sendMessage(sender, translate(sender, successMessage, talentLevel));
     }
 
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
         if (args.size() < 1){
-            CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
-            CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
-            CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
             return;
         }
 
@@ -62,15 +62,15 @@ public final class TalentCommand implements CommandHandler {
         String cmdSwitch = args.get(0);
         switch (cmdSwitch) {
             default -> {
-                CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
-                CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
-                CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
                 return;
             }
             case "set" -> {
                 if (args.size() < 3) {
-                    CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
-                    CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
                     return;
                 }
                 try {
@@ -78,13 +78,13 @@ public final class TalentCommand implements CommandHandler {
                     int newLevel = Integer.parseInt(args.get(2));
                     setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.talent.invalid_skill_id"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.talent.invalid_skill_id"));
                     return;
                 }
             }
             case "n", "e", "q" -> {
                 if (args.size() < 2) {
-                    CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
                     return;
                 }
                 AvatarSkillDepotData SkillDepot = avatar.getData().getSkillDepot();
@@ -97,7 +97,7 @@ public final class TalentCommand implements CommandHandler {
                     int newLevel = Integer.parseInt(args.get(1));
                     setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.talent.invalid_level"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.talent.invalid_level"));
                     return;
                 }
             }
@@ -105,9 +105,9 @@ public final class TalentCommand implements CommandHandler {
                 int skillIdNorAtk = avatar.getData().getSkillDepot().getSkills().get(0);
                 int skillIdE = avatar.getData().getSkillDepot().getSkills().get(1);
                 int skillIdQ = avatar.getData().getSkillDepot().getEnergySkill();
-                CommandHandler.sendMessage(sender, translate("commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk)));
-                CommandHandler.sendMessage(sender, translate("commands.talent.e_skill_id", Integer.toString(skillIdE)));
-                CommandHandler.sendMessage(sender, translate("commands.talent.q_skill_id", Integer.toString(skillIdQ)));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk)));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.talent.e_skill_id", Integer.toString(skillIdE)));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.talent.q_skill_id", Integer.toString(skillIdQ)));
             }
         }
     }
diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java
index bfa0ac821..23f9c6d40 100644
--- a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java
@@ -16,12 +16,12 @@ public final class TeleportAllCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
         
         if (!targetPlayer.getWorld().isMultiplayer()) {
-            CommandHandler.sendMessage(sender, translate("commands.teleportAll.error"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.error"));
             return;
         }
         
@@ -33,6 +33,6 @@ public final class TeleportAllCommand implements CommandHandler {
             player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos);
         }
         
-        CommandHandler.sendMessage(sender, translate("commands.teleportAll.success"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success"));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
index 8a9fb9948..62827d86c 100644
--- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
@@ -27,7 +27,7 @@ public final class TeleportCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -42,7 +42,7 @@ public final class TeleportCommand implements CommandHandler {
                 try {
                     sceneId = Integer.parseInt(args.get(3));
                 }catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
                 }  // Fallthrough
             case 3:
                 try {
@@ -50,20 +50,20 @@ public final class TeleportCommand implements CommandHandler {
                     y = parseRelative(args.get(1), y);
                     z = parseRelative(args.get(2), z);
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.teleport.invalid_position"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
                 }
                 break;
             default:
-                CommandHandler.sendMessage(sender, translate("commands.teleport.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.usage"));
                 return;
         }
 
         Position target_pos = new Position(x, y, z);
         boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos);
         if (!result) {
-            CommandHandler.sendMessage(sender, translate("commands.teleport.invalid_position"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
         } else {
-            CommandHandler.sendMessage(sender, translate("commands.teleport.success", 
+            CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", 
                     targetPlayer.getNickname(), Float.toString(x), Float.toString(y), 
                     Float.toString(z), Integer.toString(sceneId))
             );
diff --git a/src/main/java/emu/grasscutter/command/commands/UnlockTowerCommand.java b/src/main/java/emu/grasscutter/command/commands/UnlockTowerCommand.java
index bd7b8bc1f..c2b67209c 100644
--- a/src/main/java/emu/grasscutter/command/commands/UnlockTowerCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/UnlockTowerCommand.java
@@ -21,7 +21,7 @@ public class UnlockTowerCommand implements CommandHandler {
         unlockFloor(sender, sender.getServer().getTowerScheduleManager()
                 .getScheduleFloors());
 
-        CommandHandler.sendMessage(sender, translate("commands.unlocktower.success"));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.unlocktower.success"));
     }
 
     public void unlockFloor(Player player, List<Integer> floors){
diff --git a/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java b/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
index 0edbd8482..7ad347465 100644
--- a/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
@@ -17,7 +17,7 @@ public final class WeatherCommand implements CommandHandler {
     @Override
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (targetPlayer == null) {
-            CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
+            CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
             return;
         }
 
@@ -28,17 +28,17 @@ public final class WeatherCommand implements CommandHandler {
                 try {
                     climateId = Integer.parseInt(args.get(1));
                 } catch (NumberFormatException ignored) {
-                        CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id"));
+                        CommandHandler.sendMessage(sender, translate(sender, "commands.weather.invalid_id"));
                 }
             case 1:
                 try {
                     weatherId = Integer.parseInt(args.get(0));
                 } catch (NumberFormatException ignored) {
-                    CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id"));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.weather.invalid_id"));
                 }
                 break;
             default:
-                CommandHandler.sendMessage(sender, translate("commands.weather.usage"));
+                CommandHandler.sendMessage(sender, translate(sender, "commands.weather.usage"));
                 return;
         }
 
@@ -47,6 +47,6 @@ public final class WeatherCommand implements CommandHandler {
         targetPlayer.getScene().setWeather(weatherId);
         targetPlayer.getScene().setClimate(climate);
         targetPlayer.getScene().broadcastPacket(new PacketSceneAreaWeatherNotify(targetPlayer));
-        CommandHandler.sendMessage(sender, translate("commands.weather.success", Integer.toString(weatherId), Integer.toString(climateId)));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.weather.success", Integer.toString(weatherId), Integer.toString(climateId)));
     }
 }
diff --git a/src/main/java/emu/grasscutter/game/Account.java b/src/main/java/emu/grasscutter/game/Account.java
index 7e8baa291..821dea80b 100644
--- a/src/main/java/emu/grasscutter/game/Account.java
+++ b/src/main/java/emu/grasscutter/game/Account.java
@@ -8,6 +8,7 @@ import emu.grasscutter.utils.Utils;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import org.bson.Document;
 
@@ -28,10 +29,12 @@ public class Account {
 	private String token;
 	private String sessionKey; // Session token for dispatch server
 	private List<String> permissions;
+    private Locale locale;
 	
 	@Deprecated
 	public Account() {
 		this.permissions = new ArrayList<>();
+        this.locale = Grasscutter.getConfig().LocaleLanguage;
 	}
 
 	public String getId() {
@@ -96,6 +99,14 @@ public class Account {
 		return this.sessionKey;
 	}
 
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+
 	/**
 	 * The collection of a player's permissions.
 	 */
@@ -166,5 +177,10 @@ public class Account {
 		if (!document.containsKey("permissions")) {
 			this.addPermission("*");
 		}
+
+        // Set account default language as server default language
+        if (!document.containsKey("locale")) {
+            this.locale = Grasscutter.getConfig().LocaleLanguage;
+        }
 	}
 }
diff --git a/src/main/java/emu/grasscutter/utils/Language.java b/src/main/java/emu/grasscutter/utils/Language.java
index 04bd352f7..57f211020 100644
--- a/src/main/java/emu/grasscutter/utils/Language.java
+++ b/src/main/java/emu/grasscutter/utils/Language.java
@@ -3,6 +3,8 @@ package emu.grasscutter.utils;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import emu.grasscutter.Grasscutter;
+import emu.grasscutter.game.Account;
+import emu.grasscutter.game.player.Player;
 
 import javax.annotation.Nullable;
 import java.io.InputStream;
@@ -11,6 +13,7 @@ import java.util.Map;
 
 public final class Language {
     private final JsonObject languageData;
+    private final String languageCode;
     private final Map<String, String> cachedTranslations = new ConcurrentHashMap<>();
     private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
 
@@ -24,8 +27,21 @@ public final class Language {
             return cachedLanguages.get(langCode);
         }
 
-        var languageInst = new Language(langCode + ".json", Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage) + ".json");
-        cachedLanguages.put(langCode, languageInst);
+        var fallbackLanguageCode = Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage);
+        var descripter = getLanguageFileStreamDescripter(langCode, fallbackLanguageCode);
+        var actualLanguageCode = descripter.getLanguageCode();
+
+        Language languageInst = null;
+
+        if (descripter.getLanguageFile() != null) {
+            languageInst = new Language(descripter);
+            cachedLanguages.put(actualLanguageCode, languageInst);
+        }
+        else {
+            languageInst = cachedLanguages.get(actualLanguageCode);
+            cachedLanguages.put(langCode, languageInst);
+        }
+
         return languageInst;
     }
 
@@ -47,34 +63,90 @@ public final class Language {
     }
 
     /**
-     * Reads a file and creates a language instance.
-     * @param fileName The name of the language file.
-     * @param fallback The name of the fallback language file.
+     * Returns the translated value from the key while substituting arguments.
+     * @param player Target player
+     * @param key The key of the translated value to return.
+     * @param args The arguments to substitute.
+     * @return A translated value with arguments substituted.
      */
-    private Language(String fileName, String fallback) {
-        @Nullable JsonObject languageData = null;
+    public static String translate(Player player, String key, Object... args) {
+        if (player == null) {
+            return translate(key, args);
+        }
 
-        InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName);
-        if (file == null) { // Provided fallback language.
-            file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
-            Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback);
-        }
-        if(file == null) { // Fallback the fallback language.
-            file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
-            Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
-        }
-        if(file == null)
-            throw new RuntimeException("Unable to load the primary, fallback, and 'en-US' language files.");
+        var langCode = Utils.getLanguageCode(player.getAccount().getLocale());
+        String translated = Grasscutter.getLanguage(langCode).get(key);
         
         try {
-            languageData = Grasscutter.getGsonFactory().fromJson(Utils.readFromInputStream(file), JsonObject.class);
+            return translated.formatted(args);
         } catch (Exception exception) {
-            Grasscutter.getLogger().warn("Failed to load language file: " + fileName, exception);
+            Grasscutter.getLogger().error("Failed to format string: " + key, exception);
+            return translated;
+        }
+    }
+
+    /**
+     * get language code
+     */
+    public String getLanguageCode() {
+        return languageCode;
+    }
+
+    /**
+     * Reads a file and creates a language instance.
+     */
+    private Language(InternalLanguageFileStreamDescripter descripter) {
+        @Nullable JsonObject languageData = null;
+        languageCode = descripter.getLanguageCode();
+        
+        try {
+            languageData = Grasscutter.getGsonFactory().fromJson(Utils.readFromInputStream(descripter.getLanguageFile()), JsonObject.class);
+        } catch (Exception exception) {
+            Grasscutter.getLogger().warn("Failed to load language file: " + descripter.getLanguageCode(), exception);
         }
         
         this.languageData = languageData;
     }
 
+    /**
+     * create a InternalLanguageFileStreamDescripter
+     * @param languageCode The name of the language code.
+     * @param fallbackLanguageCode The name of the fallback language code.
+     */
+    private static InternalLanguageFileStreamDescripter getLanguageFileStreamDescripter(String languageCode, String fallbackLanguageCode) {
+        var fileName = languageCode + ".json";
+        var fallback = fallbackLanguageCode + ".json";
+
+        String actualLanguageCode = languageCode;
+        if (cachedLanguages.containsKey(actualLanguageCode)) {
+            return new InternalLanguageFileStreamDescripter(actualLanguageCode, null);
+        }
+        InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName);
+
+        if (file == null) { // Provided fallback language.
+            actualLanguageCode = fallbackLanguageCode;
+            if (cachedLanguages.containsKey(actualLanguageCode)) {
+                return new InternalLanguageFileStreamDescripter(actualLanguageCode, null);
+            }
+            file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
+            Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback);
+        }
+
+        if(file == null) { // Fallback the fallback language.
+            actualLanguageCode = "en-US";
+            if (cachedLanguages.containsKey(actualLanguageCode)) {
+                return new InternalLanguageFileStreamDescripter(actualLanguageCode, null);
+            }
+            file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
+            Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
+        }
+
+        if(file == null)
+            throw new RuntimeException("Unable to load the primary, fallback, and 'en-US' language files.");
+
+        return new InternalLanguageFileStreamDescripter(actualLanguageCode, file);
+    }
+
     /**
      * Returns the value (as a string) from a nested key.
      * @param key The key to look for.
@@ -107,4 +179,22 @@ public final class Language {
         
         this.cachedTranslations.put(key, result); return result;
     }
+
+    private static class InternalLanguageFileStreamDescripter {
+        private String languageCode;
+        private InputStream languageFile;
+
+        public InternalLanguageFileStreamDescripter(String languageCode, InputStream languageFile) {
+            this.languageCode = languageCode;
+            this.languageFile = languageFile;
+        }
+
+        public String getLanguageCode() {
+            return languageCode;
+        }
+
+        public InputStream getLanguageFile() {
+            return languageFile;
+        }
+    }
 }
diff --git a/src/main/resources/languages/en-US.json b/src/main/resources/languages/en-US.json
index 9e7271ea3..893f490af 100644
--- a/src/main/resources/languages/en-US.json
+++ b/src/main/resources/languages/en-US.json
@@ -188,6 +188,11 @@
       "success": "Killed %s's current character.",
       "description": "Kills the players current character"
     },
+    "language": {
+      "current_language": "current language is %s",
+      "language_changed": "language changed to %s",
+      "description": "display or change current language"
+    },
     "list": {
       "success": "There are %s player(s) online:",
       "description": "List online players"
diff --git a/src/main/resources/languages/zh-CN.json b/src/main/resources/languages/zh-CN.json
index f6a2de0ea..a326d4960 100644
--- a/src/main/resources/languages/zh-CN.json
+++ b/src/main/resources/languages/zh-CN.json
@@ -188,6 +188,11 @@
       "success": "已杀死 %s 当前角色。",
       "description": "杀死当前角色"
     },
+    "language": {
+      "current_language": "当前语言是: %s",
+      "language_changed": "语言切换至: %s",
+      "description": "显示或切换当前语言"
+    },
     "list": {
       "success": "目前在线人数:%s",
       "description": "查看所有玩家"