Multilingual Interface Implementation
<h3 class="heading-h6"><a name="THLToolboxhomegtDevelopersZonegtApplicationInterfaceIssuesgtMultilingualInterfaceImplementation" class="anchorpoint"></a><a href="/tools/wiki/home.html">THL Toolbox</a> > <a href="/tools/wiki/Developers%27%20Zone.html">Developers' Zone</a> > Application Interface Issues > Multilingual Interface Implementation</h3><p class="paragraph">
</p><h3 class="heading-h1"><a name="MultilingualInterfaceImplementation" class="anchorpoint"></a>Multilingual Interface Implementation</h3><p class="paragraph"><strong class="bold">Contributor(s)</strong>: Than Grove (PHP & XML)
</p><h3 class="heading-h2"><a name="Introduction" class="anchorpoint"></a>Introduction</h3><p class="paragraph">THL is committed to designing its core applications with multilingual interfaces so that international users can rely upon an English interface, Tibetans can rely upon a Tibetan language interface, and so forth.</p><p class="paragraph">The general approach for internationalization of THL is to use dictionary files to look up words or phrases in a particular language. In ROR and PHP-based
pages, these files are stored in YAML ("YAML Ain't Markup Language"), a simple human-readable data storage syntax. (See <img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://www.yaml.org/" target="rwikiexternal">http://www.yaml.org/</a></span> and in particular <img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://yaml.org/refcard.html" target="rwikiexternal">http://yaml.org/refcard.html</a></span> for a description of YAML.) In the XML-based Cocoon applications, such as a scholarly essay or catalog, store their dictionary files in XML.
</p><h3 class="heading-h2"><a name="PHPApplicationsandPages" class="anchorpoint"></a>PHP Applications and Pages</h3><p class="paragraph">The majority of the web pages for THL and a few of the apps are in PHP. These use YAML to store their translation equivalents.
</p><h3 class="heading-h3"><a name="HowInternationalizationisSetupInPHP" class="anchorpoint"></a>How Internationalization is Set up In PHP</h3><p class="paragraph">There are three types of YAML files used in the process of translating THL pages. Most are stored in the "/global" folder at the root of the site in a
sub-folder called "/locale". Portal-specific equivalents <em class="italic">can</em> also be stored in a "/locale" folder at the portal level, as in "/encyclopedias/literary/locale".</p><p class="paragraph">The three types of YAML files used in PHP apps are:</p><ol><li>thl-locales.yml : This is describes the locales available in PHP translation. Any new language must be added to this file. It begins with a list of "langs"</li></ol><p class="paragraph">
that contains the iso two-letter abbreviation for that language, followed by a few language specific variables set for each available language. This file is located
at <img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://{DOMAIN}/global/locale/thl-locales.yml" target="rwikiexternal">http://{DOMAIN}/global/locale/thl-locales.yml</a></span> .
</p><ol><li>General Language Dictionary: Each language has it's own general dictionary stored in the "/global/locales" folder in a sub-folder named with its two-letter</li></ol><p class="paragraph">
abbreviation and the name of the file is "thl-view-{abbr}.yml". Thus, there is for example: <img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://{DOMAIN}/global/locale/bo/thl-view-bo.yml" target="rwikiexternal">http://{DOMAIN}/global/locale/bo/thl-view-bo.yml</a></span> that contains the
translations for Tibetan.
</p><ol><li>Portal-Specific Language Dictionary: Terms or phrases specific to a certain portal within THL can be stored in the portal itself in a "/locale" folder <em class="italic">without</em></li></ol><p class="paragraph">
being put in a separate folder by language abbreviation, as in <img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://{DOMAIN}/encyclopedias/literary/locale/thl-view-zh.yml" target="rwikiexternal">http://{DOMAIN}/encyclopedias/literary/locale/thl-view-zh.yml</a></span> . There can be a specific dictionary
at any sub-level within THL and the will all be concatenated with the global one for pages within that portal.</p><p class="paragraph">In both of the latter locations, there needs to be one YAML file for each available language. If a YML file is missing, the system will default to english. However,
if a term is not found within an existing YAML file, then a blank will appear in its place on the page. <strong class="bold">All YAML files at the same level must have exactly the same
terms translated.</strong></p><p class="paragraph">The syntax of the YAML dictionaries is to have all translations subsumed under the category of "vocab". Each term has either a direct equivalent or
has a series of sub-options for different "uses" of the word. An example is:</p><p class="paragraph"><span class="pre">
home: 'home'
introduction:</span></p><p class="paragraph"><span class="pre"> this: 'introduction'
to: 'introduction to {{what}}'</span></p><p class="paragraph"><span class="pre"> …</span></p><p class="paragraph"><span class="pre"> placeNames:
drepung:
this: 'Drepung'
of: 'Drepung's'
lhasa:
this: 'Lhasa'
of: 'Lhasa's'
sera:
this: 'Sera'
of: "Sera's"</span></p><p class="paragraph">
In the PHP calls these are called by strings such as "home", "introduction.this", or "placeNames.lhasa.of", which return the corresponding (in this case English)
phrase. The "{{what}}" marks the place where a string passed to the translation function is substituted so that the function call might look something like:</p><div class="code"><pre>echo ts(<span class="java-quote">"introduction.to"</span>, t(<span class="java-quote">"encyclopedia.many"</span>));</pre></div><p class="paragraph">which would result in:</p><div class="code"><pre><span lang=<span class="java-quote">"eng"</span>>Introduction to Encyclopedias</span></pre></div><p class="paragraph">There are two specific PHP files used to create the internationalization functionality. They are both found in the /global/php folder. These are:</p><ol><li>{link:spyc.php|<img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://{DOMAIN}/global/php/spyc.php}" target="rwikiexternal">http://{DOMAIN}/global/php/spyc.php}</a></span> : This is an open-source PHP YAML parser found at <img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://code.google.com/p/spyc/" target="rwikiexternal">http://code.google.com/p/spyc/</a></span> used to read the</li></ol><p class="paragraph">
YAML dictionaries.
</p><ol><li>{link:thl-i18n.php|<img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://{DOMAIN}/global/php/thl-i18n.php}" target="rwikiexternal">http://{DOMAIN}/global/php/thl-i18n.php}</a></span> : This contains the code for implementing the dictionaries. It loads the spyc.php file and</li></ol><p class="paragraph">
then reads in the appropriate YAML dictionaries and concatenates them as necessary. It has functions to write the HTML code for the language selection
drop-down list as well as functions to look up and display the appropriate translation.</p><p class="paragraph">The thl-i18n.php file is included in the header.php global document. If for some reason you must have a separate header.php file for a particular part of the
site, then this file must include the line</p><div class="code"><pre>require_once <span class="java-quote">"$droot/global/php/thl-i18n.php"</span>;</pre></div><p class="paragraph">There are four important functions within this file for implementing the language lookups:</p><ol><li>write_lang_opts() : this writes the HTML code for the language option drop down list.</li>
<li>t($lsname,$strobj = NULL, $strobj2 = NULL) : This is the basic translation routine. The first parameter, lsname, is required. $strobj is the string that replaces</li></ol><p class="paragraph">
the "{{what}}" in the translation. The last parameter, $strobj2, is for the few situations when there is a second "{{what2}}" string to replace.
</p><ol><li>ts($lsname,$strobj = NULL, $strobj2 = NULL) : This is the same as the translation function <em class="italic">except</em> it surrounds the result string in a span element</li></ol><p class="paragraph">
whose class is set according to the appropriate style for THL CSS to apply the correct font and style characteristics. The style class is set in the information
for that language found in the "/global/locale/thl-locales.yml" file.
</p><ol><li>createI18nImageTag() : This creates separate image tags for each language and is used when there is text within the image.</li></ol><p class="paragraph"><strong class="bold">The language in which to display the page is set by the drop-down options list and is recorded in a persistent cookie, called "thl-lang".</strong>
</p><h3 class="heading-h3"><a name="HowtoImplementInternationalizationinPHP" class="anchorpoint"></a>How to Implement Internationalization in PHP</h3><p class="paragraph">In order to allow gradual implementation of internationalization, the code is globally included in all pages, but is by default turned off. To turn on the
globalization, one has to include the PHP statment,</p><div class="code"><pre>$multilingual = <span class="java-keyword">true</span>;</pre></div><p class="paragraph">Somewhere at the top of the PHP page that has been translated. This will display the language options drop down list for that page. (Ultimately, when a critical
mass of pages have been translated, we can make this on by default.)
</p><h3 class="heading-h4"><a name="Strings" class="anchorpoint"></a>Strings</h3><p class="paragraph">To call a simple string translation, use the ts() function. The first parameter should be the string that identifies the desired text, if that text has a "{{what}}"
in it, then a second parameter is added with the text for that substitution. If there is a second "{{what2}}", use the third parameter of the function. Both these
replacement texts should also be translated but with the t() function so that only the outer function for the whole phrase is surrounded by the span tags. As
both these functions return strings, the output needs to be printed or "echo"-ed to the HTML result, use the "echo" command for this. Thus, an example might
be:</p><div class="code"><pre><? echo ts(<span class="java-quote">"introduction.to"</span>,t(<span class="java-quote">"literary.of"</span>,t(<span class="java-quote">"encyclopedia.one"</span>))); ?></pre></div><p class="paragraph">
</p><h3 class="heading-h4"><a name="Wikis" class="anchorpoint"></a>Wikis</h3><p class="paragraph">Since teaser boxes contain large chunks of text that we may or may not want to translate, a separate mechanism is used to determine the text to display. This
does not rely on the YAML dictionaries, but is determined by the presence or absence of an appropriate wiki-link. In general, a wiki link for a teaser box
looks something like:</p><div class="code"><pre><a href=<span class="java-quote">"/access/wiki/site/0b308aa3-d044-469b-009a-d34c7841413d/tibetan%20literary%20encyclopedia%20introduction.html"</span> class=<span class="java-quote">"wiki c400 o1"</span>></a></pre></div><p class="paragraph">If the text for that wiki is translated into say Chinese, then another wiki is created with the same name as the first but with "-zh" appended to it and a second
wiki link tag is entered after the first. This second link has the class "zh-wiki" instead of "wiki". For Tibetan, the class would be "bo-wiki" and so forth. The
result would be:</p><div class="code"><pre><a href=<span class="java-quote">"/access/wiki/site/0b308aa3-d044-469b-009a-d34c7841413d/tibetan%20literary%20encyclopedia%20introduction.html"</span> class=<span class="java-quote">"wiki c400 o1"</span>></a>
<a href=<span class="java-quote">"/access/wiki/site/0b308aa3-d044-469b-009a-d34c7841413d/tibetan%20literary%20encyclopedia%20home%20-%20right1-zh.html"</span> class=<span class="java-quote">"zh-wiki c400 o1"</span>></a></pre></div><p class="paragraph">The code will choose the appropriate wiki depending on what language has been chosen.
</p><h3 class="heading-h4"><a name="Images" class="anchorpoint"></a>Images</h3><p class="paragraph">Another important function in the php is the createI18nImageTag() function. This is used for images that have text within them. To use this function
one must make an image for each language with the appropriate text within it. These must all be in the same image folder or sub folder and must all have the
same name except that the non-english versions must have their language code preceded by a dash appended to the name before the extension. Thus, if English,
Chinese, and Tibetan are activated, there must be three images, for example:</p><ol><li>/encyclopedia/literary/images/some-image.jpg</li>
<li>/encyclopedia/literary/images/some-image-zh.jpg</li>
<li>/encyclopedia/literary/images/some-image-bo.jpg</li></ol><p class="paragraph">The function for creating the image has the definition of:</p><div class="code"><pre>createI18nImageTag($iurl, $alttxt, $width, $height)</pre></div><p class="paragraph">The first parameter, $iurl, is a string with the URL for the English version of the image. The last three parameters can either be strings, if the values are
identical for all languages or an array of values keyed on the language code, as in:</p><div class="code"><pre><div id=<span class="java-quote">"masthead-title"</span>>
<a href=<span class="java-quote">"/encyclopedias/literary/index.php"</span> title=<span class="java-quote">"tibetan literary encyclopedia homepage link"</span>>
<? createI18nImageTag(<span class="java-quote">"/encyclopedias/literary/images/masthead-title-literary.png"</span>,
<span class="java-quote">"THL Literary Encyclopedia Link"</span>,
array(<span class="java-quote">"en"</span> => <span class="java-quote">"390"</span>, <span class="java-quote">"bo"</span> => <span class="java-quote">"310"</span>, <span class="java-quote">"zh"</span> => <span class="java-quote">"310"</span>),
array(<span class="java-quote">"en"</span> => <span class="java-quote">"28"</span>, <span class="java-quote">"bo"</span> => <span class="java-quote">"50"</span>, <span class="java-quote">"zh"</span> => <span class="java-quote">"50"</span>));
?>
</a>
</div></pre></div><p class="paragraph">
</p><h3 class="heading-h2"><a name="RoRApplications" class="anchorpoint"></a>RoR Applications</h3><p class="paragraph">TBA
</p><h3 class="heading-h2"><a name="XMLApplications" class="anchorpoint"></a>XML Applications</h3><p class="paragraph">TBA
</p><h3 class="heading-h2"><a name="OtherApplications" class="anchorpoint"></a>Other Applications</h3><p class="paragraph">TBA
</p><h3 class="heading-h6"><a name="Providedforunrestrictedusebythe123linkTibetanandHimalayanLibraryhttpwwwthliborg125" class="anchorpoint"></a><em class="italic">Provided for unrestricted use by the {link:Tibetan and Himalayan Library|<img src="/" alt="external link: " title="external link"/><span class="nobr"><a href="http://www.thlib.org}" target="rwikiexternal">http://www.thlib.org}</a></span></em></h3>