Ich habe gerade angefangen, meine erste JavaFX 2-Anwendung zu schreiben, nachdem ich die Grundlagen gelernt habe, und möchte sie internationalisieren.
Ich stelle fest, dass in JavaFX 1.x die Skriptsprache eine sehr einfache Internationalisierung von Zeichenfolgen ermöglichte. Gibt es ähnliche Funktionen in JavaFX 2?
Grundsätzlich gilt: Was ist die beste Vorgehensweise für die Internationalisierung einer JavaFX 2-Anwendung?
internationalization
javafx-2
Wackelzähne
quelle
quelle
Antworten:
Die grundlegenden Schritte (unter anderem) einer Internationalisierung einer Java-App sind das
Locale
Lizing und die Ressourcenbündelung. In JavaFX können Sie dies verwendenFXMLLoader#setResources()
. Hier eine SSCCE-Demo, um dies zu demonstrieren. Die Codes sind selbstbeschreibend.Struktur des Demopakets:
MyBundle_en.properties
MyBundle_kg.properties
MyView.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.*?> <?import javafx.scene.control.*?> <?import javafx.scene.*?> <BorderPane fx:controller="bundledemo.MyController" xmlns:fx="http://javafx.com/fxml"> <top> <!-- This label's text will be set by the controller --> <Label fx:id="lblTextByController"/> </top> <center> <!-- This label's text will be taken from the bundle automatically --> <Label text="%key2"/> </center> </BorderPane>
MyController.java
package bundledemo; import java.net.URL; import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; public class MyController implements Initializable { @FXML private Label lblTextByController; private ResourceBundle bundle; @Override public void initialize(URL location, ResourceBundle resources) { bundle = resources; lblTextByController.setText(bundle.getString("key1")); } }
BundleDemo.java
package bundledemo; // imports are ignored. public class BundleDemo extends Application { private Stage stage; @Override public void start(Stage primaryStage) { stage = primaryStage; Button btnEN = new Button(); btnEN.setText("English"); btnEN.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { loadView(new Locale("en", "EN")); } }); Button btnKG = new Button(); btnKG.setText("Kyrgyz"); btnKG.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { loadView(new Locale("kg", "KG")); } }); VBox root = new VBox(20); root.getChildren().add(HBoxBuilder.create().spacing(10).style("-fx-background-color: gray").padding(new Insets(5)).children(btnEN, btnKG).build()); root.getChildren().add(new StackPane()); primaryStage.setScene(new Scene(root, 300, 250)); primaryStage.show(); } private void loadView(Locale locale) { try { FXMLLoader fxmlLoader = new FXMLLoader(); fxmlLoader.setResources(ResourceBundle.getBundle("bundles.MyBundle", locale)); Pane pane = (BorderPane) fxmlLoader.load(this.getClass().getResource("MyView.fxml").openStream()); // replace the content StackPane content = (StackPane) ((VBox) stage.getScene().getRoot()).getChildren().get(1); content.getChildren().clear(); content.getChildren().add(pane); } catch (IOException ex) { ex.printStackTrace(); } } public static void main(String[] args) { launch(args); } }
Bildschirmfoto:
quelle
ResourceBundle.getBundle("bundles.MyBundle", locale)
. Ändern Sie jeden Text, den Sie in Ihrer Ansicht / Seite verwendet habenbundle.getString("key")
.FXMLLoader.load(getClass().getResource(sceneId), getResources())
WosceneId
ist Zeichenfolge und MethodegetResources()
gibt Ressource mit dem richtigen Gebietsschema zurück.Das funktioniert bei mir:
└───src ├───app ├───bundles // <- here the "bundles" ├───dicts ├───images ├───libs └───resources
Im Bundles-Paket sind
Beispielinhalt:
Um sie zu laden, benutze ich den folgenden Code:
@Override public void initialize(URL location, ResourceBundle resources) { ResourceBundle lngBndl = ResourceBundle .getBundle("bundles.LangBundle", new Locale("en", "EN")); tvSetupPwd.setText(lngBndl.getString("enter_pwd")); // ... }
quelle
Schau dir mein Beispiel an
Mehr habe ich hier oder auf GitHub beschrieben
Aktualisieren:
Die Lösung ist in
Messages.java
/** * The class with all messages of this application. */ public abstract class Messages { private static ResourceBundle BUNDLE; private static final String FIELD_NAME = "lookup"; private static final String BUNDLE_NAME = "messages/messages"; private static final String CONTROLS_BUNDLE_NAME = "com/sun/javafx/scene/control/skin/resources/controls"; public static final String MAIN_APP_TITLE; public static final String DIALOG_HEADER; public static final String MAIN_CONTROLLER_CONTENT_TEXT; public static final String MAIN_CONTROLLER_HELLO_TEXT; public static final String MAIN_CONTROLLER_GOODBYE_TEXT; static { final Locale locale = Locale.getDefault(); final ClassLoader classLoader = ControlResources.class.getClassLoader(); final ResourceBundle controlBundle = getBundle(CONTROLS_BUNDLE_NAME, locale, classLoader, PropertyLoader.getInstance()); final ResourceBundle overrideBundle = getBundle(CONTROLS_BUNDLE_NAME, PropertyLoader.getInstance()); final Map override = getUnsafeFieldValue(overrideBundle, FIELD_NAME); final Map original = getUnsafeFieldValue(controlBundle, FIELD_NAME); //noinspection ConstantConditions,ConstantConditions,unchecked original.putAll(override); BUNDLE = getBundle(BUNDLE_NAME, PropertyLoader.getInstance()); MAIN_APP_TITLE = BUNDLE.getString("MainApp.title"); DIALOG_HEADER = BUNDLE.getString("Dialog.information.header"); MAIN_CONTROLLER_CONTENT_TEXT = BUNDLE.getString("MainController.contentText"); MAIN_CONTROLLER_HELLO_TEXT = BUNDLE.getString("MainController.helloText"); MAIN_CONTROLLER_GOODBYE_TEXT = BUNDLE.getString("MainController.goodbyeText"); } public static ResourceBundle GetBundle() { return BUNDLE; } }
und in
PropertyLoader.java
public class PropertyLoader extends ResourceBundle.Control { private static final String PROPERTIES_RESOURCE_NAME = "properties"; private static final PropertyLoader INSTANCE = new PropertyLoader(); public static PropertyLoader getInstance() { return INSTANCE; } @Override public ResourceBundle newBundle(final String baseName, final Locale locale, final String format, final ClassLoader loader, final boolean reload) throws IllegalAccessException, InstantiationException, IOException { final String bundleName = toBundleName(baseName, locale); final String resourceName = toResourceName(bundleName, PROPERTIES_RESOURCE_NAME); ResourceBundle bundle = null; InputStream stream = null; if (reload) { final URL url = loader.getResource(resourceName); if (url != null) { final URLConnection connection = url.openConnection(); if (connection != null) { connection.setUseCaches(false); stream = connection.getInputStream(); } } } else { stream = loader.getResourceAsStream(resourceName); } if (stream != null) { try { bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); } finally { stream.close(); } } return bundle; } }
quelle