Skip to content

Commit 99c3822

Browse files
committed
feat: allow runtime language switching
1 parent cee75d5 commit 99c3822

18 files changed

+377
-123
lines changed

src/main/java/com/codedead/opal/controller/MainWindowController.java

+221-26
Large diffs are not rendered by default.

src/main/java/com/codedead/opal/controller/SettingsWindowController.java

+13-18
Original file line numberDiff line numberDiff line change
@@ -184,19 +184,23 @@ private void loadSettings() {
184184
private void resetSettingsAction() {
185185
logger.info("Attempting to reset all settings");
186186
if (FxUtils.showConfirmationAlert(translationBundle.getString("ConfirmReset"), getClass().getResourceAsStream(SharedVariables.ICON_URL))) {
187-
showAlertIfLanguageMismatch(DEFAULT_LOCALE);
188-
189187
Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet());
190188
try {
191189
settingsController.createDefaultProperties();
192190
settingsController.setProperties(settingsController.readPropertiesFile());
193191

192+
final Locale locale = Locale.forLanguageTag(DEFAULT_LOCALE);
193+
final ResourceBundle translationBundle = ResourceBundle.getBundle("translations.OpalApplication", locale);
194+
195+
mainWindowController.updateResourceBundle(translationBundle);
196+
194197
mainWindowController.loadMediaButtonVisibility(Boolean.parseBoolean(settingsController.getProperties().getProperty("mediaButtons", "true")));
195198
mainWindowController.setAudioBalance(Double.parseDouble(settingsController.getProperties().getProperty("audioBalance", "0.0")));
196199

197200
trayIconController.hideTrayIcon();
198201

199-
loadSettings();
202+
Stage stage = (Stage) sldAudioBalance.getScene().getWindow();
203+
stage.close();
200204
} catch (final IOException ex) {
201205
logger.error("Unable to reset all settings", ex);
202206
FxUtils.showErrorAlert(translationBundle.getString("ResetSettingsError"), ex.toString(), getClass().getResourceAsStream(SharedVariables.ICON_URL));
@@ -228,9 +232,13 @@ private void saveSettingsAction() {
228232
trayIconController.hideTrayIcon();
229233
}
230234

231-
showAlertIfLanguageMismatch(settingsController.getProperties().getProperty("locale", DEFAULT_LOCALE));
235+
final String languageTag = LanguageController.getLocaleFromLanguageIndex(cboLanguage.getSelectionModel().getSelectedIndex());
236+
final Locale locale = Locale.forLanguageTag(languageTag);
237+
final ResourceBundle translationBundle = ResourceBundle.getBundle("translations.OpalApplication", locale);
238+
239+
mainWindowController.updateResourceBundle(translationBundle);
232240

233-
settingsController.getProperties().setProperty("locale", LanguageController.getLocaleFromLanguageIndex(cboLanguage.getSelectionModel().getSelectedIndex()));
241+
settingsController.getProperties().setProperty("locale", languageTag);
234242

235243
settingsController.getProperties().setProperty("theme", cboTheme.getSelectionModel().getSelectedItem());
236244
settingsController.getProperties().setProperty("loglevel", cboLogLevel.getValue());
@@ -281,19 +289,6 @@ private void saveSettingsAction() {
281289
}
282290
}
283291

284-
/**
285-
* Show an information alert if a restart is required
286-
*
287-
* @param languageToMatch The language that needs to be matched to the combobox
288-
*/
289-
private void showAlertIfLanguageMismatch(final String languageToMatch) {
290-
final String newLanguage = LanguageController.getLocaleFromLanguageIndex(cboLanguage.getSelectionModel().getSelectedIndex());
291-
292-
if (!languageToMatch.equals(newLanguage)) {
293-
FxUtils.showInformationAlert(translationBundle.getString("RestartRequired"), getClass().getResourceAsStream(SharedVariables.ICON_URL));
294-
}
295-
}
296-
297292
/**
298293
* Method that is invoked when the window should be closed
299294
*

src/main/java/com/codedead/opal/controller/TrayIconController.java

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.codedead.opal.controller;
22

3+
import com.codedead.opal.domain.ObservableResourceFactory;
34
import com.codedead.opal.interfaces.TrayIconListener;
45
import javafx.application.Platform;
56
import org.apache.logging.log4j.LogManager;
@@ -11,28 +12,27 @@
1112
import java.io.IOException;
1213
import java.util.Arrays;
1314
import java.util.Objects;
14-
import java.util.ResourceBundle;
1515

1616
public final class TrayIconController {
1717

1818
private TrayIcon trayIcon;
19-
private final ResourceBundle resourceBundle;
19+
private final ObservableResourceFactory resourceFactory;
2020
private final TrayIconListener trayIconListener;
2121
private final Logger logger;
2222

2323
/**
2424
* Initialize a new TrayIconController
2525
*
26-
* @param resourceBundle The {@link ResourceBundle} object
26+
* @param resourceFactory The {@link ObservableResourceFactory} object
2727
* @param trayIconListener The {@link TrayIconListener} interface
2828
*/
29-
public TrayIconController(final ResourceBundle resourceBundle, final TrayIconListener trayIconListener) {
30-
if (resourceBundle == null)
31-
throw new NullPointerException("ResourceBundle cannot be null!");
29+
public TrayIconController(final ObservableResourceFactory resourceFactory, final TrayIconListener trayIconListener) {
30+
if (resourceFactory == null)
31+
throw new NullPointerException("ResourceFactory cannot be null!");
3232
if (trayIconListener == null)
3333
throw new NullPointerException("TrayIconListener cannot be null!");
3434

35-
this.resourceBundle = resourceBundle;
35+
this.resourceFactory = resourceFactory;
3636
this.trayIconListener = trayIconListener;
3737
this.logger = LogManager.getLogger(TrayIconController.class);
3838
}
@@ -54,10 +54,10 @@ private void createTrayIcon() throws IOException {
5454
final PopupMenu popup = new PopupMenu();
5555
final BufferedImage trayIconImage = ImageIO.read(Objects.requireNonNull(getClass().getResource("/images/opal.png")));
5656
final TrayIcon localTrayIcon = new TrayIcon(trayIconImage.getScaledInstance(trayIconSize.width, trayIconSize.height, java.awt.Image.SCALE_SMOOTH));
57-
final java.awt.MenuItem displayItem = new java.awt.MenuItem(resourceBundle.getString("Display"));
58-
final java.awt.MenuItem settingsItem = new java.awt.MenuItem(resourceBundle.getString("Settings"));
59-
final java.awt.MenuItem aboutItem = new java.awt.MenuItem(resourceBundle.getString("About"));
60-
final java.awt.MenuItem exitItem = new java.awt.MenuItem(resourceBundle.getString("Exit"));
57+
final java.awt.MenuItem displayItem = new java.awt.MenuItem(resourceFactory.getResources().getString("Display"));
58+
final java.awt.MenuItem settingsItem = new java.awt.MenuItem(resourceFactory.getResources().getString("Settings"));
59+
final java.awt.MenuItem aboutItem = new java.awt.MenuItem(resourceFactory.getResources().getString("About"));
60+
final java.awt.MenuItem exitItem = new java.awt.MenuItem(resourceFactory.getResources().getString("Exit"));
6161

6262
if (trayIconListener != null) {
6363
// Platform.runLater to run on the JavaFX thread
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.codedead.opal.domain;
2+
3+
import javafx.beans.binding.StringBinding;
4+
import javafx.beans.property.ObjectProperty;
5+
import javafx.beans.property.SimpleObjectProperty;
6+
7+
import java.util.ResourceBundle;
8+
9+
public final class ObservableResourceFactory {
10+
11+
private final ObjectProperty<ResourceBundle> resources;
12+
13+
/**
14+
* Initialize a new ObservableResourceFactory
15+
*/
16+
public ObservableResourceFactory() {
17+
resources = new SimpleObjectProperty<>();
18+
}
19+
20+
/**
21+
* Get the resources property
22+
*
23+
* @return The resources property
24+
*/
25+
public ObjectProperty<ResourceBundle> resourcesProperty() {
26+
return resources;
27+
}
28+
29+
/**
30+
* Get the resources
31+
*
32+
* @return The resources
33+
*/
34+
public ResourceBundle getResources() {
35+
return resourcesProperty().get();
36+
}
37+
38+
/**
39+
* Set the resources
40+
*
41+
* @param resources The resources
42+
*/
43+
public void setResources(final ResourceBundle resources) {
44+
resourcesProperty().set(resources);
45+
}
46+
47+
/**
48+
* Get a string binding for the given key
49+
*
50+
* @param key The key
51+
* @return The {@link StringBinding} for the given key
52+
*/
53+
public StringBinding getStringBinding(final String key) {
54+
return new StringBinding() {
55+
{
56+
bind(resourcesProperty());
57+
}
58+
59+
@Override
60+
public String computeValue() {
61+
return getResources().getString(key);
62+
}
63+
};
64+
}
65+
}

src/main/java/com/codedead/opal/domain/SoundPane.java

+9
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ public String getName() {
148148
return lblName.getText();
149149
}
150150

151+
/**
152+
* Get the name {@link Label} object
153+
*
154+
* @return The name {@link Label} object
155+
*/
156+
public Label getNameLabel() {
157+
return lblName;
158+
}
159+
151160
/**
152161
* Set the name
153162
*

src/main/resources/translations/OpalApplication.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Phone
3333
Rain=Rain
3434
Reset=Reset
3535
ResetSettingsError=Unable to reset all settings!
36-
RestartRequired=A restart is required in order to change the language!
3736
Save=Save
3837
SaveSettingsError=Unable to save settings!
3938
SaveSoundPreset=Save sound settings

src/main/resources/translations/OpalApplication_de_DE.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Telefon
3333
Rain=Regen
3434
Reset=Zurücksetzen
3535
ResetSettingsError=Einstellungen konnten nicht zurückgesetzt werden!
36-
RestartRequired=Zur Änderung der Sprache muss das Programm neu gestartet werden!
3736
Save=Speichern
3837
SaveSettingsError=Einstellungen konnten nicht gespeichert werden!
3938
SaveSoundPreset=Toneinstellungen speichern

src/main/resources/translations/OpalApplication_en_US.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Phone
3333
Rain=Rain
3434
Reset=Reset
3535
ResetSettingsError=Unable to reset all settings!
36-
RestartRequired=A restart is required in order to change the language!
3736
Save=Save
3837
SaveSettingsError=Unable to save settings!
3938
SaveSoundPreset=Save sound settings

src/main/resources/translations/OpalApplication_es_ES.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Teléfono
3333
Rain=Lluvia
3434
Reset=Restablecer
3535
ResetSettingsError=¡No se pueden restablecer todas las configuraciones!
36-
RestartRequired=¡Es necesario reiniciar para cambiar el idioma!
3736
Save=Guardar
3837
SaveSettingsError=¡No se puede guardar la configuración!
3938
SaveSoundPreset=Guardar configuración de sonido

src/main/resources/translations/OpalApplication_fr_FR.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Téléphone
3333
Rain=Pluie
3434
Reset=Réinitialiser
3535
ResetSettingsError=Impossible de réinitialiser tous les paramètres!
36-
RestartRequired=Un redémarrage est nécessaire pour changer la langue!
3736
Save=Sauvegarder
3837
SaveSettingsError=Impossible d'enregistrer les paramètres!
3938
SaveSoundPreset=Enregistrer les paramètres sonores

src/main/resources/translations/OpalApplication_hi_IN.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=फ़ोन
3333
Rain=बारिश
3434
Reset=रीसेट
3535
ResetSettingsError=सभी सेटिंग्स रीसेट करने में असमर्थ!
36-
RestartRequired=भाषा बदलने के लिए पुनः आरंभ करना आवश्यक है!
3736
Save=बचाना
3837
SaveSettingsError=सेटिंग्स सहेजने में असमर्थ!
3938
SaveSoundPreset=ध्वनि सेटिंग सहेजें

src/main/resources/translations/OpalApplication_jp_JP.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=電話
3333
Rain=雨
3434
Reset=リセット
3535
ResetSettingsError=すべての設定をリセットできません!
36-
RestartRequired=言語を変更するには再起動が必要です!
3736
Save=保存
3837
SaveSettingsError=設定を保存できません!
3938
SaveSoundPreset=サウンド設定を保存

src/main/resources/translations/OpalApplication_nl_NL.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Telefoon
3333
Rain=Regen
3434
Reset=Reset
3535
ResetSettingsError=Kan de instellingen niet resetten!
36-
RestartRequired=Gelieve de applicatie te herstarten om te taal te wijzigen!
3736
Save=Opslaan
3837
SaveSettingsError=Kan instellingen niet opslaan!
3938
SaveSoundPreset=Sla geluidsinstellingen op

src/main/resources/translations/OpalApplication_ru_RU.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Телефон
3333
Rain=Дождь
3434
Reset=Перезагрузить
3535
ResetSettingsError=Невозможно сбросить все настройки!
36-
RestartRequired=Для смены языка требуется перезагрузка!
3736
Save=Сохранять
3837
SaveSettingsError=Не удалось сохранить настройки!
3938
SaveSoundPreset=Сохранить настройки звука

src/main/resources/translations/OpalApplication_tr_TR.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Telefon
3333
Rain=Yağmur
3434
Reset=Sıfırla
3535
ResetSettingsError=Tüm ayarlar sıfırlanamıyor!
36-
RestartRequired=Dili değiştirmek için yeniden başlatma gereklidir!
3736
Save=Kaydetmek
3837
SaveSettingsError=Ayarlar kaydedilemiyor!
3938
SaveSoundPreset=Ses ayarlarını kaydet

src/main/resources/translations/OpalApplication_uk_UA.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=Телефон
3333
Rain=Дощ
3434
Reset=Скинути
3535
ResetSettingsError=Неможливо скинути всі налаштування!
36-
RestartRequired=Щоб змінити мову, потрібен перезапуск!
3736
Save=Збережіть
3837
SaveSettingsError=Не вдалося зберегти налаштування!
3938
SaveSoundPreset=Зберегти налаштування звуку

src/main/resources/translations/OpalApplication_zh_CN.properties

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Phone=电话
3333
Rain=雨
3434
Reset=重置
3535
ResetSettingsError=无法重置所有设置!
36-
RestartRequired=需要重新启动才能更改语言!
3736
Save=节省
3837
SaveSettingsError=无法保存设置!
3938
SaveSoundPreset=保存声音设置

0 commit comments

Comments
 (0)