Я только начал писать свое первое приложение JavaFX 2 после изучения основ и хотел бы интернационализировать его.
Я заметил, что в JavaFX 1.x язык сценариев допускал очень простую интернационализацию строк. Есть ли в JavaFX 2 аналогичные функции?
В основном: какова наилучшая практика интернационализации приложения JavaFX 2?
internationalization
javafx-2
шаткие
источник
источник
Ответы:
Основные этапы (среди прочего) интернационализации Java-приложения - это
Locale
сборка и объединение ресурсов. В JavaFX вы можете использоватьFXMLLoader#setResources()
для этих целей. Вот демонстрация SSCCE, чтобы продемонстрировать это. Коды информативны.Структура демонстрационного пакета:
MyBundle_ru.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); } }
Скриншот:
источник
ResourceBundle.getBundle("bundles.MyBundle", locale)
. Измените каждый текст, который вы использовали в своем представлении / страницеbundle.getString("key")
.FXMLLoader.load(getClass().getResource(sceneId), getResources())
гдеsceneId
строка, а методgetResources()
возвращает ресурс с правильной локалью.Это работает для меня:
└───src ├───app ├───bundles // <- here the "bundles" ├───dicts ├───images ├───libs └───resources
В комплекте поставки есть
Образец содержания:
Для их загрузки я использую следующий код:
@Override public void initialize(URL location, ResourceBundle resources) { ResourceBundle lngBndl = ResourceBundle .getBundle("bundles.LangBundle", new Locale("en", "EN")); tvSetupPwd.setText(lngBndl.getString("enter_pwd")); // ... }
источник
Посмотри на мой пример
Подробнее я описал здесь или на GitHub
Обновить:
решение находится в
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; } }
И в
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; } }
источник