Titanium JIRA Archive
Alloy (ALOY)

[ALOY-728] Add a CLI command to extract i18n strings from alloy code and update the strings.xml files

GitHub Issuen/a
TypeNew Feature
PriorityLow
StatusClosed
ResolutionFixed
Resolution Date2013-07-22T21:45:29.000+0000
Affected Version/sn/a
Fix Version/sAlloy 1.2.0, 2013 Sprint 15
ComponentsTooling
Labelsnotable, qe-testadded
ReporterDaniel Sefton
AssigneeTony Lukasavage
Created2013-06-26T20:28:15.000+0000
Updated2013-07-30T00:00:35.000+0000

Description

update

The alloy extract-i18n command will inspect your TSS and JS files for instances of Titanium's localization functions: * Titanium.Locale.getString() * Ti.Locale.getString() * L() and when it finds them, it will take the i18n key from the first parameter (if it is a string) and add it as an entry to your target language's i18n strings.xml file. The syntax for calling alloy extract-i18n is as follows:
// Shows a before and after of your i18n file, does NOT write the changes
$ alloy extract-i18n  

// Writes the changes to "i18n/en/strings.xml"
$ alloy extract-i18n --apply   

// Specify a different language with another parameter ("en" is the default)
$ alloy extract-i18n es

// Specify "es" as the language and write the changes to "i18n/es/strings.xml"
$ alloy extract-i18n es --apply
This command, when applied with --apply, will only add new i18n entries. It will leave any existing entries untouched. So in general, alloy extract-i18n --apply is always safe, but just in case, we provide the preview functionality when not using --apply.

original

The alloy CLI tool is really useful and streamlines the development process. It should propose more tools to the Alloy developer. One tool that i would have loved to have on one of our last projects is a tool to extract internationalized strings from the alloy code (either tss or js files). The user could type:
$ alloy extract-i18n <language>
and this would introspect all the tss and js files, searching for i18n strings (those in the L() method) and adding the new strings to the i18n file for the requested language. If no language parameter is passed, the default language is used. In order to act safely with precious i18n files, the behavior could only display the i18n strings found in the project, and only modify the i18n files if the --force option is passed. This command:
$ alloy extract-i18n fr
Would display:
[DEBUG] app/styles/account/create.tss: 5 strings found.
[DEBUG] app/styles/account/edit.tss: 13 strings found.

[DEBUG] ...

[INFO] Found 52 unique i18n strings in the code.
[INFO] Did not write the i18n file - please pass the "--force" option.
[INFO] Completed i18n extraction. Found 12 new strings.
this means: "the tool has found 52 i18n strings in the app, 12 of them didn't exist in the i18n/fr/strings.xml file. This command:
$ alloy extract-i18n fr --force
Would display:
[DEBUG] app/styles/account/create.tss: 5 strings found.
[DEBUG] app/styles/account/edit.tss: 13 strings found.

[DEBUG] ...

[INFO] Found 52 unique i18n strings in the code.
[INFO] Did not write the i18n file - please pass the "--force" option.
[INFO] Completed i18n extraction. Found 12 new strings.
Which means the same like the command before, except that, in that case, the strings are appended to i18n/fr/strings.xml. note that: * the tool must be clever enough to remove duplicates (if a string is used several times, it must appear only once in the i18n file) * there could be another option to prune the messages that are not used in the app anymore, for instance --prune This command proposal is inspired by [Symfony](http://symfony.com)'s translation:update command ([see its code](https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php)), which allows to perform the same type of operation within this PHP framework.

Comments

  1. Tony Lukasavage 2013-07-22

    PR: https://github.com/appcelerator/alloy/pull/194 test app: https://github.com/appcelerator/alloy/tree/master/test/apps/testing/ALOY-728 Significant refactoring and changes were made to the original PR. The code was made much safer, cleaner, and more powerful. You can peruse the PR for full details, but the highlights are:

    Now supports searching for Ti.Locale.getString() and Titanium.Locale.getString(), not just L()

    The regex for matching more closely follows the guidelines set forth for i18n keys in the wiki

    Handles the situation where there's no i18n folder, or no strings.xml file

    Fixed a few argument handling bugs

    merge() code now merges successfully instead of overwriting the existing strings.xml file with only the new keys

    I created a new option "-A, --apply" for writing the i18n files, instead of "-f, --force}}. --force feels like you're doing something wrong, --apply feels cleaner.

    Calling alloy extract-i18n without --apply will show you a before and after of the target strings.xml file.

    Calling alloy extract-i18n --apply will not totally overwrite the existing strings.xml file, but will instead append nodes to the end of the list. This helps preserve the file formatting previous to using alloy extract-i18n.

    Underscore.js functions were used in a number of places to make the code a bit tighter.

    File writes use os.EOL instead of \n so that the files print correctly on all host OSes.

    Added a test app for ensuring it works as expected

    That should cover it. :) Functional testing should execute the following steps:

    Run the test app (ALOY-728)

    You should see a label on the screen that says "nothing assigned yet"

    After the app starts, delete the existing *i18n* folder

    Run alloy extract-i18n. You should see a before and after that looks like this:

       [INFO] ######## BEFORE ########
       <?xml version="1.0" encoding="UTF-8"?><resources>
       </resources>
       [INFO] ######## AFTER  ########
       <?xml version="1.0" encoding="UTF-8"?><resources>
       <?xml version="1.0" encoding="UTF-8"?><resources>
         <string name="foo">foo</string>
         <string name="foo1good">foo1good</string>
         <string name="found_me">found_me</string>
         <string name="thekey1">thekey1</string>
         <string name="thekey2">thekey2</string>
         <string name="thekey3">thekey3</string>
         <string name="tester">tester</string>
       </resources>
       </resources>
       

    Next run alloy extract-i18n --apply

    Ensure that after running the above command that the *i18n/en/strings.xml* file contains the contents that you saw in the previous "after" data.

    Run alloy extract-i18n --apply again. You should get a warning message telling you that there's nothing to do since the file is already up to date.

    Run alloy extract-i18n --apply es.

    Ensure that after running the above command that the *i18n/es/strings.xml* file contains the contents that you saw in the previous "after" data.

    Go into the *i18n/en/strings.xml* and change the value for the "tester" key to "I work!"

    Make sure that your testing emulator/simulator/device is set for english language

    Restart the app

    You should see a label that says "I work!" now

  2. Federico Casali 2013-07-30

    Verified as working as expected. Titanium SDK 3.1.2.v20130726192706 Alloy 1.2.0-alpha Appcelerator Studio 3.1.3.201307252418 CLI 3.1.2 Node 0.8.22 Android 4.1.2 device and iOS 5 (6.1.4) Closing.

JSON Source