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을 갖는 것입니다 (대안으로 이것은 싱글 톤으로 구현 될 수 있습니다).
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
이 ObjectProperty
속성에 대한 바인딩을 만들 수 있습니다. 첫 번째 메소드는 JavaFX 속성을 가져오고 설정하는 표준 메소드입니다.
get(final String key, final Object... args)
은 ResourceBundle
에서 메시지를 추출하는 데 사용되는 핵심 메소드입니다.
createStringBinding
이라는 두 메서드는 locale
필드에 바인딩 된 StringBinding
을 만들고 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);
}
}
이 응용 프로그램은 I18N
클래스에 의해 생성 된 StringBinding
을 사용하는 세 가지 다른 방법을 보여줍니다.
- 윈도우 타이틀은
StringBinding
을 직접 사용하여 바인딩됩니다. - 버튼은 메시지 키와 함께 도우미 메서드를 사용합니다.
- 레이블은
Callable
과 함께 도우미 메서드를 사용합니다. 이Callable
I18N.get()
는I18N.get()
메서드를 사용하여 실제 스위치 수를 포함하는 형식화 된 변환 문자열을 가져옵니다.
버튼을 클릭하면 카운터가 증가하고 I18N
의 로케일 속성이 설정되고 문자열 바인딩이 변경되어 UI 문자열이 새 값으로 설정됩니다.