Actions

Difference between revisions of "Making templates translatable"

From Joomla! Documentation

m
m (Tutorial:Template translations moved to Making templates translatable: Moved page to main namespace because the Tutorial namespace is deprecated)

Revision as of 10:19, 15 January 2011

Contents

Introduction to template translation

Joomla is a truly international application and supports the translation of all strings contained within it. Templates are no exception and a little extra time spent ensuring that the strings used in your templates are translatable will pay dividends.

The language translation system has been designed to be as simple and error-proof as possible. For example, even if a language file is missing, or a particular string has not been translated, Joomla will transparently fall back to showing the untranslated string. There are also some useful tools built into Joomla itself to assist translators in creating a new translation.

In this chapter you will learn about constructing language definition files for your template and how to include translations in your template package file. You will also learn how to make sure that all strings used in your template are translatable and how to debug a new translation.

Location of template language definition files

Language definition files for front-end templates are stored in

[path-to-Joomla]/language/[ln-LN]

where [ln-LN] is the language code. Language codes are defined in RFC3066[1] The file must be named

[ln-LN].tpl_[template-name].ini

where [template-name] is the name of the template (in lowercase). For example, the British English language file for the Beez template is

[path-to-Joomla]/language/en-GB/en-GB.tpl_beez.ini

You should also create a separate language file for translating the Administrator back-end of your template. This will be stored in

[path-to-Joomla]/administrator/language/[ln-LN]

but the file naming convention is the same.

For administrator templates, as distinct from front-end templates, the second of these files is the only one required. For example, the British English language file for the Khepri administrator template is located in

[path-to-Joomla]/administrator/language/en-GB/en-GB.tpl_khepri.ini

Creating a language definition file

Important note: Joomla language INI files must be saved as UTF-8 without the Byte Order Mark (BOM)[2].

The format of language definition files is very basic. Blanks lines and lines beginning with “#” are ignored and the latter may be used to add comments to the file. Each line consists of a pair of strings separated by an equals sign like this

KEY=Value

where “KEY” is a string to be translated and “Value” is the translated string. For example

ADDITIONAL_INFORMATION="Additional Information"

The “KEY” must be in all capitals or the string will not be found. The case of the source string does not matter as strings are folded to upper case before searching takes place. So “additional information”, “Additional Information” or even “AdDiTiOnAl InFoRmAtIoN” will be matched.

The “KEY” can include spaces and other punctuation characters but there should not be any spaces either side of the equals sign as spaces are significant. If more than one entry has the same left-hand side, the last one to be encountered is the one that will be used.

The "VALUE" cannot include double-quote characters ("). To get a double-quote character you must use the HTML special character sequence """ instead. Single-quote characters (') are valid.

More information about the discussed changed for the Joomla 2.5 and 3.x series can be found on the page Specification of language files Joomla 2.5 Joomla 3.x

Amending the templateDetails.xml file

To ensure that your template is fully internationalised you must make sure that certain XML elements are translated and that the language definition files are listed in the templateDetails.xml file.

Translating templateDetails.xml

A couple of the elements in the templateDetails.xml file are used in the Template Manager and are themselves translatable. These should always be translated.

name Name of the template. For example, Beez
description Description of the template.

These fields are also shown to the user during template installation.

Adding language definition files to templateDetails.xml

All language files must be declared in the templateDetails.xml file. This is done by adding two <language> elements for each language to be included with the template; one for the front-end strings; the other for the administrator back-end strings. For example, the two British English language files and the two German language files for the Beez template are declared as follows

<?xml version=”1.0” encoding=”utf-8” ?>
<install version=”1.5” type=”template”>
 
     .........
 
    <languages>
        <language tag=”en-GB”>en-GB.tpl_beez.ini</language>
        <language tag=”de-DE”>de-DE.tpl_beez.ini</language>
    </languages>
 
     .........
 
    <administration>
        <languages folder=”admin”>
            <language tag=”en-GB”>en-GB.tpl_beez.ini</language>
            <language tag=”de-DE”>de-DE.tpl_beez.ini</language>
        </languages>
    </administration>
 
</install>

Note that in the administration <languages> tag the folder attribute is used. This is because the language files for the front-end and back-end have the same file names and so cannot exist in the same directory within the template package file. In this example, the administration language files have been placed in a sub-directory called admin to separate them from the front-end language files.

Embedding translatable strings in the template

In the template itself translations are handled using the JText static class. It is referred to as “static” because it does not require instantiation as an object before its methods may be used.

Simple text strings

Most text strings can be translated using the “_” (underscore) method. For example, suppose your template contains the English text “Welcome” which needs to be made translatable.

<?php
    echo 'Welcome';
?>

Then you would replace the static string like this

<?php
    echo JText::_( 'Welcome' );
?>

This would cause the translation system to search the appropriate language file for “WELCOME” on the left-hand side of an equals sign. The search is case-insensitive. If this language definition string is encountered

WELCOME=Welcome!

then the effect will be to output the string “Welcome!” to the browser. If the user switches to the German language then the German language definition file will be searched for “WELCOME” and this time might encounter the string

WELCOME=Willkommen

and so “Willkommen” will be sent to the browser. Importantly, if the user switches to German but there is no German language file present, or the appropriate string does not appear in the German language file, then Joomla will fall back to sending the untranslated string “Welcome” to the browser, also preserving its original case.

Formatted fields in language translation strings

Sometimes it is necessary to include specially formatted fields within a string to be translated. This usually happens where numbers are involved but can occur for dates and times or when precise formatting instructions are required. If the strings were not to be translated the standard PHP functions printf and sprintf could be used. The printf function outputs a string formatted using embedded formatting instructions; the sprintf function returns a string formatted using the same embedded formatting instructions.

The JText class provides wrapper methods for the printf and sprintf functions allowing static text to be translated while also allowing formatted fields to be embedded using the same syntax as the PHP functions.

For example, suppose you have the string “Donations of 12.45 GBP have been received” where the amount comes from a variable, $donations”, say. You could split the string into two like this

JText::_( 'Donations of' ) .$donations GBP “ . JText::_( 'have been received' )

with language definition strings

DONATIONS OF=Donations of
HAVE BEEN RECEIVED=have been received

but this does not work well in languages where the embedded data is not in a similar place in the translated string. Instead use the sprintf method like this

JText::sprintf( 'Donations have been received', $donations )

with language definition string

DONATIONS HAVE BEEN RECEIVED=Donations of %.2f GBP have been received

You can include more than one format specifier in a translation string. Substitutions are carried out in order so this works as expected

JText::sprintf( 'String with numbers in it', $num1, $num2, $num3 )

with language definition string

STRING WITH NUMBERS IN IT=First %d, second %d, third %d

Syntax of format specifiers

The format specifier consists of a percent sign (%), followed by one or more of these elements, in order:

Order
Type Values
Description
1.
Sign + or - Optional. Forces a sign (+ or -) to be used on a number. By default, only the – sign is used on a number if it's negative. This specifier forces positive numbers to have the + sign attached as well.
2.
Padding <space>

or 0

or '<char>

Optional. Character to be used for padding the results to the correct string size. May be a space character or a 0 (zero character). The default is to pad with spaces. An alternative padding character can be specified by prefixing it with a single quote ().
3.
Alignment <null> or - Optional. Determines if the result should be left-justified or right-justified. The default is right-justified; a - character here will make it left-justified.
4.
Width Number Optional. Number of characters (minimum) that the conversion should result in.
5.
Precision Number Optional. Number of decimal digits that should be displayed for floating-point numbers. When using this specifier on a string, it acts as a cutoff point, setting a maximum character limit to the string.
6.
Type Mandatory. The type of the argument data. Possible types are:
%
A literal percent character. No argument is required
b
The argument is treated as an integer and presented as a binary number.
c
The argument is treated as an integer and presented as the character with that ASCII value.
d
The argument is treated as an integer and presented as a signed decimal number.
e
The argument is treated as scientific notation (e.g. 1.2e+2). The precision specifier stands for the number of digits after the decimal point since PHP 5.2.1. In earlier versions, it was taken as the number of significant digits (one less).
u
The argument is treated as an integer and presented as an unsigned decimal number.
f
The argument is treated as a float and presented as a floating-point number (locale aware).
F
The argument is treated as a float and presented as a floating-point number (non-locale aware).
o
The argument is treated as an integer and presented as an octal number.
s
The argument is treated and presented as a string.
x
The argument is treated as an integer and presented as a hexadecimal number (with lowercase letters).
X
The argument is treated as an integer and presented as a hexadecimal number (with uppercase letters).

Format argument swapping

The format string supports argument numbering and even swapping. This is useful where two or more data items must be embedded in a string but differences in language structure means that the order of use of the data items is not the same.

For example, suppose we have the following code

echo JText::sprintf( 'Balls in the bucket', $number, $location );

with this language translation string

BALLS IN THE BUCKET=There are %d balls in the %s

Then if

$number = 3
$location = 'hat'

this would output “There are 3 balls in the hat”. But consider if you wanted to change the translation to

BALLS IN THE BUCKET=The %s contains %d balls

This would now output “The 3 contains hat balls” which is clearly nonsense. Rather than change the code, you can indicate in the translation string which argument each of the placeholders refer to. Change the translation to

BALLS IN THE BUCKET=The %2$s contains %1$d balls

and the output becomes “The hat contains 3 balls” as expected.

An added benefit of being able to number the arguments is that you can repeat the placeholders without adding more arguments in the code. For example, change the translation to

BALLS IN THE BUCKET=The %2$s contains %1$d balls, so there are %1$d balls in the %2$s

and this will correctly output “The hat contains 3 balls, so there are 3 balls in the hat”.

Debugging a translation

Joomla supports some useful debugging mechanisms that can make it easier to locate untranslated strings and diagnose problems with language translations in installed extensions.

Debug Language

Global-config-language-debug.png

You activate language debugging via the Administration Back-end by going into Global Configuration and clicking on the System tab. Find the Debug Language field, change the value to “Yes” and save your changes.

With this option active all translatable strings are shown surrounded with special characters that indicate their status

Code Status
●Joomla CMS● (text surrounded by bullets) indicates that a match has been found in the language definition file and the string has been translated.
 ??Joomla CMS?? (text surrounded by pairs of question marks) indicates that the string is translatable but no match was found in the language definition file.
Joomla CMS (text with no surrounding characters) indicates that the string is not translatable.

Debug System

Additional language debugging information can be obtained by activating system debugging. This is done by going into Global Configuration and clicking on the System tab. Find the Debug System field, change the value to “Yes” and save your changes.

With this option active all screens have additional debugging information at the end of each page. Currently this includes

  • Profile information. This is the amount of time taken to execute code up to various mark points in the code.
  • Memory usage. The amount of system RAM used.
  • SQL queries executed. All of the SQL queries executed in the process of building the page.
  • Language files loaded. A list of all the language files loaded in the process of building the page, including full path information. This can be useful to check that the expected files have been loaded. The number after each file path is the number of times that the file was referenced.
  • Untranslated strings diagnostic. A list of all the untranslated strings found and the likely file location given where the JText call was made.
  • Untranslated strings designer. A list of all the untranslated strings found but listed in a KEY=Value format so they can be copy-pasted directly into a language definition file (INI).

Debug Plugin

Debug-plugin.png

This system plugin controls what is displayed when debugging is activated in Global Configuration. It is enabled by default. You can access the parameters for the plugin from Extensions → Plugin Manager. Locate the “System - Debug” plugin and click on it. There are three settings of interest to translators.

  • Display loaded language files. If set to “Yes” then the debug information will include a list of the language files that were requested as the current page was being generated.
  • Display undefined language strings. If set to “diagnostic mode” then a list of untranslated strings and the location of the file containing the call to JText is included in the debug information. If set to “designer mode” then a list of untranslated strings in a format that can be copy-pasted directly into a language definition file is included in the debug information. That is, it displays the list in KEY=String format. If set to “All modes” then both the diagnostic mode and designer mode lists are included in the debug information.
  • Strip Key Prefix. Only used when Display undefined language strings is set to “Designer mode” or "All modes". This allows you to strip a prefix from the string to form the key. This is useful if the designer uses a common prefix for their extensions when using JText methods. See example below.

Note that the display of untranslated strings will only display the value passed to the appropriate JText method. For example, with the following code:

echo JText::_( 'Reports Import Configuration' );

If untranslated, Designer mode will display this as:

# /administrator/components/com_reports/views/reports/tmpl/default.php
REPORTS IMPORT CONFIGURATION=Reports Import Configuration

If the Strip Key Prefix is set to "Reports", then the display would change slightly to:

# /administrator/components/com_reports/views/reports/tmpl/default.php
REPORTS IMPORT CONFIGURATION=Import Configuration

Note that the path shown is only a best guess based on a call to the PHP debug_backtrace function. Sometimes it is accurate, sometimes it is not and there are also cases where no file could be determined. In those cases you have to use your best judgement.



  1. RFC3066: Tags for the Identification of Languages http://www.ietf.org/rfc/rfc3066.txt
  2. For more information on Byte Order Mark see http://unicode.org/faq/utf_bom.html#BOM