複数の言語をサポートするソリューションの作成

このトピックは、Dynamics 365 Customer Engagement (on-premises) に適用されます。 このトピックの Power Apps バージョンについては、以下を参照してください。 複数の言語をサポートするソリューションを作成します

Dynamics 365 for Customer Engagement は複数言語をサポートしています。 ソリューションを、異なる基本言語を含む組織や複数言語が準備されている組織にインストールする場合は、ソリューションの計画時に検討してください。 次の表は複数の言語がサポートされるソリューションに含めるソリューション コンポーネントで使用する戦略の一覧です。

戦略 ソリューション コンポーネントの種類
文字列 (RESX) Web リソース Web リソース
埋め込みラベル アプリケーションのナビゲーション (SiteMap)
リボン
翻訳のエクスポートおよびインポート 属性
グラフ
ダッシュボード
Entity
エンティティ リレーションシップ
フォーム
メッセージ
オプション セット
ビュー
基本言語の文字列のローカライズ 契約テンプレート
つながりロール
プロセス (ワークフロー)
セキュリティ ロール
フィールド セキュリティ プロファイル
ローカライズが不要な場合 SDK メッセージ処理手順
サービス エンドポイント
各言語の個別のコンポーネント 記事テンプレート
電子メール テンプレート
差し込み印刷用テンプレート
レポート
ダイアログ
言語リソースとして XML Web リソースを使用する プラグイン アセンブリ

以下のセクションで、各戦略の詳細情報を提供します。

文字列 (RESX) Web リソース

Dynamics 365 for Customer Engagement アプリ バージョン 9.0 で文字列 (RESX) Web リソースが追加されたことで、開発者は、複数言語をサポートする Web リソースを作成するための、さらに強力なオプションを利用できます。 詳細については、文字列 (RESX) Web リソース を参照してください。

以前のバージョンの場合は、開発者のオプション を参照してください

埋め込みラベル

この戦略を使用するソリューション コンポーネントごとに、ローカライズされたテキストをソリューションに含める必要があります。

リボン

言語パックをインストールすると、アプリケーション リボンは自動的にリボンのすべての既定のテキストがローカライズ済みのテキストで表示されます。 システム ラベルは内部使用限定の ResourceId 属性値で定義されます。 独自のテキストを追加するときに、<LocLabels> 要素を使用して、サポートする言語のローカライズ済みテキストを作成します。 詳細: リボンでのローカライズされたラベルの使用

SiteMap

言語パックをインストールすると、アプリケーション ナビゲーション バーの既定のテキストは、自動的にローカライズされたテキストで表示されます。 既定のテキストを上書きまたは独自のテキストを使用するには <Titles> 要素を使用します。 Titles 要素は、ソリューションでサポートされるすべての言語用のローカライズされたテキストを含む <Title> 要素も含める必要があります。 Title の要素をユーザーが優先する言語で使用できない場合、組織の基本言語に対応したタイトルが表示されます。

<SubArea> 要素では、 userlcid パラメータを使ってユーザの言語設定を渡すことができ、 SubArea.Url 属性の対象となるコンテンツがユーザーの言語設定を認識し、それに応じて調整することができます。 詳細: サイトマップを使用して URL にパラメーターを渡す方法

翻訳のエクスポートおよびインポート

次の表のソリューション コンポーネントのローカライズされたラベルは、ローカライズ用にエクスポートできます。

  • エンティティ
  • 属性
  • 関連付け
  • グローバル オプション セット
  • エンティティ メッセージ
  • エンティティ フォーム
  • エンティティ ビュー (SavedQuery)
  • グラフ
  • ダッシュボード

ラベルを翻訳して文字列を表示する

カスタマイズは、基本言語を使用したアプリケーションでしか実行できません。 そのため、カスタマイズ用のローカライズされたラベルを用意して文字列を表示する場合は、組織で使用できる他の言語にローカライズできるように、ラベルのテキストをエクスポートする必要があります。 次の手順を実行します。

  1. 作業を行う組織に、翻訳を入力する言語に向けたすべての MUI パックがインストールされており、言語が用意されていることを確認してください。

  2. ソリューションを作成し、コンポーネントを変更します。

  3. ソリューションの開発を終了した後は、"翻訳のエクスポート" 機能を使用してください。 これにより、翻訳が必要なすべてのラベルを含む Office Excel のスプレッドシート (CrmTranslations.xml) が生成されます。

  4. スプレッドシートに、対応する翻訳を入力します。

  5. "翻訳のインポート" 機能を使用して翻訳を同じ Dynamics 365 Customer Engagement (on-premises) 組織へとインポートし、変更を公開します。

  6. 次にソリューションをエクスポートしたときに、設定したすべての翻訳がソリューションに含まれます。

    ソリューションのインポートがされると、ターゲットのシステムで使用できない言語のラベルは破棄され、警告が記録されます。

    ソリューション パッケージでターゲット システムの基本言語のラベルが提供されない場合は、代わりにソースの基本言語のラベルが使用されます。 たとえば、基本言語が英語であるソリューションで、英語とフランス語のラベルを含むソリューションをインポートしたが、ターゲット システムでは基本言語が日本語で、日本語とフランス語が設定されている場合、日本語のラベルの代わりに英語のラベルが使用されます。 基本言語のラベルは、null にすることも空にすることもできません。

翻訳をエクスポートする

翻訳をエクスポートする前に、言語パックをインストールし、ローカライズするすべての言語を準備する必要があります。 翻訳は Web アプリケーションにエクスポートするか、ExportTranslationRequest メッセージを使用してエクスポートできます。 詳細については、「カスタマイズされたエンティティとフィールド テキストの翻訳用のエクスポート」を参照してください。

テキストの翻訳

Office Excel で CrmTranslations.xml ファイルを開くと、次の表に示す 3 種類のワークシートが表示されます。

ワークシート 説明
情報 ラベルおよび文字列のエクスポート元の組織とソリューションに関する情報を表示します。
表示文字列 メタデータ コンポーネントに関連するメッセージのテキストを表す文字列を表示します。 この表に、システム リボン要素に使用するエラー メッセージと文字列を示します。
ローカライズされたラベル メタデータ コンポーネントのラベルのテキストをすべて表示します。

翻訳担当者、翻訳会社、およびローカリゼーション会社にはこのファイルを送信できます。 空のセルにローカライズされた文字列を指定する必要があります。

Note

ユーザー定義エンティティに対しては作成日または作成者などのシステム エンティティと共有する、共通のラベルがあります。 この言語は既にインストールおよび準備されているため、既定のソリューションの言語をエクスポートすると、一部の、ローカライズされたテキストのあるユーザー定義エンティティのラベルを他のエンティティで使用する同一のラベルと一致させることができます。 これにより、ローカライズにかかるコストを削減し、一貫性を向上できます。

ワークシートのテキストをローカライズ後、CrmTranslations.xml および [Content_Types].xml の両方のファイルを 1 つの圧縮 .zip ファイルに追加します。 これで、このファイルをインポートできます。

翻訳済みテキストのインポート

重要

エクスポート元と同じ組織にのみ、翻訳済みテキストをインポートして戻すことができます。

カスタマイズされたエンティティまたは属性のテキストをエクスポートし、翻訳したら、ImportTranslationRequest メッセージを使用して、Web アプリケーションに翻訳済みのテキスト文字列をインポートできます。 インポートするファイルは、ルートに CrmTranslations.xml と [Content_Types].xml ファイルを含む圧縮ファイルである必要があります。 詳細については、「エンティティおよびフィールドの翻訳済みテキストのインポート」を参照してください。

完了した翻訳をインポートした後、カスタマイズされたテキストは、そのテキストの翻訳後の言語を使用するユーザーに表示されます。

Note

Dynamics 365 Customer Engagement (on-premises) では、500 文字を超える長さの翻訳済みテキストをインポートすることはできません。 翻訳ファイル内の任意のアイテムが 500 文字を超える長さの場合、インポート プロセスは失敗します。 インポート プロセスが失敗した場合は、失敗の原因となったファイル中の行を確認し、文字数を減らしてから再度インポートを試みてください。

カスタマイズは基本言語でのみサポートされるので、言語選択で設定した基本言語で Dynamics 365 Customer Engagement (on-premises) を操作している可能性があります。 翻訳済みテキストが表示されることを確認するには、Dynamics 365 Customer Engagement (on-premises) のユーザー インターフェイスの言語選択を変更する必要があります。 カスタマイズに関する追加の作業を行うには、基本言語に戻す必要があります。

基本言語の文字列のローカライズ

一部のソリューション コンポーネントは、複数の言語をサポートしていません。 これらのコンポーネントには、特定の言語で意味のある名前またはテキストのみが含まれます。 特定の言語用のソリューションを作成した後、目的の組織の基本言語に対してこれらのソリューション コンポーネントを定義します。

複数の言語をサポートする必要がある場合は、1 つの方法として、1 つの基本言語にローカライズを含める方法があります。 例えば、「Friend」という名前の接続ロールがあり、英語、スペイン語、ドイツ語をサポートする必要がある場合、接続ロールの名前として「Friend (Amigo / Freund)」というテキストを使用することができます。 テキストの長さに関する不具合があるため、この方法を使用してサポートできる言語数には制限があります。

このグループに含まれるソリューション コンポーネントの一部は管理者のみに表示されます。 システムのカスタマイズは、組織の基本言語でのみ実行できるので、複数の言語バージョンを提供する必要はありません。 セキュリティ ロールおよびフィールド セキュリティ プロファイルコンポーネントはこのグループに属します。

契約テンプレートで、サービス契約の種類を説明します。 これらは名前省略形フィールドのテキストが必要です。 一意の名前および省略形を使用し、組織のすべてのユーザーに対して適用する必要があります。

つながりロールはわかりやすいつながりロールのカテゴリおよび名前を選択しているユーザーに依存します。 これらは比較的短くできるので、基本言語文字列にローカライズの列を含めることをお勧めします。

イベントで開始されるプロセス (ワークフロー) は、ローカライズされたテキストでレコードを更新する必要がない場合は正常に動作します。 ローカライズされたテキストに適用される可能性があるロジックが、プラグイン アセンブリと同じ方法を使用できるようにワークフロー アセンブリを使用することができます (言語リソースとして XML Web リソースを使用する)。

オンデマンド ワークフローは、ユーザーがワークフローを選択できるように名前が必要です。 オンデマンド ワークフローの名前にローカライズを含める方法の他に、ローカライズされた名前の複数のワークフローを作成し、それぞれで同じ子プロセスを呼び出す方法があります。 ただし、ユーザーに該当するユーザー インターフェイスの言語のみの一覧ではなく、すべてのユーザーにオンデマンド ワークフローの完全な一覧が表示されます。

ローカライズが不要な場合

SDK メッセージ処理手順およびサービス エンドポイントソリューション コンポーネントは、ローカライズ可能なテキストが表示されません。 これらのコンポーネントの名前と説明が組織の基本言語に対応することが重要な場合は、その言語の名前と説明を含む管理ソリューションを作成してエクスポートすることができます。

各言語の個別のコンポーネント

次のソリューション コンポーネントはそれぞれ、ローカライズしたテキストが大量に含まれる可能性があります。

  • 記事テンプレート

  • 電子メール テンプレート

  • 差し込み印刷用テンプレート

  • レポート

  • ダイアログ

    このようなソリューション コンポーネントの場合に推奨される方法は、各言語に対して別のコンポーネントを作成する方法です。 これは通常、コアのソリューション コンポーネントを含む基本のマネージド ソリューションを作成してから、各言語に対するこれらのソリューション コンポーネントを含む個別のマネージド ソリューションを作成することを意味します。 顧客がソリューションをインストールしたら、組織で準備した言語の管理マネージド ソリューションをインストールできます。

    プロセス (ワークフロー) とは違い、現在のユーザーの言語設定を反映し、その言語ロ使用するユーザーのみに表示するダイアログを作成できます。

ローカライズされたダイアログを作成する

  1. 適切な言語パックをインストールして言語を準備します。

    詳細については、「言語パックのインストール手順」を参照してください。

  2. 個人用オプションを変更して、ダイアログに表示する言語をユーザー インターフェイスの言語で指定します。

  3. 設定に移動し、処理センターグループでプロセスを選択します。

  4. 新規を選択し、指定した言語でダイアログを作成します。

  5. ダイアログを作成した後は、個人用オプションを変更して組織の基本言語を指定します。

  6. 組織の基本言語を使用している間は、設定ソリューション領域に移動して、ソリューションの一部としてローカライズされたダイアログを追加できます。

    他の言語で作成したダイアログはその言語を使用して Dynamics 365 Customer Engagement (on-premises) を表示するユーザーにのみ表示されます。

言語リソースとして XML Web リソースを使用する

プラグイン アセンブリ ソリューション コンポーネントでは、エンド ユーザーに InvalidPluginExecutionException をスローしたり、レコードを作成、更新してメッセージを送信できます。 Silverlight Web リソースと違って、プラグインではリソース ファイルは使用できません。

プラグインでローカライズされたテキストが必要なときは、XML Web リソースを使用してローカライズされた文字列を格納し、必要になったときにプラグインにアクセスできるようにします。 XML の構造はオプションですが、ASP.NET リソース (.resx) ファイルで使用されている構造に従って、各言語別の XML Web リソースを作成できます。 たとえば、以下は localizedString.en_US という名前の XML Web リソースで、 resx ファイルで使用されるパターンに従います。

<root>  
 <data name="ErrorMessage">  
  <value>There was an error completing this action. Please try again.</value>  
 </data>  
 <data name="Welcome">  
  <value>Welcome</value>  
 </data>  
</root>  

次のコードは、ローカライズされたメッセージをプラグインに渡してユーザーにメッセージを表示するための方法を示します。 Account エンティティの Delete イベントの事前検証ステージで使用します。

protected void ExecutePreValidateAccountDelete(LocalPluginContext localContext)  
  {  
   if (localContext == null)  
   {  
    throw new ArgumentNullException("localContext");  
   }  
   int OrgLanguage = RetrieveOrganizationBaseLanguageCode(localContext.OrganizationService);  
   int UserLanguage = RetrieveUserUILanguageCode(localContext.OrganizationService,  
 localContext.PluginExecutionContext.InitiatingUserId);  
   String fallBackResourceFile = "";  
   switch (OrgLanguage)  
   {  
    case 1033:  
     fallBackResourceFile = "new_localizedStrings.en_US";  
     break;  
    case 1041:  
     fallBackResourceFile = "new_localizedStrings.ja_JP";  
     break;  
    case 1031:  
     fallBackResourceFile = "new_localizedStrings.de_DE";  
     break;  
    case 1036:  
     fallBackResourceFile = "new_localizedStrings.fr_FR";  
     break;  
    case 1034:  
     fallBackResourceFile = "new_localizedStrings.es_ES";  
     break;  
    case 1049:  
     fallBackResourceFile = "new_localizedStrings.ru_RU";  
     break;  
    default:  
     fallBackResourceFile = "new_localizedStrings.en_US";  
     break;  
   }  
   String ResourceFile = "";  
   switch (UserLanguage)  
   {  
    case 1033:  
     ResourceFile = "new_localizedStrings.en_US";  
     break;  
    case 1041:  
     ResourceFile = "new_localizedStrings.ja_JP";  
     break;  
    case 1031:  
     ResourceFile = "new_localizedStrings.de_DE";  
     break;  
    case 1036:  
     ResourceFile = "new_localizedStrings.fr_FR";  
     break;  
    case 1034:  
     ResourceFile = "new_localizedStrings.es_ES";  
     break;  
    case 1049:  
     ResourceFile = "new_localizedStrings.ru_RU";  
     break;  
    default:  
     ResourceFile = fallBackResourceFile;  
     break;  
   }  
   XmlDocument messages = RetrieveXmlWebResourceByName(localContext, ResourceFile);  
   String message = RetrieveLocalizedStringFromWebResource(localContext, messages, "ErrorMessage");  
   throw new InvalidPluginExecutionException(message);  
  }  
  protected static int RetrieveOrganizationBaseLanguageCode(IOrganizationService service)  
  {  
   QueryExpression organizationEntityQuery = new QueryExpression("organization");  
   organizationEntityQuery.ColumnSet.AddColumn("languagecode");  
   EntityCollection organizationEntities = service.RetrieveMultiple(organizationEntityQuery);  
   return (int)organizationEntities[0].Attributes["languagecode"];  
  }  
  protected static int RetrieveUserUILanguageCode(IOrganizationService service, Guid userId)  
  {  
   QueryExpression userSettingsQuery = new QueryExpression("usersettings");  
   userSettingsQuery.ColumnSet.AddColumns("uilanguageid", "systemuserid");  
   userSettingsQuery.Criteria.AddCondition("systemuserid", ConditionOperator.Equal, userId);  
   EntityCollection userSettings = service.RetrieveMultiple(userSettingsQuery);  
   if (userSettings.Entities.Count > 0)  
   {  
    return (int)userSettings.Entities[0]["uilanguageid"];  
   }  
   return 0;  
  }  
  protected static XmlDocument RetrieveXmlWebResourceByName(LocalPluginContext context, string webresourceSchemaName)  
  {  
   context.TracingService.Trace("Begin:RetrieveXmlWebResourceByName, webresourceSchemaName={0}", webresourceSchemaName);  
   QueryExpression webresourceQuery = new QueryExpression("webresource");  
   webresourceQuery.ColumnSet.AddColumn("content");  
   webresourceQuery.Criteria.AddCondition("name", ConditionOperator.Equal, webresourceSchemaName);  
   EntityCollection webresources = context.OrganizationService.RetrieveMultiple(webresourceQuery);  
   context.TracingService.Trace("Webresources Returned from server. Count={0}", webresources.Entities.Count);  
   if (webresources.Entities.Count > 0)  
   {  
    byte[] bytes = Convert.FromBase64String((string)webresources.Entities[0]["content"]);  
    // The bytes would contain the ByteOrderMask. Encoding.UTF8.GetString() does not remove the BOM.  
    // Stream Reader auto detects the BOM and removes it on the text  
    XmlDocument document = new XmlDocument();  
    document.XmlResolver = null;  
    using (MemoryStream ms = new MemoryStream(bytes))  
    {  
     using (StreamReader sr = new StreamReader(ms))  
     {  
      document.Load(sr);  
     }  
    }  
    context.TracingService.Trace("End:RetrieveXmlWebResourceByName , webresourceSchemaName={0}", webresourceSchemaName);  
    return document;  
   }  
   else  
   {  
    context.TracingService.Trace("{0} Webresource missing. Reinstall the solution", webresourceSchemaName);  
    throw new InvalidPluginExecutionException(String.Format("Unable to locate the web resource {0}.", webresourceSchemaName));  
    return null;  
 // This line never reached  
   }  
  }  
  protected static string RetrieveLocalizedStringFromWebResource(LocalPluginContext context, XmlDocument resource, string resourceId)  
  {  
   XmlNode valueNode = resource.SelectSingleNode(string.Format(CultureInfo.InvariantCulture, "./root/data[@name='{0}']/value", resourceId));  
   if (valueNode != null)  
   {  
    return valueNode.InnerText;  
   }  
   else  
   {  
    context.TracingService.Trace("No Node Found for {0} ", resourceId);  
    throw new InvalidPluginExecutionException(String.Format("ResourceID {0} was not found.", resourceId));  
   }  
  }  

関連項目

Dynamics 365 Customer Engagement (on-premises) ソリューションを使用した拡張機能のパッケージ化および配布
ソリューションの概要
ソリューション開発の計画
ソリューション コンポーネントの依存関係の追跡
アンマネージド ソリューションの作成、エクスポート、またはインポート
マネージド ソリューションの作成、インストール、および更新
ソリューションのアンインストールまたは削除
ソリューション エンティティ