2012-04-13 20 views
66

Ho appena iniziato a scrivere la mia prima applicazione JavaFX 2 dopo aver appreso le nozioni di base e vorrei internazionalizzarla.JavaFX 2 e Internazionalizzazione

Ho notato che in JavaFX 1.x, il linguaggio di scripting consentiva una semplicissima internazionalizzazione delle stringhe. Ci sono caratteristiche simili in JavaFX 2?

Fondamentalmente: qual è la procedura migliore per l'internazionalizzazione di un'applicazione JavaFX 2?

+0

commutazione tra lingue alcune informazioni qui: [http://stackoverflow.com/a/26318795/2131257] [ 1] [1]: http://stackoverflow.com/a/26318795/2131257 – Androdos

risposta

139

I passaggi di base (tra gli altri) di un'app per l'internazionalizzazione delle app Java, sono il lining Locale e il raggruppamento delle risorse. In JavaFX, è possibile utilizzare FXMLLoader#setResources() per tali scopi. Ecco una dimostrazione SSCCE per dimostrarlo. I codici sono auto-descrittivi.
Dimostrazione struttura del pacchetto:

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> 

MyCo ntroller.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); 
    } 
} 

Screenshot:

enter image description here

+0

Excellen t risposta e lo accetterò come è, ma avrei dovuto dire che sto costruendo l'interfaccia in codice piuttosto che FXML. C'è un modo semplice e veloce per internazionalizzare nel codice, mi rendo conto che posso fare una ricerca ResourceBundle.getBundle + ma speravo che ci fosse qualcosa di simile alla notazione% key che posso essere usata invece. – wobblycogs

+7

Quindi puoi farlo in modo normale come in qualsiasi altra applicazione Java. Determina le impostazioni locali dell'utente/client, quindi modifica le impostazioni locali dell'app (ottieni dati specifici per lang da DB vs.). Carica il pacchetto appropriato per 'ResourceBundle.getBundle (" bundles.MyBundle ", locale)'. Cambia ogni testo che hai usato nella tua vista/pagina da 'bundle.getString (" chiave ")'. –

+1

Non funziona per me se fornisco un oggetto ResourceBundle al metodo setResources(). Funziona quando fornisco il ResourceBundle tramite il metodo load(). –

12

Questo funziona per me:

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

Nel pacchetto bundle sono

LangBundle_en.properties 
LangBundle_de.properties 

contenuti del campione:

enter_pwd=Enter your password: 

Per caricare li uso il seguente codice:

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

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

Guardate il mio esempio enter image description here

Più ho descritto here o GitHub

Aggiornamento:

la soluzione è in 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; 
    } 
} 

in 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; 
    } 
} 
+0

@Moritz avresti cliccato sul link e visto la risposta dettagliata e i file di origine completi, ho incluso un link in risposta a stackoverflow.com. Grazie a te, devo inserire ovunque lo stesso codice. Mi aspetto che ti piaccia e non ti dispiaccia –