Bugzilla:L10n:Guide
Contents
Overview
This guide provides new localizers a step by step howto to localize Bugzilla in their own locale.
It also contains useful resources links to get the contribution done and to keep the localization up-to-date.
Getting Started
You should first look if somebody else is already working on localizing Bugzilla in your locale.
This page shows all the localized Bugzilla releases we aware of. If you cannot find the version of Bugzilla you want to localize on this page, that doesn't mean that this version is not currently handled. So, please contact the current maintainer or team to avoid duplicated effort. Current active locales can be found in this section.
Once you are sure that nobody is already working on your locale or when you have coordinated with the current team/owner, you can start with the localization.
Obtaining The Source Files
Unless you are sure about the release you want to localize, we advise you to start with the latest stable version. See the Release page to see the latest version and to download the tar.gz archive.
Uncompress the tarball with your favorite tool in an empty directory.
You should have the following tree structure (note: all subdirectories and files are not detailed here):
bugzilla-X.Y.Z (where X.Y.Z are the numbers for the release) --Bugzilla --contrib --docs | --lib | --pdf | --txt | --xml | --html | --images | --images --js --skins --t --templates | --en | --default | --extensions .UPGRADING .UPGRADING-pre-2.8
The localizable contents are located under the following directories:
docs/xml
templates/en
The files UPGRADING and UPGRADING-pre-2.8 are also localizable.
You should focus first on the /templates directory, which contains all the files used to build the user interface.
First, remove all the /CVS subdirectories under the /templates directory:
- GNU/Linux & Mac OSX
$cd templates $rm -rf `find . -name CVS`
- Windows
C:\bugzilla-X.Y.Z>cd templates C:\bugzilla-X.Y.Z>FOR /D %i IN (CVS) DO (rmdir /s/q %i)
Then, you should rename the /en subdirectory for your locale name.
For instance, you can use fr for French or ca for Catalan.
You can also use a four-letter locale code:
For instance, pt-BR for Brazilian Portuguese or zh-CN for Chinese (Simplified).
See page L10n:Simple_locale_names for the locale code that best fit for your locale.
The task
Terminology
Before translating your first template, you should establish a terminology for Bugzilla specific terms. Make sure you always use the same translation for a given term. This is especially important when you have a team of translators.
For instance, start thinking about translations of some of these tricky terms:
- Whine / Whining
- Requestee
- Flag / Flag status
- Target milestone
Some terms are pretty close in their dictionary (not Bugzilla) meanings. Obvious solution in one case may lead to conflicts later. Consider these examples:
- Bug (database object, default value for terms.bug) and error (in Bugzilla application itself).
- Bug report (to be created by user) and report (database statistics).
- Message (as in global/messages.html.tmpl) and whine (reminder email message).
English Bugzilla commonly uses Bug while meaning Bug report. This has implications in verb usage. Essentially user does not 'create a bug' -- it already exists elsewhere, and one can only register it in Bugzilla database.
Important: do not rely on terms.bug being equal to Bug. Beyond its original purpose of bug tracking, Bugzilla is widely used in other applications. Always read translated phrases again and try to apply other terms: Problem, Request, Defect or Service call. If your language uses grammatic gender, you will reject many phrases which sound well with Bug.
Create and maintain a dictionary of Bugzilla terms in your language. Here are some examples, listing a number of terms to consider:
Localizing Templates
The template files are identified by the extension .tmpl. The are generated with Template Toolkit.
Currently, these templates contain code and localizable strings mixed together that makes the localization of Bugzilla a bit difficult: what is to be localized and what is not?
IMPORTANT: Use an UTF8 compliant editor like Gedit, Kate or Emacs under GNU/Linux systems or Notepad++ under Windows systems and localize the templates using UTF8 encoding.
Here are some examples to help you localizing the right stuff:
A good idea is to start with the localization of /template/en/default/global/variables.none.tmpl. This file contains several terms that will be substituted all around the templates files. You can see in this file lines like these:
[%# 1.0@bugzilla.org %] [%# The contents of this file are subject to the Mozilla Public # License Version 1.1 (the "License"); you may not use this file
DO NOT translate text located after the character #: the text located after this character is comment.
[% terms = { "bug" => "bug", "Bug" => "Bug", "abug" => "a bug", "Abug" => "A bug", "ABug" => "A Bug", "bugs" => "bugs", "Bugs" => "Bugs", "zeroSearchResults" => "Zarro Boogs found", "bit" => "bit", "bits" => "bits", "Bugzilla" => "Bugzilla" } %]
DO NOT translate terms here.
What is to be translated here, is the word after =>.
For instance:
"Bug" => "Bogue",
These terms will be used in the templates. Whenever you see expressions like $terms.ABug or $terms.bugs in templates, they will be replaced in the user interface with the value you put in this file.
Another file that is use by several templates is /template/en/default/global/field-descs.none.tmpl. You can see there lines like these:
[% PROCESS global/variables.none.tmpl %] [% field_descs = { "[Bug creation]" => "[$terms.Bug creation]", "actual_time" => "Actual Hours" "alias" => "Alias", "assigned_to" => "Assignee", ...... [% USE Bugzilla %] [% FOREACH bz_field = Bugzilla.get_fields() %] [% SET field_descs.${bz_field.name} = bz_field.description IF !field_descs.${bz_field.name}.defined %] [% END %]
DO NOT translate here PROCESS or USE. As a general rule, never translate capitalized words enclosed between [% and %].
As previoulsly, translate the word after the =>.
[% PROCESS global/variables.none.tmpl %] [% field_descs = { "[Bug creation]" => "[Date de création du $terms.bug]", "actual_time" => "Heures actuelles" "alias" => "Alias", "assigned_to" => "Responsable", ...... [% USE Bugzilla %] [% FOREACH bz_field = Bugzilla.get_fields() %] [% SET field_descs.${bz_field.name} = bz_field.description IF !field_descs.${bz_field.name}.defined %] [% END %]
Now, you can start translating the other templates.
Some other examples of what need to be translated:
[% title = BLOCK %]Delete Component '[% comp.name FILTER html %]' of Product '[% product.name FILTER html %]' [% END %] [% PROCESS global/header.html.tmpl title = title %] <table border="1" cellpadding="4" cellspacing="0"> <tr bgcolor="#6666FF"> <th valign="top" align="left">Field</th> <th valign="top" align="left">Value</th> </tr>
Localized example:
[% title = BLOCK %]Suppression du composant « [% comp.name FILTER html %] » du produit « [% product.name FILTER html %] » [% END %] [% PROCESS global/header.html.tmpl title = title %] <table border="1" cellpadding="4" cellspacing="0"> <tr bgcolor="#6666FF"> <th valign="top" align="left">Champ</th> <th valign="top" align="left">Valeur</th> </tr>
You will encounter many buttons you will want to localize. These are looking like this:
<input type="submit" id="create" value="Add"> <input type="hidden" name="action" value="new"> <input type="hidden" name='product' value="[% product.name FILTER html %]"> <input type="hidden" name="token" value="[% token FILTER html %]">
Whenever you see this, the only line that needs to be localize is the one with type="submit". DO NOT translate lines with type="hidden":
<input type="submit" id="create" value="Ajouter"> <input type="hidden" name="action" value="new"> <input type="hidden" name='product' value="[% product.name FILTER html %]"> <input type="hidden" name="token" value="[% token FILTER html %]">
Other common lines through the templates are text enclosed between an opening and a closing tag:
<td valign="top">Description du produit :</td> <TD VALIGN="top">[% IF product.disallow_new %]Oui[% ELSE %]Non[% END %]</td> <a title="Liste des [% terms.bugs %] pour le composant « [% comp.name FILTER html %] »" href="buglist.cgi?component=[% comp.name FILTER url_quote %]&product= [%- product.name FILTER url_quote %]">[% comp.bug_count %]</a>
If you have doubts, you can take a look at other working locales. Though they might have some errors left, they are working and noone reported bugs at the moment about localization :
...
TBD : add other tricky examples; some examples should be in non-Latin alphabet to popup clearly. Add other links towards working locales.
Hardcoded strings
TBD
Caveats
[% %] and [%+ %]
Generally, you should follow the English model, but if you need to change the order of [% %] in a line, you should be aware of those rules:
When two [% %] members are following each other, the second member won't be separated with a space from the first one, even if you separate them with a space:
[% ELSIF message_tag == "bug_duplicate_of" %] This [% terms.bug %] has been marked as a duplicate of [% terms.bug %] [% dupe_of FILTER html %]
For instance, the previous line of code will display in the browser as:
This bug has been marked as duplicate of bug12345
Instead you should add a "+" sign in the second member:
[% ELSIF message_tag == "bug_duplicate_of" %] This [% terms.bug %] has been marked as a duplicate of [% terms.bug %] [%+ dupe_of FILTER html %]
Will then be displayed as:
This bug has been marked as duplicate of bug 12345
This is the same when a [% %] member is at the beginning of a new line:
[% IF groups_added_to.size %] <li> The account has been added to the [% groups_added_to.join(', ') FILTER html %] group[% 's' IF groups_added_to.size > 1 %]. </li> [% END %]
The previous code will be shown as:
The account has been added to thebz_sudo_protect group.
You should instead put a "+" sign:
[% IF groups_added_to.size %] <li> The account has been added to the [%+ groups_added_to.join(', ') FILTER html %] group[% 's' IF groups_added_to.size > 1 %]. </li> [% END %]
So that the sentence is displayed as:
The account has been added to thebz_sudo_protect group.
Double quotes and single quotes
You should take care of the usage of the quotes in certain cases.
You shouldn't put quotes inside a pair of quotes. The following example will broke the user interface:
[% ELSIF message_tag == "buglist_adding_field" %] [% title = "Adding field to search page..." %] [% link = "Click here if the page "does not" redisplay automatically." %]
Instead, you can escape them with a backslash ("\"):
[% ELSIF message_tag == "buglist_adding_field" %] [% title = "Adding field to search page..." %] [% link = "Click here if the page \"does not\" redisplay automatically." %]
Or you can substitute the surrounding double quotes with single quotes:
[% ELSIF message_tag == "buglist_adding_field" %] [% title = "Adding field to search page..." %] [% link = 'Click here if the page "does not" redisplay automatically.' %]
${terms.bugs} , [% terms.bugs %] and $terms.bugs
Declensions
English only deals with one plural form and has no declension. Your locale might need to implement declensions and reorder words inside a sentence. WARNING: this is a bit tricky and making mistake here will broke your Bugzilla localization (i.e. some features might not function when your locale package will be installed).
Let's say we have the following:
[% IF !Param("allowbugdeletion") %] <p> Sorry, there [% IF comp.bug_count > 1 %] are [% comp.bug_count %] [%+ terms.bugs %] [% ELSE %] is [% comp.bug_count %] [%+ terms.bug %] [% END %] pending for this component. You should reassign [% IF comp.bug_count > 1 %] these [% terms.bugs %] [% ELSE %] this [% terms.bug %] [% END %] to another component before deleting this component. </p> [% ELSE %]
Here, the following expression comp.bug_count obviously gives the count number of bugs for a component. IF comp.bug_count > 1 means "if there are more than one bug".
Let's say your language has to deal with three plural forms and that the terms "bug" and "pending" should be declensed as well.
First, you'll have to populate the /template/en/default/global/variables.none.tmp file with the declensions for "bug", which would give something like:
[% terms = { "bug0" => "declension for zero bug", "bug" => "declension for one bug", "bug2" => "declension for two bugs", "bug3" => "declension for three bugs", "bugs" => "declension for more than three bugs",
Then, the previous code should look like:
[% IF !Param("allowbugdeletion") %] <p> Sorry, there [% IF comp.bug_count > 3 %] are [% comp.bug_count %] pending [% terms.bugs %] [% ELSE %] [% IF comp.bug_count == 0 %] is [% comp.bug_count %] pending [% terms.bug0 %] [% ELSE %] [% IF comp.bug_count == 1 %] is [% comp.bug_count %] pending [% terms.bug %] [% ELSE %] [% IF comp.bug_count == 2 %] are [% comp.bug_count %] pending [% terms.bug2 %] [% ELSE %] [% IF comp.bug_count == 3 %] is [% comp.bug_count %] pending [% terms.bug3 %] [% END %] for this component. You should reassign [% IF comp.bug_count > 1 %] these [% terms.bugs %] [% ELSE %] this [% terms.bug %] [% END %] to another component before deleting this component. </p> [% ELSE %]
Test
Release
Resources
Current active locales and maintainers
Moved to Bugzilla:L10n:Localization_Teams
Tools
- WinMerge
- WinMerge is an Open Source visual text file differencing and merging tool for Win32 platforms. With full UTF-8 support, it is highly useful for determing what has changed between project versions, and then merging changes between versions.
- Ediff
- Ediff is a GNU Emacs major mode. Ediff provides a convenient way for simultaneous browsing through the differences between a pair (or a triple) of files.