1-1 Multilingual Websites in Umbraco
Heads Up!
This article is several years old now, and much has happened since then, so please keep that in mind while reading it.
What are 1-1 multilingual websites?
Quite simply, it's when you have the exact same pages in every language. A CMS like Sitecore would handle it with the ability to version any given item in several languages by clicking a flag in the backend, and then use culturecodes to fetch the right language.
How to handle it in Umbraco's backoffice
First off, we're giving the user several tabs in any document template representing the different languages. Then what we do, is to postfix all our fields with the culture code when creating them in the document type. See screenshot for my example.
When postfixing, we have the opportunity to fetch them from our macros (I'll be doing it in XSLT).
If every page doesn't have all languages, you could make a boolean field, that "activates" the language edition. This will typically help you in your navigation macros, so the pages unavailable in the current language actually won't show in navigation.
Detecting current language from XSLT
So, for some odd reason there's no extension method for fetching the current culture in default Umbraco (I know there are packages around doing that). But there's a very simple hack you could do, and I quite like it.
You simply create a dictionary item, I call it currentCulture, and then fill your field postfix texts in each language (da and en).
Helper XSLTs
I really like to make and use default helper XSLTs (thanks a bunch @greystate for the inspiration). This is basically a seperate XSLT file I include in pages where needed, containing some templates and some variables I use sitewise. In this case I use this: _MultiLingualHelper.xslt. The methods I'll be storing in this file are:
- Language detection (variable named $lang)
- Complete postfix for fields ($lang_postfix)
- Fallback language
- Some default settings to generate some content.
Fetching the right version of the field
Now for fetching the right version of a field, I'll use some XPath.
<xsl:value-of select="*[name() = concat('header', $lang_postfix)]" />
Explained shortly, the concat part adds _da or _en to the fieldname, and we then fetch the field that has that name. Easy peasy. See NavigationExample.xslt in line 24 for further inspiration.
Setting up hostnames
Now for the system to detect which language/culture the user wants, we use sub-domains, e.g.: www.domain.com and da.domain.com. Simply use native umbraco features to set up hostheaders per domain.
Is the sub-domain or extension domain necessary? Yeah, I do believe it is, since you have to be very careful not to make duplicate content, as Google won't like that. Of course there is the opportunity to do it all without domain changes, but I like the clear and obvious solution it provides.
Navigation
Navigations in a multilingual setup is basically not that different from default navigation snippets. The main difference is in this line:
<xsl:apply-templates
select="$currentPage/
ancestor-or-self::Frontpage/
*[*[name() = concat('activateLanguage', $lang_postfix)] = 1]"
mode="page"
/>
It's from NavigationExample.xslt line 16. What it basically does, is use XPath to fetch only pages that are activated through the checkbox.
Changing language
This is one of the more difficult things. What we need to consider is, if the actual page I'm viewing is available in another wanted language, link to the same page, but with the other language's domain. Otherwise link to the other language's frontpage.
See _MultiLingualHelper.xslt for templates doing this.
That's how I do 1-1 multilingual websites in Umbraco. I believe there could be more to it, if you have loads of special features. I recommend looking into differencing date- and currencyformats per language as well, but it won't be covered here.
Any questions, ideas and comments, please contact me via my twitter handle @madjor5. If you want to see what else I'm up to, take a look at illumi.dk for further information.
Mads Jørgensen
Mads is on Twitter as @madjor5