YALT 2 | Your Scripting Localization Engine
July 24, 2010 | YALT | en | fr
In August 2009, we introduced YALT —“Yet Another Localization Technique”— as an alternate way to manage multilingual strings and automatic localization in our InDesign scripts. I use it in my everyday projects and I definitely abandoned the native ExtendScript L10N feature, which I believe is too restrictive and not so clever. YALT is a lightweight, quickly includable and easy-to-use tool. Month after month I improved the snippet with the result that it now has nothing to do with the original version! Maybe it's time to share YALT 2.1 with you. . .
The basic YALT principle is: “Write all your interface code with English strings, and perform separately the localization.” YALT is a piece of code that you just need to put at the beginning of your script. It offers a reserved space and a special syntax which allows to set translated strings for each English key string that you have placed into your client code. You can add as many languages as necessary. YALT takes care of arousing the right translation according to the InDesign locale it automatically detects. If a key string is not translated into the target language, or if the target language is not available in the translation table, then YALT keeps the string in its default original state. That's the general pattern.
There are only two conditions in using that technology:
• Your translation table must be fully encoded in the YALT block by using a JavaScript single line comments syntax (see below).
• In your code, every key string should be enclosed in parentheses and preceded by two underscores, like this: __("Here's a key string")
.
Let's study a simplified example:
// THE YALT BLOCK //################################### var L10N = L10N||(function(ln) { //============================ // <L10N> :: FRENCH_LOCALE :: GERMAN_LOCALE //============================ // Good morning! :: Bonjour ! :: Guten Morgen! // Update :: Actualiser :: Aktualisieren // Cancel :: Annuler :: Abbrechen // </L10N> /* Then we have the whole YALT code. */ })(); // THE CLIENT CODE //################################### alert( __("Good morning!") ); var str = __("Update"); //etc.
You may have noticed that the structure of YALT 2 slightly differs from the original version. Now you have to set the translation table within the body of the L10N
object. It is a crucial change, because now the script grabs the translated fields using the toString()
method of the container function, rather than opening and parsing the script file! It is a considerable improvement in performance, and by the way an interesting fact to disclose: within any user-function body, arguments.callee.toString()
returns the entire code of the function itself including comments.
Syntax
The inner form of the translation table does not differ from the previous versions. Always use the header's syntax:
// <L10N> :: FRENCH_LOCALE :: GERMAN_LOCALE :: etc.
which declares all additional supported languages. Follow the exact uppercased name of the XXX_LOCALE
identifier as provided in the Locale
enumerator of the InDesign Scripting DOM.
The field splitter is still ' :: '
(space colon colon space). Note that you can change it by tweaking the SP
variable —but I discourage you to hack the core if you're not familiar with JavaScript closures.
Then, write each translation row on one line (as long as it is.) The first field is the default key string, while the next fields contain the respective translated strings into the corresponding languages, in the order that the header specifies. Don't forget to start each line by '// '
(slash slash space) and to separate your localized strings by the splitter (' :: '
).
. . . // Good morning! :: Bonjour ! :: Guten Morgen! // Update :: Actualiser :: Aktualisieren . . .
Advanced features
• Passing String Parameters. — One of the main improvement in YALT 2.1 is that you can now inject parameters within the localized strings by using %1
, %2
, etc., as placeholders:
// In the translation table //--------------------------------------- // Good morning %1! :: Bonjour %1 ! // unavailable :: indisponible // corrupted :: corrompu // The file %1 is %2! :: Le fichier %1 est %2 ! ... // In the client code //--------------------------------------- var userName = "Marc"; alert( __("Good morning %1!", userName) ); var fName = "test.indd"; var fStatus = __("corrupted"); var msg = __("The file %1 is %2!", fName, fStatus); //etc.
• “Pure ASCII” Syntax. — If, like me, you want to keep your script “100% ASCII” to prevent perennial cross-platform issues in character encoding, then simply use the \uHHHH
form in your translated fields. YALT knows how to deal with it:
// Checksum :: Somme de contr\u00F4le :: Pr\u00FCfziffer
Of course HHHH
represents the 4-digits hexadecimal Unicode value of the desired character.
• Testing YALT on a Specific Locale. — While YALT auto-detects the InDesign application locale in runtime and uses it to transparently translate the key strings into the corresponding language, script developers may want to force another locale for checking. To do so, pass the locale as a String
argument in the final parenthesis of the YALT block:
. . . The YALT Block . . . })('RUSSIAN_LOCALE'); // test the Russian translation -if available!
In normal use, the final parenthesis contains: /*'ENGLISH_LOCALE'*/
—which means that no argument is required. Note also that YALT returns a JavaScript object, L10N
, which you can use in the client code to get the actual locale in the context the script is running: L10N.locale
provides the InDesign locale string: "GERMAN_LOCALE"
, "ENGLISH_LOCALE"
, etc.
• Using YALT in a Jsxbin. — The basic YALT process won't work anymore in Binary JavaScript compiled scripts, because in this mode no function can access to its own body. So, if you deploy your script as a jsxbin, you first need to compile the translation table in a regular JS object. Here is how to do that:
1. Backup the source code in a separate file.
2. Open the file in your script editor and find the line:
//prompt( "YALT-to-JSXBIN Helper",'var lines='+lines.toSource()+';' );
.
3. Uncomment the line by removing the //
.
4. Run the script from InDesign and copy the prompt contents.
5. Go back to the code, remove the whole prompt...
statement, and replace the line just above by the contents of the clipboard: var lines=...
6. You can also remove the original translation table (all the commented lines).
7. Check that the final script still works and correctly displays the localized strings.
8. Finally, compile the file from ESTK to jsxbin.
Comments
Le principe est astucieux et je serais Mr Adobe, je pense que je m'empresserais de le généraliser.
Bon, je ne suis pas Mr Adobe et ma maman ne se prénomme pas Liliane.
Bravo Marc sur cette manière de fonctionner à l'envers…
Bon D..., un nouveau trésor mis à jour !
Merci beaucoup pou cette technique dont j'ai eu l'honneur de goûter en avant-première.
La méthode de Marc est bien plus pratique que les commandes natives de scripting pour la localisation.