データベースはi18nのJava Webアプリケーション用


6

i18nキー/値ペアを格納するデータベースを使用して、実行時にi18nデータを変更/再ロードできるようにしたいと考えています。誰もこれをしましたか?それとも誰かがこれを実装する方法のアイデアを持っていますか?私はこれについていくつかのスレッドを読んだが、私は実行可能な解決策を見ていない。

私は、具体的には、

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

としてJSTLタグで動作する何かを参照のうえてる私は、これはのResourceBundleを拡張関与すると思いますが、私はこれをしようとしたとき、私はとしなければならなかった問題に走りましたjstlタグはリソースバンドルを取得します。

2

UTF-8/16文字をDBに保存する方法を尋ねていますか? mysqlでは、UTF8サポートでビルドし、デフォルトとして設定するか、カラムまたはテーブルレベルで指定するだけです。私は以前にoracleとmysqlでこれを行ってきました。テーブルを作成し、その中にいくつかの国際化データをカット&ペーストし、何が起こるか見て...あなたが既に設定されることがあります。..

または私は完全にあなたのポイントを逃していますか?

編集:

より明確にするために...私は通常、「値」は、潜在的に外国語の単語やフレーズが含まれている3列の表...言語、キー、値を...実装... "言語 "にはいくつかの言語キーが含まれており、"キー "は英語のキー(つまり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

我々は、キーは整数であり、言語と組み合わせ、主キーであるキー/言語/用語を使用してデータベースのテーブルを持っています。

私たちは、私たちは私たちが<bean:message key="impressum.text" />ような何かを行うことができます私たち自身のPropertyMessageResources実装を書くことになった、Strutsのを使用しています。

は、これは非常にうまく機能し、私達に動的に行うフロントエンドで言語を切り替えるだけでなく、その場で翻訳を更新するための柔軟性を提供します。


13

私はついに上記のdanbの助けを借りてこの作業をしました。

これは私のリソースバンドルクラスとリソースバンドルコントロールクラスです。

@ [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

Actuly ScArcher2が必要とするのは、正しいか役立つとマークされていないダビッドレスポンスです。

ScArcher2が使用することを選択した解決策は、恐ろしいことです:すべての翻訳を一度にロードする...どんな大きなアプリケーションでも、それを殺すつもりです。各リクエストの翻訳数を読み込んでいます...

ダビッドの方法は、実稼働環境でより一般的に使用されています。 すべてのメッセージが翻訳されているdb呼び出しを制限するために、トピック、機能別に翻訳のグループを作成して事前ロードすることができます。しかしこれは少し複雑であり、良いキャッシュシステムに置き換えることができます。

  0

大きなアプリケーションですべての翻訳を読み込むと問題が生じることに同意します。私たちの場合、それはまったく問題ではなく、私たちの必要性を満たしました。私のコードは、いつでもメモリ内の翻訳のサブセットを維持するだけのキャッシュ機構を使うように修正することができます。このコードは、すべての状況でベストとなるものではなく、機能しているものの単なる例でした。 05 9月. 122012-09-05 15:01:31