internationalization javafx-2

internationalization - JavaFX 2 e internacionalización



javafx-2 (3)

Empecé a escribir mi primera aplicación JavaFX 2 después de aprender los conceptos básicos y me gustaría internacionalizarla.

Noté que en JavaFX 1.x, el lenguaje de scripting permitía una internacionalización muy simple de las cadenas. ¿Hay alguna característica similar en JavaFX 2?

Básicamente: ¿cuál es la mejor práctica para internacionalizar una aplicación JavaFX 2?


Esto funciona para mí:

└───src ├───app ├───bundles // <- here the "bundles" ├───dicts ├───images ├───libs └───resources

En el paquete de paquetes están

LangBundle_en.properties LangBundle_de.properties

Contenido de la muestra:

enter_pwd=Enter your password:

Para cargarlos utilizo el siguiente código:

@Override public void initialize(URL location, ResourceBundle resources) { ResourceBundle lngBndl = ResourceBundle .getBundle("bundles.LangBundle", new Locale("en", "EN")); tvSetupPwd.setText(lngBndl.getString("enter_pwd")); // ... }


Mira mi ejemplo

Más describí here o en GitHub

Actualizar:

la solución está en 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; } }

y en 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; } }


Los pasos básicos (entre otros) de la internacionalización de una aplicación java son la localización Locale y la agrupación de recursos. En JavaFX, puede usar FXMLLoader#setResources() para ese fin. Aquí una demostración de SSCCE para demostrarlo. Los códigos son autodescriptivos.
Estructura del paquete de demostración:

bundledemo |------ BundleDemo.java |------ MyController.java |------ MyView.fxml bundles |------ MyBundle_en.properties |------ MyBundle_kg.properties

MyBundle_en.properties

key1=Name Surname key2=How are you?

MyBundle_kg.properties

key1=Aты Жөнү key2=Кандайсың?

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); } }

Captura de pantalla: