write "Hello, World!"
      
      アプリケーションは動作し、すべてが正常です。
しかし、時間の経過、アプリケーションの開発、人気の高まり、そして今、この行を別の言語で表示する必要があり、必要な言語の数と構成は事前にわかりません。
このカットでは、Cachéでローカライズの問題がどのように解決されるかを学習します。
短いレビュー
CachéDBMSは、コンソールプログラム、Webアプリケーションのインターフェイス、JavaSciptファイルの文字列、エラーメッセージなどの文字列のローカライズを簡素化する既製のメカニズムを提供します。
注:このトピックについては、以前の記事の 1つで説明しました。
多くのクラス、プログラム、ウェブページ、jsスクリプトなどを含むプロジェクトがあるとしましょう。
ローカライズメカニズムは次のように機能します。
- プロジェクトのコンパイル段階でも、ローカライズされるすべての行は「フィッシングアウト」され、特定の形式でデータベース内に保存されます。
 - 行自体の代わりに、特定のコードがコンパイル済みコード自体に置き換えられ、 実行段階で、セッションの現在の言語に応じて、ストアから1つまたは別の値を出力します。
 
ローカライズプロセス全体は、プログラマーに対して完全に透過的です。
開発者は、特定の文字列ストア(データベースまたはリソースファイル内のテーブル)を手動で入力する必要性をなくし、実行時の言語の変更、翻訳者向けのさまざまな形式へのデータのエクスポート/インポートなど、このインフラストラクチャ全体を管理するコードを記述しますd。
その結果、次のことができます。
- 読みやすい-過度に整理されていない-ソースコード;
 -  ローカライズされた文字列の自動補完ストレージ 
注:リポジトリのコードから行を削除しても、削除されません。 このようなファントムからリポジトリをクリーンアップするには、クリーンアップしてプロジェクトを再コンパイルする方が簡単です。
 - 現在の言語を「その場で」変更します。 これは、Webアプリケーションと通常のプログラムの両方に適用されます。
 - 特定のドメイン(特定のドメインより少し低いドメイン)から特定の言語の文字列を取得する機能。
 - XMLでエクスポート/インポートストレージの既製のメソッド。
 
それでは、これがどのように機能するか、そしてあらゆる種類のローカライズの例を詳しく見てみましょう。
はじめに
次の内容でMACプログラムを作成します。
#Include %occMessages 
      
        
        
        
      
     test () { 
      
        
        
        
      
     
      
        
        
        
      
     write "$$$DefaultLanguage=" , $$$DefaultLanguage ,! 
      
        
        
        
      
     write "$$$SessionLanguage=" , $$$SessionLanguage ,! 
      
        
        
        
      
     
      
        
        
        
      
     set msg1= $$$Text ( ", !" , "asd" ) 
      
        
        
        
      
     set msg2= $$$Text ( "@my@, !" , "asd" ) 
      
        
        
        
      
     write msg1,!,msg2,! 
      
        
        
        
      
     
      
        
        
        
      
     }
      
      結果:
 USER>d ^test $$$DefaultLanguage=ru $$$SessionLanguage=ru , ! , !
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      何を得たの?
まず、データベースにグローバルが登場しました
 ^CacheMsg("asd") = "ru" ^CacheMsg("asd","ru",2915927081) = ", !" ^CacheMsg("asd","ru","my") = ", !"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      次に、 $$$ Textマクロにカーソルを合わせると、展開されたコードが表示されます。
上記の例では、中間(拡張)プログラムコード(INTコード)は次のようになります。
test () { 
      
        
        
        
      
     write "$$$DefaultLanguage=" , $get (^%SYS( "LANGUAGE" , "CURRENT" ), "en" ),! 
      
        
        
        
      
     write "$$$SessionLanguage=" , $get (^||%Language, "en" ),! 
      
        
        
        
      
     set msg1= $get (^CacheMsg( "asd" , $get (^||%Language, "en" ), "2915927081" ), ", !" ) 
      
        
        
        
      
     set msg2= $get (^CacheMsg( "asd" , $get (^||%Language, "en" ), "my" ), ", !" ) 
      
        
        
        
      
     write msg1,!,msg2,! 
      
        
        
        
      
     }
      
      上記の例に関しては 、次のことに注意する必要があります。
-  プログラムの行は、現在のロケール(管理ポータルで構成)でCachéDBMSに既定で登録されている言語で最初に記述される必要があります。 
注:ハッシュの代わりに文字列識別子を使用する場合、これはそれほど重要ではありません。
 - マクロは各行についてCRC32を計算し、すべてのデータ(CRC32 または行識別子、ドメイン、現在のシステム言語)が^ CacheMsgグローバルに保存されます。
 - 行自体の代わりに、プライベートグローバルの値を考慮するコードが挿入されます^ ||%Language ;
 - ユーザーが翻訳のない言語の文字列を要求した場合(リポジトリにデータがありません)、元の文字列が返されます。
 - ドメインメカニズムにより、ローカライズされた文字列を論理的に分離することができます。たとえば、同じ文字列に対する異なる翻訳などです。
 
何らかの理由で現在の$$$テキストマクロアルゴリズムに満足できない場合、たとえば、デフォルトの言語を別の場所に設定したり、データを別の場所に保存したりしたい場合は、アナログを作成できます。
そして、マクロ##式および/または##関数がこれを支援します。
例を続けましょう。
新しい言語を追加しましょう。 これを行うには、文字列ストアをファイルにアンロードして翻訳者に渡し、それから翻訳を別の言語でロードする必要があります。
データはさまざまな方法で、さまざまな形式でダウンロードできます。
%MessageDictionaryクラスの標準メソッドを使用します: Import ()、 ImportDir ()、 Export ()、 ExportDomainList ():
do ##class ( %MessageDictionary ). Export ( "messages.xml" , "ru" )
      
      データベースのディレクトリで、ファイル「 messages_ru.xml 」を取得します。 名前を「 messages_en.xml 」に変更し、その言語を「 en 」に変更して内容を翻訳します。
次に、リポジトリにインポートして戻します。
do ##class ( %MessageDictionary ). Import ( "messages_en.xml" )
      
      グローバルは次の形式を取ります。
 ^CacheMsg("asd") = "ru" ^CacheMsg("asd","en",2915927081) = "Hello, World!" ^CacheMsg("asd","en","my") = "Hello, World!" ^CacheMsg("asd","ru",2915927081) = ", !" ^CacheMsg("asd","ru","my") = ", !"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      次のように、言語を「オンザフライ」で変更できます。
#Include %occMessages 
      
        
        
        
      
     
      
        
        
        
      
     test () 
      
        
        
        
      
     { 
      
        
        
        
      
     
      
        
        
        
      
     set $$$SessionLanguageNode = "ru" 
      
        
        
        
      
     
      
        
        
        
      
     set msg1= $$$Text ( ", !" , "asd" ) 
      
        
        
        
      
     set msg2= $$$Text ( "@my@, !" , "asd" ) 
      
        
        
        
      
     write msg1,!,msg2,! 
      
        
        
        
      
     
      
        
        
        
      
     set $$$SessionLanguageNode = "en" 
      
        
        
        
      
     
      
        
        
        
      
     set msg1= $$$Text ( ", !" , "asd" ) 
      
        
        
        
      
     set msg2= $$$Text ( "@my@, !" , "asd" ) 
      
        
        
        
      
     write msg1,!,msg2,! 
      
        
        
        
      
     
      
        
        
        
      
     set $$$SessionLanguageNode = "pt-br" 
      
        
        
        
      
     
      
        
        
        
      
     set msg1= $$$Text ( ", !" , "asd" ) 
      
        
        
        
      
     set msg2= $$$Text ( "@my@, !" , "asd" ) 
      
        
        
        
      
     write msg1,!,msg2,! 
      
        
        
        
      
     
      
        
        
        
      
     }
      
      結果:
USER>d ^test , ! , ! Hello, World! Hello, World! , ! , !
最後のオプションに注意してください。
非 Webアプリケーションのローカライズの例(通常のクラス)
クラスメソッドのローカライズ:
Include %occErrors 
      
        
        
        
      
     
      
        
        
        
      
     Class demo.test Extends %Persistent 
      
        
        
        
      
     { 
      
        
        
        
      
     
      
        
        
        
      
     Parameter DOMAIN = "asd" ; 
      
        
        
        
      
     
      
        
        
        
      
     ClassMethod Test() 
      
        
        
        
      
     { 
      
        
        
        
      
     do ##class ( %MessageDictionary ). SetSessionLanguage ( "ru" ) 
      
        
        
        
      
     
      
        
        
        
      
     write $$$Text ( ", !" ),! 
      
        
        
        
      
     
      
        
        
        
      
     do ##class ( %MessageDictionary ). SetSessionLanguage ( "en" ) 
      
        
        
        
      
     
      
        
        
        
      
     write $$$Text ( ", !" ),! 
      
        
        
        
      
     
      
        
        
        
      
     do ##class ( %MessageDictionary ). SetSessionLanguage ( "pt-br" ) 
      
        
        
        
      
     
      
        
        
        
      
     write $$$Text ( ", !" ),! 
      
        
        
        
      
     
      
        
        
        
      
     #dim ex as %Exception.AbstractException 
      
        
        
        
      
     
      
        
        
        
      
     try 
      
        
        
        
      
     { 
      
        
        
        
      
     
      
        
        
        
      
     $$$ThrowStatus ( $$$ERR ( $$$AccessDenied )) 
      
        
        
        
      
     
      
        
        
        
      
     } catch (ex) 
      
        
        
        
      
     { 
      
        
        
        
      
     write $system .Status . GetErrorText (ex. AsStatus (), "ru" ),! 
      
        
        
        
      
     write $system .Status . GetErrorText (ex. AsStatus (), "en" ),! 
      
        
        
        
      
     write $system .Status . GetErrorText (ex. AsStatus (), "pt-br" ),! 
      
        
        
        
      
     } 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     }
      
      注:もちろん、上記のマクロを使用できます。結果:
 USER>d ##class(demo.test).Test() , ! Hello, World! , !  #822:    ERROR #822: Access Denied ERRO #822: Acesso Negado
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      次の点に注意してください。
- 例外のメッセージはすでにいくつかの言語に翻訳されています。 これらはシステムメッセージであるため、それらのデータは%qCacheMsgシステムグローバルに保存されます。
 - デフォルトでは$$$テキストマクロはクラスで使用するように設計されているため、ドメイン名を1回設定します。
 - $$$テキストマクロは、Webアプリケーションで使用するように設計されていますが、それでもオフライン環境に非常に適しています。
 
Webアプリケーションのローカライズの例
次の例を考えてみましょう。
  /// Created using the page template: Default 
      
        
        
        
      
     Class demo.test Extends %ZEN.Component.page 
      
        
        
        
      
     { 
      
        
        
        
      
     
      
        
        
        
      
     ///  ,    . 
      
        
        
        
      
     Parameter APPLICATION; 
      
        
        
        
      
     
      
        
        
        
      
     ///     . 
      
        
        
        
      
     Parameter PAGENAME; 
      
        
        
        
      
     
      
        
        
        
      
     /// ,   . 
      
        
        
        
      
     Parameter DOMAIN = "asd" ; 
      
        
        
        
      
     
      
        
        
        
      
     ///   Style   CSS  . 
      
        
        
        
      
     XData Style 
      
        
        
        
      
     { 
      
        
        
        
      
     < style type = "text/css" > 
      
        
        
        
      
     </ style > 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     ///  XML     . 
      
        
        
        
      
     XData Contents [ XMLNamespace = "www.intersystems.com/zen" ] 
      
        
        
        
      
     { 
      
        
        
        
      
     < page xmlns = "www.intersystems.com/zen" title = "" > 
      
        
        
        
      
     < checkbox onchange = "zenPage.ChangeLanguage();" /> 
      
        
        
        
      
     < button caption = "" onclick = "zenPage.clientTest(2,3);" /> 
      
        
        
        
      
     < button caption = "" onclick = "zenAlert(zenPage.ServerTest(1,2));" /> 
      
        
        
        
      
     </ page > 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     ClientMethod clientTest( 
      
        
        
        
      
     a , 
      
        
        
        
      
     b ) [ Language = javascript ] 
      
        
        
        
      
     { 
      
        
        
        
      
     zenAlert( 
      
        
        
        
      
     $$$FormatText($$$Text( "(1)^ %$# @*&' %1=%2" ), '"' ,a + b), '\n' , 
      
        
        
        
      
     zenText( 'msg3' ,a + b), '\n' , 
      
        
        
        
      
     $$$Text( "  !" ) 
      
        
        
        
      
     ); 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     ClassMethod ServerTest( 
      
        
        
        
      
     A , 
      
        
        
        
      
     B ) As %String [ ZenMethod ] 
      
        
        
        
      
     { 
      
        
        
        
      
     &js< zenAlert( #( .. QuoteJS ( $$$FormatText ( $$$Text ( "(2)^ %$# @*&' ""=%1" ),A+B)) )# ); > 
      
        
        
        
      
     quit $$$TextJS ( "  Caché!" ) 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     Method ChangeLanguage() [ ZenMethod ] 
      
        
        
        
      
     { 
      
        
        
        
      
     #dim %session as %CSP.Session 
      
        
        
        
      
     set %session. Language = $select (%session. Language = "en" : "ru" ,1: "en" ) 
      
        
        
        
      
     &js< zenPage.gotoPage( #( .. QuoteJS (.. Link ( $classname ()_ ".cls" )) )# ); > 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     Method %OnGetJSResources( ByRef pResources As %String ) As %Status [ Private ] 
      
        
        
        
      
     { 
      
        
        
        
      
     Set pResources( "msg3" ) = $$$Text ( "(3)^ %$# @*&' ""=%1" ) 
      
        
        
        
      
     Quit $$$OK 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     }
      
      革新のうち、次のことに注意する必要があります。
-  クライアント側でメッセージをローカライズするための2つのオプションがあります。 
      
- ファイル " zenutils.js "で定義されている$$$テキストメソッドを使用します。
 - クライアント側zenText()メソッドと%OnGetJSResources()サーバー側メソッドの組み合わせを使用する
 
詳細については、ドキュメントを参照してください: クライアント側テキストのローカリゼーション -   ZENコンポーネントの一部の属性は、すでに最初にローカライズをサポートしています。たとえば、あらゆる種類のヘッダー、ヒントなどです。 
      
必要に応じて、たとえばjQueryまたはextJSに基づいて、またはゼロから独自のオブジェクト指向コンポーネントを作成します。
特殊なデータ型%ZEN.Datatype.caption : Zenコンポーネントのローカライズ - 言語を変更するには、 %セッションおよび/または%応答オブジェクトのLanguageプロパティを使用できます。Zen特殊変数
 
最初、セッションはブラウザで指定された言語を使用します。
      増す
独自のエラー報告ディレクトリを作成する
これを行うには上記のツールで十分です。
それでも、このプロセスを少し自動化するのに役立つ組み込みの方法があります。
それでは始めましょう。
次の内容のエラーメッセージを含むファイル「 messages_ru.xml 」を作成します。
 <?xml version="1.0" encoding="UTF-8"?> <MsgFile Language="ru"> <MsgDomain Domain="asd"> <Message Id="-1" Name="ErrorName1">    1</Message> <Message Id="-2" Name="ErrorName2">    2 %1 %2</Message> </MsgDomain> </MsgFile>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      データベースにインポートします。
do ##class ( %MessageDictionary ). Import ( "messages_ru.xml" )
      
      データベースに2つのグローバルが作成されました。
-   ^ CacheMsg 
      
USER>zw ^CacheMsg ^CacheMsg("asd","ru",-2)=" 2 %1 %2" ^CacheMsg("asd","ru",-1)=" 1"
 -   ^ CacheMsgNames 
      
USER>zw ^CacheMsgNames ^CacheMsgNames("asd",-2)="ErrorName2" ^CacheMsgNames("asd",-1)="ErrorName1"
 
「CustomErrors」という名前のインクルードファイルを生成します。
 USER>Do ##class(%MessageDictionary).GenerateInclude("CustomErrors",,"asd",1) Generating CustomErrors.INC ...
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      注:詳細については、 GenerateInclude()メソッドのドキュメントを参照してください。
ファイル " CustomErrors.inc ":
#define asdErrorName2 "<asd>-2" 
      
        
        
        
      
     #define asdErrorName1 "<asd>-1"
      
      これで、プログラムでエラーコードおよび/または短縮エラー名を使用できます。次に例を示します。
Include CustomErrors 
      
        
        
        
      
     
      
        
        
        
      
     Class demo.test [ Abstract ] 
      
        
        
        
      
     { 
      
        
        
        
      
     
      
        
        
        
      
     ClassMethod test( A As %Integer ) As %Status 
      
        
        
        
      
     { 
      
        
        
        
      
     if A=1 Quit $$$ERROR ( $$$asdErrorName1 ) 
      
        
        
        
      
     if A=2 Quit $$$ERROR ( $$$asdErrorName2 , "f" , "6" ) 
      
        
        
        
      
     Quit $$$OK 
      
        
        
        
      
     } 
      
        
        
        
      
     
      
        
        
        
      
     }
      
      結果:
 USER>d $system.OBJ.DisplayError(##class(demo.test).test(1))  <asd>-1:     1 USER>d $system.OBJ.DisplayError(##class(demo.test).test(2))  <asd>-2:     2 f 6 USER>w $system.Status.GetErrorText(##class(demo.test).test(1),"en") ERROR <asd>-1: bla-bla-bla 1 USER>w $system.Status.GetErrorText(##class(demo.test).test(2),"en") ERROR <asd>-2: bla-bla-bla 2 f 6
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      注:英語のメッセージは、類推によって作成されました。