2008-08-21 100 views
6

我想使用數據庫來存儲國際化的鍵/值對,所以我們可以在運行時修改/重新加載國際化的數據。有沒有人做過這個?還是有人有一個如何實現這個想法?我已經閱讀了幾個主題,但我還沒有看到可行的解決方案。數據庫支持國際化的Java Web應用程序

我專門指的東西,將與JSTL標記,如

<fmt:setlocale> 
<fmt:bundle> 
<fmt:setBundle> 
<fmt:message> 

我認爲這將涉及擴大資源包的工作,但是當我嘗試這樣做,我跑成曾與做題jstl標籤獲取資源包的方式。

回答

2

你只是問如何在數據庫中存儲UTF-8/16字符?在mysql中,這只是確保您使用UTF8支持進行構建並將其設置爲默認值,或者在列或表級別指定它。我之前在oracle和mysql中完成了這項工作。創建一個表格,並將一些i18n數據剪切並粘貼到它中,看看會發生什麼......您可能已經設置好了。

或者我完全忽略了您的觀點?

編輯:

更明確的...我通常實現三頁的表...語言,鍵,值......其中「值」包含潛在的外語單詞或短語......「語言「包含一些語言鍵和」鍵「是一個英文鍵(即login.error.password.dup)...語言和密鑰索引...

我已然後在這樣的結構上構建接口它顯示每個鍵的所有翻譯(值)......它可以變得花哨,幷包括審計線索和「髒」標記以及所有其他材料,使翻譯人員和數據錄入人員能夠利用它。

編輯2:

現在,你增加了有關JSTL標記的信息,我瞭解多了一些......我從來沒有這樣做我自己..但我發現這個舊信息上theserverside ...

HttpSession session = .. [get hold of the session] 
ResourceBundle bundle = new PropertyResourceBundle(toInputStream(myOwnProperties)) [toInputStream just stores the properties into an inputstream] 
Locale locale = .. [get hold of the locale] 
javax.servlet.jsp.jstl.core.Config.set(session, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle ,locale)); 
1

我們有一個包含鍵/語言/術語的數據庫表,其中鍵是一個整數並且是與語言組合的主鍵。

我們正在使用Struts,所以我們最終編寫我們自己的PropertyMessageResources實施,使我們能夠這樣做<bean:message key="impressum.text" />

它工作得非常好,使我們能夠靈活地在前端動態切換語言以及動態更新翻譯。

13

我終於得到了這個與丹伯的幫助上面的工作。

這是我的資源包類和資源包控件類。

我使用了@ [danb]的這段代碼。

ResourceBundle bundle = ResourceBundle.getBundle("AwesomeBundle", locale, DbResourceBundle.getMyControl()); 
javax.servlet.jsp.jstl.core.Config.set(actionBeanContext.getRequest(), Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale)); 

並撰寫了此課。

public class DbResourceBundle extends ResourceBundle 
{ 
    private Properties properties; 

    public DbResourceBundle(Properties inProperties) 
    { 
     properties = inProperties; 
    } 

    @Override 
    @SuppressWarnings(value = { "unchecked" }) 
    public Enumeration<String> getKeys() 
    { 
     return properties != null ? ((Enumeration<String>) properties.propertyNames()) : null; 
    } 

    @Override 
    protected Object handleGetObject(String key) 
    { 
     return properties.getProperty(key); 
    } 

    public static ResourceBundle.Control getMyControl() 
    { 
     return new ResourceBundle.Control() 
     { 

      @Override 
      public List<String> getFormats(String baseName) 
      { 
       if (baseName == null) 
       { 
        throw new NullPointerException(); 
       } 
       return Arrays.asList("db"); 
      } 

      @Override 
      public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, 
        InstantiationException, IOException 
      { 
       if ((baseName == null) || (locale == null) || (format == null) || (loader == null)) 
        throw new NullPointerException(); 
       ResourceBundle bundle = null; 
       if (format.equals("db")) 
       { 
        Properties p = new Properties(); 
        DataSource ds = (DataSource) ContextFactory.getApplicationContext().getBean("clinicalDataSource"); 
        Connection con = null; 
        Statement s = null; 
        ResultSet rs = null; 
        try 
        { 
         con = ds.getConnection(); 
         StringBuilder query = new StringBuilder(); 
         query.append("select label, value from i18n where bundle='" + StringEscapeUtils.escapeSql(baseName) + "' "); 

         if (locale != null) 
         { 
          if (StringUtils.isNotBlank(locale.getCountry())) 
          { 
           query.append("and country='" + escapeSql(locale.getCountry()) + "' "); 

          } 
          if (StringUtils.isNotBlank(locale.getLanguage())) 
          { 
           query.append("and language='" + escapeSql(locale.getLanguage()) + "' "); 

          } 
          if (StringUtils.isNotBlank(locale.getVariant())) 
          { 
           query.append("and variant='" + escapeSql(locale.getVariant()) + "' "); 

          } 
         } 
         s = con.createStatement(); 
         rs = s.executeQuery(query.toString()); 
         while (rs.next()) 
         { 
          p.setProperty(rs.getString(1), rs.getString(2)); 
         } 
        } 
        catch (Exception e) 
        { 
         e.printStackTrace(); 
         throw new RuntimeException("Can not build properties: " + e); 
        } 
        finally 
        { 
         DbUtils.closeQuietly(con, s, rs); 
        } 
        bundle = new DbResourceBundle(p); 
       } 
       return bundle; 
      } 

      @Override 
      public long getTimeToLive(String baseName, Locale locale) 
      { 
       return 1000 * 60 * 30; 
      } 

      @Override 
      public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) 
      { 
       return true; 
      } 

     }; 
    } 
0

實際上ScArcher2需要的是davids響應,它沒有標記爲正確或有幫助。

ScArcher2選擇使用的解決方案是imo可怕的mestake :)一次加載所有翻譯...在任何更大的應用程序中它會殺死它。加載每個請求的翻譯的thousends ...

david的方法更常用於實際生產環境。 有時,爲了限制數據庫調用(每個消息翻譯後),您可以按主題,功能等創建各組翻譯以預先加載它們。但是這稍微複雜一點,可以用良好的緩存系統來代替。

+0

我同意在較大的應用程序中加載所有翻譯可能會導致問題。在我們的案例中,這根本不是問題,它滿足了我們的需求。我的代碼可以修改爲使用緩存機制,該機制在任何給定時間只保留內存中的一部分翻譯。代碼只是一個有效的例子,而不是在所有情況下都是最好的。 – ScArcher2 2012-09-05 15:01:31