多语言系统
概述
多语言系统支持游戏界面的国际化,允许玩家根据自己的语言偏好查看翻译后的文本。系统支持中文、英文等多种语言,并提供占位符替换功能。
核心类
LanguageManager(语言管理器)
路径:cn.enderrealm.disaster.lang.LanguageManager
语言管理器负责加载语言文件、获取翻译文本和处理占位符替换。
java
public class LanguageManager {
private static final String DEFAULT_LANGUAGE = "en_us";
private final Map<String, YamlConfiguration> languageFiles = new HashMap<>();
private final File dataFolder;
private String defaultLanguage = DEFAULT_LANGUAGE;
public LanguageManager(File dataFolder, String configDefaultLanguage) {
this.dataFolder = dataFolder;
if (configDefaultLanguage != null && !configDefaultLanguage.isEmpty()) {
this.defaultLanguage = configDefaultLanguage;
}
loadLanguages();
}
}语言加载
java
private void loadLanguages() {
File langFolder = new File(dataFolder, "lang");
if (!langFolder.exists()) {
langFolder.mkdirs();
return;
}
// 加载所有语言文件
File[] files = langFolder.listFiles((dir, name) -> name.endsWith(".yml"));
if (files != null) {
for (File file : files) {
String langCode = file.getName().replace(".yml", "");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
languageFiles.put(langCode.toLowerCase(), config);
}
}
}文本获取
java
public String getText(String key, Player player, Object... args) {
// 1. 获取玩家语言
String clientLang = player != null ? player.getLocale().toLowerCase() : defaultLanguage;
// 2. 尝试获取完整语言代码对应的配置
YamlConfiguration langConfig = languageFiles.get(clientLang);
// 3. 如果找不到,尝试使用语言的主要部分
if (langConfig == null && clientLang.contains("_")) {
String mainLang = clientLang.split("_")[0];
for (String availableLang : languageFiles.keySet()) {
if (availableLang.startsWith(mainLang)) {
langConfig = languageFiles.get(availableLang);
break;
}
}
}
// 4. 如果仍然没有找到,使用配置的默认语言
if (langConfig == null) {
langConfig = languageFiles.get(defaultLanguage.toLowerCase());
}
// 5. 如果配置的默认语言不存在,使用硬编码的默认语言
if (langConfig == null) {
langConfig = languageFiles.get(DEFAULT_LANGUAGE.toLowerCase());
}
// 6. 获取翻译文本
if (langConfig != null) {
String text = langConfig.getString(key);
if (text != null) {
// 7. 替换占位符
if (args != null && args.length > 0) {
for (int i = 0; i < args.length; i++) {
text = text.replace("{" + i + "}", args[i] != null ? args[i].toString() : "");
}
}
return text;
}
}
// 8. 如果所有尝试都失败了,返回 key 本身
return key;
}文本列表获取
java
public List<String> getTextList(String key, Player player) {
// 类似 getText 的逻辑,但返回列表
// ...
if (langConfig != null) {
List<String> textList = langConfig.getStringList(key);
if (textList != null && !textList.isEmpty()) {
return textList;
}
}
return new ArrayList<>();
}语言文件结构
文件位置
plugins/disaster/lang/
├── en_us.yml # 英语(美国)
├── zh_cn.yml # 中文(简体)
└── zh_tw.yml # 中文(繁体)文件格式
yaml
# en_us.yml
# 通用消息
no-permission: "§cYou don't have permission to use this command."
already-in-room: "§cYou are already in a room."
not-in-room: "§cYou are not in a room."
room-created: "§aRoom created successfully."
room-create-failed: "§cFailed to create room."
left-room: "§aYou have left the room."
# 房间消息
player-join-message: "§a{0} joined the room ({1}/{2})"
player-leave-message: "§c{0} left the room ({1}/{2})"
countdown-subtitle: "§eGame starts in {0} seconds"
countdown-cancelled: "§cCountdown cancelled - not enough players"
game-started: "§aGame started!"
# 游戏消息
game-start-title: "§6Disaster"
game-map-subtitle: "§7Map: {0}"
game-time-remaining: "§aTime: {0}"
game-over-title: "§cGame Over"
player-victory-subtitle: "§aYou survived!"
player-defeat-subtitle: "§cYou were eliminated"
# 灾难消息
disaster-countdown: "§cDisaster in {0}s"
disaster-zombie_apocalypse: "§4Zombie Apocalypse"
disaster-zombie_apocalypse-desc: "Zombies spawn around players every 30 seconds"
disaster-meteor_shower: "§6Meteor Shower"
disaster-meteor_shower-desc: "Fireballs rain from the sky every 10 seconds"
disaster-lightning: "§eLightning Storm"
disaster-lightning-desc: "Lightning strikes near players every 20 seconds"
# ... 更多灾难
# 记分板
scoreboard-title: "§6§lDisaster"
scoreboard-items:
- "§7{0}"
- "§fTime: §a{1}"
- "§fSurvivors: §e{2}"
- "§fDisaster: §c{3}"
scoreboard-no-disasters: "§7None"
# 物品
quit-item-name: "§cQuit Room"
mysterious-potion-name: "§dMysterious Potion"
mysterious-potion-lore: "§7Use to get random effects"yaml
# zh_cn.yml
# 通用消息
no-permission: "§c你没有权限使用此命令。"
already-in-room: "§c你已经在房间中。"
not-in-room: "§c你不在房间中。"
room-created: "§a房间创建成功。"
room-create-failed: "§c房间创建失败。"
left-room: "§a你已离开房间。"
# 房间消息
player-join-message: "§a{0} 加入了房间 ({1}/{2})"
player-leave-message: "§c{0} 离开了房间 ({1}/{2})"
countdown-subtitle: "§e游戏将在 {0} 秒后开始"
countdown-cancelled: "§c倒计时取消 - 玩家数量不足"
game-started: "§a游戏开始!"
# 游戏消息
game-start-title: "§6灾难生存"
game-map-subtitle: "§7地图: {0}"
game-time-remaining: "§a时间: {0}"
game-over-title: "§c游戏结束"
player-victory-subtitle: "§a你存活了下来!"
player-defeat-subtitle: "§c你已被淘汰"
# 灾难消息
disaster-countdown: "§c灾难将在 {0} 秒后爆发"
disaster-zombie_apocalypse: "§4僵尸启示录"
disaster-zombie_apocalypse-desc: "每 30 秒在玩家周围生成僵尸"
disaster-meteor_shower: "§6流星雨"
disaster-meteor_shower-desc: "每 10 秒从天空降下火球"
disaster-lightning: "§e闪电风暴"
disaster-lightning-desc: "每 20 秒在玩家附近劈下闪电"
# ... 更多灾难
# 记分板
scoreboard-title: "§6§l灾难生存"
scoreboard-items:
- "§7{0}"
- "§f时间: §a{1}"
- "§f存活: §e{2}"
- "§f灾难: §c{3}"
scoreboard-no-disasters: "§7无"
# 物品
quit-item-name: "§c退出房间"
mysterious-potion-name: "§d神秘药水"
mysterious-potion-lore: "§7使用后随机获得效果"占位符系统
占位符格式
占位符使用 {数字} 格式,从 0 开始:
yaml
player-join-message: "§a{0} 加入了房间 ({1}/{2})"使用示例
java
// 获取翻译文本并替换占位符
String message = plugin.getLanguageManager().getText("player-join-message", player,
player.getName(), // {0}
String.valueOf(players.size()), // {1}
String.valueOf(maxPlayers) // {2}
);
player.sendMessage(message);常用占位符
| 占位符 | 描述 | 示例 |
|---|---|---|
{0} | 玩家名称 | Steve |
{1} | 当前玩家数 | 3 |
{2} | 最大玩家数 | 8 |
{3} | 灾难名称 | 僵尸启示录 |
{4} | 时间 | 02:30 |
{5} | 地图名称 | Map_01 |
语言选择机制
选择流程
获取玩家语言
javaString clientLang = player != null ? player.getLocale().toLowerCase() : defaultLanguage;尝试完整语言代码
javaYamlConfiguration langConfig = languageFiles.get(clientLang);尝试语言主要部分
javaif (langConfig == null && clientLang.contains("_")) { String mainLang = clientLang.split("_")[0]; for (String availableLang : languageFiles.keySet()) { if (availableLang.startsWith(mainLang)) { langConfig = languageFiles.get(availableLang); break; } } }使用配置的默认语言
javaif (langConfig == null) { langConfig = languageFiles.get(defaultLanguage.toLowerCase()); }使用硬编码的默认语言
javaif (langConfig == null) { langConfig = languageFiles.get(DEFAULT_LANGUAGE.toLowerCase()); }
语言映射示例
| 玩家语言 | 匹配结果 |
|---|---|
zh_cn | zh_cn.yml |
zh_tw | zh_tw.yml |
zh | zh_cn.yml(第一个匹配的 zh 开头语言) |
en_us | en_us.yml |
en_gb | en_us.yml(第一个匹配的 en 开头语言) |
fr_fr | 使用默认语言 |
配置示例
yaml
# 插件配置
Language: "zh_cn" # 默认语言