Take the community feedback survey now.

Dmytro Duk
May 11, 2011
  6704
(1 votes)

Localization workaround for EPiServer CMO 2.0

Globalization support is improved in CMO next version for EPiServer CMS 6 R2. Current users of CMO 2.0 can use the following workaround to solve localization issues in campaign and LPO test settings (see details here and here). After these changes you should be able to operate dates and numbers in your current culture format. This solution doesn’t require code recompilation. It is applicable to CMO 2.0 release version published on world.episerver.com.

Let’s consider the simple scenario, when Swedish language is set as default on your site,  for example in culture and uiCulture properties of globalization section in your web.config file.

Language files

You probably will see “[Missing text...]” warnings if language file is missing for your current culture, in our case Swedish.
CMO_EN.xml file contains all CMO string resources in English and can be found in lang directory of your site. Make a copy of this file, rename corresponding to your language. In our case it is Swedish, so rename new language file to CMO_SV.xml, open file and update name and id properties of language node:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
  <languages>
    <language name="Svenska" id="sv">
      ...
    </language>
</languages>

Now you should get English texts instead of [Missed text …] warnings. Optionally texts in language file can be translated to get CMO UI in required language.

The one change is required in node /cmo/lpo/settings/datepickerformat. Please define jQuery date format that corresponds to .NET short date format for your culture. Yes, tricky one :)
Example: Swedish short date string is something like 2011-05-25. Corresponding jQuery date format for Swedish culture is yy-mm-dd:

<datepickerformat>yy-mm-dd</datepickerformat>

Norwegian short date string 25.05.2011 corresponds to jQuery pattern dd.mm.yy and so on. Refer to jQuery documentation: http://docs.jquery.com/UI/Datepicker/formatDate

It is important to have language files both for current culture and current UI culture on your site, if they are different.

CMO UI controls

Go to directory where CMO UI is installed. Typically it is somewhere like this: C:\Program Files (x86)\EPiServer\CMS\6.0.530.0\Install\Modules\CMO2.0.0.0\CMO\

Need to update settings controls for LPO tests and campaigns to make sure that date picker is initialized with required date format.

LPO Test settings

Update arguments in Cmo.SetupDatePicker method calls inside $(document).ready function in LpoTestSettings.aspx file:

// On document load finished
$(document).ready(function () {
// … omitted code … 
 
    Cmo.SetupDatePicker($(Cmo.dateFrom), '<%= TranslateForScript("/cmo/lpo/settings/datecountryformat") %>', '<%= LanguageManager.Instance.TranslateForScript("/cmo/lpo/settings/datepickerformat", System.Threading.Thread.CurrentThread.CurrentCulture.IetfLanguageTag.Substring(0, 2)) %>', '-1d');
    Cmo.SetupDatePicker($(Cmo.dateTo), '<%= TranslateForScript("/cmo/lpo/settings/datecountryformat") %>', '<%= LanguageManager.Instance.TranslateForScript("/cmo/lpo/settings/datepickerformat", System.Threading.Thread.CurrentThread.CurrentCulture.IetfLanguageTag.Substring(0, 2)) %>', '-1d');
 
});

Campaign settings

Open file Units\CampaignGeneralSettings.ascx, update arguments in Cmo.SetupDatePicker method calls inside $(document).ready function:

// On document load finished
$(document).ready(function() {
    Cmo.SetupDatePicker($(Cmo.dateFrom), '<%= TranslateForScript("/cmo/lpo/settings/datecountryformat") %>', '<%= LanguageManager.Instance.TranslateForScript("/cmo/lpo/settings/datepickerformat", System.Threading.Thread.CurrentThread.CurrentCulture.IetfLanguageTag.Substring(0, 2)) %>', '0d');
    Cmo.SetupDatePicker($(Cmo.dateTo), '<%= TranslateForScript("/cmo/lpo/settings/datecountryformadt") %>', '<%= LanguageManager.Instance.TranslateForScript("/cmo/lpo/settings/datepickerformat", System.Threading.Thread.CurrentThread.CurrentCulture.IetfLanguageTag.Substring(0, 2)) %>', '0d');
}); 

KPI settings

Update \Units\Kpi\KpiSettingsEditor.ascx to make sure that decimal KPI values are processed correctly in the current culture format. Add CultureInvariantValues="true" option for KPI values validators:

<asp:CompareValidator runat="server" ValidationGroup="<%# ValidationGroupName %>" ID="CompareValidatorValue" Display="Dynamic" 
    ErrorMessage="<%$ Resources: EPiServer, cmo.campaignMonitor.settings.kpi.valueerrorcompare %>" Text="*" 
    Type="Double" ControlToValidate="TextBoxValue" ValueToCompare="0.01" Operator="GreaterThanEqual" CssClass="kpiEditorValidator"
    CultureInvariantValues="true" />
 
<asp:CompareValidator runat="server" ValidationGroup="<%# ValidationGroupName %>" ID="CompareValidatorExpectedValue" Display="Dynamic" 
    ErrorMessage="<%$ Resources: EPiServer, cmo.campaignMonitor.settings.kpi.expectedvalueerrorcompare %>" Text="*" 
    Type="Double" ControlToValidate="TextBoxExpectedValue" ControlToCompare="TextBoxValue" Operator="GreaterThanEqual" CssClass="kpiEditorValidator" 
    CultureInvariantValues="true" />

JavaScript code in this control must be updated to fix decimal separators in KPI data for current culture. Add following code just in the beginning of initializeKpiEditor function:

$(function () {
        
    var initializeKpiEditor = function ()
    {
        var kpiData = eval($("#<%= KpiData.ClientID %>").val());
        var defaultDecimalSeparator = ".";
        var currentDecimalSeparator = "<%= System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator %>";
        $.each(kpiData, function(index, kpi) { 
            kpi.value = kpi.value.toString().replace(defaultDecimalSeparator, currentDecimalSeparator);
            kpi.expectedValue = kpi.expectedValue.toString().replace(defaultDecimalSeparator, currentDecimalSeparator);
        });
 
        // … omitted code … 
    };
    // … omitted code …
}); 

Then find the following line below in initializeKpiEditor function:

kpiList: eval($("#<%= KpiData.ClientID %>").val()),

and change it to:

kpiList: kpiData,

Scripts

Go to Scripts directory inside CMO UI folder. It should be somewhere like: C:\Program Files (x86)\EPiServer\CMS\6.0.530.0\Install\Modules\CMO2.0.0.0\CMO\Scripts\
Open cmo.min.js file. This is compressed script, so be careful when updating it. Find string:

c.datepicker("option","duration",0);

and after this string insert following code:

if(b) c.datepicker('option',"dateFormat",b);

As a result updated Cmo.SetupDatePicker function in cmo.min.js must looks like this:

Cmo.SetupDatePicker=function(c,d,b,e){var a=c.val();c.datepicker({showOtherMonths:true,showOn:"button",buttonImageOnly:false});c.datepicker("option",$.extend({showMonthAfterYear:false},$.datepicker.regional[d]));c.datepicker("option","minDate",e);c.datepicker("option","duration",0);if(b) c.datepicker('option',"dateFormat",b);c.focus(function(){if(c.val()==""){c.datepicker("show")}});c.change(function(){EPi.PageLeaveCheck.SetPageChanged(true)});c.val(a);if(c.val()!=""){c.val(Cmo.getDateInSpecifiedFormat(c.val(),b))}if(c.attr("disabled")){c.datepicker("disable")}};

Open CmoScripts.js in the same folder Scripts and define date format option for datepicker inside Cmo.SetupDatePicker function, just after the line element.datepicker('option', 'duration', 0);

Cmo.SetupDatePicker = function (element, locale, format, mindate) {
// … omitted code …
    element.datepicker('option', 'duration', 0);
 
    if (format) {
        element.datepicker('option', "dateFormat", format);
    }
 
// … omitted code …
}

Clear cache

Since changes where made in JavaScript and control markup, previous versions of scripts and compiled controls can be cached by browser, proxy, IIS or in Temporary ASP.NET Files folder. Decide how to clear that caches depending on your environment.

Download

Replace your existing files or use it to compare and make changes manually, it’s up to you. Don’t forget to backup your files before update ;)

Feedback

Please let me know if this workaround doesn’t work for you, I will try to find the solution.

May 11, 2011

Comments

May 12, 2011 06:02 AM

Great work Dmytro!
Have tested the fix, worked like a charm!

May 12, 2011 02:50 PM

well its nice to have this workaround.thanks

May 15, 2011 08:47 PM

When can we expect an official patch or a new CMO version which fixes this?

Eivind Hodneland
Eivind Hodneland May 16, 2011 10:39 AM

Thanks. This worked well. However, I also had to apply an updated EpiServer.Cmo.Ui.Dll (v. 2.0.0.10) to not have the dates in LPO test and campaign listings display garbage.

Dmytro Duk
Dmytro Duk May 16, 2011 02:54 PM

I've tried to limit changes and make sure that user is able to enter values in required culture format.
We are working on CMO next version and hopefully it will be available soon.

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP - Introducing the beta of Opti Graph Extensions add-on

Introducing Opti Graph Extensions: Enhanced Search Management for Optimizely CMS I am excited to announce the beta release of **Opti Graph...

Graham Carr | Sep 15, 2025

Content modeling for beginners

  Introduction Learning by Doing – Optimizely Build Series  is a YouTube series where I am building  a fictional  website called  TasteTrail , food...

Ratish | Sep 14, 2025 |

A day in the life of an Optimizely OMVP - Enhancing Search Relevance with Optimizely Graph: Synonyms and Pinned Results

When building search experiences for modern digital platforms, relevance is everything. Users expect search to understand their intent, even when...

Graham Carr | Sep 14, 2025

Optimizely CMS and HTML validation message: Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.

When using the W3C Markup Validation Service, some annoying information messages pop up because Optimizely CMS adds the trailing slash to...

Tomas Hensrud Gulla | Sep 14, 2025 |

Turbocharge your strings - a case of display channels

When doing a routine performance test, during a CMS 12 upgrade, I was able to achieve 95% performance improvement. Let's look at SearchValues with ...

Stefan Holm Olsen | Sep 14, 2025 |

Opal Core Concepts

Before you dive into the code, it's crucial to understand the foundational ideas that make Opal tick. Core concepts are consistent across all its...

K Khan | Sep 13, 2025