Changed bundled resources to use static base name instead.

Added options menu with selectable language
This commit is contained in:
lieght
2025-10-03 03:19:38 +02:00
parent 1dd345a290
commit 547ea55300
13 changed files with 228 additions and 33 deletions

View File

@@ -158,6 +158,7 @@ public class ResourceLoader {
Map<String, BundledResource> bundledResources = new HashMap<>();
for (File file : files) {
boolean skipAdd = false;
BaseResource resource = resourceMapper(file, BaseResource.class);
switch (resource) {
case null -> {
@@ -165,13 +166,11 @@ public class ResourceLoader {
}
case BundledResource br -> {
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);
}
if (!bundledResources.containsKey(key)) {bundledResources.put(key, br);}
bundledResources.get(key).loadFile(file);
resource = (BaseResource) bundledResources.get(key);
assets.add(new ResourceMeta<>(br.getBaseName(), resource));
skipAdd = true;
}
case PreloadResource pr -> pr.load();
default -> {
@@ -181,7 +180,7 @@ public class ResourceLoader {
BaseResource finalResource = resource;
boolean alreadyAdded = assets.stream()
.anyMatch(a -> a.getResource() == finalResource);
if (!alreadyAdded) {
if (!alreadyAdded && !skipAdd) {
assets.add(new ResourceMeta<>(file.getName(), resource));
}

View File

@@ -8,33 +8,90 @@ import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* Represents a localization resource asset that loads and manages property files
* containing key-value pairs for different locales.
* <p>
* This class implements {@link LoadableResource} to support loading/unloading
* and {@link BundledResource} to represent resources that can contain multiple
* localized bundles.
* </p>
* <p>
* Files handled by this class must have the {@code .properties} extension,
* optionally with a locale suffix, e.g., {@code messages_en_US.properties}.
* </p>
*
* <p>
* Example usage:
* <pre>{@code
* LocalizationAsset asset = new LocalizationAsset(new File("messages_en_US.properties"));
* asset.load();
* String greeting = asset.getString("hello", Locale.US);
* }</pre>
* </p>
*/
@FileExtension({"properties"})
public class LocalizationAsset extends BaseResource implements LoadableResource, BundledResource {
private final Map<Locale, ResourceBundle> bundles = new HashMap<>();
private boolean isLoaded = false;
private final Locale fallback = Locale.forLanguageTag("");
/** Map of loaded resource bundles, keyed by locale. */
private final Map<Locale, ResourceBundle> bundles = new HashMap<>();
/** Flag indicating whether this asset has been loaded. */
private boolean isLoaded = false;
/** Basename of the given asset */
private final String baseName = "localization";
/** Fallback locale used when no matching locale is found. */
private final Locale fallback = Locale.forLanguageTag("en_US");
/**
* Constructs a new LocalizationAsset for the specified file.
*
* @param file the property file to load
*/
public LocalizationAsset(File file) {
super(file);
}
/**
* Loads the resource file into memory and prepares localized bundles.
*/
@Override
public void load() {
loadFile(getFile());
isLoaded = true;
}
/**
* Unloads all loaded resource bundles, freeing memory.
*/
@Override
public void unload() {
bundles.clear();
isLoaded = false;
}
/**
* Checks whether this asset has been loaded.
*
* @return {@code true} if the asset is loaded, {@code false} otherwise
*/
@Override
public boolean isLoaded() {
return isLoaded;
}
/**
* Retrieves a localized string for the given key and locale.
* If an exact match for the locale is not found, a fallback
* matching the language or the default locale will be used.
*
* @param key the key of the string
* @param locale the desired locale
* @return the localized string
* @throws MissingResourceException if no resource bundle is available for the locale
*/
public String getString(String key, Locale locale) {
Locale target = findBestLocale(locale);
ResourceBundle bundle = bundles.get(target);
@@ -43,6 +100,13 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
return bundle.getString(key);
}
/**
* Finds the best matching locale among loaded bundles.
* Prefers an exact match, then language-only match, then fallback.
*
* @param locale the desired locale
* @return the best matching locale
*/
private Locale findBestLocale(Locale locale) {
if (bundles.containsKey(locale)) return locale;
for (Locale l : bundles.keySet()) {
@@ -51,13 +115,24 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
return fallback;
}
/**
* Returns an unmodifiable set of all locales for which bundles are loaded.
*
* @return available locales
*/
public Set<Locale> getAvailableLocales() {
return Collections.unmodifiableSet(bundles.keySet());
}
/**
* Loads a specific property file as a resource bundle.
* The locale is extracted from the file name if present.
*
* @param file the property file to load
* @throws RuntimeException if the file cannot be read
*/
@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);
@@ -68,20 +143,40 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
isLoaded = true;
}
/**
* Returns the base name of the underlying file (without locale or extension).
*
* @return the base name
*/
@Override
public String getBaseName() {
return getBaseName(getFile().getName());
return this.baseName;
}
private 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);
}
// /**
// * Extracts the base name from a file name.
// *
// * @param fileName the file name
// * @return base name without locale or extension
// */
// private String getBaseName(String fileName) {
// int dotIndex = fileName.lastIndexOf('.');
// String nameWithoutExtension = (dotIndex > 0) ? fileName.substring(0, dotIndex) : fileName;
//
// int underscoreIndex = nameWithoutExtension.indexOf('_');
// if (underscoreIndex > 0) {
// return nameWithoutExtension.substring(0, underscoreIndex);
// }
// return nameWithoutExtension;
// }
/**
* Extracts a locale from a file name based on the pattern "base_LOCALE.properties".
*
* @param fileName the file name
* @param baseName the base name
* @return extracted locale, or fallback if none found
*/
private Locale extractLocale(String fileName, String baseName) {
int underscoreIndex = fileName.indexOf('_');
int dotIndex = fileName.lastIndexOf('.');

View File

@@ -66,4 +66,9 @@ public interface BundledResource {
* @return the base name used to identify this bundled resource
*/
String getBaseName();
// /**
// Returns the name
// */
// String getDefaultName();
}