Dmytro Duk
May 11, 2011
visibility 7297
star star star star star
(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.

error Please login to comment.
Latest blogs
Add more scheduled job settings from the Optimizely CMS 12 admin UI -- with OptiScheduledJob.ExtraParameters

  Optimizely (EPiServer) CMS 12 ships a great scheduled-jobs framework, but it has one frustrating gap: a job has nowhere to store its own...

Binh Nguyen Thi | Jun 25, 2026

Automated Search & Navigation to Graph Migration with Claude Code

A Claude Code plugin that scans your S&N codebase, applies Graph SDK transformations, and validates the result. Install once, run one command. CMS ...

Connor Fortin | Jun 24, 2026

Migrating from Find to Graph: Lessons Learned from a Real CMS 13 Project

While migrating a search solution from Optimizely Search & Navigation (Find) to Optimizely Graph in CMS 13, I encountered several issues that were...

Binh Nguyen Thi | Jun 24, 2026

Optimizely: Upgrade Opti-ID and .NET 10 in CMS 12

Many Optimizely customers are planning their roadmap around a future migration to Optimizely CMS 13. As a result, upgrades such as Opti ID adoption...

Madhu | Jun 23, 2026 |