プロローグ
まず、プログラマーとしての長年の仕事の中で、ローカライズを何らかの形でプロジェクトに導入するタスクに繰り返し遭遇しましたが、通常、これらはキーと値のペアを持つロードされた辞書に基づくソリューションでした。 このアプローチは小規模なプロジェクトには適していますが、次のような重大な欠点があります。
- 既存のプロジェクトの実装の複雑さ。
- ローカライズされたメッセージのフォーマットツールの欠如(標準のstring.Formatを除く)。
- 文化的に依存する機能を埋め込むことができない。 たとえば、数値の値に応じて必要な単語の形を置き換えるという一般的なタスクは、辞書だけでは解決できません。
これらの問題を分析した後、プロジェクトをローカライズするために独自のライブラリを作成する必要があるという結論に達しました。これには、上記の欠点がありません。 この記事では、C#コードの例でどのように機能するかについて説明します。
ライブラリ構成
SourceForgeプロジェクトへのリンク: https : //sourceforge.net/projects/open-genesis/?source=navbar
例: LocalizationViewer
アセンブリには次のプロジェクトが含まれます。
- Genesis.Localizationは、主要なローカリゼーションライブラリです。
- Ru-ロシア語ローカライズの実装(例)。
- En-英語のローカライズの実装(例)。
- LocalizationViewer-ローカライズを編集する機能を備えたライブラリの機能を実証するプログラム。
基本原則
ローカリゼーションマネージャー
ライブラリはプラグインに基づいて構築され、次のように動作します。アプリケーションの起動時に、ローカリゼーションマネージャー( LocalizationManager )が作成されます。英語など)。 その後、すべてのパッケージの記述子を検索してダウンロードするコマンドが与えられ、初期化コード全体は次のようになります。
// LocalizationManager = new LocalizationManager(); LocalizationManager.BasePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Localization"); LocalizationManager.Initialize(); try { LocalizationManager.DetectAllLocalizations(); } catch (LocalizationException ex) { MessageBox.Show(ex.Message, " ", MessageBoxButtons.OK, MessageBoxIcon.Error); return; }
すべてが順調に進んだ場合、使用可能なローカリゼーションのリストが簡単な説明(記述子、 LocalizationDescriptor )の形でマネージャーに表示されます。 これらの記述子にはロジックは含まれませんが、ダウンロードしてプログラムで使用するために開始できるパッケージの説明としてのみ機能します。
すべてのローカライズのリストは、マネージャーから取得できます。
manager.Localizations
たとえば、ロシア語のローカライズを接続したいので、これをマネージャーに直接ロードする必要があります。
LocalizationPackage package = manager.Load("ru");
ロード後、ローカライズを使用して作業することができます-それから行、リソースなどを取得し、それが不要になったらアンロードできます:
manager.Unload("ru");
重要! 次のように、無制限の数のローカリゼーションをロードおよびアンロードできます。 それらはすべて独自のドメイン(AppDomain)で作成されます。
ローカリゼーションパッケージ
各ローカライズは、個別のディレクトリにあるファイルのセットです。すべてのルートは、ローカライズマネージャーの読み込み時に選択されたものです。 上記の例では、これは[ProjectDir] \ Localizationディレクトリになり、ローカライズパッケージは[ProjectDir] \ Localization \ ru 、 [ProjectDir] \ Localization \ enディレクトリなどに直接配置されます。
各標準パッケージには、次のファイルが含まれている必要があります。
- localization.info-パッケージの簡単な説明を含むxmlファイル。これらのファイルは最初にローカリゼーションマネージャーによってダウンロードされます。
ロシア語のローカライズの例:
<?xml version="1.0"?> <LocalizationInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Name></Name> <Culture>ru</Culture> </LocalizationInfo>
ご覧のとおり、フィールドは2つしかありません。特定のパッケージを識別するために、後で新しいフィールドが追加される可能性があります。 - flag.png-ローカライズを象徴する画像。 私の例では、これらは16x16ピクセルのサイズの状態フラグです。
- strings.xml-ローカライズされた文字列を含むxmlファイル。 パッケージのロジックをオーバーライドする場合、バイナリやデータベースなど、独自の文字列ソースを作成できます。
- package.dll-パッケージの実行可能モジュールは、 LocalizationPackageから継承されたクラスが存在する必要がある小さなライブラリです。
ロシア語ローカライズの実行可能コードの例:
using System; using Genesis.Localization; namespace Ru { public class Package : LocalizationPackage { protected override object Plural(int count, params object[] forms) { int m10 = count % 10; int m100 = count % 100; if (m10 == 1 && m100 != 11) { return forms[0]; } else if (m10 >= 2 && m10 <= 4 && (m100 < 10 || m100 >= 20)) { return forms[1]; } else { return forms[2]; } } } }
以下に複数法とは何かを説明します。
ローカライズパッケージの使用
そこで、ローカリゼーションマネージャーを作成し、翻訳パッケージをそこにロードしました。 これで、プログラムで3つの方法で使用できます。
- キー(特定のメソッド)で特定の文字列を取得します。 キーには、文字列またはInt32型の数値を指定できます。
使用例:
LocalizationPackage package = manager.Load(culture); string strByName = package["name"]; string strByID = package[150];
- 引数を渡して書式設定された文字列を取得します。 これは、ライブラリが作成されたメソッドです。
使用例:
LocalizationPackage package = manager.Load(culture); string formattedString = package["name", arg1, args2, ...];
任意のオブジェクトを引数として使用できます。 この方法の詳細については、以下で説明します。
- ローカライズされたリソースへのパスを取得します。 これを行うには、GetResourceFilePath(文字列ファイル名)メソッドを使用してローカライズディレクトリ内の任意のファイルへのパスを取得するか、GetImage(文字列ファイル名)メソッドを使用してそこから画像をロードします。
文字列インタープリター
ライブラリの強みは、文字列インタープリターにあります。 彼はどんな人ですか?
要するに、これはローカライズされた文字列に含まれる一連の命令であり、特定の文化に翻訳を適合させることができます。
文字列インタープリターは、上記の特定の引数で文字列を取得する方法(通常のキー処理の場合、「純粋な」形式で返される)または特別なGetFormattedStringメソッド(文字列形式、paramsオブジェクト[] args)によって呼び出されます。任意のフォーマット文字列が最初の引数として渡されます。
これらの指示について詳しく説明します。 それらの2つがあります。
- 文字列に引数を含めること。
フォーマットの手順:%index%
結果:引数番号のインデックスを文字列に埋め込みます
使用例:
package.GetFormattedString("%1% = %0%%%", 80, "");
結果:
= 80%
サービス文字である%文字は、この例と同じ別の文字でエスケープする必要があることに注意してください。
- 機能の有効化
フォーマットの手順:
%Func(arg1, arg2, ..., argN)%
引数は、 数値 、 二重引用符で囲まれた文字列 (二重リプレイで%のように引用符自体がエスケープされる)、番号による文字列引数 (%インデックス)、または他の関数の呼び出しです。
使用例:
package.GetFormattedString(" %1% %Upper(Random(\"\", \"\", \"\"))% , %0% %Plural(%0, \"\", \"\", \"\")% .", 55, "MegaDeath2000");
結果:
MegaDeath2000 , 55 .
組み込みの機能と統合
LocalizationPackageクラスには、いくつかの組み込み「標準」関数があり、その一部は上記の例で使用されました。
- 複数(int、var1、var2、...、varN)-数に応じて単語形式を埋め込みます。このメソッドは各カルチャに対して一意であり、再定義する必要があります。 特に、ロシア語には3つの形式の数字があります(たとえば、「1ユニット」、「2ユニット」、「8ユニット」)。
- ランダム(var1、var2、...、varN)-与えられたものの中からランダムな値を選択します。
- Upper(string)-大文字にキャストします。
- Lower(string)-小文字にキャストします。
- UpperF(文字列)-最初の文字のみを大文字にキャストします( "word" => "Word")。
- LowerF(文字列)-最初の文字のみを小文字にキャストします。
新しい機能を追加する必要がある場合、これを行うには2つの方法があります。
- パッケージの再定義されたクラスで、新しい関数を宣言して[Function]属性でマークすると、特定のローカリゼーションのインタープリターに自動的に含まれます。 組み込み関数はこの方法で定義されます。たとえば、複数関数とランダム関数は次のようになります。
[Function("P")] protected abstract object Plural(int count, params object[] forms); [Function] protected virtual object Random(params object[] variants) { if (variants.Length == 0) { return null; } else { return variants[_rnd.Next(variants.Length)]; } }
関数がそのエイリアスのリストを指定することは許可されていることに注意してください(短いレコードの場合)。たとえば、Pluralはメイン名( Plural )とエイリアス( P )の両方から呼び出すことができますが、関数名の大文字と小文字は関係ありません。
- 独自の関数の統合。このために、 InjectFormatterFunctionメソッドが使用されます。使用例:
var package = LocalizationManager.Load("ru"); package.InjectFormatterFunction(new Func<int, int, int>((a, b) => Math.Min(a, b)), "Min"); package.InjectFormatterFunction(new Func<int, int, int>((a, b) => Math.Max(a, b)), "Max"); package.GetFormattedString("%min(%0, max(%1, %2))%", 10, 8, 5);
結果:
8
メソッド(MethodInfo)またはデリゲートを引数としてInjectFormatterFunctionに渡すことができます(上記の例ではデリゲートが渡されます)。
追加機能
基本機能に加えて、ライブラリにはさらに2つの追加機能があります。
デバッグモード
ライブラリのデバッグバージョンには、上記の方法でローカライズされた文字列を取得する機能だけでなく、直接書き込む機能も含まれています。
var package = LocalizationManager.Load("ru"); package["New Key"] = " "; package.Save();
この場合、指定されたキーと値を使用して新しいローカライズされた文字列が作成され(または既存の文字列が上書きされ)、パッケージ自体がディスクに保存されます。 デバッグモードでは、キーがない行を読み取ろうとすると、空の値が返されますが、新しいレコードが作成されます。 これは開発の初期段階で便利です-辞書に記入する必要はありません-それ自体は空の値で補充され、それからデータを記入します。
このリリースでは、記録機能は使用できません。これは論理的です-産業用プログラムは、ローカライズ辞書を補充できないはずです。
マッピング
これが私たちのデザートです。 目的-フォーム、コントロール、その他の複雑なオブジェクトの迅速なローカライズ。
この関数は、 LocalizationViewerデモプロジェクトで使用されます。
メインフォームの説明からの抜粋を次に示します。
[LocalizableClass("Text", "CAPTION")] public partial class frmMain : Form { ... [LocalizableClass] private System.Windows.Forms.ToolStripButton cmdExit; [LocalizableClass] private System.Windows.Forms.ToolStripButton cmdSave; [LocalizableClass] private System.Windows.Forms.ToolStripLabel lblSearch; ... /// <summary> /// /// </summary> private void Localize() { LocalizationMapper mapper = new LocalizationMapper(); mapper.Current = manager["ru"]; mapper.Localize(this); } ... }
LocalizationMapperを使用すると、 ローカライズされたオブジェクト(この場合はフォーム)のフィールドおよびプロパティの[Localizable]および[LocalizableClass]属性を使用して、 Localize関数で渡されたオブジェクトをローカライズできます。 たとえば、パラメータのない[LocalizableClass]属性は、デフォルトプロパティ(テキスト)をローカライズする必要があることを意味し、<class>。<subclass>。<field>という形式の自動キーが使用されます。 cmdExitボタンのテキストフィールドの場合、キーは次のようになります。
LocalizationViewer.frmMain.cmdExit_Text
おわりに
ライブラリはまもなく私のプロジェクトの1つでテストされるため、主にパッケージの基本機能の拡張を目的としたいくつかの改善が行われる可能性があります。 SourceForgeの更新情報をお楽しみになり、ライブラリのさらなる開発に関するコメントや意見をお寄せください。
PS
あなたは私が車輪を再発明していると言うかもしれません。 だから、しかし、自転車を発明することは私の趣味です...
さらに、プログラミングの自己改善の観点からもはるかに興味深く有用です。
同じ理由で、文献や他の情報源への言及はありません-すべてがゼロから書かれました。