Windows Phoneアプリケーション名の簡単なローカライズ





Windows Phoneのアプリケーションの開発者として、モバイルアプリケーションの市場はグローバルであり、アプリケーションのプロモーションを成功させるには、利用可能な言語の最大数に合わせて定性的にローカライズする必要があることを長い間理解していました。 Windows Phoneのアプリケーションのローカライズについては、 アプリケーション開発ドキュメントで詳しく説明されています 。 ただし、 アプリケーションタイルのヘッダーとタイトルをローカライズするプロセスは 、アプリケーション自体のローカライズとは異なり、言語ごとに個別のリソースファイルを準備する必要があるため、多くの場合、問題を引き起こします。



この問題を解決するために、いくつかのリソースプロジェクトを作成し、ビルドが成功した後、結果をアプリケーションディレクトリにコピーしました。 このソリューションは私に完全に適していましたが、私のアプリケーションは3言語しかサポートしていませんでした。 より多くの言語でアプリケーションをローカライズする必要が生じた後、このアプローチは面倒になりました。



この検索は、多くの人がこの問題を便利に解決する方法を探していることを示しました。 しかし、自分にとって便利な方法が見つからなかったため、リソースファイルを作成および管理できるユーティリティを作成することにしました。 私にとって、最も便利な方法は、XMLファイルでヘッダーを記述し、それに基づいて必要なファイルを自動的に生成することでした。





アプリケーションヘッダー記述ファイルの場合、次の形式が選択されます。



<Localization> <Application> <Name /> <Description /> </Application> <Languages> <Default inactive="false"> <Title /> <TileTitle /> </Default> <Albanian inactive="true"> <Title /> <TileTitle /> </Albanian></Languages> </Localization>
      
      







このユーティリティをVisual Studioのカスタムツールとして作成することにしました







カスタムツールとして使用できるオブジェクトを実装するには、 IVsSingleFileGeneratorインターフェイスを実装する必要があります。



 interface IVsSingleFileGenerator { int DefaultExtension(out string); int Generate(string, string, string, IntPtr[], out uint, IVsGeneratorProgress); }
      
      







インターフェイスの名前と説明が示すように、その助けを借りて作成できるファイルは1つだけであり、タスクを解決するには不十分です。 ただし、この調査では、ユーティリティの生成中に、プロジェクトを任意に変更できるVisual Studioコンテキストにアクセスできることが示されました。



プロジェクトを管理するには、 ProjectItemオブジェクトへのリンクを取得する必要があります。ProjectItemオブジェクトは、ソースデータを記述するXMLファイルに関連付けられています



 var dte = (EnvDTE.DTE)Package.GetGlobalService(typeof(EnvDTE.DTE)); var sourceControl = dte.SourceControl; var projectItem = dte.Solution.FindProjectItem(sourceFilePath); if (projectItem == null) { throw new ApplicationException("Unable to locate a ProjectItem associated to the file"); }
      
      







その後、この要素のProjectItemsコレクションから子ファイルを追加および削除できます。



 private static void UpdateNestedProjectItems(ProjectItem projectItem, HashSet<string> generatedFiles) { foreach (ProjectItem item in projectItem.ProjectItems) { if (item.Properties != null) { var property = item.Properties.Item("FullPath"); if (property != null) { var value = property.Value as string; if (value != null) { if (generatedFiles.Contains(value)) { item.Properties.Item("BuildAction").Value = 2; generatedFiles.Remove(value); } else { if(value.EndsWith("txt", StringComparison.CurrentCultureIgnoreCase)) { item.Properties.Item("BuildAction").Value = 0; } else { item.Remove(); } } } } } } foreach (var file in generatedFiles) { var item = projectItem.ProjectItems.AddFromFile(file); item.Properties.Item("BuildAction").Value = 2; } }
      
      







作成されたユーティリティの2番目の重要な部分はリソースファイルの作成です;それを解決するために、空のdllファイルが作成され、ユーティリティリソースに導入されました。 操作中に、このファイルはリソースファイルの命名要件に従ってコピーされ、名前が変更されます。 その後、WIN API関数BeginUpdateResourceUpdateResourceEndUpdateResourceを使用して、このファイルにリソースが追加されます。



 internal static class APIHelper { public const int RT_STRING = 6; [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool UpdateResource(IntPtr hUpdate, int lpType, int lpName, ushort wLanguage, IntPtr lpData, uint cbData); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard); }
      
      







文字列リソースを作成するとき、ちょっとしたトリックがあります;実際には、リソース内の文字列は最適化のために行われた16行のブロックとして保存されます。 行を変更するには、その行が含まれる行ブロック全体を上書きする必要があります。 このタスクでは、データを変更する必要はありません。したがって、必要なデータを記録するだけでよく、ブロックの他の行の安全性は気にしません。



行ブロック番号は、次のアルゴリズムを使用して計算できます。



N = STRID / 16 + 1



ここで、Nはラインブロック番号、STRIDはリソースラインIDです(ローカライズドキュメントでは、アプリケーションタイトル100、タイルタイトル200で受け入れられます)。



完成したユーティリティをGACに登録するとともに、レジストリにエントリを追加してクラスをカスタムツールとして登録し、その後プロジェクトで使用できるようにする必要があります。



ユーティリティの結果は次のようになります



画像



ユーティリティをより便利に使用するために、Visual Studioの要素テンプレートも作成され、ユーティリティの自動登録用のインストーラが作成されました。



利用可能なソースコード: http : //wptitlelocalizationtool.codeplex.com/

利用可能なインストールパッケージ: http : //visualstudiogallery.msdn.microsoft.com/527c7d79-55f7-4ff2-9ab8-d6122bf6e75d



All Articles