こんにちは。 SilverLightテクノロジーを使用して開発されたアプリケーションのローカライズの自動化の分野で少し基礎を共有したいと思います。 この投稿(Silverlightのローカリゼーション)を読んだ後、すべての文字列定数をリソースファイルに配置する必要があることが明らかになりました。これは特にインテリジェントな作業とは言えません。 したがって、私は長い道のりを踏み、Visual Studioの組み込みマクロを使用してこのプロセスを自動化することにしました。
また、コードを少しコームする必要があるため、完全な自動化(すべてのxamlファイルの完全なスキャンでロシア文字を検索し、リソースに配置する)を中止することにしました。 さらに、.csファイル内の文字列定数を置き換える通常の自動化を思い付くことができませんでした。
分析後、次のマクロ要件が作成されました。
- ユーザーが選択したフレーズを分析します(特定のキーの組み合わせを押します)。
- google translateでフレーズの翻訳を見つけます(リソースの名前を発明してユーザーに負担をかけないようにするため)。
- 事前に示されたリソースにフレーズを追加します(生成されたプロキシクラスが必要なので、VSを介して変更を行う必要があります)。
- ユーザーが選択したフレーズをリソースへのバインドに置き換えます。
Visual Studioにはマクロエディターが組み込まれています。 それを呼び出すには、メニューからツール/マクロ/マクロIDEを選択する必要があります。 開始する前に、マクロを含むファイルを作成する必要があります(コードはVB .Netで記述されています)。 パラメータのないパブリックプロシージャはマクロのリストに表示され、ホットキーを押すか、マクロエクスプローラーから呼び出すことができます。
タスク1. VSで選択した単語の定義
Dim doc As Document = DTE.ActiveDocument Dim d As TextDocument = doc.Object Dim bp = d.Selection.AnchorPoint.CreateEditPoint, ep = d.Selection.BottomPoint.CreateEditPoint Dim caption As String = bp.GetText(ep) If (String.IsNullOrWhiteSpace(caption)) Then Exit Sub ' -
アクティブなドキュメントを取得し、それをテキストドキュメントに取り込みます(テキストを操作するためのより便利なクラス)。 2つのポイントを取得します:選択の開始と終了(doc.Selection.Textを使用する方が簡単かもしれませんが、スタジオで新しいファイルを開いて編集したファイルに戻ると、選択が失敗します。これは非常に不便です。これらのポイントはテキストの選択を復元するのに役立ちます)
タスク2.リソース名の取得
リソースの名前を取得する最も簡単な方法は、強調表示されたフレーズを英語に翻訳することです(注:最も簡単な方法は最も正確ではありません)。 このサービスにはシンプルなAPIがあるため、翻訳にはGoogle翻訳サービスを使用することが決定されました
リクエストの結果、次のJSONオブジェクトを取得します。
{"responseData": {"translatedText":"Organization Structure"}, "responseDetails": null, "responseStatus": 200}
Private Function ConvertToResourceName(ByVal text As String) As String Dim result As String = (New WebClient()).DownloadString("http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=" + text + "&langpair=ru|en") Dim stream As New MemoryStream(Encoding.Unicode.GetBytes(result)) Dim serializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(TranslateResult)) Return String.Join("", CType(serializer.ReadObject(stream), TranslateResult).responseData.translatedText _ .Split(" ", ".", ",", "!", "(", ")", vbCrLf, vbCr) _ .Where(Function(word) Not String.IsNullOrWhiteSpace(word)) _ .Select(Function(word) word(0).ToString().ToUpper() + word.Substring(1)) _ .ToArray()) End Function
転送を受け取るには、Googleサービスへの特別なリクエストを完了し、テキストを含む行を渡す必要があります。 このコードをかなり複雑にした唯一のことは、結果が単なる文字列ではなく、最初にデシリアライズする必要があるJSONオブジェクトであることです。 逆シリアル化には、DataContractJsonSerializerクラスが使用されました。 マクロでDataContractJsonSerializerを使用するには、アセンブリSystem.Runtime.Serialization.dllを参照に追加し、Googleの答えに対応するクラス、より正確には2つのクラスを実装する必要があります。
注:名前を使用する前に、翻訳の正しい選択を確認する要求をユーザーに与えることができます(調整の可能性があります)。
注: LINQ to Objectが機能するには、System.Core.dllへの参照を追加する必要があります
<DataContract()> _ Public Class TranslateResult <DataContract()> _ Public Class ResponseDataClass <DataMember()> _ Public translatedText As String <DataMember()> _ Public responseDetails As String <DataMember()> _ Public responseStatus As String End Class <DataMember()> _ Public responseData As ResponseDataClass End Class
翻訳を受け取った後、結果をわずかに装飾する必要があります。つまり、禁止されているすべての文字を削除し、 キャメルケーススタイルにします。
タスク3.リソースに新しい行を追加する
最初に、リソースエディターでウィンドウをアクティブにするか、VSで新しいウィンドウを開く必要があります。 さらに、新しいウィンドウが開かれた場合、フォーカスはそれに移動します。 ユーザーを混乱させないために、フォーカスを戻す必要があります。
Private Function FindWindow(ByVal fileName As String) As Window For i As Integer = 1 To DTE.Windows.Count If Not (DTE.Windows.Item(i).ProjectItem Is Nothing) Then If (DTE.Windows.Item(i).ProjectItem.FileNames(0) = fileName) Then Return DTE.Windows.Item(i) End If End If Next Dim oldactive As Document = DTE.ActiveDocument Dim newf = DTE.ItemOperations.OpenFile(fileName, Constants.vsViewKindTextView) oldactive.Activate() Return newf End Function
さまざまな言語のリソースファイルがいくつかある可能性があるため、それらを配列で記憶しています。
Dim resourceFiles() As String = {" \ProjectResources.resx", _ " \ProjectResources.kk-KZ.resx"}
この部分を最適化して、リソースを含むファイルを自動的に検索することができます。
次に、各リソースファイルを調べて開き、同じ名前のリソースの可用性を確認し、ない場合は追加します。
Dim paramName As String = ConvertToResourceName(caption) For Each item As String In resourceFiles Dim textDocument As TextDocument = FindWindow(item).Document.Object Dim startPoint = textDocument.StartPoint.CreateEditPoint, endPoint = textDocument.EndPoint.CreateEditPoint Dim root = XElement.Parse(startPoint.GetText(endPoint)) Dim param As XElement = root.Elements("data").FirstOrDefault(Function(el) el.Attribute("name") = paramName) If (param Is Nothing) Then root.Add(New XElement("data", New XAttribute("name", paramName) _ , New XAttribute(XName.Get("space", "http://www.w3.org/XML/1998/namespace"), "preserve") _ , New XElement("value", caption))) startPoint.ReplaceText(endPoint, root.ToString(), vsEPReplaceTextOptions.vsEPReplaceTextAutoformat) textDocument.Parent.Save() End If Next
リソースファイルは、それぞれデータフィールドを備えた単純なxml-kuであり、ファイルのコンテンツ全体を直接変更する最も簡単な方法(コンテンツは開いているドキュメントから取得されます)で、ドキュメント全体を完全に更新します。
ドキュメントを変更した後、変更を保存する必要があります。これにより、プロキシクラスが生成されます。
注: XElementが機能するには、System.Xml、System.Xml.Linqへの参照を追加します。
タスク4.ユーザーが選択した単語を新しいリソースへのバインディングテンプレートに置き換える
xaml / cs / vbファイル内のリソースへのアクセスが異なるという事実により、開いているファイル拡張子を確認し、これに従って行を形成する必要があります。
Dim replaceString As String Select Case Path.GetExtension(doc.FullName).ToLower() Case ".xaml" : replaceString = "{Binding Source={StaticResource ResourceProvider},Path=ProjectResources." + paramName + "}" Case ".cs" : replaceString = "ProjectResources." + paramName Case Else : replaceString = paramName End Select bp.ReplaceText(ep, replaceString, 0) ' d.Selection.MoveToPoint(bp) d.Selection.SwapAnchor() d.Selection.MoveToPoint(ep, True) ' ,
すべてのマクロはすぐに使用できます。
マクロを使用する利点/欠点
- キーボードセクションのメニュー項目ツール/オプションを使用して、マクロ呼び出しをホットキーにかけることができます。
- コードを少し修正する必要がある場合、コードを修正するのは非常に簡単です(たとえば、リソースを含むファイルを見つけるための複雑なメカニズムを作成することはできませんが、コードに一定のパスを作成し、必要に応じて修正するだけです);
- かなり簡単なコードデバッグ。
- VSとの良好な統合。
明らかな欠陥の
- C#でコードを書くことはできません。
- 低い生産性、かなりの期間開始。
- 頻繁なクラッシュ、特にデバッグ中。
この記事では、リソースファイルの形成を自動化する一般的なアプローチを提供しているため、必要に応じて調整できます。