JavaFX 2 및 국제화


84

기본 사항을 배운 후 첫 번째 JavaFX 2 응용 프로그램을 작성하기 시작했으며이를 국제화하고 싶습니다.

JavaFX 1.x에서 스크립팅 언어는 문자열의 매우 간단한 국제화를 허용했습니다. JavaFX 2에 유사한 기능이 있습니까?

기본적으로 : JavaFX 2 애플리케이션을 국제화하기위한 모범 사례는 무엇입니까?


[: 언어를 전환하기위한 몇 가지 정보 인 stackoverflow.com/a/26318795/2131257][1] [1] stackoverflow.com/a/26318795/2131257
Androdos

답변:


166

자바 앱 국제화의 기본 단계는 Locale라이징 및 리소스 번들링입니다. JavaFX에서는 이러한 FXMLLoader#setResources()용도로 사용할 수 있습니다 . 여기에 SSCCE 데모가 있습니다. 코드는 자명합니다.
데모 패키지 구조 :

bundledemo
    |------ BundleDemo.java
    |------ MyController.java
    |------ MyView.fxml  
bundles
    |------ MyBundle_en.properties
    |------ MyBundle_kg.properties

MyBundle_en.properties

key1=Name Surname
key2=How are you?

MyBundle_kg.properties

key1=Aты Жөнү
key2=Кандайсың?

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);
    }
}

스크린 샷 :

여기에 이미지 설명 입력


훌륭한 대답이며 그대로 받아들이 겠지만 FXML이 아닌 코드로 인터페이스를 구축하고 있다고 언급 했어야했습니다. 코드에서 국제화하는 빠르고 쉬운 방법이 있습니까? ResourceBundle.getBundle + 조회를 수행 할 수 있지만 대신 사용할 수있는 % key 표기법과 같은 것이 있기를 바랐습니다.
wobblycogs 2012

7
그런 다음 다른 Java 응용 프로그램에서와 같이 일반적인 방법으로 수행 할 수 있습니다. 사용자 / 클라이언트의 로케일을 결정한 다음 그에 따라 앱의 로케일을 변경합니다 (DB 대에서 언어 별 데이터 가져 오기). 으로 적절한 번들을로드합니다 ResourceBundle.getBundle("bundles.MyBundle", locale). 보기 / 페이지에서 사용한 모든 텍스트를 bundle.getString("key").
Uluk Biy 2012

2
setResources () 메서드를 통해 ResourceBundle을 제공하면 작동하지 않습니다. load () 메서드를 통해 ResourceBundle을 제공 할 때 작동합니다.
Jurica Krizanic 2013 년

1
@Jurica Krizanic는 : 같은 문제가 있고, 같은 방법을 통해 해결 : 문자열과 방법 적절한 로케일을 반환 자원. FXMLLoader.load(getClass().getResource(sceneId), getResources())sceneIdgetResources()
TG

훌륭합니다. oracle 튜토리얼과 같은 정적 방식의 변형도 작동합니다 (짧은 길이 임). Pane pane = (BorderPane) FxmlLoader.load (this.getClass (). getResource ( "MyView.fxml"), ResourceBundle.getBundle ( "bundles.MyBundle", 로케일));
pdem

15

이것은 나를 위해 작동합니다.

└───src
    ├───app
    ├───bundles // <- here the "bundles"
    ├───dicts
    ├───images
    ├───libs
    └───resources

번들 패키지에는

LangBundle_en.properties
LangBundle_de.properties

샘플 내용 :

enter_pwd=Enter your password:

로드하려면 다음 코드를 사용합니다.

@Override
public void initialize(URL location, ResourceBundle resources) {
    ResourceBundle lngBndl = ResourceBundle
            .getBundle("bundles.LangBundle", new Locale("en", "EN"));

    tvSetupPwd.setText(lngBndl.getString("enter_pwd"));
    // ...
}

4

내 예를 봐 여기에 이미지 설명 입력

여기 또는 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;
    }
}

@Moritz는 링크를 클릭하고 자세한 응답과 전체 소스 파일을 보았을 것입니다. stackoverflow.com에 대한 응답으로 링크를 포함했습니다. 당신 때문에 나는 모든 곳에 동일한 코드를 삽입해야합니다. 싫어하는처럼이 아니라 내가 당신을 기대
안드레이 Krasutski
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.