Kniganapolke Tech Blog

How to create locale selector in Orchard CMS

Posted on: August 5, 2016

Hello guys

I’m building a web site with Orchard 1.9.2. There is Localization module available that enables you to add Localization Part to any content type to make it localizable.

As for user locale selection Orchard renders a link to available translations for each applicable content item (that is localizable and has translations). But if you want a global locale selector that would change all translated content including menus this locale selector doesn’t do the job.

So, I managed to create a widget that renders links to available translations of the whole page. The code takes URL of the page and tries to retrieve content item that is bound to it. And then builds links to this content item’s translations.

The nice part is that menu items that point to localizable content items (pages, projection etc.) are localized automatically. If such a menu item does not have the current translation it is excluded from menu.

Let me admit that my web site is quite simple and I’ve assembled this solution just today. So I’m sure it isn’t perfect for some specific scenarios.

Here are the steps I’ve accomplished:

1. Create a new content type (creatable, listable) with just Common and Widget content parts. Let it be LocaleSelector, for example.
2. Add Widget stereotype to it.
3. Add a template for this content type to your theme (for ex, Widget-LocaleSelector.cshtml).
4. Add references to Orchard.Alias and Orchard.Localization projects to your theme’s project.
5. Add the following code to the template:

@using System.Globalization 
@using Orchard.Alias 
@using Orchard.ContentManagement 
@using Orchard.Localization.Services 
@using Orchard.Localization.Models

 var localizationService = WorkContext.Resolve<ILocalizationService>(); 
 var aliasService = WorkContext.Resolve<IAliasService>(); 
 var contentManager = WorkContext.Resolve<IContentManager>(); 
 var cultureManager = WorkContext.Resolve<ICultureManager>();

 string path = Request.Url.PathAndQuery; 
 IContent content = GetByPath(path, aliasService, contentManager); 

@if (content != null)
  IEnumerable<LocalizationPart> localizations = localizationService.GetLocalizations(content);

@foreach (var l in localizations) { var localized = content.As(); string culture = l.Culture.Culture; if(localized.MasterContentItem != null) { content = localized.MasterContentItem.ContentItem; } var localizedContentItem = localizationService.GetLocalizedContentItem(content, culture).ContentItem; var cultureInfo = CultureInfo.GetCultureInfo(l.Culture.Culture);   }
} @functions{ public IContent GetByPath(string path, IAliasService aliasService, IContentManager contentManager) { if (path == null || aliasService == null || contentManager == null) { return null; } string aliasPath = HttpUtility.UrlDecode(path); aliasPath = aliasPath.TrimStart(new char[] { '/' }); var contentRouting = aliasService.Get(aliasPath); if (contentRouting != null) { object id; if (contentRouting.TryGetValue("id", out id)) { int contentId; if (int.TryParse(id as string, out contentId)) { return contentManager.Get(contentId); } } } return null; } }

After that you’ll be able to add the widget easily through Orchard admin interface in any zone (the widget will be available in the list). Also you can modify the HTML and add styles to make the locale selector look as you need.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s


  • None
  • kniganapolke: Happy to hear that )))
  • Khuong: You save my life!!! I have been dealing with this for a whole week! When I was about to commit a suicide, you showed up and saved my life!!! Tha
  • kniganapolke: Thanks, your code seems to be more generic.


%d bloggers like this: