2014-09-11 17 views
5

Sto provando ad aggiungere un ResourceBundle per la mia lingua per i controlli JavaFx ma non riesco a farlo.Localizzazione dei controlli JavaFx

Ho provato ad aggiungere controls_fi_FI.properties nel classpath .. e spero che funzionerebbe, ma no.

Quindi ho esaminato la classe ControlResources di JavaFx, che è responsabile della localizzazione dei controlli e ho notato che il nome base del pacchetto è "com \ sun \ javafx \ scene \ control \ skin \ resources \ controls".

Come posso aggiungere il mio file di proprietà a questo pacchetto? Trovo strano che non ci sia praticamente nessuna informazione su come farlo?

+0

Utilizzando un 'ResourceBundle' definito da un file delle proprietà nel classpath dovrebbe funzionare. Puoi mostrare come stai recuperando i valori dal tuo pacchetto? –

+0

Penso che tu abbia frainteso il mio problema. Ho la mia localizzazione che funziona già con ResourceBundle, è solo che sto cercando di localizzare le stringhe di controllo incorporate. Ad esempio, ProgressIndicator ha questa stringa "completata", che viene visualizzata quando il controllo è al 100%. Ho semplicemente copiato il file controls.properties dal jre e l'ho tradotto da solo, e l'ho aggiunto a classpath. – user2499946

+0

Ah, sì: ho frainteso. Grazie per il chiarimento. –

risposta

4

Posso solo farlo funzionare tramite un hack piuttosto massiccio, che non è nemmeno remotamente portatile. Tuttavia, forse ti darà abbastanza da lavorare per creare una soluzione praticabile. (Questo funziona in Java 8.)

ho creato un pacchetto com.sun.javafx.scene.control.skin.resources, e ha creato un file controls_fi_FI.properties in essa con la sola linea

ProgressIndicator.doneString=Valmis 

ho creato un'applicazione di test con il seguente:

import java.util.Locale; 
import java.util.ResourceBundle; 

import javafx.application.Application; 
import javafx.stage.Stage; 
import javafx.scene.Scene; 
import javafx.scene.control.ProgressIndicator; 
import javafx.scene.layout.BorderPane; 


public class Main extends Application { 
    @Override 
    public void start(Stage primaryStage) { 
      System.out.println(ResourceBundle.getBundle("com/sun/javafx/scene/control/skin/resources/controls").getString("ProgressIndicator.doneString")); 

      BorderPane root = new BorderPane(); 
      ProgressIndicator progressIndicator = new ProgressIndicator(1); 
      root.setCenter(progressIndicator); 
      Scene scene = new Scene(root,400,400); 
      primaryStage.setScene(scene); 
      primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     Locale.setDefault(new Locale("fi", "FI")); 
     launch(args); 
    } 
} 

L'esecuzione di questa app in molti modi non funziona come desiderato: mentre il System.out.println(...) produce il risultato corretto, il testo visualizzato nell'indicatore di avanzamento è errato.

Tuttavia, se raggrupparli in fasci com/sun/javafx/control/skin/resources/controls_fi_FI.properties in un file jar e spostare il file jar al jre/lib/ext sottodirectory della mia installazione JDK (. Vale a dire la stessa posizione jfxrt.jar), viene eseguito come previsto (almeno nella mia semplice test; come ho detto, non pretendo che questo sia un qualsiasi tipo di soluzione robusta).

Il problema sembra essere che ControlsResources viene caricato dal programma di caricamento classe estensione, e quindi sta utilizzando lo stesso programma di caricamento classe per caricare il pacchetto di risorse.

Con una migliore conoscenza dei caricatori di classe di me, potrebbe essere in grado di plasmare questo in una soluzione ragionevole ...

+0

In realtà ho provato a creare questo pacchetto nella cartella del mio progetto, a inserire il pacchetto e ho notato che non funzionava. Tuttavia, non pensavo davvero di inserirlo nell'ext-folder. Questo è un bel compromesso per me, dato che in realtà sto raggruppando un JRE con la mia app, quindi non ho problemi ad aggiungere cose a ext. Tuttavia, mi asterrò ancora (per ora) dall'accettare la tua soluzione, poiché anch'io penso che potrebbe esserci una soluzione migliore. Grazie! – user2499946

-2

è solo che sto cercando di localizzare le stringhe di controllo incorporati.

JavaFX è un progetto open source ospitato presso: http://openjdk.java.net/projects/openjfx/

suggerisco di presentare un problema a: https://javafx-jira.kenai.com

ed eventualmente fornire una patch.

+1

possibilmente OP dovrebbe determinare se è effettivamente rotto prima. Esiste un modo per realizzare ciò di cui l'OP non è a conoscenza. da qui il post. – simpleuser

-1

Ho creato Simple "Hello, world!" esempio che mostra un progetto JavaFX pronto per il rollover che utilizza il supporto di più lingue è per coloro che hanno bisogno di un linguaggio più esotico (be-BY, ru-RU ecc.)

Ecco come ho risolto il problema, per me funziona

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

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

Più ho descritto here o GitHub

Ecco una dimostrazione nella lingua bielorussa: enter image description here

0

ho invertito carico a fascio e si avvicinò con una soluzione sporca nel caso in cui mettere un vaso per jre/lib/ext non è un'opzione. L'algoritmo predefinito richiede un file bundle per essere codificato ISO-8859-1 e non fornisce alcun mezzo per specificare la codifica. La mia soluzione si occupa anche della questione della codifica.

Il seguente metodo carica la risorsa con il classloader dell'applicazione e inserisce il bundle risultante nella cache del bundle utilizzando il classloader di estensione (utilizzato in runtime dalle classi javafx per cercare i pacchetti).

import com.sun.javafx.scene.control.skin.resources.ControlResources; 
import java.util.Locale; 
import java.util.PropertyResourceBundle; 
import java.util.ResourceBundle; 
// rest of the imports is ommitted 

private void putResourceBundleInCache(String baseName, Charset cs) throws ReflectiveOperationException, IOException { 
    Locale currentLocale = Locale.getDefault(); 
    ResourceBundle.Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); 
    String resourceName = control.toResourceName(control.toBundleName(baseName, currentLocale), "properties"); 
    ResourceBundle bundle; 
    try (Reader reader = new InputStreamReader(getClass().getClassLoader().getResourceAsStream(resourceName), cs)) { 
     bundle = new PropertyResourceBundle(reader); 
    } 
    Class<?> cacheKeyClass = Class.forName("java.util.ResourceBundle$CacheKey"); 
    Constructor<?> cacheKeyClassConstructor = cacheKeyClass.getDeclaredConstructor(String.class, Locale.class, ClassLoader.class); 
    cacheKeyClassConstructor.setAccessible(true); 
    Object cacheKey = cacheKeyClassConstructor.newInstance(baseName, currentLocale, ControlResources.class.getClassLoader()); 
    Method putBundleInCache = ResourceBundle.class.getDeclaredMethod("putBundleInCache", cacheKeyClass, ResourceBundle.class, ResourceBundle.Control.class); 
    putBundleInCache.setAccessible(true); 
    putBundleInCache.invoke(null, cacheKey, bundle, control); 
} 

mi chiamano da questo modo:

public void start(Stage primaryStage) throws Exception { 
    putResourceBundleInCache("com/sun/javafx/scene/control/skin/resources/controls", StandardCharsets.UTF_8); 
    // mian logic here 
} 
Problemi correlati