<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Internationalisation Tips &#187; localisation</title>
	<atom:link href="http://internationalisationtips.com/tag/localisation/feed/" rel="self" type="application/rss+xml" />
	<link>http://internationalisationtips.com</link>
	<description>practical tips on building an international presence</description>
	<lastBuildDate>Wed, 24 Aug 2011 14:20:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Localising templates</title>
		<link>http://internationalisationtips.com/2011/08/24/localising-templates/</link>
		<comments>http://internationalisationtips.com/2011/08/24/localising-templates/#comments</comments>
		<pubDate>Wed, 24 Aug 2011 14:18:42 +0000</pubDate>
		<dc:creator>Isofarro</dc:creator>
				<category><![CDATA[Templates]]></category>
		<category><![CDATA[dimensions]]></category>
		<category><![CDATA[facets]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[localisation]]></category>
		<category><![CDATA[markup]]></category>
		<category><![CDATA[specialising]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://internationalisationtips.com/?p=77</guid>
		<description><![CDATA[Most of the time the HTML for a site doesn&#8217;t need to change as you localise an already internationalised site for a specific locale. Though your website needs the flexibility to specify locale-specific markup, so it is well worth having a system in place that allows that. And implemented properly, a mechanism for specialising templates [...]]]></description>
			<content:encoded><![CDATA[<p>Most of the time the HTML for a site doesn&#8217;t need to change as you localise an already internationalised site for a specific locale. Though your website needs the flexibility to specify locale-specific markup, so it is well worth having a system in place that allows that. And implemented properly, a mechanism for specialising templates based on multiple dimensions (locale being just one dimension) can be a very powerful tool.</p>
<h3>Componentising a site</h3>
<p>The typical structure for localising markup is to split a page into multiple templates and components. Typically these reusable templates are derived from the structure of your website, but essentially, any repeating patterns of markup should have it&#8217;s own template (be it a component or a partial).</p>
<p>The idea is that we have one place that defines how a particular design element is rendered.</p>
<h3>Inheritance structure</h3>
<p>An important feature of an effectively internationalised site is the ability to override specific templates or components for localisation-specific requirements. This is either to customise the markup of a particular component, or not displaying that component, or displaying something not available to any other locale.</p>
<p>In it&#8217;s most basic form what you want is a templating system that, when a template is required, instead of looking for it in one specific place, it looks in a series of locations (based on the requested locale) until the most appropriate one is found, and then uses that. The most appropriate template is in the range of one specialised just for that locale right up to the generic default that applies to all locales.</p>
<p>Essentially in a well internationalised site there&#8217;s a generic set of components that are applicable to most locales most of the time. Then there is a locale specific overrides that either customise the component, stop it from rendering, or insert something not offered in the generic set. In this way each locale can override any template at any point.</p>
<h3>Template inheritance gotchas</h3>
<p>One very common mistake in inheritance is to use a site&#8217;s primary locale as the default level of localisation. Yahoo US made this mistake time and time again. Mainly because they built the US version of each media property first (because the US is Yahoo&#8217;s primary market). When they tried to create a Canadian version of Yahoo Finance (in English only: ca.finance.yahoo.com), for example, instead of refactoring the code to have a generic localisation level and both the US version and the Canadian version would specialise from that, they decided to keep the US version at the top of this tree, and the Canadian version became a descendent of that.</p>
<p>This created a serious maintenance headache. Since the size of the Canadian audience was miniscule in comparison to the US audience, there was no dedicated development team for it. Of course, with a proper internationalisation framework in place this isn&#8217;t a problem. But because Canada inherited the US codebase, every change to the US codebase became immediately available to Canada. Including features that could contractually only be offered in the US. That means for every change to the US codebase, some poor sap needed to undo that change for Canada by finding the previous version of the changed template, and localising it down to Canada, thus undoing the US change. This do/undo process wasted a large number of developer hours.</p>
<p>They realised the minefield of this approach, and instead of refactoring the Finance property to have a generic, rather than a US as a default localisation, they copied the templates for Canada into a separate codebase, and had a dedicated team in Canada to support their own offshoot.</p>
<p>Luckily, Yahoo in Europe had a tiny fraction of resources the US had access to, and in that scarcity they adopted a much better approach by building their own bespoke templating system, and having a generic localisation level at the top. That allowed Yahoo Europe to support 5 countries, and a dozen independent media sites, with one small team of developers maintaining the templates. (Which worked well for close on a decade; until Yahoo US decided that global properties / one codebase with everything inheriting from the US locale was the preferred solution.)</p>
<h3>Specialisation on steroids: Yahoo Europe</h3>
<p>At Yahoo! Europe we had a very powerful in-house template editing system (developed in the 20th century) that allowed us to build a generic Yahoo media site. Then we had the ability to specialise<sup>[<a href="#footnote-1">1</a>]</sup> these templates to various dimensions:</p>
<ul>
<li>A site dimension: so a Sports site could customise a particular component just for Sport, without affecting the other media sites</li>
<li>A country dimension<sup>[<a href="#footnote-2">2</a>]</sup>: We could specialise to each of the five European countries we supported (independent or dependent on the site dimension)</li>
<li>A site section dimension</li>
<li>A content-type dimension</li>
<li>A content data-provider dimension</li>
<li>A page-specific dimension</li>
<li>A template specific dimension</li>
</ul>
<p>Although from the perspective of the page every template had a localisation path which looked like a list of paths to look for a specific template, starting from the most-specific (the template-specific level), and going up the list until it found an existing component.</p>
<p>The actual inheritance structure was a lot more complicated, and frankly ingenious. Proper localisation is a set of dimensions. And each dimension inter-relates independently of the others, which makes using a localisation tree impractical and limiting. Dimensions are the factors that can affect how a component displays. As I&#8217;ve mentioned, at Yahoo, the actual site itself is one major dimension (A Sports site, as opposed to a News site), then we have dimensions for the country, the data provider, the site section, the type of page, the type of data, and even the individual template itself. New dimensions could be added fairly simply: when we needed to co-brand a section of the site for a particular advertiser/partner we would introduce that as a new dimension and specialise any templates needing customisation to that level. Then when the advertising campaign was over we&#8217;d just remove the dimension from the specialism path.</p>
<h3>Finding the right level of specialism</h3>
<p>Picking the right specialism level is not entirely straightforward, it needs to be considered. It&#8217;s far too easy to specialise a template right to the bottom so that you ensure that there&#8217;s no impact elsewhere on the site. This approach isn&#8217;t ideal and in the long-term it proves to be more costly, despite being the simplest and safest way to implement one change.</p>
<p>It takes knowledge of the available dimensions, what they are used for and where to accurately identify the appropriate level of specialism for a change. You need confidence in making the change at a higher level won&#8217;t break parts of the site you are not immediately looking at. That means understanding the implications of your change, and being in a good position to identify and test the affected areas of the site.</p>
<p>Focusing just on the primary locale of the site is only viable when developers are very confident of the scope and impact of their changes. Developers do need to consider the localisation implications of their changes. It&#8217;s not enough to get it working in your preferred locale and just assume everywhere else will be just fine. You need to know the impact, either before you make the change, or by confirming it as so by testing it thoroughly.</p>
<p>One of the weaknesses of templating systems of a dynamic and flexible nature is quickly identifying which pages are affected by changing a template. Sometimes a grep isn&#8217;t going to be enough, if the template inclusion is something other than a static reference. A developer needs good tools that know about the templating framework and help identify affected pages.</p>
<h3>Open-source templating frameworks</h3>
<p>Although my experience in internationalisation-supporting frameworks is based on an internal Yahoo templating framework called Jake, it isn&#8217;t entirely Yahoo specific. Jake is written in Perl. When Yahoo adopted PHP as it&#8217;s framework of choice a team quickly got involved in creating a very flexible dimension-supporting <a href="http://developer.yahoo.com/r3/">templating system called r3</a>. This got released as open source a few years ago. It&#8217;s very powerful, but it really needs <a href="http://marknormanfrancis.com/">someone who understands r3</a> to write us a <a href="https://github.com/norm/content-usingr3">guide in how to use r3</a> and wield it properly.</p>
<p>In the meantime, start with a templating system that allows you to define a generic default localisation for your website, and a specialisation level for each locale where every template can be specialised to for locale-specific customisation. This is the bare minimum for localisation of website templates. Though, if you build it right and allow independent dimensions, you have a very powerful and flexible templating system that will do amazing things.</p>
<h3>Footnotes</h3>
<p id="footnote-1">[1] At Yahoo we referred to the specialism path as the localisation path, although this path wasn&#8217;t strictly about localisation but also covered many mutually-exclusive dimensions. Within the European webdev team we understood when we were talking about localisation of templates, and when we were talking about localisation in an internationalisation context. But it was evident that using localisation for templates in this instance can be confusing, so instead calling this specific feature &#8220;specialism&#8221; and &#8220;specialising templates&#8221; would make the difference clearer. I&#8217;m adopting this nomenclature here.</p>
<p id="footnote-2">[2] The choice of country as the primary specialism level of localisation is a classic mistake of internationalisation: a locale or culture doesn&#8217;t necessarily map to a country. Yahoo&#8217;s Spanish News site contains stories in multiple languages, including Spanish, Catalan, Basque etc. But there&#8217;s only one Spanish news site. Instead of a country locale, Yahoo should have established a locale level &#8211; Spain-Spanish, Spain-Catalan, Spain-Basque, so three separate locales, not one country with articles in three different languages. The specialism for language is definitely needed, plus another extra level in case there&#8217;s a geographic/natural/cultural boundary between groups of people in the same country and language, but still are independent of each other. Yahoo&#8217;s insistence on countries defining locales is what limits their ability to accommodate citizens who do not use what Yahoo defines as that country&#8217;s acceptable language.</p>
<h3>Related resources:</h3>
<ul>
<li><a href="http://developer.yahoo.com/r3/">Easy localisation and templating with Yahoo r3</a></li>
<li><a href="http://alfonsojimenez.com/tag/yahoo-r3/">Integrating Yahoo r3 with Phing</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://internationalisationtips.com/2011/08/24/localising-templates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Translating dynamic text strings</title>
		<link>http://internationalisationtips.com/2009/03/24/translating-dynamic-text-strings/</link>
		<comments>http://internationalisationtips.com/2009/03/24/translating-dynamic-text-strings/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 13:24:15 +0000</pubDate>
		<dc:creator>Isofarro</dc:creator>
				<category><![CDATA[Translations]]></category>
		<category><![CDATA[internationalisation]]></category>
		<category><![CDATA[localisation]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[tokens]]></category>
		<category><![CDATA[variables]]></category>

		<guid isPermaLink="false">http://www.internationalisationtips.com/?p=17</guid>
		<description><![CDATA[Translating text dynamically generated at request time is more complicated than static non-changing text. Depending on the reason why the text needs to be flexible at request time means taking a different approach. In the last post we looked at simple static text replacement where the text doesn&#8217;t change from request to request. But as [...]]]></description>
			<content:encoded><![CDATA[<p>Translating text dynamically generated at request time is more complicated than static non-changing text. Depending on the reason why the text needs to be flexible at request time means taking a different approach.</p>
<p>In the last post we looked at <a href="http://www.internationalisationtips.com/2009/03/24/replacing-static-text-strings-with-references/">simple static text replacement</a> where the text doesn&#8217;t change from request to request. But as soon as we use conditionals to build up a text string this simple lookup method is no longer sufficient.</p>
<h3>Simple data inclusion</h3>
<p>The simplest of dynamic text examples we have is a message telling us which page we are on.</p>
<pre><code>
&lt;?php
$pageNo = 6;
echo "You are currently on page ", $pageNo;
?&gt;
</code></pre>
<p>The first pitfall to avoid is to resist creating a translation string for the static-looking text <q>You are currently on page</q>. Yes, this is a static piece of text, but it requires additional context for the message to make sense. This is done in the code by tacking on the page number at the end of the string. The resulting string is <q>You are currently on page 16</q> which makes sense without further context.</p>
<p>This works in English, but in other languages it may not be appropriate, or grammatically correct for the page number to be at the end. We need to ensure that the placement of the page number is as flexible as possible.</p>
<p>The most straightforward solution is to use a token to represent the <code>$pageNo</code> variable in the text string. And at request time replace these tokens with their variable amounts. This is a three step process:</p>
<ul>
<li>Refactor the static looking text to use a text replacement</li>
<li>Process the refactored string at request time</li>
<li>Add the refactored string to the translation table</li>
</ul>
<p>The commonly accepted practice for tokens is to use a single word wrapped in curly brackets. I&#8217;d recommend this approach because translation strings are independent of any language limitations, it&#8217;s easy to do replacement in PHP. And if you need to use these translations in JavaScript then YUI&#8217;s <a href="http://developer.yahoo.com/yui/docs/YAHOO.lang.html#method_substitute"><code>YAHOO.lang.substitute()</code></a> handles curly bracket replacement right out of the box. (The alternative is <code>sprintf</code>&#8216;s <code>%s</code> syntax, but be careful if there are multiple tokens that could be in a different order to what you&#8217;d expect)</p>
<pre><code>
&lt;?php
// Step 1: Refactor string
$pageNo = 6;
$pageMsg = "You are currently on page {page}";
echo $pageMsg;
?&gt;
</code></pre>
<p>With this refactoring we are basically just echoing out a static string that&#8217;s sitting in a new variable. Between defining the variable and writing it out we need to add in some extra code to replace <code>{page}</code> with the actual page number:</p>
<pre><code>
&lt;?php
// Step 2: Replace tokens
$pageMsg = "You are currently on page {page}";
$pageMsg = preg_replace('/{page}/', $pageNo, $pageMsg);
echo $pageMsg;
?&gt;
</code></pre>
<p>The <code>preg_replace</code> looks for an occurrence of <samp>{page}</samp> and replaces it with the contents of the variable <code>$pageNo</code>.</p>
<p>Now we can treat the starting string as a static text string and add it to our translations array:</p>
<pre><code>
&lt;?php
$translations = array(
	"pageMessage" => "You are currently on page {page}";
);
?&gt;
</code></pre>
<p>And update our main code to reference this translation</p>
<pre><code>
&lt;?php
// Step 3: Add to the translations dictionary
$pageMsg = $translations['pageMessage'];
$pageMsg = preg_replace('/{page}/', $pageNo, $pageMsg);
echo $pageMsg;
?&gt;
</code></pre>
<p>The benefit of this approach is that the token can be anywhere in the string and now requires no code modifications if in one language the token needs to be somewhere other than at the end. We&#8217;ve removed the locale dependencies.</p>
<h3>Grammatical differences</h3>
<p>One of the difficult problems of creating text on the fly is grammatical differences between languages. We have to be careful where our code is implementing grammar rules. For example, here&#8217;s a PHP snippet that prints out the number of unread email items:</p>
<pre><code>
&lt;?php
$unread = 2;
echo $unread, " unread email", ($unread==1)?'':'s';
?&gt;
</code></pre>
<p>This just about works in English. But translating for a different locale we can&#8217;t assume the same grammar rules apply. Obviously pluralising a word isn&#8217;t as straightforward as adding the letter &#8216;s&#8217; to the end.</p>
<p>This particular piece of code needs to be refactored to remove the grammar logic, and then it is in a state to be localised. The obvious first step, along with our text replacement token, is to remove the conditional logic and create two separate text strings:</p>
<pre><code>
&lt;?php
$unread = 2;

// Select the right message
$unreadMsg = "{total} unread emails";
if ($unread==1) {
	$unreadMsg = "{total} unread email";
}

// Replace the token
$unreadMsg = preg_replace('/{total}/', $unread, $unreadMsg);

echo $unreadMsg;
?&gt;
</code></pre>
<p>And we are back into the normal lines of replacing static text with a reference to a translation. (Although Polish pluralisation is more complicated, so would need more logic or perhaps a different approach &#8211; hat tip <a href="http://intranation.com/">Brad</a>).</p>
<h3>String translation libraries</h3>
<p>It becomes a little tedious to create a regex rule for every token that needs to be replaced. And there are classes or libraries to do this for just about any web-facing programming language. A very elegant solution is <a href="http://ejeliot.com/">Ed Eliot&#8217;s</a> PHP 5 <a href="http://www.ejeliot.com/blog/114">text translation library</a>.</p>
<p>Ed&#8217;s class gets the basics right:</p>
<ul>
<li>Translations are in a separate file, one per language</li>
<li>Specifying the language code and it grabs the right translations file</li>
<li>the <code>Get</code> method takes an array of token replacements, and applies them to the translations for you</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://internationalisationtips.com/2009/03/24/translating-dynamic-text-strings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Replacing static text strings with references</title>
		<link>http://internationalisationtips.com/2009/03/24/replacing-static-text-strings-with-references/</link>
		<comments>http://internationalisationtips.com/2009/03/24/replacing-static-text-strings-with-references/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 11:55:56 +0000</pubDate>
		<dc:creator>Isofarro</dc:creator>
				<category><![CDATA[Translations]]></category>
		<category><![CDATA[internationalisation]]></category>
		<category><![CDATA[localisation]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[translation]]></category>

		<guid isPermaLink="false">http://www.internationalisationtips.com/?p=9</guid>
		<description><![CDATA[The first major step to localising a website or web application is to translate all the static text strings into the preferred language. Static text being text that doesn&#8217;t change from request to request. The typical approach to translating this text is to replace every piece of static text with a variable reference that points [...]]]></description>
			<content:encoded><![CDATA[<p>The first major step to localising a website or web application is to translate all the static text strings into the preferred language. Static text being text that doesn&#8217;t change from request to request.</p>
<p>The typical approach to translating this text is to replace every piece of static text with a variable reference that points to a translation dictionary. For example the simple code:</p>
<pre><code>
echo "Hello world";
</code></pre>
<p>The static text <samp>&#8220;Hello World&#8221;</samp> should be replaced with a variable reference. In this example, let&#8217;s create a simple lookup array in PHP (in its own external file, and <code>include</code> it in):</p>
<pre><code>
&lt;?php
$translations = array(
    'hello_world' =&gt; 'Hello World'
    // Other translation strings
);
?&gt;
</code></pre>
<p>We can now replace our original text with the reference <code>$translations['hello_world']</code>, like so:</p>
<pre><code>
echo $translations['hello_world'];
</code></pre>
<p>With the <code>$translations</code> array being in an external PHP file we can have one of these files per locale or language and include the right one at request time.</p>
<p>This is the first step at separating the locale specific information from our code. Adding a new locale means creating a new translations file for that locale and more importantly, no code changes.</p>
<p>A large chunk of internationalising code for localisation involves just replacing existing text with translated versions. It is an important step, and the first one to get right. The next step will involve dealing with strings that are <a href="http://www.internationalisationtips.com/2009/03/24/translating-dynamic-text-strings/">dynamically altered at request time</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://internationalisationtips.com/2009/03/24/replacing-static-text-strings-with-references/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

