{ "id": "116517", "key": "ALOY-728", "fields": { "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false }, "project": { "id": "11113", "key": "ALOY", "name": "Alloy", "projectCategory": { "id": "10400", "description": "Tools for developing applications", "name": "Tooling" } }, "fixVersions": [ { "id": "15402", "description": "Alloy 1.2.0, concurrent with SDK 3.1.0", "name": "Alloy 1.2.0", "archived": false, "released": true, "releaseDate": "2013-08-15" }, { "id": "15571", "description": "2013 Sprint 15", "name": "2013 Sprint 15", "archived": true, "released": true, "releaseDate": "2013-07-29" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2013-07-22T21:45:29.000+0000", "created": "2013-06-26T20:28:15.000+0000", "priority": { "name": "Low", "id": "4" }, "labels": [ "notable", "qe-testadded" ], "versions": [], "issuelinks": [], "assignee": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2013-07-30T00:00:35.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "13604", "name": "Tooling", "description": "Items related to Alloy tooling and workflow" } ], "description": "h2. update\r\n\r\nThe {{alloy extract-i18n}} command will inspect your TSS and JS files for instances of Titanium's localization functions:\r\n\r\n* Titanium.Locale.getString()\r\n* Ti.Locale.getString()\r\n* L()\r\n\r\nand 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. \r\n\r\nThe syntax for calling {{alloy extract-i18n}} is as follows:\r\n\r\n{code}\r\n// Shows a before and after of your i18n file, does NOT write the changes\r\n$ alloy extract-i18n \r\n\r\n// Writes the changes to \"i18n/en/strings.xml\"\r\n$ alloy extract-i18n --apply \r\n\r\n// Specify a different language with another parameter (\"en\" is the default)\r\n$ alloy extract-i18n es\r\n\r\n// Specify \"es\" as the language and write the changes to \"i18n/es/strings.xml\"\r\n$ alloy extract-i18n es --apply\r\n{code}\r\n\r\nThis 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.\r\n\r\n\r\nh2. original\r\n\r\nThe alloy CLI tool is really useful and streamlines the development process. It should propose more tools to the Alloy developer.\r\n\r\nOne 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).\r\n\r\nThe user could type:\r\n\r\n{code}\r\n$ alloy extract-i18n \r\n{code}\r\n\r\nand 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.\r\n\r\nIn 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.\r\n\r\nThis command:\r\n{code}\r\n$ alloy extract-i18n fr\r\n{code}\r\n\r\nWould display:\r\n{code}\r\n[DEBUG] app/styles/account/create.tss: 5 strings found.\r\n[DEBUG] app/styles/account/edit.tss: 13 strings found.\r\n\r\n[DEBUG] ...\r\n\r\n[INFO] Found 52 unique i18n strings in the code.\r\n[INFO] Did not write the i18n file - please pass the \"--force\" option.\r\n[INFO] Completed i18n extraction. Found 12 new strings.\r\n{code}\r\n\r\nthis means: \"the tool has found 52 i18n strings in the app, 12 of them didn't exist in the {{i18n/fr/strings.xml}} file.\r\n\r\n\r\nThis command:\r\n{code}\r\n$ alloy extract-i18n fr --force\r\n{code}\r\n\r\nWould display:\r\n{code}\r\n[DEBUG] app/styles/account/create.tss: 5 strings found.\r\n[DEBUG] app/styles/account/edit.tss: 13 strings found.\r\n\r\n[DEBUG] ...\r\n\r\n[INFO] Found 52 unique i18n strings in the code.\r\n[INFO] Did not write the i18n file - please pass the \"--force\" option.\r\n[INFO] Completed i18n extraction. Found 12 new strings.\r\n{code}\r\n\r\nWhich means the same like the command before, except that, in that case, the strings are appended to {{i18n/fr/strings.xml}}.\r\n\r\n\r\nnote that:\r\n* 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)\r\n* there could be another option to prune the messages that are not used in the app anymore, for instance {{--prune}}\r\n\r\n\r\nThis 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.", "attachment": [], "flagged": false, "summary": "Add a CLI command to extract i18n strings from alloy code and update the strings.xml files", "creator": { "name": "xavier", "key": "xavier", "displayName": "Xavier Lacot", "active": true, "timeZone": "Europe/Paris" }, "subtasks": [], "reporter": { "name": "dsefton", "key": "dsefton", "displayName": "Daniel Sefton", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "262727", "author": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "body": "PR: https://github.com/appcelerator/alloy/pull/194\r\ntest app: https://github.com/appcelerator/alloy/tree/master/test/apps/testing/ALOY-728\r\n\r\nSignificant 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:\r\n\r\n# Now supports searching for {{Ti.Locale.getString()}} and {{Titanium.Locale.getString()}}, not just {{L()}}\r\n# The regex for matching more closely follows the guidelines set forth for i18n keys in the wiki\r\n# Handles the situation where there's no i18n folder, or no strings.xml file\r\n# Fixed a few argument handling bugs\r\n# merge() code now merges successfully instead of overwriting the existing strings.xml file with only the new keys\r\n# 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.\r\n# Calling {{alloy extract-i18n}} without --apply will show you a before and after of the target strings.xml file. \r\n# 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}}.\r\n# Underscore.js functions were used in a number of places to make the code a bit tighter.\r\n# File writes use {{os.EOL}} instead of {{\\n}} so that the files print correctly on all host OSes.\r\n# Added a test app for ensuring it works as expected\r\n\r\nThat should cover it. :)\r\n\r\nFunctional testing should execute the following steps:\r\n\r\n# Run the test app (ALOY-728)\r\n# You should see a label on the screen that says \"nothing assigned yet\"\r\n# After the app starts, delete the existing *i18n* folder\r\n# Run {{alloy extract-i18n}}. You should see a before and after that looks like this:\r\n{code}\r\n[INFO] ######## BEFORE ########\r\n\r\n\r\n[INFO] ######## AFTER ########\r\n\r\n\r\n foo\r\n foo1good\r\n found_me\r\n thekey1\r\n thekey2\r\n thekey3\r\n tester\r\n\r\n\r\n{code}\r\n# Next run {{alloy extract-i18n --apply}}\r\n# 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.\r\n# 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.\r\n# Run {{alloy extract-i18n --apply es}}.\r\n# 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.\r\n# Go into the *i18n/en/strings.xml* and change the value for the \"tester\" key to \"I work!\"\r\n# Make sure that your testing emulator/simulator/device is set for english language\r\n# Restart the app\r\n# You should see a label that says \"I work!\" now ", "updateAuthor": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-07-22T21:45:29.000+0000", "updated": "2013-07-22T21:46:22.000+0000" }, { "id": "263822", "author": { "name": "fcasali", "key": "fcasali", "displayName": "Federico Casali", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Verified as working as expected.\n\nTitanium SDK 3.1.2.v20130726192706\nAlloy 1.2.0-alpha\nAppcelerator Studio 3.1.3.201307252418\nCLI 3.1.2\nNode 0.8.22\n\nAndroid 4.1.2 device and iOS 5 (6.1.4)\n\nClosing.", "updateAuthor": { "name": "fcasali", "key": "fcasali", "displayName": "Federico Casali", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-07-30T00:00:06.000+0000", "updated": "2013-07-30T00:00:06.000+0000" } ], "maxResults": 2, "total": 2, "startAt": 0 } } }