Commit ecf028d0 authored by Secretboy's avatar Secretboy Committed by GitHub
Browse files

add /language command (#780)

* Fix the following issues:
1. HashMap non-thread-safe issus
2. Fix the same problem in pr621, but use a better implementation

Add the following functions:
1. There is now a language cache inside getLanguage to prepare for different languages corresponding to different time zones where the accounts in the server are located

* add /language command,each account has their own Locate
parent 0f134151
...@@ -15,12 +15,12 @@ public final class PositionCommand implements CommandHandler { ...@@ -15,12 +15,12 @@ public final class PositionCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
Position pos = targetPlayer.getPos(); 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()), Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()),
Integer.toString(targetPlayer.getSceneId()))); Integer.toString(targetPlayer.getSceneId())));
} }
......
...@@ -14,7 +14,7 @@ public final class ReloadCommand implements CommandHandler { ...@@ -14,7 +14,7 @@ public final class ReloadCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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.loadConfig();
Grasscutter.loadLanguage(); Grasscutter.loadLanguage();
...@@ -23,6 +23,6 @@ public final class ReloadCommand implements CommandHandler { ...@@ -23,6 +23,6 @@ public final class ReloadCommand implements CommandHandler {
Grasscutter.getGameServer().getShopManager().load(); Grasscutter.getGameServer().getShopManager().load();
Grasscutter.getDispatchServer().loadQueries(); Grasscutter.getDispatchServer().loadQueries();
CommandHandler.sendMessage(sender, translate("commands.reload.reload_done")); CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_done"));
} }
} }
...@@ -17,13 +17,13 @@ public final class ResetConstCommand implements CommandHandler { ...@@ -17,13 +17,13 @@ public final class ResetConstCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) { if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
targetPlayer.getAvatars().forEach(this::resetConstellation); targetPlayer.getAvatars().forEach(this::resetConstellation);
CommandHandler.sendMessage(sender, translate("commands.resetConst.reset_all")); CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.reset_all"));
} else { } else {
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
if (entity == null) { if (entity == null) {
...@@ -33,7 +33,7 @@ public final class ResetConstCommand implements CommandHandler { ...@@ -33,7 +33,7 @@ public final class ResetConstCommand implements CommandHandler {
Avatar avatar = entity.getAvatar(); Avatar avatar = entity.getAvatar();
this.resetConstellation(avatar); 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 { ...@@ -43,4 +43,4 @@ public final class ResetConstCommand implements CommandHandler {
avatar.recalcStats(); avatar.recalcStats();
avatar.save(); avatar.save();
} }
} }
\ No newline at end of file
...@@ -15,12 +15,12 @@ public final class ResetShopLimitCommand implements CommandHandler { ...@@ -15,12 +15,12 @@ public final class ResetShopLimitCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0)); targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0));
targetPlayer.save(); targetPlayer.save();
CommandHandler.sendMessage(sender, translate("commands.status.success")); CommandHandler.sendMessage(sender, translate(sender, "commands.status.success"));
} }
} }
...@@ -39,7 +39,7 @@ public final class SendMailCommand implements CommandHandler { ...@@ -39,7 +39,7 @@ public final class SendMailCommand implements CommandHandler {
MailBuilder mailBuilder; MailBuilder mailBuilder;
switch (args.get(0).toLowerCase()) { switch (args.get(0).toLowerCase()) {
case "help" -> { 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; return;
} }
case "all" -> mailBuilder = new MailBuilder(true, new Mail()); case "all" -> mailBuilder = new MailBuilder(true, new Mail());
...@@ -47,16 +47,16 @@ public final class SendMailCommand implements CommandHandler { ...@@ -47,16 +47,16 @@ public final class SendMailCommand implements CommandHandler {
if (DatabaseHelper.getPlayerById(Integer.parseInt(args.get(0))) != null) { if (DatabaseHelper.getPlayerById(Integer.parseInt(args.get(0))) != null) {
mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail()); mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail());
} else { } 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; return;
} }
} }
} }
mailBeingConstructed.put(senderId, mailBuilder); 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")); case 2 -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.templates"));
default -> CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments")); default -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments"));
} }
} else { } else {
MailBuilder mailBuilder = mailBeingConstructed.get(senderId); MailBuilder mailBuilder = mailBeingConstructed.get(senderId);
...@@ -65,28 +65,28 @@ public final class SendMailCommand implements CommandHandler { ...@@ -65,28 +65,28 @@ public final class SendMailCommand implements CommandHandler {
switch (args.get(0).toLowerCase()) { switch (args.get(0).toLowerCase()) {
case "stop" -> { case "stop" -> {
mailBeingConstructed.remove(senderId); mailBeingConstructed.remove(senderId);
CommandHandler.sendMessage(sender, translate("commands.sendMail.sendCancel")); CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.sendCancel"));
return; return;
} }
case "finish" -> { case "finish" -> {
if (mailBuilder.constructionStage == 3) { if (mailBuilder.constructionStage == 3) {
if (!mailBuilder.sendToAll) { if (!mailBuilder.sendToAll) {
Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail); 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 { } else {
for (Player player : DatabaseHelper.getAllPlayers()) { for (Player player : DatabaseHelper.getAllPlayers()) {
Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail); 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); mailBeingConstructed.remove(senderId);
} else { } 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; return;
} }
case "help" -> { 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; return;
} }
default -> { default -> {
...@@ -94,19 +94,19 @@ public final class SendMailCommand implements CommandHandler { ...@@ -94,19 +94,19 @@ public final class SendMailCommand implements CommandHandler {
case 0 -> { case 0 -> {
String title = String.join(" ", args.subList(0, args.size())); String title = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.title = title; 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++; mailBuilder.constructionStage++;
} }
case 1 -> { case 1 -> {
String contents = String.join(" ", args.subList(0, args.size())); String contents = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.content = contents; 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++; mailBuilder.constructionStage++;
} }
case 2 -> { case 2 -> {
String msgSender = String.join(" ", args.subList(0, args.size())); String msgSender = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.sender = msgSender; 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++; mailBuilder.constructionStage++;
} }
case 3 -> { case 3 -> {
...@@ -119,21 +119,21 @@ public final class SendMailCommand implements CommandHandler { ...@@ -119,21 +119,21 @@ public final class SendMailCommand implements CommandHandler {
try { try {
refinement = Integer.parseInt(args.get(3)); refinement = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement")); CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
return; return;
} // Fallthrough } // Fallthrough
case 3: // <itemId|itemName> [amount] [level] case 3: // <itemId|itemName> [amount] [level]
try { try {
lvl = Integer.parseInt(args.get(2)); lvl = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel")); CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
return; return;
} // Fallthrough } // Fallthrough
case 2: // <itemId|itemName> [amount] case 2: // <itemId|itemName> [amount]
try { try {
amount = Integer.parseInt(args.get(1)); amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount")); CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
return; return;
} // Fallthrough } // Fallthrough
case 1: // <itemId|itemName> case 1: // <itemId|itemName>
...@@ -141,33 +141,33 @@ public final class SendMailCommand implements CommandHandler { ...@@ -141,33 +141,33 @@ public final class SendMailCommand implements CommandHandler {
item = Integer.parseInt(args.get(0)); item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook. // 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; return;
} }
break; break;
default: // *No args* default: // *No args*
CommandHandler.sendMessage(sender, translate("commands.give.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.give.usage"));
return; return;
} }
mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl)); 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 { } 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) { return switch(stage) {
case 0 -> translate("commands.sendMail.title"); case 0 -> translate(sender, "commands.sendMail.title");
case 1 -> translate("commands.sendMail.message"); case 1 -> translate(sender, "commands.sendMail.message");
case 2 -> translate("commands.sendMail.sender"); case 2 -> translate(sender, "commands.sendMail.sender");
case 3 -> translate("commands.sendMail.arguments"); case 3 -> translate(sender, "commands.sendMail.arguments");
default -> translate("commands.sendMail.error", Integer.toString(stage)); default -> translate(sender, "commands.sendMail.error", Integer.toString(stage));
}; };
} }
......
...@@ -15,16 +15,16 @@ public final class SendMessageCommand implements CommandHandler { ...@@ -15,16 +15,16 @@ public final class SendMessageCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
if (args.size() == 0) { if (args.size() == 0) {
CommandHandler.sendMessage(null, translate("commands.sendMessage.usage")); CommandHandler.sendMessage(null, translate(sender, "commands.sendMessage.usage"));
return; return;
} }
String message = String.join(" ", args); String message = String.join(" ", args);
CommandHandler.sendMessage(targetPlayer, message); 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
...@@ -18,19 +18,19 @@ public final class SetFetterLevelCommand implements CommandHandler { ...@@ -18,19 +18,19 @@ public final class SetFetterLevelCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
if (args.size() != 1) { if (args.size() != 1) {
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.usage"));
return; return;
} }
try { try {
int fetterLevel = Integer.parseInt(args.get(0)); int fetterLevel = Integer.parseInt(args.get(0));
if (fetterLevel < 0 || fetterLevel > 10) { if (fetterLevel < 0 || fetterLevel > 10) {
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.range_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.range_error"));
return; return;
} }
Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar(); Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
...@@ -42,9 +42,9 @@ public final class SetFetterLevelCommand implements CommandHandler { ...@@ -42,9 +42,9 @@ public final class SetFetterLevelCommand implements CommandHandler {
avatar.save(); avatar.save();
targetPlayer.sendPacket(new PacketAvatarFetterDataNotify(avatar)); 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) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.level_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.level_error"));
} }
} }
......
...@@ -175,13 +175,13 @@ public final class SetStatsCommand implements CommandHandler { ...@@ -175,13 +175,13 @@ public final class SetStatsCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 syntax = sender == null ? translate(sender, "commands.setStats.usage_console") : translate(sender, "commands.setStats.usage_ingame");
String usage = syntax + translate("commands.setStats.help_message"); String usage = syntax + translate(sender, "commands.setStats.help_message");
String statStr; String statStr;
String valueStr; String valueStr;
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
...@@ -203,7 +203,7 @@ public final class SetStatsCommand implements CommandHandler { ...@@ -203,7 +203,7 @@ public final class SetStatsCommand implements CommandHandler {
value = Float.parseFloat(valueStr); value = Float.parseFloat(valueStr);
} }
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.setStats.value_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.value_error"));
return; return;
} }
...@@ -217,10 +217,10 @@ public final class SetStatsCommand implements CommandHandler { ...@@ -217,10 +217,10 @@ public final class SetStatsCommand implements CommandHandler {
valueStr = String.format("%.0f", value); valueStr = String.format("%.0f", value);
} }
if (targetPlayer == sender) { 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 { } else {
String uidStr = targetPlayer.getAccount().getId(); 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 { } else {
CommandHandler.sendMessage(sender, usage); CommandHandler.sendMessage(sender, usage);
......
...@@ -16,19 +16,19 @@ public final class SetWorldLevelCommand implements CommandHandler { ...@@ -16,19 +16,19 @@ public final class SetWorldLevelCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
if (args.size() < 1) { if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage"));
return; return;
} }
try { try {
int level = Integer.parseInt(args.get(0)); int level = Integer.parseInt(args.get(0));
if (level > 8 || level < 0) { if (level > 8 || level < 0) {
CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.value_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.value_error"));
return; return;
} }
...@@ -36,9 +36,9 @@ public final class SetWorldLevelCommand implements CommandHandler { ...@@ -36,9 +36,9 @@ public final class SetWorldLevelCommand implements CommandHandler {
targetPlayer.getWorld().setWorldLevel(level); targetPlayer.getWorld().setWorldLevel(level);
targetPlayer.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) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, translate("commands.setWorldLevel.invalid_world_level")); CommandHandler.sendMessage(null, translate(sender, "commands.setWorldLevel.invalid_world_level"));
} }
} }
} }
...@@ -28,7 +28,7 @@ public final class SpawnCommand implements CommandHandler { ...@@ -28,7 +28,7 @@ public final class SpawnCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
...@@ -40,23 +40,23 @@ public final class SpawnCommand implements CommandHandler { ...@@ -40,23 +40,23 @@ public final class SpawnCommand implements CommandHandler {
try { try {
level = Integer.parseInt(args.get(2)); level = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough } // Fallthrough
case 2: case 2:
try { try {
amount = Integer.parseInt(args.get(1)); amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount")); CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
} // Fallthrough } // Fallthrough
case 1: case 1:
try { try {
id = Integer.parseInt(args.get(0)); id = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.entityId")); CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId"));
} }
break; break;
default: default:
CommandHandler.sendMessage(sender, translate("commands.spawn.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.usage"));
return; return;
} }
...@@ -64,7 +64,7 @@ public final class SpawnCommand implements CommandHandler { ...@@ -64,7 +64,7 @@ public final class SpawnCommand implements CommandHandler {
GadgetData gadgetData = GameData.getGadgetDataMap().get(id); GadgetData gadgetData = GameData.getGadgetDataMap().get(id);
ItemData itemData = GameData.getItemDataMap().get(id); ItemData itemData = GameData.getItemDataMap().get(id);
if (monsterData == null && gadgetData == null && itemData == null) { 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; return;
} }
Scene scene = targetPlayer.getScene(); Scene scene = targetPlayer.getScene();
...@@ -100,7 +100,7 @@ public final class SpawnCommand implements CommandHandler { ...@@ -100,7 +100,7 @@ public final class SpawnCommand implements CommandHandler {
scene.addEntity(entity); 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){ private Position GetRandomPositionInCircle(Position origin, double radius){
......
...@@ -14,9 +14,9 @@ public final class StopCommand implements CommandHandler { ...@@ -14,9 +14,9 @@ public final class StopCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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()) { 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); System.exit(1000);
......
...@@ -19,7 +19,7 @@ public final class TalentCommand implements CommandHandler { ...@@ -19,7 +19,7 @@ public final class TalentCommand implements CommandHandler {
private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) { private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) {
int oldLevel = avatar.getSkillLevelMap().get(talentId); int oldLevel = avatar.getSkillLevelMap().get(talentId);
if (talentLevel < 0 || talentLevel > 15) { if (talentLevel < 0 || talentLevel > 15) {
CommandHandler.sendMessage(sender, translate("commands.talent.lower_16")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.lower_16"));
return; return;
} }
...@@ -40,20 +40,20 @@ public final class TalentCommand implements CommandHandler { ...@@ -40,20 +40,20 @@ public final class TalentCommand implements CommandHandler {
} else if (talentId == depot.getEnergySkill()) { } else if (talentId == depot.getEnergySkill()) {
successMessage = "commands.talent.set_q"; successMessage = "commands.talent.set_q";
} }
CommandHandler.sendMessage(sender, translate(successMessage, talentLevel)); CommandHandler.sendMessage(sender, translate(sender, successMessage, talentLevel));
} }
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
if (args.size() < 1){ if (args.size() < 1){
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
return; return;
} }
...@@ -62,15 +62,15 @@ public final class TalentCommand implements CommandHandler { ...@@ -62,15 +62,15 @@ public final class TalentCommand implements CommandHandler {
String cmdSwitch = args.get(0); String cmdSwitch = args.get(0);
switch (cmdSwitch) { switch (cmdSwitch) {
default -> { default -> {
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
return; return;
} }
case "set" -> { case "set" -> {
if (args.size() < 3) { if (args.size() < 3) {
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
return; return;
} }
try { try {
...@@ -78,13 +78,13 @@ public final class TalentCommand implements CommandHandler { ...@@ -78,13 +78,13 @@ public final class TalentCommand implements CommandHandler {
int newLevel = Integer.parseInt(args.get(2)); int newLevel = Integer.parseInt(args.get(2));
setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel); setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.talent.invalid_skill_id")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.invalid_skill_id"));
return; return;
} }
} }
case "n", "e", "q" -> { case "n", "e", "q" -> {
if (args.size() < 2) { if (args.size() < 2) {
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
return; return;
} }
AvatarSkillDepotData SkillDepot = avatar.getData().getSkillDepot(); AvatarSkillDepotData SkillDepot = avatar.getData().getSkillDepot();
...@@ -97,7 +97,7 @@ public final class TalentCommand implements CommandHandler { ...@@ -97,7 +97,7 @@ public final class TalentCommand implements CommandHandler {
int newLevel = Integer.parseInt(args.get(1)); int newLevel = Integer.parseInt(args.get(1));
setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel); setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.talent.invalid_level")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.invalid_level"));
return; return;
} }
} }
...@@ -105,9 +105,9 @@ public final class TalentCommand implements CommandHandler { ...@@ -105,9 +105,9 @@ public final class TalentCommand implements CommandHandler {
int skillIdNorAtk = avatar.getData().getSkillDepot().getSkills().get(0); int skillIdNorAtk = avatar.getData().getSkillDepot().getSkills().get(0);
int skillIdE = avatar.getData().getSkillDepot().getSkills().get(1); int skillIdE = avatar.getData().getSkillDepot().getSkills().get(1);
int skillIdQ = avatar.getData().getSkillDepot().getEnergySkill(); int skillIdQ = avatar.getData().getSkillDepot().getEnergySkill();
CommandHandler.sendMessage(sender, translate("commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk))); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk)));
CommandHandler.sendMessage(sender, translate("commands.talent.e_skill_id", Integer.toString(skillIdE))); CommandHandler.sendMessage(sender, translate(sender, "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.q_skill_id", Integer.toString(skillIdQ)));
} }
} }
} }
......
...@@ -16,12 +16,12 @@ public final class TeleportAllCommand implements CommandHandler { ...@@ -16,12 +16,12 @@ public final class TeleportAllCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
if (!targetPlayer.getWorld().isMultiplayer()) { if (!targetPlayer.getWorld().isMultiplayer()) {
CommandHandler.sendMessage(sender, translate("commands.teleportAll.error")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.error"));
return; return;
} }
...@@ -33,6 +33,6 @@ public final class TeleportAllCommand implements CommandHandler { ...@@ -33,6 +33,6 @@ public final class TeleportAllCommand implements CommandHandler {
player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos); player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos);
} }
CommandHandler.sendMessage(sender, translate("commands.teleportAll.success")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success"));
} }
} }
...@@ -27,7 +27,7 @@ public final class TeleportCommand implements CommandHandler { ...@@ -27,7 +27,7 @@ public final class TeleportCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
...@@ -42,7 +42,7 @@ public final class TeleportCommand implements CommandHandler { ...@@ -42,7 +42,7 @@ public final class TeleportCommand implements CommandHandler {
try { try {
sceneId = Integer.parseInt(args.get(3)); sceneId = Integer.parseInt(args.get(3));
}catch (NumberFormatException ignored) { }catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough } // Fallthrough
case 3: case 3:
try { try {
...@@ -50,20 +50,20 @@ public final class TeleportCommand implements CommandHandler { ...@@ -50,20 +50,20 @@ public final class TeleportCommand implements CommandHandler {
y = parseRelative(args.get(1), y); y = parseRelative(args.get(1), y);
z = parseRelative(args.get(2), z); z = parseRelative(args.get(2), z);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.teleport.invalid_position")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
} }
break; break;
default: default:
CommandHandler.sendMessage(sender, translate("commands.teleport.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.usage"));
return; return;
} }
Position target_pos = new Position(x, y, z); Position target_pos = new Position(x, y, z);
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos); boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos);
if (!result) { if (!result) {
CommandHandler.sendMessage(sender, translate("commands.teleport.invalid_position")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
} else { } else {
CommandHandler.sendMessage(sender, translate("commands.teleport.success", CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
targetPlayer.getNickname(), Float.toString(x), Float.toString(y), targetPlayer.getNickname(), Float.toString(x), Float.toString(y),
Float.toString(z), Integer.toString(sceneId)) Float.toString(z), Integer.toString(sceneId))
); );
......
...@@ -21,7 +21,7 @@ public class UnlockTowerCommand implements CommandHandler { ...@@ -21,7 +21,7 @@ public class UnlockTowerCommand implements CommandHandler {
unlockFloor(sender, sender.getServer().getTowerScheduleManager() unlockFloor(sender, sender.getServer().getTowerScheduleManager()
.getScheduleFloors()); .getScheduleFloors());
CommandHandler.sendMessage(sender, translate("commands.unlocktower.success")); CommandHandler.sendMessage(sender, translate(sender, "commands.unlocktower.success"));
} }
public void unlockFloor(Player player, List<Integer> floors){ public void unlockFloor(Player player, List<Integer> floors){
......
...@@ -17,7 +17,7 @@ public final class WeatherCommand implements CommandHandler { ...@@ -17,7 +17,7 @@ public final class WeatherCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate("commands.execution.need_target")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return; return;
} }
...@@ -28,17 +28,17 @@ public final class WeatherCommand implements CommandHandler { ...@@ -28,17 +28,17 @@ public final class WeatherCommand implements CommandHandler {
try { try {
climateId = Integer.parseInt(args.get(1)); climateId = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id")); CommandHandler.sendMessage(sender, translate(sender, "commands.weather.invalid_id"));
} }
case 1: case 1:
try { try {
weatherId = Integer.parseInt(args.get(0)); weatherId = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id")); CommandHandler.sendMessage(sender, translate(sender, "commands.weather.invalid_id"));
} }
break; break;
default: default:
CommandHandler.sendMessage(sender, translate("commands.weather.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.weather.usage"));
return; return;
} }
...@@ -47,6 +47,6 @@ public final class WeatherCommand implements CommandHandler { ...@@ -47,6 +47,6 @@ public final class WeatherCommand implements CommandHandler {
targetPlayer.getScene().setWeather(weatherId); targetPlayer.getScene().setWeather(weatherId);
targetPlayer.getScene().setClimate(climate); targetPlayer.getScene().setClimate(climate);
targetPlayer.getScene().broadcastPacket(new PacketSceneAreaWeatherNotify(targetPlayer)); 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)));
} }
} }
...@@ -8,6 +8,7 @@ import emu.grasscutter.utils.Utils; ...@@ -8,6 +8,7 @@ import emu.grasscutter.utils.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import org.bson.Document; import org.bson.Document;
...@@ -28,10 +29,12 @@ public class Account { ...@@ -28,10 +29,12 @@ public class Account {
private String token; private String token;
private String sessionKey; // Session token for dispatch server private String sessionKey; // Session token for dispatch server
private List<String> permissions; private List<String> permissions;
private Locale locale;
@Deprecated @Deprecated
public Account() { public Account() {
this.permissions = new ArrayList<>(); this.permissions = new ArrayList<>();
this.locale = Grasscutter.getConfig().LocaleLanguage;
} }
public String getId() { public String getId() {
...@@ -96,6 +99,14 @@ public class Account { ...@@ -96,6 +99,14 @@ public class Account {
return this.sessionKey; return this.sessionKey;
} }
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
/** /**
* The collection of a player's permissions. * The collection of a player's permissions.
*/ */
...@@ -166,5 +177,10 @@ public class Account { ...@@ -166,5 +177,10 @@ public class Account {
if (!document.containsKey("permissions")) { if (!document.containsKey("permissions")) {
this.addPermission("*"); this.addPermission("*");
} }
// Set account default language as server default language
if (!document.containsKey("locale")) {
this.locale = Grasscutter.getConfig().LocaleLanguage;
}
} }
} }
...@@ -3,6 +3,8 @@ package emu.grasscutter.utils; ...@@ -3,6 +3,8 @@ package emu.grasscutter.utils;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.InputStream; import java.io.InputStream;
...@@ -11,6 +13,7 @@ import java.util.Map; ...@@ -11,6 +13,7 @@ import java.util.Map;
public final class Language { public final class Language {
private final JsonObject languageData; private final JsonObject languageData;
private final String languageCode;
private final Map<String, String> cachedTranslations = new ConcurrentHashMap<>(); private final Map<String, String> cachedTranslations = new ConcurrentHashMap<>();
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>(); private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
...@@ -24,8 +27,21 @@ public final class Language { ...@@ -24,8 +27,21 @@ public final class Language {
return cachedLanguages.get(langCode); return cachedLanguages.get(langCode);
} }
var languageInst = new Language(langCode + ".json", Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage) + ".json"); var fallbackLanguageCode = Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage);
cachedLanguages.put(langCode, languageInst); 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; return languageInst;
} }
...@@ -46,33 +62,89 @@ public final class Language { ...@@ -46,33 +62,89 @@ public final class Language {
} }
} }
/**
* 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.
*/
public static String translate(Player player, String key, Object... args) {
if (player == null) {
return translate(key, args);
}
var langCode = Utils.getLanguageCode(player.getAccount().getLocale());
String translated = Grasscutter.getLanguage(langCode).get(key);
try {
return translated.formatted(args);
} catch (Exception 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. * 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.
*/ */
private Language(String fileName, String fallback) { private Language(InternalLanguageFileStreamDescripter descripter) {
@Nullable JsonObject languageData = null; @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); InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName);
if (file == null) { // Provided fallback language. if (file == null) { // Provided fallback language.
actualLanguageCode = fallbackLanguageCode;
if (cachedLanguages.containsKey(actualLanguageCode)) {
return new InternalLanguageFileStreamDescripter(actualLanguageCode, null);
}
file = Grasscutter.class.getResourceAsStream("/languages/" + fallback); file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback); Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback);
} }
if(file == null) { // Fallback the fallback language. 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"); file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json"); Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
} }
if(file == null) if(file == null)
throw new RuntimeException("Unable to load the primary, fallback, and 'en-US' language files."); throw new RuntimeException("Unable to load the primary, fallback, and 'en-US' language files.");
try { return new InternalLanguageFileStreamDescripter(actualLanguageCode, file);
languageData = Grasscutter.getGsonFactory().fromJson(Utils.readFromInputStream(file), JsonObject.class);
} catch (Exception exception) {
Grasscutter.getLogger().warn("Failed to load language file: " + fileName, exception);
}
this.languageData = languageData;
} }
/** /**
...@@ -107,4 +179,22 @@ public final class Language { ...@@ -107,4 +179,22 @@ public final class Language {
this.cachedTranslations.put(key, result); return result; 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;
}
}
} }
...@@ -188,6 +188,11 @@ ...@@ -188,6 +188,11 @@
"success": "Killed %s's current character.", "success": "Killed %s's current character.",
"description": "Kills the players 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": { "list": {
"success": "There are %s player(s) online:", "success": "There are %s player(s) online:",
"description": "List online players" "description": "List online players"
......
...@@ -188,6 +188,11 @@ ...@@ -188,6 +188,11 @@
"success": "已杀死 %s 当前角色。", "success": "已杀死 %s 当前角色。",
"description": "杀死当前角色" "description": "杀死当前角色"
}, },
"language": {
"current_language": "当前语言是: %s",
"language_changed": "语言切换至: %s",
"description": "显示或切换当前语言"
},
"list": { "list": {
"success": "目前在线人数:%s", "success": "目前在线人数:%s",
"description": "查看所有玩家" "description": "查看所有玩家"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment