Язык лукапа
Если у вас используется два языка в системе, то Вы можете столкнутся с требованием пользователей, отображать в лукапах основной атрибут на языке текущего пользователя. В особенности это касается справочников. Но стандартный функционал этого не позволяет. В общем пичалька… 🙂
Поэтому нарисуем плагин, который в зависимости от языковых настроек текущего пользователя будет выводить в лукапах «основной» атрибут на соответствующем языке.
Суть маневра заключается в том, чтобы добавить на нужный объект столько дополнительных полей, сколько языков у Вас установлено – по одному на каждый язык. И при их заполнении конкатенировать всех их в стандартный основной атрибут. А когда происходит Retrieve или Retrieve-Multiple, в зависимости от текущих языковых настроек, распарсивать его и оставлять только значение на нужном языке.
В качестве примера рассмотрим как это работает для Продуктов и Продуктов для возможной сделки.
Подготовка:
- Добавьте атрибут «new_name_en» «new_name_ru» на объект Продукта (и у Вас должны быть установлены оба эти языка);
- При создании или обновлении Продукта, каждый из языков конкатенируется в поле Название. Это сделано для того чтобы не выполнять дополнительные запросы, а все необходимые значения были доступны сразу. Каждый раз при запросе Названия мы будем парсить его, вычленять название на нужном языке и перезаписываем его в Называние. Поэтому увеличьте длину Названия до 4000 символов.
Итак:
- Создайте плагин с таким кодом:
using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; namespace MultiLanguage { public class PackNameTranslations : IPlugin { private readonly string[] languages = new string[] { "ru", "en" }; // Возможные языки static public int[] locales = new int[] { 1049, 1033 }; // LCID'ы каждого из языков // При создании или обновлении Продукта конкатенируем названия на разных языках в поле name public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); Entity target = context.InputParameters["Target"] as Entity; Entity preImage = (context.PreEntityImages != null && context.PreEntityImages.Contains("PreImage")) ? context.PreEntityImages["PreImage"] : null; string[] names = new string[languages.Length]; for (int i = 0; i < languages.Length; i++) names[i] = Common.GetAttributeValue("new_name_" + languages[i], preImage, target); target["name"] = string.Join(",", names); } } public class UnpackNameOnRetrieve : IPlugin { // Подставляем нужное название при возвращении продукта public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); Entity target = (Entity)context.OutputParameters["BusinessEntity"]; // Разделяем языки string[] labels = ((string)target["name"]).Split(','); // Возвращаем индек нужного языка int labelIndex = Common.LanguageIndex(context, serviceProvider); // Перезаписываем поле Навзание target["name"] = labels[labelIndex]; } } public class UnpackNameOnRetrieveMultiple : IPlugin { // Подставляем нужное название при возвращении множества Продуктов public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); EntityCollection collection = (EntityCollection)context.OutputParameters["BusinessEntityCollection"]; // Возвращаем индек нужного языка int labelIndex = Common.LanguageIndex(context, serviceProvider); foreach (Entity e in collection.Entities) if (e.Attributes.ContainsKey("name")) { // Разделяем языки string[] labels = ((string)e["name"]).Split(','); // Перезаписываем поле Навзание e["name"] = labels[labelIndex]; } } } public class UnpackNameOnRetrieveMultipleRelated : IPlugin { // Подставляем нужное название в столбец Название при отображении связанных Продуктой для возможных сделок public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); EntityCollection collection = (EntityCollection)context.OutputParameters["BusinessEntityCollection"]; // Возвращаем индек нужного языка int labelIndex = Common.LanguageIndex(context, serviceProvider); foreach (Entity e in collection.Entities) if (e.Attributes.ContainsKey("productid")) { // Разделяем языки string[] labels = (((EntityReference)e["productid"]).Name).Split(','); // Перезаписываем Навзание ((EntityReference)e["productid"]).Name = labels[labelIndex]; } } } public class UnpackNameOnRetrieveRelated : IPlugin { // Unpack the product lookup name when Opportunity Products are retrieved via lookup searches or advanced find public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); Entity target = (Entity)context.OutputParameters["BusinessEntity"]; if (target.Attributes.ContainsKey("productid")) { // Разделяем языки string[] labels = (((EntityReference)target["productid"]).Name).Split(','); // Возвращаем индек нужного языка int labelIndex = Common.LanguageIndex(context, serviceProvider); // Подменяем Название ((EntityReference)target["productid"]).Name = labels[labelIndex]; } } } public class Common { // Разбиваем название на состовляющие и возвращаем на нужно языке public static int LanguageIndex(IPluginExecutionContext context, IServiceProvider serviceProvider) { IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); // Получаем язык текущего пользователя int userLanguageId = 0; // ... либо из контекста (если есть) if (context.SharedVariables.ContainsKey("UserLocaleId")) { userLanguageId = (int)context.SharedVariables["UserLocaleId"]; } // ... либо из личных настроек пользователя else { Entity userSettings = service.Retrieve("usersettings", context.InitiatingUserId, new ColumnSet("uilanguageid")); userLanguageId = (int)userSettings.Attributes["uilanguageid"]; } // Определяем порядковый номер языка из массива и возвращаем его return Array.IndexOf(PackNameTranslations.locales, userLanguageId); } public static string GetAttributeValue(string attributeName, Entity preImage, Entity targetImage) { if (targetImage.Contains(attributeName)) { return (string)targetImage[attributeName]; } else if (preImage != null) return (string)preImage[attributeName]; else return ""; } } }
Тут у нас несколько функций. Пять полезных и две вспомогательные. Полезные регистрируются на разные событий системы и на разные объекты (в которых так или иначе задействован Продукт) и выполняют парсинг. А вспомогательные: одна определяет язык текущего пользователя, а вторая возвращает значений из заполенного Entity (таргета или пре-снимка);
- Подпишите сборку и подключите к проекту «обычные» библиотеки;
- Регистрируем плагин:
- PackNameTranslations:
- Событие: Create, Update
- Стадия: Pre
- Объект: product
- UnpackNameOnRetrieve
- Событие: Retrieve
- Стадия: Post
- Объект: product
- UnpackNameOnRetrieveMultiple
- Событие: RetrieveMultiple
- Стадия: Post
- Объект: product
- UnpackNameOnRetrieveRelated
- Событие: Retrieve
- Стадия: Post
- Объект: opportunityproduct
- UnpackNameOnRetrieveMultipleRelated
- Событие: RetrieveMultiple
- Стадия: Post
- Объект: opportunityproduct
- PackNameTranslations:
Готово.
По аналогии можете зарегистрировать UnpackNameOnRetrieveRelated и UnpackNameOnRetrieveMultipleRelated для Предложений, Заказов и Прайс листов.