#1936: Improve localization of gui#1979
Conversation
- Added testing class for modals
- Added logging to IdeGuiStateManager. - Added functionality, that selecting a different project now switches the IdeContext to the new project.
- Added testing class for modals
- Added logging to IdeGuiStateManager. - Added functionality, that selecting a different project now switches the IdeContext to the new project.
…t-for-gui' into devonfw#1785-implement-modals-in-idecontext
- Added functionality, that selecting a different project now switches the IdeContext to the new project.
…plementation' into devonfw#1802-state-management-implementation
…r other ui feature branches
- added DI for IdeGuiStateManager.switchContext
…reading the list of workspaces/projects instead of reading those from the UI
…nager, when switchContext(Path rootDirectory, ...) is called.
This reverts commit 6f92d93.
…plementation' into devonfw#1802-state-management-implementation
…tateManager is now set when calling getInstance(), allowing us to provide a getInstance() method with a DI parameter
… getInstance()) (see previous commit)
…can be extended by tests
…plementation' into devonfw#1802-state-management-implementation
Coverage Report for CI Build 28107858485Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage decreased (-0.08%) to 71.305%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions55 previously-covered lines in 4 files lost coverage.
Coverage Stats💛 - Coveralls |
laim2003
left a comment
There was a problem hiding this comment.
looks good! just left some thoughts😊
| public static synchronized I18nService getInstance() { | ||
|
|
||
| if (instance == null) { | ||
| return getInstance(null); | ||
| } | ||
| return instance; | ||
| } |
There was a problem hiding this comment.
@hohwille said that we should avoid Singleton patterns where possible and use Dependency Injection. I know i used this pattern a lot in my own state management implementation, but I will also be moving away from Singeltons there. Maybe we can discuss about whether its okay to use them in some instances in the Next daily, probably would also help me clear up some questions. I would probably leave this how it is here for now, but then open a second issue for the future where we update this to DI.
…/1936-improve-localization-of-gui"
| @@ -0,0 +1,17 @@ | |||
| # IDEasy GUI - English (default) Translation File | |||
There was a problem hiding this comment.
In cli we named the folder nls for "Native Language Support".
For homogeneity, it would be nice to have both folder named the same.
If the team better understands localization we can also change nls but it is short and maybe more speaking than l10n what other projects use as shortcut for localization.
There was a problem hiding this comment.
So should localization be changed to nls , and accordingly the usage of the service also to nls ?
| public void testGetInstanceSingleton() { | ||
|
|
||
| LocalizationService service1 = LocalizationService.getInstance(Locale.ENGLISH); | ||
| LocalizationService service2 = LocalizationService.getInstance(); |
There was a problem hiding this comment.
Better do not rely on default locale in JUnits.
If the user has a different local configured than English, the test will fail.
This will happen sooner or later and cause confusion if some developers have red tests and others have green tests.
| service.setLocale(Locale.GERMAN); | ||
|
|
||
| assertThat(service.getLocale().getLanguage()).isEqualTo("de"); | ||
| assertThat(service.getResourceBundle()).isNotNull(); |
There was a problem hiding this comment.
I would also expect that we lookup some key for German and assert the expected translation.
If you choose a generic key that will not likely change, the test should also stay stable.
| @BeforeEach | ||
| public void setUp() { | ||
|
|
||
| // Reset the singleton instance before each test | ||
| LocalizationService.resetInstance(); | ||
| // Preload English bundle keys used by bundle-completion tests | ||
| ResourceBundle englishBundle = ResourceBundle.getBundle("localization.messages", Locale.ENGLISH); | ||
| this.englishKeys = extractKeys(englishBundle); | ||
| } |
There was a problem hiding this comment.
Only needed for testing the German keys match the English keys.
I usually expect that setup method does some generic setup used for all test methods.
Nothing wrong here but you could simply do a single test that checks that English keys and German keys are identical and then move this from setup to that single test method.
Surely nice to have...
|
|
||
| // Initialize language choices | ||
| selectedLanguage.getItems().clear(); | ||
| selectedLanguage.getItems().addAll("English", "Deutsch"); |
There was a problem hiding this comment.
we should not hardcode the lanugages.
Instead simply add a key like CurrentLanguage so e.g.
CurrentLanguage=English (en)
or
CurrentLanguage=Deutsch (de)
Then we can dynamically lookup the available resource bundles and add new languages without changing the code.
There was a problem hiding this comment.
BTW: Adding the ISO-Codes in parenthesis improves UX if you see languages that you cannot read but still want to get an idea of. Example
แบบไทย (th)
| // Set Labels | ||
| labelProject.setText(localizationService.get("label.project")); | ||
| labelWorkspace.setText(localizationService.get("label.workspace")); | ||
| labelLanguage.setText(localizationService.get("label.language")); | ||
|
|
||
| // Set ComboBox prompts | ||
| selectedProject.setPromptText(localizationService.get("prompt.chooseProject")); | ||
| selectedWorkspace.setPromptText(localizationService.get("prompt.chooseWorkspace")); | ||
| selectedLanguage.setPromptText(localizationService.get("prompt.chooseLanguage")); | ||
|
|
||
| // Set Button texts | ||
| androidStudioOpen.setText(localizationService.get("button.open")); | ||
| eclipseOpen.setText(localizationService.get("button.open")); | ||
| intellijOpen.setText(localizationService.get("button.open")); | ||
| vsCodeOpen.setText(localizationService.get("button.open")); |
There was a problem hiding this comment.
This also looks unmaintainable.
We cannot hard-code all labels, buttons, etc. of all dialogues here.
KISS solution: To change the language, the GUI has to be restarted.
Otherwise research how to tell JavaFx to reload the messages (or the entire FXML).
| public void setLocale(Locale locale) { | ||
|
|
||
| this.locale = locale; | ||
| loadBundle(); | ||
| LOG.info("Locale set to: {}", locale.getLanguage()); | ||
| for (Runnable listener : this.localeListeners) { | ||
| try { | ||
| listener.run(); | ||
| } catch (Exception e) { | ||
| LOG.warn("Locale change listener threw: {}", e.getMessage()); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
usually the language is set on operating system level and then Java takes it from there via the default locale. Would be sufficient for KISS. Custom language for IDEasy can IMHO be set via
export IDE_OPTIONS=-Duser.lang=de
in ~/.ide/ide.properties what should already work for the CLI0.
It is nice that you add the option to change in individually in the GUI.
But if you do this, we have to persist the value so that if I close the GUI and reopen it, I do not have to change it every time again.
FYI: If you want to go for KISS, you may keep this out of this first PR and we will add that later. But when we already introduce it, we should IMHO do it properly.
hohwille
left a comment
There was a problem hiding this comment.
@KarimALotfy thanks for your PR.
Very nice that you figured out how to do NLS (i18n and l10n) with JavaFx (using Locale, ResourceBundle and the % syntax in fxml files). Great that you also added a proper JUnit test and some advanced features. 👍
I left quite some comments for rework.
In some cases you may decide to go for more KISS and keep some advanced features out of this first PR and introduce in a later improving PR after this one is merged or you should go for the full solution if you already start it.
- Generalize localization keys in the `.properties` files - Detect available resource bundles automatically instead of hardcoding languages - Persist the selected language in `~/.ide/ide.properties` using `IDE_LOCALE` - Load and apply the persisted locale during GUI initialization - Remove `updateTexts()` from `MainController` - Reload the app after each language selection to apply localization changes - Refactor tests to match the updated localization flow
This PR fixes #1936
Implemented changes:
Testing instructions
Please add conscise, understandable instructions on how a reviewer can test/verify the functionality of your contribution here:
/ide-guiAppLauncher, interact with the third combo box (Language) -- check if language is correctly switchedmessages.propertiesandmessages_de.properties--> runI18nServiceTestChecklist for this PR
Make sure everything is checked before merging this PR. For further info please also see
our DoD.
mvn clean testlocally all tests pass and build is successful#«issue-id»: «brief summary»(e.g.#921: fixed setup.bat). If no issue ID exists, title only.In Progressand assigned to you or there is no issue (might happen for very small PRs)with
internal