如何在JavaFX中更改语言时重新加载屏幕?

时间:2014-01-16 19:38:19

标签: internationalization javafx screen

好吧,我是java和fxml的初学者。

我创建了一个应用程序,需要更改屏幕的语言。我有国际化的密钥文件,但我不知道用更改的语言重新加载屏幕。 该应用程序有一个菜单,其中有可用的语言。我只想在用户更改语言时刷新屏幕。

更改仍然是手动的,您可以在代码中看到:(Main.java):

public class Main extends Application {

private Locale locale = new Locale("en", "US");
private Image icon = new Image("picture.jpg");

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"), ResourceBundle.getBundle("label", locale));
    Scene scene = new Scene(root);
    stage.setTitle("GUI");
    stage.getIcons().add(icon);
    stage.setScene(scene);
    stage.show();
}
public static void main(String[] args) {
    launch(args);
}

当更改语言时,此代码在控制器上:

    @FXML
private void btnMenuLanguageEnglishAction(ActionEvent event) {
    this.locale = new Locale("en", "US");
}

@FXML
private void btnMenuLanguagePortuguesAction(ActionEvent event) {
    this.locale = new Locale("pt", "BR");
}

如何将此区域设置发送到main并刷新屏幕? 我将使用哪种方法?我尝试了一些我在网站上看到的,但没有人回答我的问题。

4 个答案:

答案 0 :(得分:5)

这是我的实施:

import javafx.fxml.FXMLLoader;
import javafx.geometry.NodeOrientation;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

/**
 * Created by Fouad on 3/20/2015.
 */
public abstract class I18NController
{
    private Stage primaryStage;

    public void setPrimaryStage(Stage primaryStage){this.primaryStage = primaryStage;}
    public Stage getPrimaryStage(){return primaryStage;}

    public final void changeLanguage(I18NLanguage language) throws IOException
    {
        StateBundle stateBundle = new StateBundle();
        onSaveState(stateBundle);

        Locale locale = language.getLocale();
        Locale.setDefault(locale);

        ResourceBundle resourceBundle = getResourceBundle(locale);
        URL fxml = getFXMLResource();
        FXMLLoader loader = new FXMLLoader(fxml, resourceBundle);
        Parent root = loader.load();

        NodeOrientation nodeOrientation = language.getNodeOrientation();
        root.setNodeOrientation(nodeOrientation);

        primaryStage.setScene(new Scene(root));
        primaryStage.sizeToScene();

        I18NController newController = loader.getController();
        newController.setPrimaryStage(primaryStage);

        onLoadState(newController, language, resourceBundle, stateBundle);
    }

    protected abstract ResourceBundle getResourceBundle(Locale locale);
    protected abstract URL getFXMLResource();
    protected abstract void onSaveState(StateBundle stateBundle);
    protected abstract void onLoadState(I18NController newController, I18NLanguage newLanguage, ResourceBundle resourceBundle, StateBundle stateBundle);

    public static interface I18NLanguage
    {
        Locale getLocale();
        NodeOrientation getNodeOrientation();
    }

    public static class StateBundle
    {
        private Map<String, Object> sMap = new HashMap<>();

        StateBundle(){}

        public void putData(String key, Object value)
        {
            sMap.put(key, value);
        }

        public <T> T getDate(String key, Class<T> type)
        {
            return type.cast(sMap.get(key));
        }
    }
}

您可以将此类用作控制器的基类,如下所示:

<强> JavaFXController.java:

public class JavaFXController extends I18NController implements Initializable
{
    @FXML private DatePicker dpDate;
    @FXML private RadioButton rdoArabic;
    @FXML private RadioButton rdoEnglish;

    // ...

    @Override
    public void initialize(URL location, ResourceBundle resources)
    {
        // ...

        rdoEnglish.setOnAction(e ->
        {
            try
            {
                changeLanguage(AppSettings.Language.ENGLISH);
            }
            catch(IOException e1)
            {
                e1.printStackTrace();
            }
        });

        rdoArabic.setOnAction(e ->
        {
            try
            {
                changeLanguage(AppSettings.Language.ARABIC);
            }
            catch(IOException e1)
            {
                e1.printStackTrace();
            }
        });
    }

    // ...

    @Override
    protected ResourceBundle getResourceBundle(Locale locale)
    {
        return ResourceBundle.getBundle("com/stackoverflow/gui/resources/JavaFXResourceBundle", locale, new UTF8Control());
    }

    @Override
    protected URL getFXMLResource()
    {
        return getClass().getResource("resources/JavaFXDocument.fxml");
    }

    @Override
    protected void onSaveState(StateBundle stateBundle)
    {
        LocalDate localDate = dpDate.getValue();
        boolean isRdoArabicSelected = rdoArabic.isSelected();
        boolean isRdoEnglishSelected = rdoEnglish.isSelected();

        stateBundle.putData("localDate", localDate);
        stateBundle.putData("isRdoArabicSelected", isRdoArabicSelected);
        stateBundle.putData("isRdoEnglishSelected", isRdoEnglishSelected);
    }

    @Override
    protected void onLoadState(I18NController newController, I18NLanguage newLanguage, ResourceBundle resourceBundle, StateBundle stateBundle)
    {
        JavaFXController controller = (JavaFXController) newController;
        controller.getPrimaryStage().setTitle(resourceBundle.getString("window.title"));
        NodeOrientation nodeOrientation = newLanguage.getNodeOrientation();

        LocalDate localDate = stateBundle.getDate("localDate", LocalDate.class);
        boolean isRdoArabicSelected = stateBundle.getDate("isRdoArabicSelected", Boolean.class);
        boolean isRdoEnglishSelected = stateBundle.getDate("isRdoEnglishSelected", Boolean.class);

        controller.dpDate.setValue(localDate);
        controller.rdoArabic.setSelected(isRdoArabicSelected);
        controller.rdoEnglish.setSelected(isRdoEnglishSelected);
    }
}

<强> AppSettings.java:

import com.parmajeyat.autobooking.gui.I18NController;
import javafx.geometry.NodeOrientation;

import java.util.Locale;

/**
 * Created by Fouad on 2/7/2015.
 */
public final class AppSettings
{
    private static final class Locales
    {
        public static final Locale SAUDI_AR_LOCALE = new Locale.Builder().setLanguageTag("ar-SA-u-nu-arab").build(); // nu is for numbers
        public static final Locale SAUDI_EN_LOCALE = new Locale("en", "SA");
    }

    public static enum Language implements I18NController.I18NLanguage
    {
        ARABIC(Locales.SAUDI_AR_LOCALE, NodeOrientation.RIGHT_TO_LEFT),
        ENGLISH(Locales.SAUDI_EN_LOCALE, NodeOrientation.LEFT_TO_RIGHT);

        private Locale locale;
        private NodeOrientation nodeOrientation;

        Language(Locale locale, NodeOrientation nodeOrientation)
        {
            this.locale = locale;
            this.nodeOrientation = nodeOrientation;
        }

        public Locale getLocale(){return locale;}
        public NodeOrientation getNodeOrientation(){return nodeOrientation;}
    }
}

<强> UTF8Control.java:

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

/**
 * Created by Fouad on 2/1/2015.
 */
public class UTF8Control extends ResourceBundle.Control
{
    public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException
    {
        // The below is a copy of the default implementation.
        String bundleName = toBundleName(baseName, locale);
        String resourceName = toResourceName(bundleName, "properties");
        ResourceBundle bundle = null;
        InputStream stream = null;

        if(reload)
        {
            URL url = loader.getResource(resourceName);
            if(url != null)
            {
                URLConnection connection = url.openConnection();
                if(connection != null)
                {
                    connection.setUseCaches(false);
                    stream = connection.getInputStream();
                }
            }
        }
        else
        {
            stream = loader.getResourceAsStream(resourceName);
        }

        if(stream != null)
        {
            try
            {
                // Only this line is changed to make it to read properties files as UTF-8.
                bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
            }
            finally
            {
                stream.close();
            }
        }

        return bundle;
    }
}

答案 1 :(得分:2)

我知道,这是一个很老的问题,但我是JavaFX的新手,我遇到了同样的问题。 这是我在应用程序中更改语言的最终解决方案。它可能不太理想,但它对我有用。 在控制器中我有这种方法:

@FXML
private BorderPane root;  //root pane 

@FXML
private void changeLocale(ActionEvent event) throws IOException{
    Scene scene = root.getScene();
        if(event.getSource().equals(lang_en)){
            scene.setRoot(FXMLLoader.load(getClass().getResource("Layout.fxml"),ResourceBundle.getBundle("resources/Bundle", Locale.ENGLISH))); // = new Locale("en")
        }else if(event.getSource().equals(lang_cs)){
            scene.setRoot(FXMLLoader.load(getClass().getResource("Layout.fxml"),ResourceBundle.getBundle("resources/Bundle", new Locale("cs", "CZ"))));
        }else{
        }
}

该方法将新加载器加载到我的场景中(加载到舞台也可以)。

对于完整的场景......我可以在菜单中用两个放射性设备更改当前语言,因此在加载新的加载器后(在控制器中的方法“public void initialize(URL location,ResourceBundle resources)”中)我改变了放射对准的选择这个开关:

switch(resources.getLocale().getLanguage()){
        case "en":
            lang_en.setSelected(true);
            break;
        case "cs":
            lang_cs.setSelected(true);
            break;
        default:
            break;
        }

这很简单,对于有这个问题的其他人可能会有用。

答案 2 :(得分:0)

我设法解决了代码:

主:

public class Main extends Application {
private static Locale locale = new Locale("pt", "BR");
private static Image icone = new Image("picture.jpg");
private Scene scene;
public static Stage stage;

/**
 *
 * @param st
 * @throws Exception
 */

@Override
public void start(Stage st) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"), ResourceBundle.getBundle("label", locale));
    stage = st;
    scene = new Scene(root);
    stage.setTitle("GUI");
    stage.getIcons().add(icone);
    stage.setScene(scene);
    stage.show();
}

public static Image getIcone() {
    return icone;
}

public static Locale getLocale() {
    return locale;
}

public static void setLocale(Locale locale) {
    Main.locale = locale;
}

public void reload() throws IOException {
    Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"), ResourceBundle.getBundle("label", locale));
    scene = new Scene(root);
    stage.setTitle("GUI");
    stage.getIcons().add(icone);
    stage.setScene(scene);
    stage.show();

}

public static void main(String[] args) {
    launch(args);
}

}

控制器:

    @FXML
private void btnMenuLanguageEnglishAction(ActionEvent event) throws IOException {
    Main.setLocale(new Locale("en", "US")); // change to english
    Main.stage.close();
    Main reload = new Main();
    reload.reload();

}

@FXML
private void btnMenuLanguagePortuguesAction(ActionEvent event) throws IOException {
    Main.setLocale(new Locale("pt", "BR")); // change to Portuguese;
    Main.stage.close();
    Main reload = new Main();
    reload.reload();
}

但仍有问题:语言更改只能发生一次,第二次发出致命错误...希望能帮助某人。

答案 3 :(得分:0)

与您的Labeled(Label,Text,TitledPane等)一起使用绑定。