Créer des solutions qui prennent en charge différentes langues.
Microsoft Dataverse acceptent plusieurs langues. Pour installer votre solution pour les organisations qui incluent différentes langues de base ou qui ont plusieurs langues, tenez-en compte lorsque vous planifiez votre solution. Le tableau suivant répertorie la tactique à utiliser avec des composants de solution à inclure dans une solution qui accepte plusieurs langues.
Tactique | Type de composant de solution |
---|---|
Ressources Web sur les chaînes (RESX) | Ressources web |
Étiquettes intégrées | Navigation dans l’application (SiteMap) Rubans |
Exporter et importer des traductions | Attributs Graphiques Tableau de bord Entité Entité-relation Formulaires Messages Groupes d’options Vues |
Localisation dans les chaînes de langue de base | Modèles de contrats Rôles de connexion Processus (Workflow) Rôles de sécurité Profils de sécurité de champ |
Localisation non requise | Étapes de traitement du message SDK Points de terminaison de service |
Composant séparé pour chaque langue | Modèles d’article Modèles de courr. électr. Modèles de publipostage Rapports Boîtes de dialogue |
Utiliser les ressources Web XML comme ressources linguistiques | Assemblys du plug-in |
Les sections suivantes fournissent des informations supplémentaires pour chaque tactique.
Ressources web de chaîne (RESX)
Lorsque les ressources web de chaîne (RESX) sont ajoutées avec Dataverse, les développeurs ont une option plus robuste pour créer des ressources web qui prennent en charge plusieurs langues. Pour plus d’informations, voir Ressources Web de chaîne (RESX).
Étiquettes imbriquées
Chaque composant de solution qui utilise cette tactique nécessite que tout texte localisé soit inclus dans le composant de solution.
Rubans
Lorsqu’un module linguistique est installé, le ruban de l’application affiche automatiquement le texte traduit pour tout le texte par défaut dans le ruban. Les étiquettes système sont définies dans une valeur d’attribut ResourceId
destinée uniquement à une utilisation interne.
Lorsque vous ajoutez votre propre texte, vous devez utiliser l’élément <LocLabels>
pour fournir du texte localisé pour les langues que vous prenez en charge. Pour plus d’informations : Utiliser les étiquettes localisées avec des rubans
SiteMap
Lorsqu’un module linguistique est installé, le texte par défaut dans la barre de navigation de l’application affiche automatiquement le texte localisé.
Pour remplacer le texte par défaut ou fournir votre propre texte, utilisez l’élément <Titles>
.
L’élément Titles
doit contenir un élément <Title>
contenant le texte localisé pour toutes les langues prises en charge par votre solution.
Si un élément Title
n’est pas disponible pour la langue par défaut de l’utilisateur, le titre correspondant à la langue de base de l’organisation est affiché.
L’élément <SubArea>
permet de passer la préférence de langue de l’utilisateur à l’aide du paramètre userlcid
afin que le contenu qui est la cible de l’attribut SubArea.Url
puisse être informé de la préférence de langue de l’utilisateur et ajuster en conséquence.
Pour plus d’informations, voir Transmission de paramètres à une URL à l’aide de SiteMap.
Exporter et importer des traductions
Les étiquettes localisables pour les composants de solution du tableau suivant peuvent être exportées en vue de leur localisation.
Entités | Attributs | Relations |
Groupe d’options généraux | Messages de l’entité | Formulaires d’entités |
Vues d’entités (SavedQuery) | Graphiques | Tableau de bord |
Traduction des étiquettes et des chaînes d’affichage
Vous ne pouvez effectuer de personnalisations dans l’application qu’en utilisant la langue de base. Par conséquent, si vous souhaitez fournir les étiquettes et les chaînes d’affichage localisées correspondant à ces personnalisations, vous devez exporter le texte des étiquettes pour qu’elles puissent être localisées pour les autres langues activées pour l’organisation. Effectuez les opérations suivantes :
Assurez-vous que l’organisation sur laquelle vous travaillez a tous les packs d’interface utilisateur multilingue installés et les langues approvisionnées pour lesquelles vous souhaitez fournir des traductions.
Créez votre solution et modifiez les composants.
Après avoir terminé de développer votre solution, utilisez la fonctionnalité Exporter les traductions. Cette opération génère une feuille de calcul Office Excel (CrmTranslations.xml) qui contient toutes les étiquettes qui doivent être traduites.
Dans la feuille de calcul, fournissez les traductions correspondantes.
Réimportez les traductions dans la même organisation Dataverse à l’aide de la fonctionnalité Importer les traductions et publiez vos modifications.
La prochaine fois que la solution sera exportée, elle conservera toutes les traductions que vous avez fournies.
Lorsqu’une solution est importée, les étiquettes pour les langues non disponibles dans le système cible sont ignorées et un avertissement est consigné.
Si les étiquettes pour la langue de base du système cible ne sont pas disponibles dans le package de solution, les étiquettes de la langue de base de la source sont utilisées à la place. Par exemple, si vous importez une solution contenant les étiquettes pour l’anglais et le français avec l’anglais comme langue de base mais que le système cible a le japonais et le français avec le japonais comme langue de base, les étiquettes anglaises sont utilisées au lieu des étiquettes japonaises. Les étiquettes des langues de base ne peuvent pas être null ou vides.
Exportation des traductions
Avant d’exporter des traductions, vous devez commencer par installer les modules linguistiques et regrouper toutes les langues que vous voulez localiser. Vous pouvez exporter les traductions dans l’application web ou en utilisant le message ExportTranslationRequest. Pour plus d’informations, voir Exportation d’une entité personnalisée et d’un texte de champ à convertir.
Traduction d’un texte
Lorsque vous ouvrez le fichier CrmTranslations.xml dans Office Excel, vous voyez les trois feuilles de calcul répertoriées dans le tableau suivant.
Feuille de calcul | Description |
---|---|
Informations | Affiche les informations sur l’organisation et la solution depuis lesquelles les étiquettes et chaînes ont été exportées. |
Chaînes d’affichage | Chaînes d’affichage représentant le texte de tous les messages associés à un composant métadonnées. Ce tableau contient des messages d’erreur et des chaînes qui sont utilisés pour les éléments de ruban système. |
Étiquettes localisées | Affiche le texte intégral des étiquettes de composant métadonnées. |
Vous pouvez envoyer ce fichier à un linguiste, à une agence de traduction ou à une société de localisation. Ils doivent fournir des chaînes localisées pour les cellules vides.
Note
Pour les entités personnalisées, certaines étiquettes courantes sont partagées avec les entités système, comme Créé le ou Créé par. Comme vous avez déjà installé et mis en service les langues, si vous exportez des langues pour la solution par défaut, vous pouvez probablement mettre en correspondance certaines étiquettes de vos entités personnalisées avec le texte traduit pour les étiquettes identiques utilisées par d’autres entités. Cela peut réduire les coûts de localisation et améliorer la cohérence.
Une fois que le texte présent dans les feuilles de calcul a été localisé, ajoutez les fichiers CrmTranslations.xml et [Content_Types].xml à un même fichier .zip compressé. Vous pouvez maintenant importer ce fichier.
Si vous préférez utiliser les fichiers exportés par programme comme document XML, consultez Support des normes Word, Excel et PowerPoint pour plus d’informations sur les schémas utilisés par ces fichiers.
Importation d’un texte traduit
Important
Vous pouvez uniquement réimporter du texte traduit dans la même organisation d’où il a été exporté.
Après avoir exporté le texte d’entité ou d’attribut personnalisé et l’avoir fait traduire, vous pouvez importer les chaînes de texte traduites dans l’application web en utilisant le message ImportTranslationRequest. Le fichier à importer doit être un dossier compressé contenant le fichier CrmTranslations.xml et le fichier [Content_Types].xml à la racine. Pour plus d’informations, consultez Importation d’un texte de champ et d’entité traduit.
Après avoir importé les traductions terminées, le texte personnalisé s’affiche pour les utilisateurs qui travaillent dans les langues dans lesquelles le texte a été traduit.
Note
Dataverse ne peut pas importer du texte traduit dépassant 500 caractères. Si un des éléments de votre fichier de traductions dépasse 500 caractères, le processus d’importation échoue. Dans ce cas, vérifiez la ligne du fichier à l’origine de l’échec, réduisez le nombre de caractères et réessayez.
La personnalisation n’est possible que dans la langue de base. C’est pourquoi vous serez peut-être amené à travailler dans Dataverse avec la langue de base définie comme préférence. Pour vérifier que le texte traduit s’affiche, vous devez changer de langue dans l’interface utilisateur Dataverse. Si vous souhaitez effectuer des personnalisations supplémentaires, vous devez revenir dans la langue de base.
Localisation en chaînes de la langue de base
Certains composants de solution ne prennent pas en charge plusieurs langues. Ces composants comprennent les noms ou le texte qui ne peuvent avoir de sens que dans une langue spécifique. Si vous créez une solution pour une langue spécifique, définissez ces composants de solution pour la langue de base prévue pour l’organisation.
Si vous devez prendre en charge plusieurs langues, une tactique consiste à inclure la localisation dans les chaînes de la langue de base. Par exemple, si vous avez un rôle de connexion nommé « Ami » et que vous devez prendre en charge l’anglais, l’espagnol et l’allemand, vous pouvez utiliser le texte « Ami (Amigo/Freund) » comme nom du rôle de connexion. En raison des problèmes de longueur de texte, il existe des limitations quant au nombre de langues qui peuvent être prises en charge avec cette tactique.
Certains composants de solution appartenant à ce groupe sont uniquement visibles par les administrateurs. Comme la personnalisation du système ne peut être effectuée que dans la langue de base de l’organisation, il n’est pas nécessaire de fournir plusieurs versions linguistiques. Les composants Rôles de sécurité et Profil de sécurité de champ appartiennent à ce groupe.
Les modèles de contrat fournissent une description d’un type de contrat de service. Ils nécessitent du texte pour les champs Nom et Abréviation. Vous devez penser à utiliser des noms et abréviations uniques et appropriés pour tous les utilisateurs de l’organisation.
Les rôles de connexion reposent sur une personne sélectionnant des catégories et des noms de rôles de connexion descriptifs. Étant donné que ceux-ci peuvent être relativement courts, il est recommandé d’inclure la localisation dans les chaînes en langue de base.
Les processus (workflows) qui sont initiés pour des événements peuvent bien fonctionner tant qu’ils n’ont pas besoin de mettre à jour des enregistrements avec du texte à localiser. Il est possible d’utiliser un assembly de workflow afin que la logique qui peut s’appliquer au texte localisé puisse utiliser la même stratégie que les assemblys de plug-in (Utiliser des ressources web XML comme ressources linguistiques).
Les flux de travail à la demande nécessitent un nom pour que les utilisateurs puissent les Sélectionner. En plus d’inclure la traduction dans le nom du workflow à la demande, une autre tactique consiste à créer plusieurs workflows avec des noms localisés qui appellent tous le même processus enfant. Toutefois, tous les utilisateurs verront la liste complète des workflows à la demande, pas simplement ceux de leur langue d’interface par défaut de l’utilisateur.
Localisation facultative
Les composants de la solution de traitement des messages SDK étape and Service point de terminaison n’exposent pas le texte localisable aux utilisateurs. S’il est important que ces composants aient des noms et des descriptions qui correspondent à la langue de base de l’organisation, vous pouvez créer et exporter une solution gérée avec des noms et des descriptions dans cette langue.
Composant distinct pour chaque langue
Les composants de solution suivants peuvent contenir chacun une quantité considérable de texte à localiser :
Modèles d’article
Modèles de courr. électr.
Modèles de publipostage
Rapports
Boîtes de dialogue
Pour ces types de composants de solution, la tactique recommandée consiste à créer des composants distincts pour chaque langue. Cela signifie que vous créez généralement une solution gérée de base qui contient vos composants de solution principales puis une solution gérée distincte qui contient ces composants de solution pour chaque langue. Une fois que les clients ont installé la solution de base, ils peuvent installer les solutions gérées pour les langues qu’ils ont mis en service pour l’organisation.
Contrairement à Processus (workflows), vous pouvez créer des Boîtes de dialogue qui reflètent les paramètres existants de préférence de la langue de l’utilisateur et qui n’affichent les boîtes de dialogue qu’aux utilisateurs de cette langue.
Création d’une boîte de dialogue localisée
Installez le module linguistique approprié et mettez la langue en service.
Pour plus d’informations, voir Instructions d’installation du module linguistique.
Modifiez vos options personnelles pour spécifier la Langue de l’interface utilisateur pour la langue souhaitée pour la boîte de dialogue.
Accédez à Paramètres et, dans le groupe Centre de traitement, sélectionnez Processus.
Cliquez sur Nouveau et créez la boîte de dialogue dans la langue que vous avez spécifiée.
Après avoir créé la boîte de dialogue, modifiez vos options personnelles pour spécifier la langue de base de l’organisation.
Lorsque vous utilisez la langue de base de l’organisation, vous pouvez accéder à la zone Solutions dans Paramètres et ajouter la boîte de dialogue localisée dans le cadre d’une solution.
La boîte de dialogue créée dans l’autre langue ne sera affichée qu’aux utilisateurs qui affichent Dataverse avec cette langue.
Utiliser des ressources web XML comme ressources linguistiques
Les composants de solution d’assembly de plug-in peuvent envoyer des messages à un utilisateur final en levant une exception InvalidPluginExecutionException ainsi qu’en créant et en mettant à jour des enregistrements. Contrairement aux ressources web Silverlight, les plug-ins ne peuvent pas utiliser de fichiers de ressources.
Lorsqu’un plug-in nécessite du texte localisé, vous pouvez utiliser une ressource web XML pour stocker les chaînes localisées pour permettre au plug-in d’y accéder si nécessaire. La structure du fichier XML est votre option, mais vous pouvez suivre la structure utilisée par les fichiers de ressource ASP.NET (.resx) pour créer des ressources web XML distinctes pour chaque langue. Par exemple, la ressource suivante est une ressource web XML nommée localizedString.en_US qui suit le modèle utilisé par les fichiers . 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>
Le code suivant montre comment un message localisé peut être retransmis dans un plug-in pour afficher un message à un utilisateur. Il concerne la phase de prévalidation d’un événement Delete
pour l’entité Account
:
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));
}
}