diff --git a/G-Earth/src/main/java/gearth/GEarth.java b/G-Earth/src/main/java/gearth/GEarth.java index 4be384e..25ae10a 100644 --- a/G-Earth/src/main/java/gearth/GEarth.java +++ b/G-Earth/src/main/java/gearth/GEarth.java @@ -11,6 +11,7 @@ import gearth.ui.themes.Theme; import gearth.ui.themes.ThemeFactory; import gearth.ui.titlebar.TitleBarConfig; import gearth.ui.titlebar.TitleBarController; +import gearth.ui.translations.LanguageBundle; import javafx.application.Application; import javafx.application.Platform; import javafx.fxml.FXMLLoader; @@ -20,11 +21,6 @@ import javafx.scene.control.Alert; import javafx.scene.image.Image; import javafx.stage.Stage; import javafx.stage.StageStyle; -import sun.misc.Cache; - -import java.util.Locale; -import java.util.ResourceBundle; -import java.util.function.Consumer; public class GEarth extends Application { @@ -32,7 +28,7 @@ public class GEarth extends Application { public static String version = "1.5.2"; public static String gitApi = "https://api.github.com/repos/sirjonasxx/G-Earth/releases/latest"; public static ObservableObject observableTheme; - public static ResourceBundle translation; + public static LanguageBundle translation; private Stage stage; private GEarthController controller; @@ -50,7 +46,7 @@ public class GEarth extends Application { main = this; stage = primaryStage; - translation = ResourceBundle.getBundle("gearth.ui.translations.messages", new Locale("pt")); + translation = new LanguageBundle(); FXMLLoader loader = new FXMLLoader(getClass().getResource("/gearth/ui/G-Earth.fxml"), translation); Parent root = loader.load(); diff --git a/G-Earth/src/main/java/gearth/ui/GEarthController.java b/G-Earth/src/main/java/gearth/ui/GEarthController.java index 557295b..be6333b 100644 --- a/G-Earth/src/main/java/gearth/ui/GEarthController.java +++ b/G-Earth/src/main/java/gearth/ui/GEarthController.java @@ -3,8 +3,8 @@ package gearth.ui; import gearth.protocol.connection.proxy.ProxyProviderFactory; import gearth.protocol.connection.proxy.SocksConfiguration; import gearth.ui.subforms.logger.loggerdisplays.PacketLoggerFactory; +import gearth.ui.translations.TranslatableString; import javafx.scene.control.*; -import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import gearth.protocol.HConnection; import gearth.ui.subforms.connection.ConnectionController; @@ -21,7 +21,7 @@ import java.util.List; public class GEarthController { - public Tab tab_Logger; + public Tab tab_Connection, tab_Logger, tab_Injection, tab_Tools, tab_Scheduler, tab_Extensions, tab_Extra, tab_Info; public TabPane tabBar; private Stage stage = null; private volatile HConnection hConnection; @@ -67,6 +67,10 @@ public class GEarthController { trySetController(); } + if (PacketLoggerFactory.usesUIlogger()) { + tabBar.getTabs().remove(tab_Logger); + } + List uiTabs = tabBar.getTabs(); for (int i = 0; i < uiTabs.size(); i++) { Tab tab = uiTabs.get(i); @@ -79,11 +83,7 @@ public class GEarthController { }); } - if (PacketLoggerFactory.usesUIlogger()) { - tabBar.getTabs().remove(tab_Logger); - } - - + initLanguageBinding(); } public void setStage(Stage stage) { @@ -120,4 +120,13 @@ public class GEarthController { hConnection.abort(); } + private void initLanguageBinding() { + tab_Connection.textProperty().bind(new TranslatableString("tab.connection")); + tab_Injection.textProperty().bind(new TranslatableString("tab.injection")); + tab_Tools.textProperty().bind(new TranslatableString("tab.tools")); + tab_Scheduler.textProperty().bind(new TranslatableString("tab.scheduler")); + tab_Extensions.textProperty().bind(new TranslatableString("tab.extensions")); + tab_Extra.textProperty().bind(new TranslatableString("tab.extra")); + tab_Info.textProperty().bind(new TranslatableString("tab.info")); + } } diff --git a/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java b/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java index 056616e..2f70ec0 100644 --- a/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java +++ b/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java @@ -6,6 +6,7 @@ import gearth.protocol.connection.HClient; import gearth.protocol.connection.HState; import gearth.protocol.connection.proxy.ProxyProviderFactory; import gearth.services.Constants; +import gearth.ui.translations.TranslatableString; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.scene.control.*; @@ -29,7 +30,7 @@ public class ConnectionController extends SubForm { public ComboBox inpPort; public ComboBox inpHost; public Button btnConnect; - public Label lblState; + public Label lblInpPort, lblInpHost, lblPort, lblHost, lblHotelVersion, lblClient, lblStateHead, lblState; public TextField outHost; public TextField outPort; public CheckBox cbx_autodetect; @@ -131,6 +132,8 @@ public class ConnectionController extends SubForm { synchronized (this) { tryMaybeConnectOnInit(); } + + initLanguageBinding(); } @@ -176,20 +179,20 @@ public class ConnectionController extends SubForm { getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(() -> { updateInputUI(); if (newState == HState.NOT_CONNECTED) { - lblState.setText(GEarth.translation.getString("tab.connection.state.notconnected")); - btnConnect.setText(GEarth.translation.getString("tab.connection.connect")); + lblState.textProperty().bind(ConnectionState.NOTCONNECTED.value); + btnConnect.textProperty().bind(ConnectButton.CONNECT.value); outHost.setText(""); outPort.setText(""); } else if (oldState == HState.NOT_CONNECTED) { - btnConnect.setText(GEarth.translation.getString("tab.connection.abort")); + btnConnect.textProperty().bind(ConnectButton.ABORT.value); } if (newState == HState.CONNECTED) { - lblState.setText(GEarth.translation.getString("tab.connection.state.connected")); + lblState.textProperty().bind(ConnectionState.CONNECTED.value); } if (newState == HState.WAITING_FOR_CLIENT) { - lblState.setText(GEarth.translation.getString("tab.connection.state.waiting")); + lblState.textProperty().bind(ConnectionState.WAITING.value); } if (newState == HState.CONNECTED && useFlash()) { @@ -314,4 +317,45 @@ public class ConnectionController extends SubForm { return false; } + + private enum ConnectButton { + CONNECT ("tab.connection.button.connect"), + ABORT ("tab.connection.button.abort"); + + public final TranslatableString value; + + ConnectButton(String key) { + this.value = new TranslatableString(key); + } + } + + private enum ConnectionState { + CONNECTED ("tab.connection.state.connected"), + NOTCONNECTED ("tab.connection.state.notconnected"), + WAITING ("tab.connection.state.waiting"); + + public final TranslatableString value; + + ConnectionState(String key) { + this.value = new TranslatableString(key); + } + } + + private void initLanguageBinding() { + TranslatableString port = new TranslatableString("tab.connection.port"); + TranslatableString host = new TranslatableString("tab.connection.host"); + lblInpPort.textProperty().bind(port); + lblInpHost.textProperty().bind(host); + lblPort.textProperty().bind(port); + lblHost.textProperty().bind(host); + cbx_autodetect.textProperty().bind(new TranslatableString("tab.connection.autodetect")); + btnConnect.textProperty().bind(ConnectButton.CONNECT.value); + lblHotelVersion.textProperty().bind(new TranslatableString("tab.connection.version")); + lblClient.textProperty().bind(new TranslatableString("tab.connection.client")); + rd_unity.textProperty().bind(new TranslatableString("tab.connection.client.unity")); + rd_flash.textProperty().bind(new TranslatableString("tab.connection.client.flash")); + rd_nitro.textProperty().bind(new TranslatableString("tab.connection.client.nitro")); + lblStateHead.textProperty().bind(new TranslatableString("tab.connection.state")); + lblState.textProperty().bind(ConnectionState.NOTCONNECTED.value); + } } diff --git a/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java b/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java index 45747b0..3206116 100644 --- a/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java +++ b/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java @@ -5,6 +5,7 @@ import gearth.misc.Cacher; import gearth.services.packet_info.PacketInfoManager; import gearth.protocol.HMessage; import gearth.protocol.connection.HState; +import gearth.ui.translations.TranslatableString; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.scene.control.*; @@ -27,7 +28,7 @@ public class InjectionController extends SubForm { private static final int historylimit = 69; public TextArea inputPacket; - public Text lbl_corrruption; + public Text lbl_corruption; public Text lbl_pcktInfo; public Button btn_sendToServer; public Button btn_sendToClient; @@ -53,7 +54,8 @@ public class InjectionController extends SubForm { } }); - lblHistory.setTooltip(new Tooltip(GEarth.translation.getString("tab.injection.history.tooltip"))); + lblHistory.setTooltip(new Tooltip()); + lblHistory.getTooltip().textProperty().bind(new TranslatableString("tab.injection.history.tooltip")); List rawHistory = Cacher.getList(HISTORY_CACHE_KEY); if (rawHistory != null) { @@ -104,33 +106,33 @@ public class InjectionController extends SubForm { private void updateUI() { boolean dirty = false; - lbl_corrruption.setText(GEarth.translation.getString("tab.injection.corrupted.false")); - lbl_corrruption.getStyleClass().clear(); - lbl_corrruption.getStyleClass().add("not-corrupted-label"); + lbl_corruption.setText(GEarth.translation.getString("tab.injection.corrupted.false")); + lbl_corruption.getStyleClass().clear(); + lbl_corruption.getStyleClass().add("not-corrupted-label"); HPacket[] packets = parsePackets(inputPacket.getText()); if (packets.length == 0) { dirty = true; - lbl_corrruption.setFill(Paint.valueOf("#ee0404b2")); - lbl_corrruption.getStyleClass().clear(); - lbl_corrruption.getStyleClass().add("corrupted-label"); + lbl_corruption.setFill(Paint.valueOf("#ee0404b2")); + lbl_corruption.getStyleClass().clear(); + lbl_corruption.getStyleClass().add("corrupted-label"); } for (int i = 0; i < packets.length; i++) { if (packets[i].isCorrupted()) { if (!dirty) { - lbl_corrruption.setText(String.format("%s -> %d", GEarth.translation.getString("tab.injection.corrupted.true"), i)); - lbl_corrruption.getStyleClass().clear(); - lbl_corrruption.getStyleClass().add("corrupted-label"); + lbl_corruption.setText(String.format("%s -> %d", GEarth.translation.getString("tab.injection.corrupted.true"), i)); + lbl_corruption.getStyleClass().clear(); + lbl_corruption.getStyleClass().add("corrupted-label"); dirty = true; } else - lbl_corrruption.setText(lbl_corrruption.getText() + ", " + i); + lbl_corruption.setText(lbl_corruption.getText() + ", " + i); } } if (dirty && packets.length == 1) { - lbl_corrruption.setText(GEarth.translation.getString("tab.injection.corrupted.true")); // no index needed + lbl_corruption.setText(GEarth.translation.getString("tab.injection.corrupted.true")); // no index needed } if (!dirty) { diff --git a/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java b/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java index b2a7c16..21186df 100644 --- a/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java +++ b/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java @@ -2,16 +2,18 @@ package gearth.ui.titlebar; import gearth.GEarth; import gearth.ui.themes.ThemeFactory; +import gearth.ui.translations.Language; +import gearth.ui.translations.LanguageBundle; import javafx.application.Platform; import javafx.beans.InvalidationListener; +import javafx.event.ActionEvent; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; -import javafx.scene.control.Alert; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Label; +import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.MouseEvent; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; @@ -19,6 +21,7 @@ import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.stage.StageStyle; +import javafx.stage.WindowEvent; import java.io.IOException; import java.util.Optional; @@ -30,6 +33,7 @@ public class TitleBarController { public ImageView titleIcon; public ImageView themeBtn; public ImageView minimizeBtn; + public MenuButton languagePicker; private Stage stage; private TitleBarConfig config; @@ -83,6 +87,9 @@ public class TitleBarController { stage.titleProperty().addListener((i) -> controller.setTitle(stage.getTitle())); controller.setTitle(stage.getTitle()); + controller.languagePicker.getItems().addAll(Language.getMenuItems()); + controller.languagePicker.setGraphic(LanguageBundle.getLanguage().getIcon()); + stage.getIcons().addListener((InvalidationListener) observable -> controller.updateIcon()); controller.updateIcon(); @@ -96,11 +103,16 @@ public class TitleBarController { if (!config.displayThemePicker()) { ((GridPane) controller.themeBtn.getParent()).getChildren().remove(controller.themeBtn); + ((GridPane) controller.languagePicker.getParent()).getChildren().remove(controller.languagePicker); } }); return controller; } + private static void initLanguagePicker() { + + } + public void updateIcon() { Platform.runLater(() -> titleIcon.setImage(stage.getIcons().size() > 0 ? stage.getIcons().get(0) : new Image(GEarth.class.getResourceAsStream( @@ -158,5 +170,4 @@ public class TitleBarController { } return Optional.empty(); } - } diff --git a/G-Earth/src/main/java/gearth/ui/translations/Language.java b/G-Earth/src/main/java/gearth/ui/translations/Language.java new file mode 100644 index 0000000..bb67985 --- /dev/null +++ b/G-Earth/src/main/java/gearth/ui/translations/Language.java @@ -0,0 +1,57 @@ +package gearth.ui.translations; + +import javafx.event.ActionEvent; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.MenuButton; +import javafx.scene.control.MenuItem; +import javafx.scene.image.ImageView; + +import java.util.Arrays; +import java.util.Locale; +import java.util.ResourceBundle; + +public enum Language { + DEFAULT ("en"), + DUTCH ("nl"), + FRENCH ("fr"), + GERMAN ("de"), + SPANISH ("es"), + PORTUGUESE ("pt"), + ITALIAN ("it"), + FINNISH ("fi"), + TURKISH ("tr"); + + public final ResourceBundle messages; + private final String locale; + + Language(String locale) { + this.locale = locale; + messages = ResourceBundle.getBundle("gearth.ui.translations.messages", new Locale(locale)); + } + + public MenuItem asMenuItem() { + MenuItem menuItem = new MenuItem(null, getIcon()); + menuItem.setOnAction(this::onSelect); + return menuItem; + } + + private void onSelect(ActionEvent actionEvent) { + ContextMenu ctxMenu = ((MenuItem) actionEvent.getSource()).getParentPopup(); + ((MenuButton) ctxMenu.getOwnerNode()).setGraphic(getIcon()); + LanguageBundle.setLanguage(this); + } + + public ImageView getIcon() { + ImageView icon = new ImageView(); + icon.getStyleClass().addAll("language-icon", locale); + icon.setFitWidth(18); + icon.setFitHeight(18); + return icon; + } + + public static MenuItem[] getMenuItems() { + return Arrays.stream(values()) + .map(Language::asMenuItem) + .toArray(MenuItem[]::new); + } +} diff --git a/G-Earth/src/main/java/gearth/ui/translations/LanguageBundle.java b/G-Earth/src/main/java/gearth/ui/translations/LanguageBundle.java new file mode 100644 index 0000000..ca36311 --- /dev/null +++ b/G-Earth/src/main/java/gearth/ui/translations/LanguageBundle.java @@ -0,0 +1,54 @@ +package gearth.ui.translations; + +import gearth.GEarth; +import gearth.misc.Cacher; +import gearth.ui.themes.Theme; + +import java.util.Enumeration; +import java.util.HashSet; +import java.util.ResourceBundle; +import java.util.Set; + +public class LanguageBundle extends ResourceBundle { + + private static final String LANGUAGE_CACHE_KEY = "language"; + private static Language current; + private static final Set requireUpdate = new HashSet<>(); + + static { + try { + current = Language.valueOf((String) Cacher.get(LANGUAGE_CACHE_KEY)); + } catch (Exception e) { + current = Language.DEFAULT; + Cacher.put(LANGUAGE_CACHE_KEY, current.toString()); + } + } + + public static void addTranslatableString(TranslatableString translatableString) { + requireUpdate.add(translatableString); + } + + @Override + protected Object handleGetObject(String key) { + return current.messages.getObject(key); + } + + @Override + public Enumeration getKeys() { + return current.messages.getKeys(); + } + + public static void setLanguage(Language lang) { + current = lang; + requireUpdate.forEach(TranslatableString::trigger); + Cacher.put(LANGUAGE_CACHE_KEY, current.toString()); + } + + public static Language getLanguage() { + return current; + } + + public static String get(String key) { + return current.messages.getString(key); + } +} diff --git a/G-Earth/src/main/java/gearth/ui/translations/TranslatableString.java b/G-Earth/src/main/java/gearth/ui/translations/TranslatableString.java new file mode 100644 index 0000000..4bdf181 --- /dev/null +++ b/G-Earth/src/main/java/gearth/ui/translations/TranslatableString.java @@ -0,0 +1,22 @@ +package gearth.ui.translations; + +import javafx.beans.value.ObservableValueBase; + +public class TranslatableString extends ObservableValueBase { + private final String key; + + public TranslatableString(String key) { + this.key = key; + this.fireValueChangedEvent(); + LanguageBundle.addTranslatableString(this); + } + + @Override + public String getValue() { + return LanguageBundle.get(key); + } + + protected void trigger() { + fireValueChangedEvent(); + } +} diff --git a/G-Earth/src/main/resources/gearth/services/internal_extensions/uilogger/UiLogger.fxml b/G-Earth/src/main/resources/gearth/services/internal_extensions/uilogger/UiLogger.fxml index 52d9fc5..072518d 100644 --- a/G-Earth/src/main/resources/gearth/services/internal_extensions/uilogger/UiLogger.fxml +++ b/G-Earth/src/main/resources/gearth/services/internal_extensions/uilogger/UiLogger.fxml @@ -5,7 +5,7 @@ - + diff --git a/G-Earth/src/main/resources/gearth/ui/G-Earth.fxml b/G-Earth/src/main/resources/gearth/ui/G-Earth.fxml index 8246f98..3db6aa7 100644 --- a/G-Earth/src/main/resources/gearth/ui/G-Earth.fxml +++ b/G-Earth/src/main/resources/gearth/ui/G-Earth.fxml @@ -7,28 +7,29 @@ - + + tab.connection - + - + - + - + - + - + diff --git a/G-Earth/src/main/resources/gearth/ui/subforms/connection/Connection.fxml b/G-Earth/src/main/resources/gearth/ui/subforms/connection/Connection.fxml index 65974ea..d2106ac 100644 --- a/G-Earth/src/main/resources/gearth/ui/subforms/connection/Connection.fxml +++ b/G-Earth/src/main/resources/gearth/ui/subforms/connection/Connection.fxml @@ -5,7 +5,7 @@ - + @@ -45,7 +45,7 @@ -