DBMSCachéのローカライズ

「Hello、World!」を出力するプログラムを書いたとします。例えば:
write "Hello, World!"

アプリケーションは動作し、すべてが正常です。
しかし、時間の経過、アプリケーションの開発、人気の高まり、そして今、この行を別の言語で表示する必要があり、必要な言語の数と構成は事前にわかりません。
このカットでは、Cachéでローカライズの問題がどのように解決されるかを学習します。


短いレビュー


CachéDBMSは、コンソールプログラム、Webアプリケーションのインターフェイス、JavaSciptファイルの文字列、エラーメッセージなどの文字列のローカライズを簡素化する既製のメカニズムを提供します。
注:このトピックについては、以前の記事の 1つで説明しました。

多くのクラス、プログラム、ウェブページ、jsスクリプトなどを含むプロジェクトがあるとしましょう。
ローカライズメカニズムは次のように機能します。
  1. プロジェクトのコンパイル段階でも、ローカライズされるすべての行は「フィッシングアウト」され、特定の形式でデータベース内に保存されます。
  2. 行自体の代わりに、特定のコードがコンパイル済みコード自体に置き換えられ、 実行段階で、セッションの現在の言語に応じて、ストアから1つまたは別の値を出力します。

ローカライズプロセス全体は、プログラマーに対して完全に透過的です。
開発者は、特定の文字列ストア(データベースまたはリソースファイル内のテーブル)を手動で入力する必要性をなくし、実行時の言語の変更、翻訳者向けのさまざまな形式へのデータのエクスポート/インポートなど、このインフラストラクチャ全体を管理するコードを記述しますd。

その結果、次のことができます。
  1. 読みやすい-過度に整理されていない-ソースコード;
  2. ローカライズされた文字列の自動補完ストレージ
    注:リポジトリのコードから行を削除しても、削除されません。 このようなファントムからリポジトリをクリーンアップするには、クリーンアップしてプロジェクトを再コンパイルする方が簡単です。
  3. 現在の言語を「その場で」変更します。 これは、Webアプリケーションと通常のプログラムの両方に適用されます。
  4. 特定のドメイン(特定のドメインより少し低いドメイン)から特定の言語の文字列を取得する機能。
  5. 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,!
}


上記の例に関しては 、次のことに注意する必要があります。
  1. プログラムの行は、現在のロケール(管理ポータルで構成)でCachéDBMSに既定で登録されている言語で最初に記述される必要があります。
    注:ハッシュの代わりに文字列識別子を使用する場合、これはそれほど重要ではありません。
  2. マクロは各行についてCRC32を計算し、すべてのデータ(CRC32 または行識別子、ドメイン、現在のシステム言語)が^ CacheMsgグローバルに保存されます。
  3. 行自体の代わりに、プライベートグローバルの値を考慮するコードが挿入されます^ ||%Language ;
  4. ユーザーが翻訳のない言語の文字列を要求した場合(リポジトリにデータがありません)、元の文字列が返されます。
  5. ドメインメカニズムにより、ローカライズされた文字列を論理的に分離することができます。たとえば、同じ文字列に対する異なる翻訳などです。

何らかの理由で現在の$$$テキストマクロアルゴリズムに満足できない場合、たとえば、デフォルトの言語を別の場所に設定したり、データを別の場所に保存したりしたい場合は、アナログを作成できます。
そして、マクロ##式および/または##関数がこれを支援します。

例を続けましょう。
新しい言語を追加しましょう。 これを行うには、文字列ストアをファイルにアンロードして翻訳者に渡し、それから翻訳を別の言語でロードする必要があります。
データはさまざまな方法で、さまざまな形式でダウンロードできます。
%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 

次の点に注意してください。

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
}

}


革新のうち、次のことに注意する必要があります。
  1. クライアント側でメッセージをローカライズするための2つのオプションがあります。
    • ファイル " zenutils.js "で定義されている$$$テキストメソッドを使用します。
    • クライアント側zenText()メソッドと%OnGetJSResources()サーバー側メソッドの組み合わせを使用する

    詳細については、ドキュメント参照してください: クライアント側テキストのローカリゼーション
  2. ZENコンポーネントの一部の属性は、すでに最初にローカライズをサポートしています。たとえば、あらゆる種類のヘッダー、ヒントなどです。
    必要に応じて、たとえばjQueryまたはextJSに基づいて、またはゼロから独自のオブジェクト指向コンポーネントを作成します。
    特殊なデータ型%ZEN.Datatype.captionZenコンポーネントのローカライズ
  3. 言語を変更するには、 %セッションおよび/または%応答オブジェクトの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つのグローバルが作成されました。

「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 
注:英語のメッセージは、類推によって作成されました。

Source: https://habr.com/ru/post/J144312/


All Articles