en en en en en en en en en en en pa fr en en en en en en en en es en en en en fi en en en en en en en en en en en en en es en pa en en es en en ml en en en fr en en en en en en en en en en en en en en en en en en en en en en de en en en en en en en en es en en en pt en sv fr fr en en en en en en pa fr en en en en en en en de es en
When business rules are used in many different locales (countries in which different languages are spoken), then it makes sense to model and designs them in a way that multilingual concepts apply, to the following topics:
Options (option for values in the glossary)
Let’s consider the following simple business rules:
If Accounting Concept is Payable then write Account concept is cash
As it is highlighted, the two parts of the rule must support multilingual.
Let’s assume we want to model this rule in two languages – English and Spanish.
Let’s model this rule in a decision table that has an input parameter named ac:
In XML this will be modeled as follows:
Payable   Account concept is cash
Let’s model this rule in a Decision Table that has an input parameter named ac:
In XML, this will be modeled as follows:
Pagadero   Concepto de cuentas es dinero en efectivo
In both rules, in the condition column:
are both referring to the same thing, but in different languages. In resolving the values on evaluation, all translations (e.g., English, Spanish, German, etc.) must be resolved against the same reference value. This reference value can be either a key (e.g., code, id, number, etc.) or a default main locale (e.g., in English, which is Payable).
Let’s say we are going to assume 1 is an identifier or code we want to be resolved for all the translations of Payable.
const string payableValue = "1"; var termsTranslation = new NameValueCollection { {"Payable", payableValue}, {"Pagadero", payableValue} };
As you can see, at this stage all of the translations of the Payable term are registered against payableValue.
When the engine (i.e. RuntimeEngine) is created, simply use the Entries property and add these translations:
foreach (var term in termsTranslation.AllKeys) engine.Entries.Add(term, string.Format("'{0}'", termsTranslation[term]), false);
Notification is smart and will simply pick the correct message based on the current Thread’s UI Culture. Therefore, all of the messages must be registered for the target culture:
var msg1_spanish = new Dictionary  { { "MSG_1", "Concepto de cuentas es dinero en efectivo" } }; var msg1_english = new Dictionary  { { "MSG_1", "Account concept is cash" } }; engine.OnRunning = (e) => { e.ExecutorSetup.MultilingualMessages.Register(msg1_spanish, CultureInfo.GetCultureInfo("es-ES")); e.ExecutorSetup.MultilingualMessages.Register(msg1_english, CultureInfo.GetCultureInfo("en-US")); };
Please note that in this example, MSG_1 is the key to different translations of the message corresponding to the business rule. Make sure in your decision table you set useMessageId, or if you use FlexRule Designer then you need to set it as an Action of the Decision Table:
In the final Decision Table, we do not add a direct message, instead, we will be using a message code or id. Now for the values, all the translations of the term (i.e., Payable) will be accepted.
Putting it all together
public void test_multilingual_value_and_message() { const string dt = @"                      Payable   MSG_1        "; var engine = RuntimeEngine.FromXml(Encoding.UTF8.GetBytes(dt)); // Register all terms' value translations const string payableValue = "1"; var termsTranslation = new NameValueCollection { {"Payable", payableValue}, {"Pagadero", payableValue} }; foreach (var term in termsTranslation.AllKeys) engine.Entries.Add(term, string.Format("'{0}'", termsTranslation[term]), false); // Register notifications messages for different culture: // load messageId and translation for Spanish var msg1_spanish = new Dictionary  { { "MSG_1", "Concepto de cuentas es dinero en efectivo" } }; engine.RegisterMultilingualMessage(msg1_spanish, CultureInfo.GetCultureInfo("es-ES")); // load messageId and translation for English var msg1_english = new Dictionary  { { "MSG_1", "Account concept is cash" } }; engine.RegisterMultilingualMessage(msg1_english, CultureInfo.GetCultureInfo("en-US")); System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US"); var result = engine.Run(termsTranslation["Payable"]); Assert.AreEqual(msg1_english["MSG_1"], result.Notifications.Default.Notices.First().Message); result = engine.Run(termsTranslation["Pagadero"]); Assert.AreEqual(msg1_english["MSG_1"], result.Notifications.Default.Notices.First().Message); System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es-ES"); result = engine.Run(termsTranslation["Pagadero"]); Assert.AreEqual(msg1_spanish["MSG_1"], result.Notifications.Default.Notices.First().Message); result = engine.Run(termsTranslation["Payable"]); Assert.AreEqual(msg1_spanish["MSG_1"], result.Notifications.Default.Notices.First().Message); }
A business glossary is a dictionary of the set of your business terminologies, definitions, synonyms, and translations. With the use of the business glossary, the rule integration, packaging, deployment, and integration of multilingual values are streamlined.
Let’s assume we have the following Decision Table and glossary defined and we load it as a ruleset:
private static IRuleSet GetAccountingRuleSet() { var mc = new ModelContainer(); const string dt = @"                            Payable   MSG_1        "; LoadAdapterUtility.FillNavigableSource(mc, Encoding.UTF8.GetBytes(dt)); const string gl = @"           "; LoadAdapterUtility.FillNavigableSource(mc, Encoding.UTF8.GetBytes(gl)); var rs = RuleSet.HierarchicalRuleSet(); rs.AddModel("", mc); return rs; }
The Decision Table is the same as we discussed earlier, but in addition, it has a reference to a defined glossary.
When your application maintains a business glossary outside of the rule definition, this approach allows you to load the business glossary from any external data source and inject it during business rule load and execution.
var rs = GetAccountingRuleSet(); const string rsUri = "ruleset:///cash decision table"; // load glossary from ruleset var glossary = Glossary.Load(rs.SelectFirst(rsUri), rs); // create engine instance and provide the pre-loaded glossary var engine = RuntimeEngine.FromRuleSet(rs, rsUri, glossary); // Register all terms' value translations engine.Entries.ImportFromGlossary(glossary);
In this approach, the engine loads the glossary from the ruleset that is referenced in the Decision Table automatically.
var rs = GetAccountingRuleSet(); const string rsUri = "ruleset:///cash decision table"; // create engine instance and let the embedded glossary load and be utilised var engine = RuntimeEngine.FromRuleSet(rs, rsUri); // Get the glossary from the loaded ruleset var glossary = Glossary.Load(rs.SelectFirst(rsUri), rs); // Register all terms' value translations engine.Entries.ImportFromGlossary(glossary);
Multilingual using Business Glossary Sample
The example below shows how to use the business glossary to make values multilingual in a sample Decision Table:
[TestMethod] public void test_multilingual_load_glossary_onload() { var rs = GetAccountingRuleSet(); const string rsUri = "ruleset:///cash decision table"; var engine = RuntimeEngine.FromRuleSet(rs, rsUri); var glossary = Glossary.Load(rs.SelectFirst(rsUri), rs); // Register all terms' value translations engine.Entries.ImportFromGlossary(glossary); // Register notifications var msg1_spanish = new Dictionary  { { "MSG_1", "Concepto de cuentas es dinero en efectivo" } }; engine.RegisterMultilingualMessage(msg1_spanish, CultureInfo.GetCultureInfo("es-ES")); var msg1_english = new Dictionary  { { "MSG_1", "Account concept is cash" } }; engine.RegisterMultilingualMessage(msg1_english, CultureInfo.GetCultureInfo("en-US")); System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US"); var result = engine.Run(glossary.Lookup("Payable")); Assert.AreEqual(msg1_english["MSG_1"], result.Notifications.Default.Notices.First().Message); result = engine.Run(glossary.Lookup("Pagadero")); Assert.AreEqual(msg1_english["MSG_1"], result.Notifications.Default.Notices.First().Message); System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es-ES"); result = engine.Run(glossary.Lookup("Pagadero")); Assert.AreEqual(msg1_spanish["MSG_1"], result.Notifications.Default.Notices.First().Message); result = engine.Run(glossary.Lookup("Payable")); Assert.AreEqual(msg1_spanish["MSG_1"], result.Notifications.Default.Notices.First().Message); }