2012-09-02 6 views
5

Oczywiście wymaga się pliku właściwości, takiego jak składnia w znalezionych plikach."ResourceBundle" dla całego zbioru?

Mamy sytuację, w której chcemy wykorzystać całe pliki (w naszym przypadku pliki HTML) jako "wartości". Oznacza to, że nie mamy kluczy jako takich. Cóż, może nazwa pliku będzie działać jako klucz.

Oto drzewo katalogów:

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 

Teraz musimy logiki, aby znaleźć właściwy plik na podstawie bieżącej lokalizacji. Jeśli bieżącym ustawieniem jest język niemiecki i szukam pliku html/content.html, powinien on znaleźć html/content_de.html. To niekoniecznie musi załadować go od razu. Czy istnieje jakiś mechanizm w Javie? Czy musimy to zrobić ręcznie?

Z powodu pewnych ograniczeń, obecnie nie planujemy używać bibliotek innych firm. Więc jeśli jest coś dostępnego w Javie 6 SE, byłby to nasz najlepszy wybór; Jeśli jednak znasz bibliotekę firm trzecich, możesz ją nazwać.

EDYCJA # 1: Oczywistym rozwiązaniem byłoby posiadanie klucza w messages.properties w celu nazwania tego pliku HTML. Mimo że to zadziałałoby, może to być długotrwałym bólem w kolbie (a poza tym nie sądzę, że rozwiązałoby to wszystkie nasze problemy).

EDYCJA # 2: Zapomniałem powiedzieć, że jest to aplikacja komputerowa.

+0

Może rozważyć podejście oparte na filtrach - szybki start znajduje się tutaj: http://www.servletsuite.com/servlets/i18nflt.htm – Jayan

+0

@Jayan Zapomniałem powiedzieć, że potrzebuję tego dla aplikacji komputerowej, będę edytuj pytanie. Jednak dzięki za wzmiankę o tym, może to być pomocne dla kogoś. – sjngm

+0

Możesz rozważyć użycie prędkości lub innego silnika szablonów (nie są to aplikacje internetowe). –

Odpowiedz

1

Aby pokazać, że nie robi nic, tu są dwie próby stosując „na własną rękę”, podejściem:

pierwsza próba z locale-postfix budować i prosty załadunek do przodu zasobów:

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

druga próba "nadużywanie" ResourceBundle i jego 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()); 
    } 

Przykładowe połączenia:

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

Obie znajdują ten sam plik.

Szczerze mówiąc, nie lubię ani.

+0

@ ResourceBundle.Control ma na celu ułatwienie ładowania zasobów. twój jest rodzajem ładowania zasobów. dla mnie podejście 2 jest dobre. – Jayan

+0

@Jayan Cóż, słyszałem, że 'ResourceBundle' jest trochę przestarzały z powodu jego złej implementacji (buforowanie, przyklejone do kodowania znaków JVM). Ponieważ nie ma innej alternatywy, muszę podjąć próbę nr 1 ... Nie pamiętam, żebym był tak niechętny, aby kontynuować pracę nad moim pomysłem ... – sjngm

1

Aby było to bardziej idealne, jeśli konwencja nazewnictwa dla plików pozostanie spójna (tj. Dla każdego locale użyjesz dwuliterowego prefiksu języka - oznaczającego "en" dla języka angielskiego, "fr" dla języka francuskiego i "es" w języku hiszpańskim), wtedy ten proces jest niezwykle prosty.

Będziemy korzystać z klasy Properties do odczytywania właściwości w, a następnie użyć MessageFormat formatować odpowiedniego lokum chcemy od obiektu wynikowego.

Najpierw wprowadzamy zmiany w pliku właściwości - sparametryzujemy go tak, abyśmy mogli przekazać to, co nam się podoba.

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

Parametr {0} przedstawia pierwszy parametr tej właściwości.

Teraz wystarczy załadować właściwość i przekazać odpowiedni parametr.

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

ten wypisuje:

content_en.html 

Upewnij się, że plik HTML chcesz dostępem istnieje przed dokonaniem to wezwanie, albo przekształcić to funkcja, która zwraca String, i upewnić się, że plik istnieje przed wrócił.

+0

Uzgodnione, to lepsze niż mój pomysł w edycji nr 1 mojego pytania. Jednak nadal muszę sprawdzić, czy istnieje zasób dla tego locale. Jeśli nie, zmień ustawienia na bardziej ogólne, aż do podstawowego zasobu. Więc skończę gdzieś z próbą # 1, którą napisałem. Z tego, co słyszałem, będziemy mieli kilka zasobów o określonej lokalizacji i inne bardziej ogólne, niektóre nawet angielskie. Tak więc logika powinna być "elastyczna". – sjngm

0

Wiem, że to stare pytanie, ale właśnie natknąłem się na ten sam problem i znalazłem bardziej eleganckie rozwiązanie. Potrzebujesz delegowania lokalizacji do mapowania plików do standardowego interfejsu API języka Java w taki sam sposób, w jaki interfejs API rozwiązuje tłumaczenia kluczy. W twoim przykładzie, jeśli bieżącym locale jest fr_FR, chcesz załadować pliki o nazwach "content_fr.html" i "order_fr.html", tak?

Następnie wystarczy mieć zestaw zasobów plików wiązek oraz wyznaczyć zmienną tłumaczyć bieżące locale do najbliższej istniejącej lokalizacji:

pliku translation.properties:

localeCode = 

pliku translation_fr.properties:

localeCode = fr 

pliku translation_en.properties:

localeCode = en 

Następnie wystarczy odczytać wartość "localeCode" i połączyć ją z "treścią" i ".html" lub "zamówieniem" i ".html".