- command: replace /lp alias with /lpk (LuckPerms conflict, p.144);
parkour alias kept; docs/changelog/javadoc updated
- lint p.169: restructure last 69 void early-returns into if-blocks and
helpers; ReturnCount is now an error gate (0 violations)
- lint p.170: Throwable->RuntimeException on 3 boundaries; narrow 5
catches to concrete types; document 14 intentional boundary catches
- scheduler p.21: add runTimerAsync to the facade (Bukkit + Folia
backends); MetricsCacheStore and duels go through the facade, no
BukkitRunnable/Bukkit.getScheduler outside scheduler/ (archunit
freeze-store emptied); drop the unverified Folia badge from README
- tracker: mark p.26-29/32-33 done (fixed in fea15e6, verified)
119 lines
4.3 KiB
Java
119 lines
4.3 KiB
Java
package dev.loki.loparkour.config.locale;
|
|
|
|
import dev.loki.loparkour.LoParkour;
|
|
import org.bukkit.configuration.ConfigurationSection;
|
|
import org.bukkit.configuration.file.FileConfiguration;
|
|
import org.bukkit.configuration.file.YamlConfiguration;
|
|
import org.bukkit.plugin.Plugin;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.stream.Stream;
|
|
|
|
/**
|
|
* Loads locale files from disk with validation and auto-fix.
|
|
*/
|
|
public final class LocaleLoader {
|
|
|
|
private LocaleLoader() {
|
|
}
|
|
|
|
/**
|
|
* Load all locale files from the locales/ folder.
|
|
* Returns a map of locale name → FileConfiguration.
|
|
*/
|
|
@NotNull
|
|
public static Map<String, FileConfiguration> loadAll() {
|
|
final Plugin plugin = LoParkour.getPlugin();
|
|
try {
|
|
final FileConfiguration embedded = YamlConfiguration.loadConfiguration(
|
|
new InputStreamReader(plugin.getResource("locales/en.yml"), StandardCharsets.UTF_8));
|
|
|
|
return loadFromDisk(embedded);
|
|
} catch (Exception ex) {
|
|
// Boundary: locale loading must never break enable; disk files may be corrupt.
|
|
plugin.getLogger().severe("Error while loading locale files: " + ex.getMessage());
|
|
return Collections.emptyMap();
|
|
}
|
|
}
|
|
|
|
@NotNull
|
|
private static Map<String, FileConfiguration> loadFromDisk(@NotNull FileConfiguration embedded) throws Exception {
|
|
final Map<String, FileConfiguration> result = new HashMap<>();
|
|
final File folder = LoParkour.getInFolder("locales");
|
|
ensureFolder(folder);
|
|
|
|
try (Stream<Path> stream = Files.list(folder.toPath())) {
|
|
stream.forEach(path -> {
|
|
final File file = path.toFile();
|
|
if (!file.getName().endsWith(".yml")) {
|
|
return;
|
|
}
|
|
|
|
final String locale = file.getName().split("\\.")[0];
|
|
LoParkour.log("Found locale " + locale);
|
|
|
|
final FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
|
validateAndFix(embedded, config, file);
|
|
result.put(locale, config);
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static void ensureFolder(@NotNull File folder) {
|
|
if (!folder.exists()) {
|
|
folder.mkdirs();
|
|
}
|
|
final String[] files = folder.list();
|
|
if (files == null || files.length == 0) {
|
|
final Plugin plugin = LoParkour.getPlugin();
|
|
plugin.saveResource("locales/en.yml", false);
|
|
plugin.saveResource("locales/ru.yml", false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate a locale file against the reference (en.yml) and auto-fix missing keys.
|
|
*/
|
|
private static void validateAndFix(@NotNull FileConfiguration reference,
|
|
@NotNull FileConfiguration locale,
|
|
@NotNull File file) {
|
|
final List<String> refNodes = getChildren(reference);
|
|
final List<String> locNodes = getChildren(locale);
|
|
|
|
boolean modified = false;
|
|
for (final String node : refNodes) {
|
|
if (!locNodes.contains(node)) {
|
|
LoParkour.log("Fixing missing config node %s in %s".formatted(node, file.getName()));
|
|
locale.set(node, reference.get(node));
|
|
modified = true;
|
|
}
|
|
}
|
|
if (modified) {
|
|
try {
|
|
locale.save(file);
|
|
} catch (IOException ex) {
|
|
LoParkour.getPlugin().getLogger().severe(
|
|
"Error saving fixed locale %s — delete and restart — %s".formatted(file.getName(), ex.getMessage()));
|
|
}
|
|
}
|
|
LoParkour.log("Validated locale " + file.getName());
|
|
}
|
|
|
|
@NotNull
|
|
private static List<String> getChildren(@NotNull FileConfiguration config) {
|
|
final ConfigurationSection section = config.getConfigurationSection("");
|
|
return section != null ? new ArrayList<>(section.getKeys(true)) : Collections.emptyList();
|
|
}
|
|
}
|