JavaFX 2 और अंतर्राष्ट्रीयकरण


84

मैंने अभी मूल बातें सीखने के बाद अपना पहला JavaFX 2 एप्लिकेशन लिखना शुरू किया है और इसे अंतर्राष्ट्रीय करना चाहूंगा।

मुझे लगता है कि JavaFX 1.x में, स्क्रिप्टिंग भाषा में स्ट्रिंग्स के बहुत ही सरल अंतर्राष्ट्रीयकरण की अनुमति है। क्या JavaFX 2 में कोई समान विशेषताएं हैं?

मूल रूप से: JavaFX 2 एप्लिकेशन का अंतर्राष्ट्रीयकरण करने के लिए सबसे अच्छा अभ्यास क्या है?


भाषाओं के बीच स्विच करने के लिए कुछ जानकारी यहाँ दी गई है: [ stackoverflow.com/a/26318795/2131257
जगहों

जवाबों:


166

एक जावा ऐप अंतर्राष्ट्रीयकरण के मूल चरण (अन्य के अलावा), आकार Localeऔर संसाधन बंडल हैं। जावाएफएक्स में, आप 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);
    }
}

स्क्रीनशॉट:

यहां छवि विवरण दर्ज करें


उत्कृष्ट उत्तर और मैं इसे स्वीकार करूंगा, लेकिन मुझे यह उल्लेख करना चाहिए कि मैं एफएक्सएमएल के बजाय कोड में इंटरफ़ेस का निर्माण कर रहा हूं। क्या कोड में अंतर्राष्ट्रीयकरण करने का एक त्वरित और आसान तरीका है, मुझे लगता है कि मैं एक ResourceBundle.getBundle + लुकअप कर सकता हूं, लेकिन मैं उम्मीद कर रहा था कि% कुंजी संकेतन जैसा कुछ था जिसे मैं इसके बजाय उपयोग कर सकता हूं।
wobblycogs

7
तब आप किसी अन्य जावा एप्लिकेशन की तरह साधारण तरीके से कर सकते हैं। उपयोगकर्ता के / ग्राहक के स्थान का निर्धारण करें फिर उसके अनुसार ऐप के लोकेल को बदलें (डीबी बनाम से लंग विशिष्ट डेटा प्राप्त करें)। द्वारा उपयुक्त बंडल लोड करें ResourceBundle.getBundle("bundles.MyBundle", locale)। आपके द्वारा उपयोग किए गए प्रत्येक पाठ को अपने दृश्य / पृष्ठ में बदलें bundle.getString("key")
उलूक बाय

2
यह मेरे लिए काम नहीं कर रहा है अगर मैं setResource () विधि पर एक संसाधन संसाधन प्रदान करता हूं। यह काम कर रहा है जब मैं लोड () पद्धति से रिसोर्सबंडल प्रदान करता हूं।
ज्यूरिका क्रिआज़िक

1
@ ज्यूरिका क्रिआज़िक: के पास एक ही समस्या थी, और इसे उसी तरह से हल किया गया: FXMLLoader.load(getClass().getResource(sceneId), getResources())जहाँ sceneIdस्ट्रिंग और विधि getResources()रिटर्न संसाधन उचित लोकेल के साथ है।
TG

अच्छा है, जैसे कि ओरेकल ट्यूटोरियल में स्थिर तरीके के साथ एक संस्करण भी काम करता है (और यह छोटा है): फलक फलक = (BorderPane) FxmlLoader.load (this.getClass ()। GetResource ("MyView.fxml"), ResourceBundle.getBundle। ("बंडल। मायबंडल", लोकेल));
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 आपने लिंक पर क्लिक किया होगा और विस्तृत प्रतिक्रिया और पूर्ण स्रोत फ़ाइलों को देखा होगा, मैंने stacklflow.com के जवाब में एक लिंक शामिल किया है। यू की वजह से मुझे हर जगह एक ही कोड डालना होगा। मुझे उम्मीद है कि आप पसंद करेंगे और नापसंद नहीं होंगे
आंद्रेई कर्सुट्स्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.