Refactor Localization Service

- Updated LocalizationService interface to load localization data from a Path instead of InputStream.
- Enhanced LocalizationServiceImpl to handle loading and saving of localization data from directories.
- Introduced LocalizationLanguage and LocalizationMetadata classes to encapsulate language entries and metadata.
- Refactored Localizations class to manage language files and metadata more effectively.
- Added unit tests for loading localizations from directory and verifying language translations.
- Created YAML files for English and German languages along with a metadata file for localization information.
This commit is contained in:
extio-de
2026-05-15 16:32:18 +02:00
parent 99cbee4515
commit f54e07b984
14 changed files with 470 additions and 313 deletions

View File

@@ -2,11 +2,11 @@ package de.extio.game_engine.i18n;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -14,25 +14,36 @@ import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import de.extio.game_engine.resource.StaticResourceService;
import de.extio.game_engine.storage.StorageService;
class LocalizationManagerTest {
@Mock
private StorageService storageService;
@Mock
private StaticResourceService staticResourceService;
private LocalizationService localizationManager;
private LocalizationServiceImpl localizationManager;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
this.localizationManager = new LocalizationServiceImpl(storageService);
this.localizationManager = new LocalizationServiceImpl(storageService, staticResourceService);
}
private static LocalizationLanguage language(final String shortName, final Map<String, String> entries) {
final var language = new LocalizationLanguage(shortName);
language.setEntries(new LinkedHashMap<>(entries));
return language;
}
@Test
@@ -44,40 +55,31 @@ class LocalizationManagerTest {
@Test
void testResetEntries() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
this.localizationManager.setLanguage("en");
this.localizationManager.resetEntries();
assertTrue(localizations.getLanguages().get("en").isEmpty());
assertTrue(localizations.getLanguageEntries("en").isEmpty());
}
@Test
void testLoadLocalizations() {
Localizations localizationsToSave = new Localizations();
Language english = new Language("English", "en");
Map<String, String> englishEntries = new LinkedHashMap<>(Map.of("greeting", "Hello", "farewell", "Goodbye"));
localizationsToSave.getLanguagesInfo().put("en", english);
localizationsToSave.getLanguages().put("en", englishEntries);
localizationsToSave.setPrefix("i18n.");
localizationsToSave.setCurId(1);
final LocalizationMetadata metadata = new LocalizationMetadata();
final Language english = new Language("English", "en");
final Map<String, String> englishEntries = new LinkedHashMap<>(Map.of("greeting", "Hello", "farewell", "Goodbye"));
metadata.getLanguagesInfo().put("en", english);
metadata.setPrefix("i18n.");
this.localizationManager.load(metadata, List.of(language("en", englishEntries)));
byte[] serialized = de.extio.game_engine.util.ObjectSerialization.serialize(
localizationsToSave, false, false, false, null, digest -> {
});
InputStream stream = new ByteArrayInputStream(serialized);
this.localizationManager.load(stream);
Localizations loaded = this.localizationManager.getLocalizations();
final Localizations loaded = this.localizationManager.getLocalizations();
assertNotNull(loaded);
assertEquals("i18n.", loaded.getPrefix());
List<Language> languages = this.localizationManager.getLanguages();
final List<Language> languages = this.localizationManager.getLanguages();
assertEquals(1, languages.size());
assertEquals("en", languages.getFirst().getShortName());
@@ -86,15 +88,33 @@ class LocalizationManagerTest {
assertEquals("Goodbye", this.localizationManager.translate("farewell"));
}
@Test
void testLoadLocalizationsFromDirectory(@TempDir final Path directory) throws Exception {
final LocalizationMetadata metadata = new LocalizationMetadata();
metadata.getLanguagesInfo().put("en", new Language("English", "en"));
metadata.getLanguagesInfo().put("de", new Language("German", "de"));
metadata.setPrefix("i18n.");
Files.write(directory.resolve(LocalizationServiceImpl.METADATA_FILE_NAME), de.extio.game_engine.util.ObjectSerialization.serialize(metadata, false, false, false, null, digest -> {}));
Files.write(directory.resolve(LocalizationServiceImpl.languageFileName("en")), de.extio.game_engine.util.ObjectSerialization.serialize(language("en", Map.of("i18n.greeting", "Hello")), false, false, false, null, digest -> {}));
Files.write(directory.resolve(LocalizationServiceImpl.languageFileName("de")), de.extio.game_engine.util.ObjectSerialization.serialize(language("de", Map.of("i18n.greeting", "Hallo")), false, false, false, null, digest -> {}));
this.localizationManager.loadWoService(directory);
// this.localizationManager.setLanguage("en");
assertEquals("Hello", this.localizationManager.translate("i18n.greeting"));
this.localizationManager.setLanguage("de");
assertEquals("Hallo", this.localizationManager.translate("i18n.greeting"));
}
@Test
void testSetLanguage() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
Language german = new Language("German", "de");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
final Language german = new Language("German", "de");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguagesInfo().put("de", german);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.getLanguages().put("de", new LinkedHashMap<>(Map.of("greeting", "Hallo")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("de").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hallo")));
this.localizationManager.setLanguage("de");
@@ -103,10 +123,10 @@ class LocalizationManagerTest {
@Test
void testSetLanguageInvalid() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
this.localizationManager.setLanguage("en");
this.localizationManager.setLanguage("fr");
@@ -116,15 +136,15 @@ class LocalizationManagerTest {
@Test
void testGetLanguages() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
Language german = new Language("German", "de");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
final Language german = new Language("German", "de");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguagesInfo().put("de", german);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.getLanguages().put("de", new LinkedHashMap<>(Map.of("greeting", "Hallo")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("de").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hallo")));
List<Language> languages = this.localizationManager.getLanguages();
final List<Language> languages = this.localizationManager.getLanguages();
assertEquals(2, languages.size());
assertTrue(languages.stream().anyMatch(lang -> "en".equals(lang.getShortName())));
@@ -133,10 +153,10 @@ class LocalizationManagerTest {
@Test
void testGetCurrentLanguage() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
this.localizationManager.setLanguage("en");
assertEquals("en", this.localizationManager.getCurrentLanguage());
@@ -144,103 +164,100 @@ class LocalizationManagerTest {
@Test
void testTranslateWithStringId() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
this.localizationManager.setLanguage("en");
String result = this.localizationManager.translate("greeting");
final String result = this.localizationManager.translate("greeting");
assertEquals("Hello", result);
}
@Test
void testTranslateWithStringIdNotFound() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>());
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>());
this.localizationManager.setLanguage("en");
String result = this.localizationManager.translate("unknown");
final String result = this.localizationManager.translate("unknown");
assertEquals("unknown", result);
}
@Test
void testTranslateWithStringIdAndDefault() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>());
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>());
this.localizationManager.setLanguage("en");
String result = this.localizationManager.translate("unknown", "Default Text");
final String result = this.localizationManager.translate("unknown", "Default Text");
assertEquals("Default Text", result);
}
@Test
void testPut() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>());
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>());
this.localizationManager.setLanguage("en");
this.localizationManager.put("en", "greeting", "Hello");
String result = this.localizationManager.translate("greeting");
final String result = this.localizationManager.translate("greeting");
assertEquals("Hello", result);
}
@Test
void testPutInvalidLanguage() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>());
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>());
this.localizationManager.put("fr", "greeting", "Bonjour");
assertTrue(localizations.getLanguages().get("en").isEmpty());
assertTrue(localizations.getLanguageEntries("en").isEmpty());
}
@Test
void testRemove() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
Map<String, String> entries = new LinkedHashMap<>(Map.of("greeting", "Hello", "farewell", "Goodbye"));
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
final Map<String, String> entries = new LinkedHashMap<>(Map.of("greeting", "Hello", "farewell", "Goodbye"));
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", entries);
localizations.ensureLanguageFile("en").setEntries(entries);
this.localizationManager.setLanguage("en");
this.localizationManager.remove("greeting");
assertFalse(localizations.getLanguages().get("en").containsKey("greeting"));
assertTrue(localizations.getLanguages().get("en").containsKey("farewell"));
assertFalse(localizations.getLanguageEntries("en").containsKey("greeting"));
assertTrue(localizations.getLanguageEntries("en").containsKey("farewell"));
}
@Test
void testGetNextId() {
Localizations localizations = this.localizationManager.getLocalizations();
localizations.setCurId(5);
final Localizations localizations = this.localizationManager.getLocalizations();
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("test-5", "Hello")));
this.localizationManager.load(localizations.getMetadata(), List.of(localizations.getLanguageFile("en")));
Integer nextId = this.localizationManager.getNextId();
final Integer nextId = this.localizationManager.getNextId();
assertEquals(6, nextId);
assertEquals(6, localizations.getCurId());
}
@Test
void testGetNextIdIncremental() {
Localizations localizations = this.localizationManager.getLocalizations();
localizations.setCurId(0);
Integer id1 = this.localizationManager.getNextId();
Integer id2 = this.localizationManager.getNextId();
Integer id3 = this.localizationManager.getNextId();
final Integer id1 = this.localizationManager.getNextId();
final Integer id2 = this.localizationManager.getNextId();
final Integer id3 = this.localizationManager.getNextId();
assertEquals(1, id1);
assertEquals(2, id2);
@@ -249,7 +266,7 @@ class LocalizationManagerTest {
@Test
void testGetLocalizations() {
Localizations localizations = this.localizationManager.getLocalizations();
final Localizations localizations = this.localizationManager.getLocalizations();
assertNotNull(localizations);
assertEquals(localizations, this.localizationManager.getLocalizations());
@@ -257,14 +274,14 @@ class LocalizationManagerTest {
@Test
void testTranslateCaching() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("1", "Hello")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("1", "Hello")));
this.localizationManager.setLanguage("en");
String result1 = this.localizationManager.translate("1");
String result2 = this.localizationManager.translate("1");
final String result1 = this.localizationManager.translate("1");
final String result2 = this.localizationManager.translate("1");
assertEquals("Hello", result1);
assertEquals("Hello", result2);
@@ -273,19 +290,19 @@ class LocalizationManagerTest {
@Test
void testMultipleLanguages() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
Language german = new Language("German", "de");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
final Language german = new Language("German", "de");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguagesInfo().put("de", german);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.getLanguages().put("de", new LinkedHashMap<>(Map.of("greeting", "Hallo")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("de").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hallo")));
this.localizationManager.setLanguage("en");
String englishGreeting = this.localizationManager.translate("greeting");
final String englishGreeting = this.localizationManager.translate("greeting");
this.localizationManager.setLanguage("de");
String germanGreeting = this.localizationManager.translate("greeting");
final String germanGreeting = this.localizationManager.translate("greeting");
assertEquals("Hello", englishGreeting);
assertEquals("Hallo", germanGreeting);
@@ -293,10 +310,10 @@ class LocalizationManagerTest {
@Test
void testPersistCurrentLanguage() {
Localizations localizations = this.localizationManager.getLocalizations();
Language english = new Language("English", "en");
final Localizations localizations = this.localizationManager.getLocalizations();
final Language english = new Language("English", "en");
localizations.getLanguagesInfo().put("en", english);
localizations.getLanguages().put("en", new LinkedHashMap<>(Map.of("greeting", "Hello")));
localizations.ensureLanguageFile("en").setEntries(new LinkedHashMap<>(Map.of("greeting", "Hello")));
this.localizationManager.setLanguage("en");
@@ -308,20 +325,10 @@ class LocalizationManagerTest {
when(storageService.loadByPath(String.class, List.of("gameEngine"), "currentLanguage"))
.thenReturn(Optional.of("de"));
// Load localizations with "de"
Localizations localizationsToSave = new Localizations();
Language german = new Language("German", "de");
Map<String, String> germanEntries = new LinkedHashMap<>(Map.of("greeting", "Hallo"));
localizationsToSave.getLanguagesInfo().put("de", german);
localizationsToSave.getLanguages().put("de", germanEntries);
localizationsToSave.setPrefix("i18n.");
localizationsToSave.setCurId(1);
byte[] serialized = de.extio.game_engine.util.ObjectSerialization.serialize(
localizationsToSave, false, false, false, null, digest -> {});
InputStream stream = new ByteArrayInputStream(serialized);
this.localizationManager.load(stream);
final LocalizationMetadata metadata = new LocalizationMetadata();
metadata.getLanguagesInfo().put("de", new Language("German", "de"));
metadata.setPrefix("i18n.");
this.localizationManager.load(metadata, List.of(language("de", Map.of("greeting", "Hallo"))));
assertEquals("de", this.localizationManager.getCurrentLanguage());
}