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に次の行が含まれているとします。
ui.button.text=I'm a Button
FXMLに以下のようなボタン定義がある場合:
<Button text="%ui.button.text"/>
ui.button.textキーの翻訳が自動的に受信されます。
コントローラ
リソースバンドルには、ロケール固有のオブジェクトが含まれています。バンドルはFXMLLoader作成時に渡すことができます。コントローラはInitializableインターフェイスを実装し、 initialize(URL location, ResourceBundle resources)メソッドをオーバーライドする必要があります。このメソッドの2番目のパラメータは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を持つことです(代替として、これはシングルトンに実装されるかもしれません)。
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;
}
}
このクラスには、JavaFX ObjectPropertyラップされたJava Localeオブジェクトである静的フィールドlocaleがあり、このプロパティに対してバインディングを作成できます。最初のメソッドは、JavaFXプロパティを取得および設定するための標準的なメソッドです。
get(final String key, final Object... args)は、 ResourceBundleからの実際のメッセージ抽出に使用されるコアメソッドです。
createStringBindingという2つのメソッドは、 localeフィールドにバインドされたStringBindingを作成し、 localeプロパティが変更されるたびにバインディングが変更されるようにしlocale 。最初の引数は、上記のgetメソッドを使用してメッセージを取得および書式設定する引数を使用し、2番目の引数はCallableに渡され、新しい文字列値を生成する必要があります。
最後の2つのメソッドは、JavaFXコンポーネントを作成するメソッドです。最初のメソッドは、 Labelを作成するために使用され、内部文字列バインディングのためにCallableを使用します。 2番目はButtonを作成し、キー値を使用してStringバインディングを取得します。
もちろん、 MenuItemやToolTipように多くの異なるオブジェクトを作成することができToolTipが、これらの2つの例で十分です。
このコードは、このクラスがアプリケーション内でどのように使用されるかを示しています。
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);
}
}
このアプリケーションは、 I18Nクラスによって作成されたStringBindingを使用する3つの異なる方法を示しています。
- ウィンドウタイトルは
StringBinding直接使用してバインドされます。 - ボタンはヘルパーメソッドをメッセージキーと共に使用します
- ラベルは
Callableヘルパーメソッドを使用します。このCallableはI18N.get()メソッドを使用して、スイッチの実際の数を含む書式付きの変換された文字列を取得します。
ボタンをクリックすると、カウンタが増加し、 I18Nのロケールプロパティが設定され、文字列バインディングの変更がトリガされ、UIの文字列が新しい値に設定されます。