javafx
Интернационализация в JavaFX
Поиск…
Загрузка пакета ресурсов
JavaFX обеспечивает простой способ интернационализировать ваши пользовательские интерфейсы. При создании представления из файла FXML вы можете предоставить FXMLLoader
пакет ресурсов:
Locale locale = new Locale("en", "UK");
ResourceBundle bundle = ResourceBundle.getBundle("strings", locale);
Parent root = FXMLLoader.load(getClass().getClassLoader()
.getResource("ui/main.fxml"), bundle);
Этот предоставленный комплект автоматически используется для перевода всех текстов в ваш файл FXML, начинающийся с %
. strings_en_UK.properties
ваш файл свойств strings_en_UK.properties
содержит следующую строку:
ui.button.text=I'm a Button
Если в вашем FXML есть определение кнопки:
<Button text="%ui.button.text"/>
Он автоматически получит перевод для ключа ui.button.text
.
контроллер
Пакеты ресурсов содержат локальные объекты. Вы можете передать пакет на FXMLLoader
во время его создания. Контроллер должен реализовать интерфейс Initializable
и переопределить метод initialize(URL location, ResourceBundle resources)
. Второй параметр этого метода - ResourceBundle
который передается из FXMLLoader в контроллер и может использоваться контроллером для дальнейшего перевода текстов или изменения другой информации, зависящей от локали.
public class MyController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
label.setText(resources.getString("country"));
}
}
Динамическое переключение языка при запуске приложения
В этом примере показано, как создать приложение JavaFX, где язык может переключаться динамически во время работы приложения.
Это файлы пакета сообщений, используемые в примере:
messages_en.properties :
window.title=Dynamic language change
button.english=English
button.german=German
label.numSwitches=Number of language switches: {0}
messages_de.properties :
window.title=Dynamischer Sprachwechsel
button.english=Englisch
button.german=Deutsch
label.numSwitches=Anzahl Sprachwechsel: {0}
Основная идея состоит в том, чтобы иметь класс утилиты I18N (в качестве альтернативы это может быть реализовано singleton).
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.concurrent.Callable;
/**
* I18N utility class..
*/
public final class I18N {
/** the current selected Locale. */
private static final ObjectProperty<Locale> locale;
static {
locale = new SimpleObjectProperty<>(getDefaultLocale());
locale.addListener((observable, oldValue, newValue) -> Locale.setDefault(newValue));
}
/**
* get the supported Locales.
*
* @return List of Locale objects.
*/
public static List<Locale> getSupportedLocales() {
return new ArrayList<>(Arrays.asList(Locale.ENGLISH, Locale.GERMAN));
}
/**
* get the default locale. This is the systems default if contained in the supported locales, english otherwise.
*
* @return
*/
public static Locale getDefaultLocale() {
Locale sysDefault = Locale.getDefault();
return getSupportedLocales().contains(sysDefault) ? sysDefault : Locale.ENGLISH;
}
public static Locale getLocale() {
return locale.get();
}
public static void setLocale(Locale locale) {
localeProperty().set(locale);
Locale.setDefault(locale);
}
public static ObjectProperty<Locale> localeProperty() {
return locale;
}
/**
* gets the string with the given key from the resource bundle for the current locale and uses it as first argument
* to MessageFormat.format, passing in the optional args and returning the result.
*
* @param key
* message key
* @param args
* optional arguments for the message
* @return localized formatted string
*/
public static String get(final String key, final Object... args) {
ResourceBundle bundle = ResourceBundle.getBundle("messages", getLocale());
return MessageFormat.format(bundle.getString(key), args);
}
/**
* creates a String binding to a localized String for the given message bundle key
*
* @param key
* key
* @return String binding
*/
public static StringBinding createStringBinding(final String key, Object... args) {
return Bindings.createStringBinding(() -> get(key, args), locale);
}
/**
* creates a String Binding to a localized String that is computed by calling the given func
*
* @param func
* function called on every change
* @return StringBinding
*/
public static StringBinding createStringBinding(Callable<String> func) {
return Bindings.createStringBinding(func, locale);
}
/**
* creates a bound Label whose value is computed on language change.
*
* @param func
* the function to compute the value
* @return Label
*/
public static Label labelForValue(Callable<String> func) {
Label label = new Label();
label.textProperty().bind(createStringBinding(func));
return label;
}
/**
* creates a bound Button for the given resourcebundle key
*
* @param key
* ResourceBundle key
* @param args
* optional arguments for the message
* @return Button
*/
public static Button buttonForKey(final String key, final Object... args) {
Button button = new Button();
button.textProperty().bind(createStringBinding(key, args));
return button;
}
}
Этот класс имеет статическое поле locale
, которая является Java Locale
объекта , завернутым в JavaFX ObjectProperty
, так что переплеты могут быть созданы для этого свойства. Первые методы - это стандартные методы получения и установки свойства JavaFX.
get(final String key, final Object... args)
- это основной метод, который используется для реального извлечения сообщения из ResourceBundle
.
Два метода с именем createStringBinding
создают StringBinding
, привязанный к locale
и поэтому привязки будут меняться всякий раз, когда изменяется свойство locale
. Первый использует свои аргументы для извлечения и форматирования сообщения с использованием метода get
упомянутого выше, второй передается в Callable
, который должен вызывать новое строковое значение.
Последние два метода - это методы создания компонентов JavaFX. Первый метод используется для создания Label
и использует Callable
для его внутренней привязки строк. Второй создает Button
и использует значение ключа для извлечения привязки String.
Конечно, можно было бы создать много других объектов, таких как MenuItem
или ToolTip
но этих двух должно быть достаточно для примера.
Этот код показывает, как этот класс используется в приложении:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import java.util.Locale;
/**
* Sample application showing dynamic language switching,
*/
public class I18nApplication extends Application {
/** number of language switches. */
private Integer numSwitches = 0;
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.titleProperty().bind(I18N.createStringBinding("window.title"));
// create content
BorderPane content = new BorderPane();
// at the top two buttons
HBox hbox = new HBox();
hbox.setPadding(new Insets(5, 5, 5, 5));
hbox.setSpacing(5);
Button buttonEnglish = I18N.buttonForKey("button.english");
buttonEnglish.setOnAction((evt) -> switchLanguage(Locale.ENGLISH));
hbox.getChildren().add(buttonEnglish);
Button buttonGerman = I18N.buttonForKey("button.german");
buttonGerman.setOnAction((evt) -> switchLanguage(Locale.GERMAN));
hbox.getChildren().add(buttonGerman);
content.setTop(hbox);
// a label to display the number of changes, recalculating the text on every change
final Label label = I18N.labelForValue(() -> I18N.get("label.numSwitches", numSwitches));
content.setBottom(label);
primaryStage.setScene(new Scene(content, 400, 200));
primaryStage.show();
}
/**
* sets the given Locale in the I18N class and keeps count of the number of switches.
*
* @param locale
* the new local to set
*/
private void switchLanguage(Locale locale) {
numSwitches++;
I18N.setLocale(locale);
}
}
Приложение показывает три разных способа использования StringBinding
созданных классом I18N
:
- заголовок окна связан напрямую с помощью
StringBinding
. - кнопки используют вспомогательный метод с помощью клавиш сообщения
- метка использует вспомогательный метод с помощью
Callable
. ЭтотCallable
использует методI18N.get()
для получения форматированной переведенной строки, содержащей фактическое количество переключателей.
При нажатии кнопки счетчик увеличивается, и I18N
свойство locale I18N
s, которое, в свою очередь, вызывает изменение привязок строк и, таким образом, устанавливает строку пользовательского интерфейса в новые значения.