Crie soluções que oferecem suporte a vários idiomas
Publicado: novembro de 2016
Aplicável a: Dynamics CRM 2015
O Atualização do Microsoft Dynamics CRM 2015 e Microsoft Dynamics CRM Online 2015 oferece suporte a vários idiomas. Se desejar que a solução seja instalada para organizações que incluam diferentes idiomas base ou que tenham vários idiomas provisionados, leve isto em conta ao planejar a sua solução. A tabela a seguir lista as táticas para uso em conjunto com os componentes da solução que podem ser incluídos em uma solução que oferece suporte a vários idiomas.
Tática |
Tipo de componente da solução |
---|---|
Opção do desenvolvedor |
Recursos da Web |
Rótulos inseridos |
Navegação do aplicativo (SiteMap) |
Importar e exportar traduções |
Atributos |
Localização nas cadeias de caracteres do idioma base |
Modelos de contrato |
Localização não necessária |
Etapas de processamento de mensagens do SDK |
Componente separado para cada idioma |
Modelos de artigo |
Usar os recursos da Web em XML como recursos de idiomas |
Assemblies de Plug-in |
As seções a seguir fornecem detalhes adicionais de cada tática.
Opção do desenvolvedor
Os recursos da Web têm um atributo LanguageCode, que pode ser definido na interface do usuário; porém, esse valor não é usado pelo aplicativo. Como os recursos da Web são endereçáveis pela URL, geralmente, você acessa um recurso da Web pelo nome, em vez de consultar os recursos da Web disponíveis com LanguageCode como um critério. Portanto, LanguageCode tem um valor limitado. O cenário mais comum é que você precisará detectar o idioma base adequado com base no contexto no qual o recurso da Web é exibido. Para os recursos da Web, o objeto de contexto fornece acesso às funções d7d0b052-abca-4f81-9b86-0b9dc5e62a66#BKMK_getOrgLcid e d7d0b052-abca-4f81-9b86-0b9dc5e62a66#BKMK_getUserLcid. Essas duas funções retornam um valor inteiro que corresponde aos valores do ID de Localidade (LCID).Os valores de ID de localidade válidos podem ser encontrados em Gráfico de LCID (ID de localidade).
Para os recursos da Web que expõem o texto na interface do usuário, é possível usar qualquer método desejado para gerenciar a forma como o texto e o layout oferecerão suporte às preferências de idioma do usuário. A implementação específica depende do tipo de recurso da Web.
Recursos da Web em HTML
Uma das opções é criar recursos da Web localizados separados que podem variar de acordo com o nome aplicado. Por exemplo, você pode ter um recurso da Web chamado new_/my_solution/1033/content.htm com suporte para inglês e um chamado new_/my_solution/1041/content.htm com suporte para japonês. Para os idiomas que exigem a direção da direita para a esquerda, consulte Como exibir textos da direita para a esquerda usando marcas HTML para globalização.
Se desejar a possibilidade de definir de forma dinâmica o texto da interface do usuário com base no idioma de um usuário, é possível armazenar todos os valores da cadeia de caracteres localizados em um objeto definido por todo um arquivo de script do recurso da Web. Com base na preferência de idioma do usuário, é possível definir os elementos de texto da interface do usuário usando cadeias de caracteres armazenadas no objeto durante o carregamento da página. O seguinte código de exemplo do JavaScript mostra um método para definir cadeias de caracteres localizadas.
var userLcid = 1033;
var localizedStrings = {
ErrorMessage: {
_1033: "There was an error completing this action. Please try again.",
_1041: "このアクションを完了、エラーが発生しました。もう一度実行してください。",
_1031: "Es ist ein Fehler aufgetreten, der Abschluss dieser Aktion. Bitte versuchen Sie es erneut.",
_1036: "Il y avait une erreur complétant cette action. Veuillez essayer à nouveau.",
_1034: "Hubo un error al completar esta acción. Vuelva a intentarlo.",
_1049: "Произошла ошибка, выполнение этого действия. Пожалуйста, попробуйте снова."
},
Welcome: {
_1033: "Welcome",
_1041: "ようこそ",
_1031: "Willkommen",
_1036: "Bienvenue",
_1034: "Bienvenido",
_1049: "Добро пожаловать"
}
};
var LocalizedErrorMessage = localizedStrings.ErrorMessage["_" + userLcid];
var LocalizedWelcomeMessage = localizedStrings.Welcome["_" + userLcid];
Recursos da Web do Silverlight
Os aplicativos do Silverlight podem ser escritos para oferecer suporte aos recursos de idioma localizados.Para obter mais informações:Localizando aplicativos baseados no Silverlight.
A seguinte classe fornece acesso à preferência de idioma do usuário com base no contexto no qual o recurso da Web do Silverlight é apresentado. Esta classe tem suporte para inglês (Estados Unidos), árabe, alemão, hebraico e japonês. Ela precisa ser alterada para os idiomas específicos que têm suporte pelo recurso da Web do Silverlight.
public static class Localization
{
// The locale ID.
public static int LCID { get; set; }
// Create a dictionary of right-to-left language codes (Hebrew and Arabic).
private static Dictionary<int, bool> _rightToLeftLanguages =
new Dictionary<int, bool>
{
{ 1025, true },
{ 1037, true },
};
private static Dictionary<int, String> _lcidToCultureNameMap =
new Dictionary<int, String>
{
{ 1025, "ar-SA" },
{ 1031, "de-DE" },
{ 1033, "en-US" },
{ 1037, "he-IL" },
{ 1041, "ja-JP" }
};
public static void InitializeCulture()
{
// Get the user's LCID from the page's context to determine what language to
// display.
dynamic window = HtmlPage.Window;
//Get the user's language code from the context.
try
{
//If the containing window is a CRM form
LCID = Convert.ToInt32(window.Xrm.Page.context.getUserLcid());
// For testing, comment the line above and uncomment one of the lines below
//representing a user language.
//LCID = 1033; //English
//LCID = 1041; //Japanese
//LCID = 1031; //German
//LCID = 1037; //Hebrew - a right-to-left language.
//LCID = 1025; //Arabic - a right-to-left language.
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
{
try
{
//If the containing window is a CRM web resource with
//the WebResources/ClientGlobalContext.js.aspx page linked
LCID = Convert.ToInt32(window.GetGlobalContext().getUserLcid());
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
{
LCID = 1033; //Setting a default for design time when the context
//object is not present and one of the sample languages are not set.
}
}
// Sets the culture of the thread to the appropriate culture, based on what
// LCID was retrieved.
if (_lcidToCultureNameMap.ContainsKey(LCID))
{
var culture = new CultureInfo(_lcidToCultureNameMap[LCID]);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
}
public static FlowDirection GetFlowDirection()
{
if (_rightToLeftLanguages.ContainsKey(LCID))
{
return FlowDirection.RightToLeft;
}
return FlowDirection.LeftToRight;
}
}
Para os idiomas que exigem a direção da direita para a esquerda, consulte Propriedade FrameworkElement.FlowDirection.
Recursos da Web em XML
Embora os recursos da Web em XML não sejam geralmente exibidos aos usuários, eles podem ser úteis para armazenar cadeias de caracteres localizadas como recursos para outros componentes da solução, conforme descrito em Usar os recursos da Web em XML como recursos de idiomas.
Rótulos inseridos
Cada um dos componentes da solução que usa esta tática exige que todo o texto localizado esteja incluído no componente da solução.
Faixas de opções
Quando o pacote de idiomas é instalado, a faixa de opções do aplicativo exibe automaticamente o texto localizado para todo o texto padrão na faixa de opções. Os rótulos do sistema são definidos em um valor do atributo ResourceId, que serve apenas para uso interno. Ao adicionar seu próprio texto, use o elemento <LocLabels> (RibbonDiffXml) para fornecer o texto localizado nos idiomas para os quais você oferece suporte.Para obter mais informações:Usar rótulos localizados com faixas de opções
SiteMap
Quando o pacote de idiomas é instalado, o texto padrão da barra de navegação do aplicativo exibe automaticamente o texto localizado. Para substituir o texto padrão ou fornecer o seu próprio texto, use o elemento <Titles> (SiteMap). O elemento Titles deve conter um elemento <Title> (SiteMap), que contenha o texto localizado em todos os idiomas com suporte pela solução. Se um elemento Title não estiver disponível no idioma preferido do usuário, o título que corresponde ao idioma base da organização é exibido.
O elemento <SubArea> (SiteMap) permite transmitir a preferência de idioma do usuário com o parâmetro userlcid, para que o conteúdo que é o destino do atributo SubArea.Url possa saber a preferência de idioma do usuário e ajustar de acordo.Para obter mais informações:Transmitir parâmetros para uma URL usando o SiteMap
Importar e exportar traduções
Os rótulos localizáveis dos componentes da solução apresentados na tabela a seguir podem ser exportados para localização.
Entidades |
Atributos |
Relações |
Conjuntos de opções globais |
Mensagens de Entidade |
Formulários de entidade |
Exibições de entidade (SavedQuery) |
Gráficos |
Painéis |
Como traduzir rótulos e cadeias de exibição
Somente é possível realizar personalizações no aplicativo usando o idioma base. Portanto, quando desejar fornecer rótulos e cadeias de exibição localizados para essas personalizações, será necessário exportar o texto dos rótulos, para que eles possam ser localizados em todos os outros idiomas habilitados para a organização. Use as seguintes etapas:
Verifique se a organização para a qual você está trabalhando tem todos os pacotes multilíngues instalados e idiomas provisionados para os idiomas nos quais você deseja fornecer traduções.
Crie a solução e modifique os componentes.
Ao concluir o desenvolvimento da solução, use a funcionalidade “Exportar traduções”. Isso gera uma planilha do Microsoft Office Excel (CrmTranslations.xml) que contém todos os rótulos que precisam de tradução.
Na planilha, forneça as traduções correspondentes.
Importe as traduções de volta para a mesma organização do Microsoft Dynamics 365 usando a funcionalidade “Importar traduções” e publique suas alterações.
Na próxima vez em que a solução for exportada, ela levará todas as traduções fornecidas.
Quando uma solução é importada, os rótulos para os idiomas que não estão disponíveis no sistema de destino são descartados e um aviso é registrado.
Se os rótulos do idioma base do sistema de destino não forem fornecidos no pacote da solução, os rótulos do idioma base da origem serão usados em seu lugar. Por exemplo, se você importar uma solução que contenha rótulos em inglês e francês, com inglês como o idioma base, mas o sistema de destino tiver japonês e francês, com japonês como o idioma base, os rótulos em inglês serão usados em vez dos rótulos em japonês. Os rótulos dos idiomas base não podem ser nulos ou vazios.
Como exportar traduções
Antes de exportar traduções, é necessário instalar primeiro os pacotes de idiomas e provisionar todos os idiomas que você deseja localizar. É possível exportar as traduções no aplicativo Web ou usando a mensagem ExportTranslationRequest. Para obter mais informações, consulte Ajuda e Treinamento: Exportar entidade personalizada e texto de campo para tradução.
Como traduzir um texto
Ao abrir o arquivo CrmTranslations.xml no Excel, você verá as três planilhas listadas na tabela a seguir.
Planilha |
Descrição |
---|---|
Informações |
Exibe informações sobre a organização e a solução das quais os rótulos e as cadeias de caracteres foram exportados. |
Cadeias de Exibição |
Exibe as cadeias de caracteres que representam o texto das mensagens associadas a um componente dos metadados. Esta tabela inclui as mensagens de erro e as cadeias de caracteres usadas para os elementos da faixa de opções do sistema. |
Rótulos Localizados |
Exibe todo o texto de todos os rótulos do componentes dos metadados. |
É possível enviar este arquivo para um especialista em idiomas, agência de tradução ou empresa de localização. Eles precisarão fornecer cadeias de caracteres localizadas para as células vazias.
Observação
Para as entidades personalizadas, existem alguns rótulos comuns que são compartilhados com as entidades do sistema, como Data de criação ou Criado por. Como você já instalou e provisionou os idiomas, se você exportar os idiomas para a solução padrão, é possível fazer a correspondência de alguns rótulos das entidades personalizadas com o texto localizado dos rótulos idênticos usados por outras entidades. Isso pode reduzir o custo da localização e melhorar a consistência.
Após a localização do texto das planilhas, adicione os arquivos CrmTranslations.xml e [Content_Types].xml a um único arquivo .zip compactado. Agora você pode importar este arquivo.
Se preferir trabalhar com os arquivos exportados de forma programática, como um documento XML, consulte Esquemas de referência do XML do Office 2003 para obter informações sobre os esquemas usados por esses arquivos.
Como importar o texto traduzido
Importante
Só é possível importar o texto traduzido de volta para a mesma organização da qual ele foi exportado.
Depois de exportar e traduzir o texto personalizado da entidade ou do atributo, é possível importar as cadeias de texto traduzidas no aplicativo Web usando a mensagem ImportTranslationRequest. O arquivo importado deve ser um arquivo compactado que contenha os arquivos CrmTranslations.xml e [Content_Types].xml na raiz. Para obter mais informações, consulte Ajuda e Treinamento: Importar entidades e texto de campo traduzidos.
Após a importação das traduções concluídas, o texto personalizado será exibido para os usuários que trabalham nos idiomas para os quais você traduziu o texto.
Observação
O Microsoft Dynamics 365 não pode importar texto traduzido que possua mais de 500 caracteres. Se algum dos itens do arquivo de tradução ultrapassar 500 caracteres, haverá uma falha no processo de importação. Se isso acontecer, revise a linha do arquivo que causou a falha, reduza a quantidade de caracteres e tente importar novamente.
Como há suporte para a personalização somente no idioma base, talvez você esteja trabalhando no Microsoft Dynamics 365 com o idioma base definido como sua preferência de idioma. Para verificar se o texto traduzido é exibido, é necessário alterar sua preferência de idioma para a interface do usuário do Microsoft Dynamics 365. Para executar trabalho adicional de personalização, você deve retornar para o idioma base.
Localização nas cadeias de caracteres do idioma base
Alguns componentes da solução não oferecem suporte a vários idiomas. Esses componentes incluem nomes ou textos que podem ser significativos em um idioma específico. Se você criar uma solução em um idioma específico, defina estes componentes da solução para o idioma base da organização pretendida.
Se você precisar oferecer suporte a vários idiomas, uma das táticas é incluir a localização nas cadeias de caracteres do idioma base. Por exemplo, se você tiver a Função de conexão chamada “Amigo” e precisar oferecer suporte para inglês, espanhol e alemão, é possível usar o texto “Friend (Amigo/Freund)” como o nome da função de conexão. Devido a problemas de tamanho de texto, existem limitações no número de idiomas que podem ter suporte com esta tática.
Alguns componentes da solução deste grupo só serão visíveis pelos administradores. Como a personalização do sistema só pode ser feita no idioma base da organização, não é necessário fornecer versões com vários idiomas. Os componentes Direitos de acesso e Perfil de segurança de campo pertencem a este grupo.
Os Modelos de contrato fornecem uma descrição de um tipo de contrato de serviço. Eles exigem um texto para os campos Nome e Abreviação. Considere usar nomes e abreviações que sejam exclusivos e adequados para todos os usuários da organização.
As Funções de conexão dependem da seleção de categorias e nomes descritivos da Função de conexão por um usuário. Como eles podem ser relativamente curtos, é recomendável incluir a localização nas cadeias de caracteres do idioma base.
Os Processos (Fluxos de trabalho) que são iniciados para os eventos podem funcionar corretamente quando não precisam atualizar registros com textos que devem ser localizados. É possível usar um assembly de fluxos de trabalho, para que a lógica que pode ser aplicada ao texto localizado possa usar a mesma estratégia que os assemblies de plug-ins (Usar os recursos da Web em XML como recursos de idiomas).
Os Fluxos de trabalho sob demanda exigem um nome para que os usuários possam escolhê-los. Além de incluir a localização no nome do fluxo de trabalho sob demanda, outra tática é criar vários fluxos de trabalho com nomes localizados para cada um deles chamar o mesmo processo secundário. No entanto, todos os usuários visualizarão a lista completa de fluxos de trabalho sob demanda, não somente os que estiverem no idioma de interface preferido do usuário.
Localização não necessária
Os componentes da solução Etapa de processamento de mensagens do SDK e Ponto de extremidade de serviços não expõem o texto localizável aos usuários. Se for necessário que esses componentes tenham nomes e descrições que correspondam ao idioma base da organização, você poderá criar e exportar uma solução gerenciada com nomes e descrições nesse idioma.
Componente separado para cada idioma
Os seguintes componentes da solução podem incluir uma quantidade considerável de texto que precisará ser localizado:
Modelos de Artigo
Modelos de Email
Modelos de Mala Direta
Relatórios
Caixas de Diálogo
Para estes tipos de componentes da solução, a tática recomendável é criar componentes separados para cada idioma. Isso significa criar geralmente uma solução gerenciada base que contenha os componentes básicos da solução e, em seguida, uma solução gerenciada separada que contenha esses componentes da solução para cada idioma. Após a instalação da solução base, os clientes podem instalar as soluções gerenciadas para os idiomas provisionados para a organização.
Diferentemente dos Processos (Fluxos de trabalho), é possível criar Diálogos que refletirão as configurações atuais do idioma preferido do usuário e exibirão os diálogos somente aos usuários desse idioma.
Crie uma caixa de diálogo localizada
Instale o pacote de idiomas correto e provisione o idioma.
Para obter mais informações, consulte TechNet: Instruções de instalação do pacote de idiomas.
Altere suas opções pessoais para especificar o Idioma de interface do usuário do idioma desejado para o diálogo.
Acesse Configurações e no grupo Centro de Processos selecione Processos.
Clique em Novo e crie o diálogo no idioma especificado.
Depois de criar o diálogo, altere suas opções pessoais para especificar o idioma base da organização.
Ao usar o idioma base da organização, é possível acessar a área Soluções em Configurações e adicionar o diálogo localizado como parte de uma solução.
O diálogo criado em outro idioma é exibido somente para usuários que exibem o Microsoft Dynamics 365 nesse idioma.
Usar os recursos da Web em XML como recursos de idiomas
Os componentes da solução do assembly de plug-ins podem enviar mensagens para um usuário final acionando uma InvalidPluginExecutionException, além de criar e atualizar registros. Diferentemente dos recursos da Web do Silverlight, os plug-ins não podem usar os arquivos de recursos.
Quando um plug-in exigir o texto localizado, é possível usar um recurso da Web em XML para armazenar as cadeias de caracteres localizadas, para que o plug-in possa acessá-las quando necessário. A estrutura do XML é opcional, mas você pode desejar acompanhar a estrutura usada pelos arquivos de Recursos do ASP.NET (.resx) para criar recursos da Web em XML separados para cada idioma. Por exemplo, o código a seguir é um recurso da Web em XML chamado localizedString.en_US, que acompanha o padrão usado pelos arquivos. Arquivos 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>
O código a seguir mostra como uma mensagem localizada pode ser transmitida de volta em um plug-in para exibir uma mensagem para um usuário. Ele serve para o estágio de pré-validação de um evento Delete da entidade 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));
}
}
Confira Também
Embalar e distribuir extensões usando soluções
Introdução às soluções
Plano para desenvolvimento de solução
Rastreamento de dependência para componentes de solução
Criar, exportar ou importar uma solução não gerenciada
Criar, instalar e atualizar uma solução gerenciada
Desinstalar ou excluir uma solução
Entidades de solução
Traduzir valores de propriedade do produto
© 2017 Microsoft. Todos os direitos reservados. Direitos autorais