2016-04-19 14 views
3

私は現在、内部の.propertyリソースとresourceBundlesを通じて静的および動的な文字列をローカライズする標準的な方法を使用して、多言語のXpages駆動型アプリケーションを開発しています。アプリケーション内で、ユーザーは好みの言語を選択できます。この決定は現在ユーザー設定文書に格納されています。私はこれらの決定をブラウザのクッキーとして保存する予定もあります。ユーザー定義のプリファレンスがない場合、ブラウザーのデフォルト言語はアプリケーション内で使用されるロケールを駆動します。これは、すべてのサーバー側の要素で正常に機能します。Xpages:クライアントサイドのJSコードのローカライズをどのように実装できますか?

私はいくつかのクライアントサイドスクリプトを追加しなければなりません。ローカライズされた文字列も使用する必要があります。私はこれに最善のアプローチである手がかりがないことを認めなければならない。

主な質問は以下のとおりです。

  1. 私は何とか既存のファイルリソース/リソースバンドルを使用することができますか?
  2. もしそうなら、スクリプトコードからそれらのリソースをどのように参照できますか?
  3. もしそうでない場合は、自分のファイルリソースを整理して参照するにはどうすればよいですか?
  4. 最後に、自分ですべてをやる必要がある場合:どのロケールがユーザーの好みのロケールであるかを確認するにはどうすればよいですか?クッキーが設定されていれば簡単です(上記参照)が、ブラウザーの設定を参照する必要がある場合、またはユーザーがクッキーの使用を許可していない場合はどうなりますか?

編集:私はdojo i18n wayを行くと考えられますが、私は、このようなカスタムプラグインを実装する方法がわかりません。

+1

  • 必要ありません答えは...のXPageで
  • 答え1からは、ユーザーのロケール(ブラウザの言語設定)に基づいて、適切なリソースバンドルをロードすることができます最善の方法はJavaの方法です。 CSJSでは、ssjsを挿入して、バッキングされたBeanからラベルを取得することもできます。私のブログが役立つかもしれません。 http://elstarit.nl/2016/03/08/xpages-tip-add-a-new-language-to-your-app/ –

    +0

    コメントのおかげで@FrankvanderLinden。それらのリソースを維持するための非常に有用なアプローチであるように見える、私はそれを次の数日にわたってより強く読むだろう –

    +1

    私はあなたに助けが必要であることを私に知らせる、あなたは私のブログを持っている;-) –

    答えて

    3

    代わりに、リソースバンドルをブラウザで直接読み取って、必要な場所でJavaScriptで参照することもできます。あなたの主な質問に答えてください:

    1. はい、それをNSFから直接読み込むと、まだ実際には使用できません。私は、JSONオブジェクトとしてあなたのための出力にそれをのXPageを作成することをお勧めします:

      <?xml version="1.0" encoding="UTF-8"?> 
      <xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false"> 
      
      <xp:this.resources> 
          <xp:bundle 
          src="/labels_en.properties" 
          var="translations"> 
          </xp:bundle> 
      </xp:this.resources> 
      
      <xp:this.afterRenderResponse><![CDATA[#{javascript: 
      try { 
      
      var externalContext = facesContext.getExternalContext(); 
      var writer = facesContext.getResponseWriter(); 
      var response = externalContext.getResponse(); 
      
      response.setContentType("application/json"); 
      
      var jsonOutput = {}; 
      var keys = translations.keySet(); 
      
      for (var key in keys) { 
          jsonOutput[key] = translations[key]; 
      } 
      
      writer.write( "var translations = " + toJson(jsonOutput) ) ; 
      writer.endDocument(); 
      
      } catch (e) { 
          print(e); 
      } 
      }]]> 
          </xp:this.afterRenderResponse> 
      
      </xp:view> 
      
    2. あなたのページ上のJavaScriptライブラリクライアント側として1からのXPageを含める必要があります。私はXPageに1からのtranslationsというグローバルJavaScript変数を作成しました。translations.keyという名前で呼び出すことができます。keyは、プロパティファイルの変数を参照しています。私が思う

      <xp:this.resources> 
          <xp:bundle var="translations"> 
          <xp:this.src><![CDATA[#{javascript: 
      var language = "en";  //default language 
      
      switch (context.getLocaleString()) { 
      case "nl": 
          language = "nl"; 
          break; 
      } 
      
      return "/labels_" + language + ".properties";}]]></xp:this.src> 
          </xp:bundle> 
      </xp:this.resources> 
      
    +0

    素晴らしいもの!内部プロパティーフォーマットに関するもう1つのQ:{"key": "value"}のようにJSONフォーマットを使用しますか、それともエンジン自体によって作成され維持される "key = value"のようなXSP標準フォーマットですか? –

    +0

    気にしないで、自分自身を見つけました:標準の "key = value"形式をjsonオブジェクトに変換していますよね? –

    +0

    正しい。標準の 'key = value'書式を使うことができます。 –

    2

    以下のアプローチを使用します。私のクライアントサイドJavaScript(CSJS)ライブラリはすべて、データベース設計(リソース>ファイル)にファイルリソースとして保存されます。私は、例えば、translateable部品をマークするELのような表記を使用したライブラリのコードでは:

    var text="#{TRLT.TextToTranslate}"; 
    

    私はのXPage上のライブラリを使用したいときはいつでも、私は直接のXPageの中でそれらを参照しませんリソースが、その代わりに「ヘルパーのXPage」(js.xsp)への参照を追加します。

    <xp:this.resources> 
        <xp:headTag tagName="script"> 
         <xp:this.attributes> 
          <xp:parameter name="src" value="js.xsp?lng=#{sessionScope.language}&amp;v=#{applicationScope.versionApp}"/> 
          <xp:parameter name="type" value="text/javascript"/> 
         </xp:this.attributes> 
        </xp:headTag> 
    </xp:this.resources> 
    

    js.xspは、JavaScriptのリソースのように振る舞う:私はのXPage上rendered="false"を設定し、手動でContent-Type="text/javascript"で応答を作成しますbeforeRenderResponseイベント。 XPageが呼び出されると、はすべてのCSJSライブラリを読み込み、それらを連結し、サーバ側の翻訳で一般的に使用する辞書に基づいてすべての翻訳を入力します。ここで

    はjs.xspのbeforeRenderResponseイベントのコードです:

    importPackage(java.io); 
    importPackage(java.lang); 
    importPackage(java.util.regex); 
    importPackage(javax.servlet.http); 
    importPackage(org.apache.commons.io); // AFAIK this package is not installed by default (but generally very helpful) 
    
    var i,arr,lng,js,libs,c,s,m,bfr,dct,response,ec,is,os; 
    
    //---------------------------- initialize main variables 
    ec=facesContext.getExternalContext(); // the external context 
    
    lng=(param.lng || "en"); // the language can be provided as url parameter, otherwise use a default 
    
    dct=(applicationScope["TRLT_"+lng] || {}); // in my case, the dictionaries (HashMaps) containing the translations are stored in the applicationScope, but of course they can be loaded from anywhere (resource bundles etc.) 
    
    libs=(param.libs ? fromJson(param.libs) : ["mylib1.js","mylib2.js"]) // the library names can be provided as url parameter, otherwise use a default 
    
    //---------------------------- concatenate all libraries 
    js=new StringBuilder(); 
    for (i=0;i<libs.length;i++) { 
        if (s=IOUtils.toString(ec.getResourceAsStream(libs[i]),"UTF-8")) js.append("\n\n"+s); 
    } 
    js=js.toString(); 
    
    //---------------------------- search for and replace translateable parts 
    m=Pattern.compile("[#$]\\{TRLT\\.([^}]+)\\}").matcher(js); 
    bfr=new StringBuffer(); 
    c=0; 
    while (m.find() && c<1e6) { 
        c++; 
        s=m.group(1); 
        m.appendReplacement(bfr,dct[s] || s || ""); 
    } 
    m.appendTail(bfr); 
    js=bfr.toString(); 
    
    //---------------------------- create the response and finalize 
    response=ec.getResponse(); 
    response.setHeader("Cache-Control","max-age="+(60*60*24*365).toFixed(0)); // its important to set the expiration "a bit" into the future to prevent the browser from reloading the js.xsp everytime you reference it on another XPage; in order to force the browser to update the XPage, use versioning (see url parameter "v" in the headTag definition above) 
    response.setDateHeader("Expires",new Date().getTime()+(1000*60*60*24*365)); 
    response.setHeader("Content-Type","text/javascript; name=\"libs.js\""); 
    response.setHeader("Content-Disposition","inline; filename=\"libs.js\""); 
    
    is=new ByteArrayInputStream(js.getBytes("UTF-8")); 
    os=response.getOutputStream(); 
    IOUtils.copy(is,os); 
    is.close(); 
    os.close(); 
    facesContext.responseComplete(); 
    return; 
    

    PS:元のバージョンは、私の一般的なフレームワークにはいくつかの依存性だけでなく、いくつかの追加を持っているので、私はここで紹介するコードを変更する必要がありましたキャッシングとエラー処理。したがって、私はタイプミスがないことを保証することはできませんが、原則として動作するはずです。

    +0

    多くのありがとう;私が受け入れるはずの2つの同様の回答のどちらを決定するのは難しい。私は、上記の@MarkLeusinkから1つを選んだのですが、少しシンプルです。 –

    +1

    @LotharMueller:Mark Leusinkのソリューションは、実装するのがはるかに簡単で、達成したいものに適しています。私がこの種のアプローチを使用しない理由は、翻訳辞書がHTMLテンプレートを含んでいるので、私の翻訳辞書がかなり大きい(> 5Mb)ということです。その多くのコンテンツをHTMLページにロードすると、ユーザーが最初にページにアクセスするときの読み込み時間が長くなります。さらにキャッシュ制御ヘッダーの設定を忘れると、ユーザーがページをロードするたびにこのことが起こります。もちろん、私はCSJSの翻訳のための余分な辞書を作成することができますが、それは維持するのが難しくなります –

    関連する問題