Tutorials

From BabelWiki

Jump to: navigation, search

Contents


How to localize the initial description of an extension

IMPORTANT NOTE: this tutorial is still valid but there is another way of localizing metadata in the install.rdf since Gecko 1.9 . Please read this article https://developer.mozilla.org/en/Localizing_extension_descriptions


This short tutorial is dedicated to those who already know basics about editing and localizing an extension for Gecko-engined apps : Firefox, Thunderbird, Mozilla. It is heavily inspired from an article of Mozilla Developer Center.

Here are the steps to localize the description of an extension that we shall call tournicoti

1. Check that the extension has this tree structure , else create what is missing:

Tree structure


2. Write this line in prefs.js file:

pref("extensions.{616f2aa8-9674-4009-90de-94ce4ea9d29a}.description","chrome://tournicoti/locale/tournicoti.properties"); ...where the red string is the extension ID number that you can copy/paste from the install.rdf

If you used a pseudo-mail address as id for your extension, remove the special curly brackets, it should be something like:

pref("extensions.tournicoti.extension@mydomain.org.description", "chrome://tournicoti/locale/tournicoti.properties");

3. Write this line in tournicoti.properties file:

extensions.{616f2aa8-9674-4009-90de-94ce4ea9d29a}.description=An extension that makes you dizzy.

or

extensions.tournicoti.extension@mydomain.org.description= An extension that makes you dizzy.


Now you have just to re-zip correctly the whole stuff and that's all!

How to localize strings included in a .js file

The problem is : sometimes, extensions have locale folders with localized strings, but some little bits of words and sentences remain, which you cannot transform in entities as usual, because they belong to a .js file.

Suppose you have found these strings nested in a .js file:

if ( password == userPassword ) {
oPrefs.setBoolPref("access.authenticated", true);
}
else {
alert ("Invalid password");
......
function clear()
{
sure = confirm("Are you sure?");
First, you have to find or create a myextension.properties file in your locale folder. Then you simply write variable names and the sentences or words that should appear to the final user.

Something like :

wrongPassMessage=Invalid password
areYouSureMessage=Are you sure?

(where Invalid password and Are you sure? are the strings to be displayed to the final user)
Notice : a simple = sign is enough

Now you go back to the .js file where the strings to be localized are nested.
At the very beginning of the file you create one string bundle with the address of the properties file where to find strings.


var gmyextensionBundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);

var _bundle = gmyextensionBundle.createBundle("chrome://myextension/locale/myextension.properties");

You can now use your string substitutes in the .js where they are needed: see examples below


if ( password == userPassword ) {
oPrefs.setBoolPref("access.authenticated", true);
}
else {
alert (_bundle.GetStringFromName("wrongPassMessage"));

function clear()
{
sure = confirm(_bundle.GetStringFromName("areYouSureMessage"));


How to localize strings included in a .py file

Original embedded string in a Python file

   def _asktabwidth(self):
       dialogproxy = components.classes['@activestate.com/asDialogProxy;1'].\
           getService(components.interfaces.asIDialogProxy)
       tabwidth = self._view.prefs.getLongPref('tabWidth')
       value = dialogproxy.prompt("Tab Width (between 0 and 16)", str(tabwidth), "OK", None)
       if value is not None:
           return int(value)
       else:
           return value



editor/koLanguageCommandHandler.py

     def _asktabwidth(self):
         dialogproxy = components.classes['@activestate.com/asDialogProxy;1'].\
             getService(components.interfaces.asIDialogProxy)
               bundle = components.classes["@mozilla.org/intl/stringbundle;1"].\
               getService(components.interfaces.nsIStringBundleService).\
               createBundle("chrome://komodo/locale/editor.properties")
         tabwidth = self._view.prefs.getLongPref('tabWidth')
      msg = bundle.GetStringFromName("tabWidthBetween0and16.message")
      value = dialogproxy.prompt(msg, str(tabwidth), "OK", None)
         if value is not None:
             return int(value)
         else:

chrome/komodo/locale/en-US/editor.properties

tabWidthBetween0and16.message=Tab Width (between 0 and 16)



How to localize strings with variable included in a .js file

Suppose you have this kind of message to localize in a javascript file

 }
     if (!osPath.exists(extract.Location)) {
         alert("The '"+extract.Location+"' directory does not exist. Please choose the "+regular.Path+ " default directory");
           return false;
        }
       return true;
    }

If you use the classical method, translators will have 3 different strings to translate

  • The
  • directory does not exist. Please choose the
  • as default directory

It may be difficult for certain languages to keep the final translation valid, because of the syntax inherent to each lang: the location of sentence elements may vary heavily. Hence this solution :


1. This must be set on top of the javascript file

//------------- Note the locale/*.properties file where strings are externalized --/
var _bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
    .getService(Components.interfaces.nsIStringBundleService)
    .createBundle("chrome://tournicoti/locale/tournicoti.properties");


2. Change the original javascript line for this one

          alert(_bundle.formatStringFromName("theDirectoryDoesNotExist", ["extract.Location", "regular.Path"], 2));

In this example:

  • theDirectoryDoesNotExist is the key referred to in the locale/tournicoti.properties file
  • extractLocation and regularPath are the two variables
  • 2 is the number of variables that are to be replaced in the string



3. Have this key in the locale/tournicoti.properties file

theDirectoryDoesNotexist=The '%S' directory does not exist. Please choose the %S default directory

...where translators can move the %S token just where they want to match their language syntax :)

The first %S corresponds to first array element, and so on... If you need to pass same string twice (or more than twice) you need to specify another %S and add again the same variable to array which is between square brackets in the javascript line. For example

["extract.location", "regular.path", "extract.location", "extract.location"]

The '%S' directory does not exist. Please choose the %S default directory blah blah %S and again blah blah %S


Many thanks to Davide Ficano who gave me this tip among so many !

How to resize a xul pref dialog according to every language


The problem

Preferences Dialog is not resizable (see Bugzilla #122345), so it happens every now and then that the size of the window can be perfect for English language but not so perfect for other languages, once translation is done.
Here is a simple example:

This is the original en-US dialog

English language pref dialog

This is the French version, same size. One sentence is longer, so the last word on the right is sadly cut, as well as the right-hand side frame border..French pref dialog trimmed


A simple solution

Important: there is another solution provided by teo for more advanced coders. Just read this thread http://www.babelzilla.org/forum/index.php?showtopic=3229

All you have to do is to add a style attribute to your prefwindow and make the width a localizable entity. Translors will have to determine the optimum value to give to this entity in their locale, they will adjust after some tests so that it matches perfectly for their own language.

Here is one code example

in prefs.xul

<!DOCTYPE prefwindow SYSTEM "chrome://attachmentextractor/locale/attachmentextractor-prefs.dtd" >
<prefwindow type="prefwindow"
id="attachmentextractorPreferences"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
windowtype="attachmentextractor:preferences"
title="&attachmentextractor.settings.windowtitle;"
style = "width:&attachmentextractor.settings.width;; height: 55em;">

in attachmentextractor-prefs.dtd in en-US locale

<!ENTITY attachmentextractor.settings.width "80ex">

80 ex is not enough for French language, it needs "100ex" in the fr-FR locale, so now the sentence is complete

French size OK


Note about units

Width (or height) can be set in various units and is generally in px or em, but it seems it is recommended to use ex. See this article in Mozilla Knowledge Base


How to localize strings from the help.html file of an extension


If you are reading this, you are a developer that deserves consideration, because you have documented your extension, which is a pretty good idea to make it more user-friendly.

So you have a help.html or howto.html file shipped with your extension. Let's suppose you have it in the locale folder, so that translators may do their work and spread it worldwide.

Then the problem is:

  • a help.html file in each language subfolder makes your extension bigger in size (consider we have several extensions on BabelZilla that include more than 25 locales)
  • translators are not developers, they are generally uncomfortable at the idea of sneaking inside html code, slaloming between tags and attributes to get strings to translate. Moreover, encoding errors may happen when editing an html document.

The solution can be:

  • Transform your html file into a help.xhtml one and move it into the content folder
  • Entitize all the strings of the xhtml file and drop them in a locale/help.dtd file

Let's see how to do that.

We shall take outliner extension by Roman Mashirov as a test case.
First, create a help.dtd file or use an already existing .dtd in the locale folder, and move the .html to the content folder. Then follow these simple steps:

Make a xhtml file out of a html one


You have to delete everything before the <head> tag and paste this piece of code instead:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html SYSTEM "chrome://outliner/locale/help.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

of course, you can put your extension name and the dtd name you wish.

The DOCTYPE part is important because it tells the extension where to find strings |}

Check the validity of your new xhtml file

Xhtml syntax seems to be more demanding than plain html in terms of tags correctness. Check every closing tag especially, else you will encounter a parsing error. To check your xhtml file, just open it with Firefox and if there is anything wrong, your favourite browser will display a useful debugging message such as : error on line x, found , expected </br>.

You will also take a special care about html entities that must be replaced with their decimal equivalent. Examples:


 & copy; --> & #169;
 & amp; --->& #38;
 & nbsp; --->& #160;

Transform the strings in localizable entities

Now it is just the same process as when moving strings from content/*.xul to locale/*.dtd. Each time you encounter a message for the user interface :


1. Use an entity instead.

<title>Outliner Help</title>
<p>This is Outliner extension for Mozilla, or at least some day it will be. For now this is just notekeeper with notes arranged in tree.
</p>
<title>&outliner.help.title;</title>
<p>&outliner.help.info;</p>

Make some adjustments

  • remember to modify the path of your help file where it is invoked (usually in a .js file)
chrome://outliner/locale/help.html  --->  chrome://outliner/content/help.xhtml

  • if you have linked images, javascript or css in your document, check their new path too.
  • you may have to add some non-breaking spaces here and there for a better layout.
  • In case you need more here are the original outliner extension and the modified one


...And you have done with it. Congratulations!

How to translate the accesskeys for an extension

What is an accesskey?

 An accesskey is an underlined letter in a user interface string. It tells which key must be pressed on the keyboard to get the same result as a mouse-click.

On the screenshot below, striking Alt+A (Ctrl+A for Mac users) will check  "Automatically log in. "

Correct choice of English AK‎

Here are the relative codelines in the .dtd file of the en-US locale, where you can see clearly letters "C", "A" and "u" as separate entities:

Code lines for correct accesskeys

>>>>> Read more (en)


Why must accesskeys  be translated?

An accesskey is a letter from the word or string which is displayed. And obviously this word or string is not the same in other languages than English. So the same letter may or may not appear in another language.

If we have "C" as accesskey for "Checked", we cannot find any "C" in the French translation "Vérifier" nor in the Swedish "Kontrollera".

Here is an example of what happens if we choose not to translate accesskeys, leaving the en-US letters in the fr-FR translation:

 

incorrect French ak

 

An ugly accesskey letter appears between brackets at the end of the string. Else the target accesskey letter is found and underlined somewhere else in the string,  but not necessarily in a user-friendly position...  Now this is a more correct choice for the French user:

 

Correct output for French

 

 

Here you can see the relative .dtd lines:

 

Correct code for French

... and this is how it appears in the WTS on BabelZilla:

 


Lines on the WTS

 

 

 

How to choose accesskeys for your language?

  • Always prefer the first letter of a string, whenever it is possible, at least the first letter of a significant word of a string.

 

 

  • Never use twice the same accesskey in the same window, otherwise it simply will not work. That is why the final displaying must always been checked and tested.

 

 

  • Choose it easy to see and easy to remember. Avoid letters where the underline is difficult to notice, such as p, g, I, etc. (p, g, l... . Also don't use diacritic, diaeresis and ligature characters (well let's say special characterssuch as É Û þ Ñ....

 

 

  • Note that the accesskey is case sensitive. When you use upper case character as accesskey, but in the phrase there is only lower case, as accesskey will be used first lower case character. If you use lower case character, but in the phrase are 2 or more same characters, as accesskey also will be used first character.




>>>>> Read more (en)

 

- A Goofy minihowto -

How can I use a smart script to build my extension ?

The little story (you can skip it)

Mr Frederik Vanderstraeten who is the developer of Country Lookup extension for Thunderbird encountered one familiar annoyance while submitting an updated version of his extension on the WTS. As he neglected to add the path to every locale in his chrome.manifest, some of the language files were not recognized, though duly included in the submitted xpi. Note that the same problem may have occured for a final user if the extension was released on a public site without all languages registered.

This happens every now and then, and who can blame a developer about that?

The interesting point in the episode is: our submitter wrote some additional lines to his build script to make this annoying issue fixed.

And he is kind enough to share his script with everyone.

The precious script

  • It's a command-line PHP script.
  • It must be run from a shell script.
  • It has some cool functions, such as
    • automatically updating a website
    • making a seperate version for AMO without updateURL
    • warning when a locale isn't in chrome.manifest.
  • If you want more information on how it works, feel free to e-mail the author. THANKS FREDERIK !


Now you can Download (right-click and choose Save link as) and enjoy [img]/style_emoticons/default/smile.gif[/img]