mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Added ability to load in BundledResource for localization
This commit is contained in:
@@ -8,6 +8,8 @@ import javafx.application.Application;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import org.toop.framework.asset.AssetManager;
|
||||||
|
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -18,8 +20,8 @@ public class App extends Application {
|
|||||||
private static Scene scene;
|
private static Scene scene;
|
||||||
private static StackPane root;
|
private static StackPane root;
|
||||||
|
|
||||||
private Locale currentLocale = AppContext.getLocale();
|
private Locale currentLocale = AppContext.getLocale();
|
||||||
private ResourceBundle resourceBundle = ResourceBundle.getBundle("Localization", currentLocale);
|
private LocalizationAsset loc = AssetManager.get("localization.properties");
|
||||||
|
|
||||||
public static void run(String[] args) {
|
public static void run(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
@@ -30,7 +32,7 @@ public class App extends Application {
|
|||||||
final StackPane root = new StackPane(new MainMenu().getPane());
|
final StackPane root = new StackPane(new MainMenu().getPane());
|
||||||
final Scene scene = new Scene(root);
|
final Scene scene = new Scene(root);
|
||||||
|
|
||||||
stage.setTitle(resourceBundle.getString("windowTitle"));
|
stage.setTitle(loc.getString("windowTitle", currentLocale));
|
||||||
stage.setMinWidth(1080);
|
stage.setMinWidth(1080);
|
||||||
stage.setMinHeight(720);
|
stage.setMinHeight(720);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.toop.app.menu;
|
package org.toop.app.menu;
|
||||||
|
|
||||||
|
import org.toop.framework.asset.AssetManager;
|
||||||
|
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -7,7 +9,7 @@ import java.util.ResourceBundle;
|
|||||||
|
|
||||||
public final class CreditsMenu extends Menu {
|
public final class CreditsMenu extends Menu {
|
||||||
private Locale currentLocale = AppContext.getLocale();
|
private Locale currentLocale = AppContext.getLocale();
|
||||||
private ResourceBundle resourceBundle = ResourceBundle.getBundle("Localization", currentLocale);
|
private LocalizationAsset loc = AssetManager.get("localization.properties");
|
||||||
public CreditsMenu() {
|
public CreditsMenu() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,31 +4,30 @@ import javafx.geometry.Pos;
|
|||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import org.toop.framework.asset.AssetManager;
|
import org.toop.framework.asset.AssetManager;
|
||||||
import org.toop.framework.asset.resources.CssAsset;
|
import org.toop.framework.asset.resources.CssAsset;
|
||||||
import org.toop.framework.asset.resources.ImageAsset;
|
import org.toop.framework.asset.resources.ImageAsset;
|
||||||
|
|
||||||
public final class MainMenu extends Menu {
|
public final class MainMenu extends Menu {
|
||||||
private Locale currentLocale = AppContext.getLocale();
|
private Locale currentLocale = Locale.of("nl");
|
||||||
private ResourceBundle resourceBundle = ResourceBundle.getBundle("Localization", currentLocale);
|
private LocalizationAsset loc = AssetManager.get("localization.properties");
|
||||||
|
|
||||||
public MainMenu() {
|
public MainMenu() {
|
||||||
final Button tictactoe = createButton(resourceBundle.getString("mainMenuSelectTicTacToe"), () -> {});
|
final Button tictactoe = createButton(loc.getString("mainMenuSelectTicTacToe", currentLocale), () -> {});
|
||||||
final Button reversi = createButton(resourceBundle.getString("mainMenuSelectReversi"), () -> {});
|
final Button reversi = createButton(loc.getString("mainMenuSelectReversi", currentLocale), () -> {});
|
||||||
final Button sudoku = createButton(resourceBundle.getString("mainMenuSelectSudoku"), () -> {});
|
final Button sudoku = createButton(loc.getString("mainMenuSelectSudoku", currentLocale), () -> {});
|
||||||
final Button battleship = createButton(resourceBundle.getString("mainMenuSelectBattleship"), () -> {});
|
final Button battleship = createButton(loc.getString("mainMenuSelectBattleship", currentLocale), () -> {});
|
||||||
final Button other = createButton(resourceBundle.getString("mainMenuSelectOther"), () -> {});
|
final Button other = createButton(loc.getString("mainMenuSelectOther", currentLocale), () -> {});
|
||||||
|
|
||||||
final VBox gamesBox = new VBox(tictactoe, reversi, sudoku, battleship, other);
|
final VBox gamesBox = new VBox(tictactoe, reversi, sudoku, battleship, other);
|
||||||
gamesBox.setAlignment(Pos.TOP_CENTER);
|
gamesBox.setAlignment(Pos.TOP_CENTER);
|
||||||
|
|
||||||
final Button credits = createButton(resourceBundle.getString("mainMenuSelectCredits"), () -> {});
|
final Button credits = createButton(loc.getString("mainMenuSelectCredits", currentLocale), () -> {});
|
||||||
final Button options = createButton(resourceBundle.getString("mainMenuSelectOptions"), () -> {});
|
final Button options = createButton(loc.getString("mainMenuSelectOptions", currentLocale), () -> {});
|
||||||
final Button quit = createButton(resourceBundle.getString("mainMenuSelectQuit"), () -> {});
|
final Button quit = createButton(loc.getString("mainMenuSelectQuit", currentLocale), () -> {});
|
||||||
|
|
||||||
final VBox creditsBox = new VBox(credits, options, quit);
|
final VBox creditsBox = new VBox(credits, options, quit);
|
||||||
creditsBox.setAlignment(Pos.BOTTOM_CENTER);
|
creditsBox.setAlignment(Pos.BOTTOM_CENTER);
|
||||||
|
|||||||
@@ -6,16 +6,19 @@ import javafx.animation.FadeTransition;
|
|||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.toop.framework.asset.Asset;
|
||||||
|
import org.toop.framework.asset.AssetManager;
|
||||||
|
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
public abstract class Menu {
|
public abstract class Menu {
|
||||||
protected Pane pane;
|
protected Pane pane;
|
||||||
public Pane getPane() { return pane; }
|
public Pane getPane() { return pane; }
|
||||||
private Locale currentLocale = AppContext.getLocale();
|
private Locale currentLocale = AppContext.getLocale();
|
||||||
private ResourceBundle resourceBundle = ResourceBundle.getBundle("Localization", currentLocale);
|
private LocalizationAsset loc = AssetManager.get("localization.properties");
|
||||||
|
|
||||||
public void fadeBackgroundImage(String imagePath, float from, float to, float milliseconds) {
|
public void fadeBackgroundImage(String imagePath, float from, float to, float milliseconds) {
|
||||||
final FadeTransition fade = new FadeTransition(Duration.millis(milliseconds), App.getRoot());
|
final FadeTransition fade = new FadeTransition(Duration.millis(milliseconds), App.getRoot());
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.toop.app.menu;
|
package org.toop.app.menu;
|
||||||
|
|
||||||
|
import org.toop.framework.asset.AssetManager;
|
||||||
|
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -7,7 +9,7 @@ import java.util.ResourceBundle;
|
|||||||
|
|
||||||
public final class OptionsMenu extends Menu {
|
public final class OptionsMenu extends Menu {
|
||||||
private Locale currentLocale = AppContext.getLocale();
|
private Locale currentLocale = AppContext.getLocale();
|
||||||
private ResourceBundle resourceBundle = ResourceBundle.getBundle("Localization", currentLocale);
|
private LocalizationAsset loc = AssetManager.get("localization.properties");
|
||||||
public OptionsMenu() {
|
public OptionsMenu() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,29 +10,30 @@ import javafx.scene.text.Text;
|
|||||||
import org.toop.app.App;
|
import org.toop.app.App;
|
||||||
import org.toop.framework.asset.AssetManager;
|
import org.toop.framework.asset.AssetManager;
|
||||||
import org.toop.framework.asset.resources.CssAsset;
|
import org.toop.framework.asset.resources.CssAsset;
|
||||||
|
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public final class QuitMenu extends Menu {
|
public final class QuitMenu extends Menu {
|
||||||
private Locale currentLocale = AppContext.getLocale();
|
private Locale currentLocale = AppContext.getLocale();
|
||||||
private ResourceBundle resourceBundle = ResourceBundle.getBundle("Localization", currentLocale);
|
private LocalizationAsset loc = AssetManager.get("localization.properties");
|
||||||
public QuitMenu() {
|
public QuitMenu() {
|
||||||
final Region background = new Region();
|
final Region background = new Region();
|
||||||
background.getStyleClass().add("quit-background");
|
background.getStyleClass().add("quit-background");
|
||||||
background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||||
|
|
||||||
final Text sure = new Text(resourceBundle.getString("quitMenuTextSure"));
|
final Text sure = new Text(loc.getString("quitMenuTextSure", currentLocale));
|
||||||
sure.getStyleClass().add("quit-text");
|
sure.getStyleClass().add("quit-text");
|
||||||
|
|
||||||
final Button yes = new Button(resourceBundle.getString("quitMenuButtonYes"));
|
final Button yes = new Button(loc.getString("quitMenuButtonYes", currentLocale));
|
||||||
yes.getStyleClass().add("quit-button");
|
yes.getStyleClass().add("quit-button");
|
||||||
yes.setOnAction(_ -> {
|
yes.setOnAction(_ -> {
|
||||||
App.quit();
|
App.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
final Button no = new Button(resourceBundle.getString("quitMenuButtonNo"));
|
final Button no = new Button(loc.getString("quitMenuButtonNo", currentLocale));
|
||||||
no.getStyleClass().add("quit-button");
|
no.getStyleClass().add("quit-button");
|
||||||
no.setOnAction(_ -> {
|
no.setOnAction(_ -> {
|
||||||
App.pop();
|
App.pop();
|
||||||
|
|||||||
@@ -3,30 +3,27 @@ package org.toop.framework.asset;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.toop.framework.asset.events.AssetEvents;
|
import org.toop.framework.asset.events.AssetEvents;
|
||||||
import org.toop.framework.asset.resources.BaseResource;
|
import org.toop.framework.asset.resources.*;
|
||||||
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.reflections.Reflections;
|
|
||||||
import org.toop.framework.asset.resources.FileExtension;
|
|
||||||
import org.toop.framework.asset.resources.FontAsset;
|
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
|
||||||
|
|
||||||
public class AssetLoader {
|
public class AssetLoader {
|
||||||
private static final Logger logger = LogManager.getLogger(AssetLoader.class);
|
private static final Logger logger = LogManager.getLogger(AssetLoader.class);
|
||||||
private final List<Asset<? extends BaseResource>> assets = new CopyOnWriteArrayList<>();
|
private static final List<Asset<? extends BaseResource>> assets = new CopyOnWriteArrayList<>();
|
||||||
private final Map<String, Function<File, ? extends BaseResource>> registry = new ConcurrentHashMap<>();
|
private final Map<String, Function<File, ? extends BaseResource>> registry = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private volatile int loadedCount = 0;
|
private final AtomicInteger loadedCount = new AtomicInteger(0);
|
||||||
private volatile int totalCount = 0;
|
private int totalCount = 0;
|
||||||
|
|
||||||
public AssetLoader(File rootFolder) {
|
public AssetLoader(File rootFolder) {
|
||||||
autoRegisterResources(); // make sure resources are registered!
|
autoRegisterResources();
|
||||||
|
|
||||||
List<File> foundFiles = new ArrayList<>();
|
List<File> foundFiles = new ArrayList<>();
|
||||||
fileSearcher(rootFolder, foundFiles);
|
fileSearcher(rootFolder, foundFiles);
|
||||||
this.totalCount = foundFiles.size();
|
this.totalCount = foundFiles.size();
|
||||||
@@ -38,19 +35,19 @@ public class AssetLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public double getProgress() {
|
public double getProgress() {
|
||||||
return (this.totalCount == 0) ? 1.0 : (this.loadedCount / (double) this.totalCount);
|
return (totalCount == 0) ? 1.0 : (loadedCount.get() / (double) totalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLoadedCount() {
|
public int getLoadedCount() {
|
||||||
return this.loadedCount;
|
return loadedCount.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTotalCount() {
|
public int getTotalCount() {
|
||||||
return this.totalCount;
|
return totalCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Asset<? extends BaseResource>> getAssets() {
|
public List<Asset<? extends BaseResource>> getAssets() {
|
||||||
return new ArrayList<>(this.assets);
|
return new ArrayList<>(assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends BaseResource> void register(String extension, Function<File, T> factory) {
|
public <T extends BaseResource> void register(String extension, Function<File, T> factory) {
|
||||||
@@ -59,8 +56,7 @@ public class AssetLoader {
|
|||||||
|
|
||||||
private <T extends BaseResource> T resourceMapper(File file, Class<T> type) {
|
private <T extends BaseResource> T resourceMapper(File file, Class<T> type) {
|
||||||
String ext = getExtension(file.getName());
|
String ext = getExtension(file.getName());
|
||||||
Function<File, ? extends BaseResource> factory = this.registry.get(ext);
|
Function<File, ? extends BaseResource> factory = registry.get(ext);
|
||||||
|
|
||||||
if (factory == null) return null;
|
if (factory == null) return null;
|
||||||
|
|
||||||
BaseResource resource = factory.apply(file);
|
BaseResource resource = factory.apply(file);
|
||||||
@@ -70,32 +66,49 @@ public class AssetLoader {
|
|||||||
"File " + file.getName() + " is not of type " + type.getSimpleName()
|
"File " + file.getName() + " is not of type " + type.getSimpleName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return type.cast(resource);
|
return type.cast(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loader(List<File> files) {
|
private void loader(List<File> files) {
|
||||||
|
Map<String, BundledResource> bundledResources = new HashMap<>();
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
BaseResource resource = resourceMapper(file, BaseResource.class);
|
BaseResource resource = resourceMapper(file, BaseResource.class);
|
||||||
if (resource != null) {
|
switch (resource) {
|
||||||
Asset<? extends BaseResource> asset = new Asset<>(file.getName(), resource);
|
case null -> {
|
||||||
this.assets.add(asset);
|
continue;
|
||||||
|
}
|
||||||
if (resource instanceof FontAsset fontAsset) {
|
case BundledResource br -> {
|
||||||
fontAsset.load();
|
String key = resource.getClass().getName() + ":" + br.getBaseName();
|
||||||
|
if (bundledResources.containsKey(key)) {
|
||||||
|
bundledResources.get(key).loadFile(file);
|
||||||
|
resource = (BaseResource) bundledResources.get(key);
|
||||||
|
} else {
|
||||||
|
br.loadFile(file);
|
||||||
|
bundledResources.put(key, br);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FontAsset fontAsset -> fontAsset.load();
|
||||||
|
default -> {
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Loaded {} from {}", resource.getClass().getSimpleName(), file.getAbsolutePath());
|
|
||||||
|
|
||||||
this.loadedCount++; // TODO: Fix non atmomic operation
|
|
||||||
new EventFlow()
|
|
||||||
.addPostEvent(new AssetEvents.LoadingProgressUpdate(this.loadedCount, this.totalCount))
|
|
||||||
.postEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseResource finalResource = resource;
|
||||||
|
boolean alreadyAdded = assets.stream()
|
||||||
|
.anyMatch(a -> a.getResource() == finalResource);
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
assets.add(new Asset<>(file.getName(), resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Loaded {} from {}", resource.getClass().getSimpleName(), file.getAbsolutePath());
|
||||||
|
loadedCount.incrementAndGet();
|
||||||
|
new EventFlow()
|
||||||
|
.addPostEvent(new AssetEvents.LoadingProgressUpdate(loadedCount.get(), totalCount))
|
||||||
|
.postEvent();
|
||||||
}
|
}
|
||||||
logger.info("Loaded {} assets", files.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void fileSearcher(final File folder, List<File> foundFiles) {
|
private void fileSearcher(final File folder, List<File> foundFiles) {
|
||||||
for (File fileEntry : Objects.requireNonNull(folder.listFiles())) {
|
for (File fileEntry : Objects.requireNonNull(folder.listFiles())) {
|
||||||
if (fileEntry.isDirectory()) {
|
if (fileEntry.isDirectory()) {
|
||||||
@@ -114,7 +127,7 @@ public class AssetLoader {
|
|||||||
if (!cls.isAnnotationPresent(FileExtension.class)) continue;
|
if (!cls.isAnnotationPresent(FileExtension.class)) continue;
|
||||||
FileExtension annotation = cls.getAnnotation(FileExtension.class);
|
FileExtension annotation = cls.getAnnotation(FileExtension.class);
|
||||||
for (String ext : annotation.value()) {
|
for (String ext : annotation.value()) {
|
||||||
this.registry.put(ext, file -> {
|
registry.put(ext, file -> {
|
||||||
try {
|
try {
|
||||||
return cls.getConstructor(File.class).newInstance(file);
|
return cls.getConstructor(File.class).newInstance(file);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -125,6 +138,13 @@ public class AssetLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getBaseName(String fileName) {
|
||||||
|
int underscoreIndex = fileName.indexOf('_');
|
||||||
|
int dotIndex = fileName.lastIndexOf('.');
|
||||||
|
if (underscoreIndex > 0) return fileName.substring(0, underscoreIndex);
|
||||||
|
return fileName.substring(0, dotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public static String getExtension(String name) {
|
public static String getExtension(String name) {
|
||||||
int i = name.lastIndexOf('.');
|
int i = name.lastIndexOf('.');
|
||||||
return (i > 0) ? name.substring(i + 1) : "";
|
return (i > 0) ? name.substring(i + 1) : "";
|
||||||
|
|||||||
@@ -61,4 +61,22 @@ public class AssetManager {
|
|||||||
assets.put(asset.getName(), asset);
|
assets.put(asset.getName(), asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public static LocalizationAsset getLocalization(Locale locale) {
|
||||||
|
// for (Asset<? extends BaseResource> asset : assets.values()) {
|
||||||
|
// if (asset.getResource() instanceof LocalizationAsset locAsset) {
|
||||||
|
// if (!locAsset.isLoaded()) locAsset.load();
|
||||||
|
// if (locAsset.hasLocale(locale)) return locAsset;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // fallback NL
|
||||||
|
// Locale fallback = Locale.forLanguageTag("nl");
|
||||||
|
// for (Asset<? extends BaseResource> asset : assets.values()) {
|
||||||
|
// if (asset.getResource() instanceof LocalizationAsset locAsset) {
|
||||||
|
// if (!locAsset.isLoaded()) locAsset.load();
|
||||||
|
// if (locAsset.hasLocale(fallback)) return locAsset;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// throw new NoSuchElementException("No localization asset available for locale: " + locale + " or fallback: nl");
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.toop.framework.asset.resources;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public interface BundledResource {
|
||||||
|
/**
|
||||||
|
* Load or merge an additional file into this resource.
|
||||||
|
*/
|
||||||
|
void loadFile(File file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a base name for grouping multiple files into this single resource.
|
||||||
|
*/
|
||||||
|
String getBaseName();
|
||||||
|
}
|
||||||
@@ -5,9 +5,10 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@FileExtension({"properties"})
|
@FileExtension({"properties"})
|
||||||
public class LocalizationAsset extends BaseResource implements LoadableResource {
|
public class LocalizationAsset extends BaseResource implements LoadableResource, BundledResource {
|
||||||
private final Map<Locale, ResourceBundle> bundles = new HashMap<>();
|
private final Map<Locale, ResourceBundle> bundles = new HashMap<>();
|
||||||
private boolean isLoaded = false;
|
private boolean isLoaded = false;
|
||||||
|
private final Locale fallback = Locale.forLanguageTag("");
|
||||||
|
|
||||||
public LocalizationAsset(File file) {
|
public LocalizationAsset(File file) {
|
||||||
super(file);
|
super(file);
|
||||||
@@ -15,53 +16,57 @@ public class LocalizationAsset extends BaseResource implements LoadableResource
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
// Convention: file names like messages_en.properties, ui_de.properties, etc.
|
loadFile(getFile());
|
||||||
String baseName = getBaseName(getFile().getName());
|
isLoaded = true;
|
||||||
|
|
||||||
// Scan the parent folder for all matching *.properties with same basename
|
|
||||||
File folder = getFile().getParentFile();
|
|
||||||
File[] files = folder.listFiles((dir, name) ->
|
|
||||||
name.startsWith(baseName) && name.endsWith(".properties"));
|
|
||||||
|
|
||||||
if (files != null) {
|
|
||||||
for (File f : files) {
|
|
||||||
Locale locale = extractLocale(f.getName(), baseName);
|
|
||||||
try (InputStreamReader reader =
|
|
||||||
new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8)) {
|
|
||||||
this.bundles.put(locale, new PropertyResourceBundle(reader));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Failed to load localization file: " + f, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unload() {
|
public void unload() {
|
||||||
this.bundles.clear();
|
bundles.clear();
|
||||||
this.isLoaded = false;
|
isLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLoaded() {
|
public boolean isLoaded() {
|
||||||
return this.isLoaded;
|
return isLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getString(String key, Locale locale) {
|
public String getString(String key, Locale locale) {
|
||||||
ResourceBundle bundle = this.bundles.get(locale);
|
Locale target = findBestLocale(locale);
|
||||||
|
ResourceBundle bundle = bundles.get(target);
|
||||||
if (bundle == null) throw new MissingResourceException(
|
if (bundle == null) throw new MissingResourceException(
|
||||||
"No bundle for locale: " + locale, getClass().getName(), key);
|
"No bundle for locale: " + target, getClass().getName(), key);
|
||||||
return bundle.getString(key);
|
return bundle.getString(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasLocale(Locale locale) {
|
private Locale findBestLocale(Locale locale) {
|
||||||
return this.bundles.containsKey(locale);
|
if (bundles.containsKey(locale)) return locale;
|
||||||
|
for (Locale l : bundles.keySet()) {
|
||||||
|
if (l.getLanguage().equals(locale.getLanguage())) return l;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Locale> getAvailableLocales() {
|
public Set<Locale> getAvailableLocales() {
|
||||||
return Collections.unmodifiableSet(this.bundles.keySet());
|
return Collections.unmodifiableSet(bundles.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadFile(File file) {
|
||||||
|
String baseName = getBaseName(file.getName());
|
||||||
|
try (InputStreamReader reader =
|
||||||
|
new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
|
||||||
|
Locale locale = extractLocale(file.getName(), baseName);
|
||||||
|
bundles.put(locale, new PropertyResourceBundle(reader));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to load localization file: " + file, e);
|
||||||
|
}
|
||||||
|
isLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBaseName() {
|
||||||
|
return getBaseName(getFile().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBaseName(String fileName) {
|
private String getBaseName(String fileName) {
|
||||||
@@ -80,6 +85,6 @@ public class LocalizationAsset extends BaseResource implements LoadableResource
|
|||||||
String localePart = fileName.substring(underscoreIndex + 1, dotIndex);
|
String localePart = fileName.substring(underscoreIndex + 1, dotIndex);
|
||||||
return Locale.forLanguageTag(localePart.replace('_', '-'));
|
return Locale.forLanguageTag(localePart.replace('_', '-'));
|
||||||
}
|
}
|
||||||
return Locale.getDefault(); // fallback
|
return fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user