2008-08-21 97 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