我正在開發具有多種語言支持的JavaFX應用程序。我的應用程序有時會顯示一個警告框,例如:使用自定義語言的Javafx國際化
package application;
import java.util.Locale;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
Button btn = new Button("Show alert");
btn.setOnAction(this::handleButton);
BorderPane root = new BorderPane();
root.setCenter(btn);
Scene scene = new Scene(root,200, 200);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
void handleButton(ActionEvent e){
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.showAndWait();
}
static Locale getLocaleSettingFromConfigurationFile(){
return Locale.FRENCH;
//return new Locale("vi");
}
public static void main(String[] args) {
Locale appLocale = getLocaleSettingFromConfigurationFile();
Locale.setDefault(appLocale);
launch(args);
}
}
語言設置通過getLocaleSettingFromConfigurationFile()
方法
在上面的代碼中,我使用Locale.FRENCH
作爲應用程序的語言獲得,一切工作文件:
兩確認按鈕已被翻譯成法語。
現在我想讓我的應用支持越南語(從上面的代碼中取消註釋return new Locale("vi")
)。深入挖掘細節之後,我發現:
- >雙確認「確定」按鈕,「取消」從構造:
package javafx.scene.control;
import com.sun.javafx.scene.control.skin.resources.ControlResources;
import javafx.beans.NamedArg;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar.ButtonData;
/**
* The ButtonType class is used as part of the JavaFX {@link Dialog} API (more
* specifically, the {@link DialogPane} API) to specify which buttons should be
* shown to users in the dialogs. Refer to the {@link DialogPane} class javadoc
* for more information on how to use this class.
*
* @see Alert
* @see Dialog
* @see DialogPane
* @since JavaFX 8u40
*/
public final class ButtonType {
/**
* A pre-defined {@link ButtonType} that displays "Apply" and has a
* {@link ButtonData} of {@link ButtonData#APPLY}.
*/
public static final ButtonType APPLY = new ButtonType(
"Dialog.apply.button", null, ButtonData.APPLY);
/**
* A pre-defined {@link ButtonType} that displays "OK" and has a
* {@link ButtonData} of {@link ButtonData#OK_DONE}.
*/
public static final ButtonType OK = new ButtonType(
"Dialog.ok.button", null, ButtonData.OK_DONE);
/**
* A pre-defined {@link ButtonType} that displays "Cancel" and has a
* {@link ButtonData} of {@link ButtonData#CANCEL_CLOSE}.
*/
public static final ButtonType CANCEL = new ButtonType(
"Dialog.cancel.button", null, ButtonData.CANCEL_CLOSE);
/**
* A pre-defined {@link ButtonType} that displays "Close" and has a
* {@link ButtonData} of {@link ButtonData#CANCEL_CLOSE}.
*/
public static final ButtonType CLOSE = new ButtonType(
"Dialog.close.button", null, ButtonData.CANCEL_CLOSE);
/**
* A pre-defined {@link ButtonType} that displays "Yes" and has a
* {@link ButtonData} of {@link ButtonData#YES}.
*/
public static final ButtonType YES = new ButtonType(
"Dialog.yes.button", null, ButtonData.YES);
/**
* A pre-defined {@link ButtonType} that displays "No" and has a
* {@link ButtonData} of {@link ButtonData#NO}.
*/
public static final ButtonType NO = new ButtonType(
"Dialog.no.button", null, ButtonData.NO);
/**
* A pre-defined {@link ButtonType} that displays "Finish" and has a
* {@link ButtonData} of {@link ButtonData#FINISH}.
*/
public static final ButtonType FINISH = new ButtonType(
"Dialog.finish.button", null, ButtonData.FINISH);
/**
* A pre-defined {@link ButtonType} that displays "Next" and has a
* {@link ButtonData} of {@link ButtonData#NEXT_FORWARD}.
*/
public static final ButtonType NEXT = new ButtonType(
"Dialog.next.button", null, ButtonData.NEXT_FORWARD);
/**
* A pre-defined {@link ButtonType} that displays "Previous" and has a
* {@link ButtonData} of {@link ButtonData#BACK_PREVIOUS}.
*/
public static final ButtonType PREVIOUS = new ButtonType(
"Dialog.previous.button", null, ButtonData.BACK_PREVIOUS);
private final String key;
private final String text;
private final ButtonData buttonData;
/**
* Creates a ButtonType instance with the given text, and the ButtonData set
* as {@link ButtonData#OTHER}.
*
* @param text The string to display in the text property of controls such
* as {@link Button#textProperty() Button}.
*/
public ButtonType(@NamedArg("text") String text) {
this(text, ButtonData.OTHER);
}
/**
* Creates a ButtonType instance with the given text, and the ButtonData set
* as specified.
*
* @param text The string to display in the text property of controls such
* as {@link Button#textProperty() Button}.
* @param buttonData The type of button that should be created from this ButtonType.
*/
public ButtonType(@NamedArg("text") String text,
@NamedArg("buttonData") ButtonData buttonData) {
this(null, text, buttonData);
}
/**
* Provide key or text. The other one should be null.
*/
private ButtonType(String key, String text, ButtonData buttonData) {
this.key = key;
this.text = text;
this.buttonData = buttonData;
}
/**
* Returns the ButtonData specified for this ButtonType in the constructor.
*/
public final ButtonData getButtonData() { return this.buttonData; }
/**
* Returns the text specified for this ButtonType in the constructor;
*/
public final String getText() {
if (text == null && key != null) {
return ControlResources.getString(key);
} else {
return text;
}
}
/** {@inheritDoc} */
@Override public String toString() {
return "ButtonType [text=" + getText() + ", buttonData=" + getButtonData() + "]";
}
}
- >按鈕顯示文本從ControlResources.getString(key)
呈現,其源代碼:
package com.sun.javafx.scene.control.skin.resources;
import java.util.ResourceBundle;
public final class ControlResources {
// Translatable properties
private static final String BASE_NAME = "com/sun/javafx/scene/control/skin/resources/controls";
// Non-translateable properties
private static final String NT_BASE_NAME = "com/sun/javafx/scene/control/skin/resources/controls-nt";
// Do not cache the bundle here. It is cached by the ResourceBundle
// class and may be updated if the default locale changes.
private ControlResources() {
// no-op
}
/*
* Look up a string in the properties file corresponding to the
* default locale (i.e. the application's locale). If not found, the
* search then falls back to the base controls.properties file,
* containing the default string (usually English).
*/
public static String getString(String key) {
return ResourceBundle.getBundle(BASE_NAME).getString(key);
}
/*
* Look up a non-translatable string in the properties file
* corresponding to the default locale (i.e. the application's
* locale). If not found, the search then falls back to the base
* controls-nt.properties file, containing the default string.
*
* Note that property values may be set in locale-specific files,
* e.g. when a property value is defined for a country rather than
* a language. However, there are no such files included with
* JavaFX 8, but may be added to the classpath by developers or
* users.
*/
public static String getNonTranslatableString(String key) {
return ResourceBundle.getBundle(NT_BASE_NAME).getString(key);
}
}
現在,我想我的解決方案如下:
步驟1:在越南創建資源文件com/sun/javafx/scene/control/skin/resources/controls_vi.properties
項目
### Dialogs ###
Dialog.apply.button = Áp d\u1EE5ng
Dialog.ok.button = OK
Dialog.close.button = \u0110óng
Dialog.cancel.button = H\u1EE7y b\u1ECF
Dialog.yes.button = Có
Dialog.no.button = Không
Dialog.finish.button = Hoàn thành
Dialog.next.button = Ti\u1EBFp
Dialog.previous.button = Tr\u01B0\u1EDBc
空空的應用程序,該按鈕語言還是英語之後。
第2步:我發現加載JavaFx資源文件的類加載器與我的應用類加載器不同(請參閱ResourceBundle.getBundle(BASE_NAME)
API)。這是資源的內部jfxrt.jar
:
我試圖加載ControlResources
類應用程序類加載器,但還是沒有結果:
public static void main(String[] args) throws Exception {
List<Locale> fxSupported = Arrays.asList(Locale.ENGLISH, Locale.FRENCH); // Add later ....
Locale appLocale = getLocaleSettingFromConfigurationFile();
Locale.setDefault(appLocale);
// Load class from current class loader
if (!fxSupported.contains(appLocale)){
ClassLoader loader = Main.class.getClassLoader();
Class<?> loadedCls = Class.forName("com.sun.javafx.scene.control.skin.resources.ControlResources", true, loader);
System.out.printf("Loader 1: %s\nloader 2: %s\n", loader, loadedCls.getClassLoader());
// Loader 1: [email protected]
// loader 2: [email protected]
}
launch(args);
}
備用解決方案
我可以創建自己的ButtonType
「OK」, 「取消」並加載我自己的資源字符串,將創建的按鈕列表設置爲Alert
對象,但我想使用系統提供的資源。
ResourceBundle res = ResourceBundle.getBundle("application.myownres");
ButtonType OK = new ButtonType(res.getString("btn.ok"), ButtonData.OK_DONE);
ButtonType CANCEL = new ButtonType(res.getString("btn.cancel"), ButtonData.CANCEL_CLOSE);
Alert alert = new Alert(AlertType.CONFIRMATION, "Are you sure", OK, CANCEL);
alert.showAndWait();
因此,任何人有解決方案,並不需要創建新ButtonType
對象。
謝謝
你可以打包你的翻譯文件放在一個單獨的JAR並將它添加到引導類路徑,從而使JavaFX的類加載器可以看到他們:'java的-Xbootclasspath/A :my-translations.jar -cp ...'。無論是自定義按鈕類型是否值得...我不知道! –