2012-09-02 11 views
5

Ovviamente ResourceBundle richiede un file di proprietà come la sintassi nei file che trova."ResourceBundle" per interi file?

Abbiamo una situazione in cui vogliamo utilizzare interi file (nel nostro caso file HTML) come "valori". Ciò significa che non abbiamo le chiavi in ​​quanto tali. Bene, forse il nomefile funzionerebbe come chiave.

Ecco un albero di directory:

src/ 
    main/ 
     resources/ 
      html/ 
       content.html 
       content_de.html 
       content_fr.html 
       content_es.html 
       order.html 
       order_de.html 
       order_fr.html 
       order_es.html 

Ora abbiamo bisogno logica per trovare il file corretto in base alla localizzazione corrente. Se il locale corrente è tedesco e sto cercando il file html/content.html, dovrebbe trovare html/content_de.html. Non ha necessariamente bisogno di caricarlo subito. Esiste qualche meccanismo esistente in Java? Dobbiamo farlo manualmente?

A causa di alcune restrizioni, al momento stiamo pianificando di non utilizzare alcuna libreria di terze parti. Quindi, se c'è qualcosa di disponibile in Java 6 SE, sarebbe la nostra scelta migliore; tuttavia, se conosci una libreria di terze parti, non esitare a nominarla.

EDIT # 1: Una soluzione ovvia sarebbe avere una chiave in messages.properties per denominare il file HTML. Mentre funzionerebbe potrebbe diventare un rompicapo a lungo andare (e inoltre non credo che questo risolverebbe tutti i nostri problemi con questo).

EDIT # 2: Ho dimenticato di dire che questa è un'applicazione desktop.

+0

Potrebbe prendere in considerazione un approccio basato su filtro: un avvio rapido è qui: http://www.servletsuite.com/servlets/i18nflt.htm – Jayan

+0

@Jayan Ho dimenticato di dire che ho bisogno di questo per un'applicazione desktop, lo farò modifica la domanda. Tuttavia, grazie per averlo menzionato, forse è utile a qualcuno. – sjngm

+0

Si potrebbe prendere in considerazione l'utilizzo di Velocity o di un altro motore di template (quelli non sono limitati alle applicazioni Web) –

risposta

1

per dimostrare che non stavo facendo nulla, qui ci sono due tentativi con un "da soli" -approach:

Il primo tentativo con il locale-postfix accumulo e dritto di carico che precede risorse:

public void attempt1(String baseName, String extension) { 
    List<String> locales = buildLocaleStrings(Locale.getDefault()); 
    String resourceFound = null; 

    for (String locale : locales) { 
     String resourceName = baseName + locale + "." + extension; 
     URL resource = getClass().getClassLoader().getResource(resourceName); 
     if (resource != null) { 
     resourceFound = resourceName; 
     break; 
     } 
    } 
    System.out.println("found #1: " + resourceFound); 
    } 

    private List<String> buildLocaleStrings(Locale localeBase) { 
    String locale = "_" + localeBase; 
    List<String> locales = new ArrayList<String>(); 

    while (locale.length() > 0) { 
     locales.add(locale); 
     locale = locale.replaceFirst("_[^_]*?$", ""); 
    } 
    locales.add(""); 

    return locales; 
    } 

Il secondo tentativo "abusare" ResourceBundle e il suo toString():

public void attempt2(String baseName, final String extension) { 
    ResourceBundle.Control control = new ResourceBundle.Control() { 

     private String resourceFound = null; 

     @Override 
     public List<String> getFormats(String baseName) { 
     return Arrays.asList(extension); 
     } 

     @Override 
     public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { 
     String bundleName = toBundleName(baseName, locale); 
     String resourceName = toResourceName(bundleName, format); 

     if (loader.getResource(resourceName) != null) { 
      resourceFound = resourceName; 
      return new ResourceBundle() { 

      @Override 
      public Enumeration<String> getKeys() { 
       return null; 
      } 

      @Override 
      protected Object handleGetObject(String key) { 
       return null; 
      } 

      }; 
     } 
     return null; 
     } 

     @Override 
     public String toString() { 
     return resourceFound; 
     } 
    }; 

    ResourceBundle.getBundle(baseName, control); 

    System.out.println("found #2: " + control.toString()); 
    } 

chiamate campione:

public void proof() { 
    attempt1("html/content", "html"); 
    attempt2("html/content", "html"); 
    } 

Entrambi trovano lo stesso file.

A dire il vero, non mi piace neanche.

+0

@ ResourceBundle.Control ha lo scopo di aiutare il caricamento delle risorse. il tuo è una sorta di caricamento delle risorse. per me l'approccio 2 è buono. – Jayan

+0

@Jayan Bene, ho sentito che 'ResourceBundle' è un po 'obsoleto con la sua implementazione piuttosto brutta (memorizzazione nella cache, incollata alla codifica dei caratteri di JVM). Quindi, dato che non c'è alternativa, devo prendere il mio tentativo n. 1 ... _Non ricordo di essere così riluttante a continuare a lavorare con un'idea mia ... – sjngm

1

Per rendere questo più ideale, se la convenzione di denominazione per i file rimane coerente (ad esempio per ogni locale, si utilizza il prefisso a due lettere della lingua - che significa "en" per l'inglese, "fr" per il francese e 'es' per lo spagnolo), quindi questo processo è estremamente semplice.

Faremo uso della classe Properties per leggere le proprietà in, quindi utilizzare MessageFormat per formattare le impostazioni internazionali desiderate dalla proprietà risultante.

In primo luogo, apportiamo una modifica al file delle proprietà: la parametrizziamo in modo tale da consentirci di passare ciò che ci piace.

content=content_{0}.html 
order=order_{0}.html 

Il {0} rappresenta il primo parametro della proprietà.

Ora, abbiamo solo bisogno di caricare la proprietà in e passare il parametro appropriato.

Properties prop = new Properties(); 
try { 
    MessageFormat messageFormat = new MessageFormat(""); 
    String property; 
    // change to suit the locale you wish to serve 
    String[] param = {"en"}; 

    prop.load(new FileReader(new File("/full/path/to/property/file.properties"))); 
    property = prop.getProperty("content"); 
    messageFormat.applyPattern(property); 
    System.out.println(messageFormat.format(param)); 
} catch(IOException ioex) { 
    System.out.println("no property file here"); 
} 

Questo stampa:

content_en.html 

Assicurarsi che il file HTML che si desidera l'accesso esiste prima di fare questa chiamata, o trasformare questo in un funzione che restituisce String, e assicurarsi che il file esiste prima è tornato.

+0

D'accordo, è meglio della mia idea nella modifica n. 1 della mia domanda. Tuttavia, devo ancora controllare se esiste una risorsa per questa locale. Altrimenti, lavorare con impostazioni internazionali più generali fino alla risorsa di base. Quindi andrei a finire da qualche parte con il tentativo n. 1 che ho postato. Da quanto ho sentito avremo alcune risorse con localizzazione specifica e altre più generali, alcune anche solo in inglese. Quindi la logica dovrebbe essere "flessibile". – sjngm

0

So che questa è una vecchia domanda, ma mi sono imbattuto nello stesso identico problema e ho trovato una soluzione più elegante. Ciò di cui hai bisogno è delegare le impostazioni internazionali alla mappatura dei file all'API Java standard nello stesso modo in cui l'API risolve le traduzioni per le chiavi. Quindi nel tuo esempio, se la locale corrente è fr_FR, vuoi caricare i file chiamati "content_fr.html" e "order_fr.html", giusto?

Poi basta avere una serie di file di pacchetto di risorse e di designare una variabile di tradurre il locale corrente al locale esistente più vicina:

translation.properties file:

localeCode = 

translation_fr.properties file:

localeCode = fr 

translation_en.properties file:

localeCode = en 

Quindi è sufficiente leggere il valore di "localeCode" e concatenarlo con "contenuto" e ".html" o "ordine" e ".html".

Problemi correlati