Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit f046ccabae0136c938396f2712a1a92e76d6dcc0 @rubenv committed Jul 29, 2013
@@ -0,0 +1,3 @@
+.*.swp
+/node_modules
+/tmp
@@ -0,0 +1,2 @@
+src
+test
@@ -0,0 +1,56 @@
+module.exports = (grunt) ->
+ @loadNpmTasks('grunt-contrib-clean')
+ @loadNpmTasks('grunt-contrib-coffee')
+ @loadNpmTasks('grunt-contrib-watch')
+ @loadNpmTasks('grunt-mocha-cli')
+ @loadNpmTasks('grunt-release')
+
+ @loadTasks('tasks')
+
+ @initConfig
+ coffee:
+ tasks:
+ options:
+ bare: true
+ expand: true
+ cwd: 'src'
+ src: ['*.coffee']
+ dest: 'tasks'
+ ext: '.js'
+
+ clean:
+ tasks: ['tasks']
+ tmp: ['tmp']
+
+ watch:
+ all:
+ files: ['src/**.coffee']
+ tasks: ['build']
+ test:
+ files: ['tasks/**.js', 'test/*{,/*}.coffee']
+ tasks: ['runtests']
+
+ mochacli:
+ options:
+ files: 'test/*_test.coffee'
+ compilers: ['coffee:coffee-script']
+ spec:
+ options:
+ reporter: 'spec'
+
+ nggettext_extract:
+ auto:
+ files:
+ 'tmp/test1.pot': 'test/fixtures/single.html'
+ 'tmp/test2.pot': ['test/fixtures/single.html', 'test/fixtures/second.html']
+ 'tmp/test3.pot': 'test/fixtures/plural.html'
+ 'tmp/test4.pot': 'test/fixtures/merge.html'
+ manual:
+ files:
+ 'tmp/test5.pot': 'test/fixtures/corrupt.html'
+
+ @registerTask 'default', ['test']
+ @registerTask 'build', ['clean', 'coffee']
+ @registerTask 'package', ['build', 'release']
+ @registerTask 'runtests', ['clean:tmp', 'nggettext_extract:auto', 'mochacli']
+ @registerTask 'test', ['build', 'runtests']
@@ -0,0 +1,22 @@
+Copyright (c) 2013 Ruben Vermeersch
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,66 @@
+# grunt-angular-gettext
+
+> Tasks for extracting/compiling angular-gettext strings.
+
+Used in combination with [`angular-gettext`](https://github.com/rubenv/angular-gettext).
+
+
+## Getting Started
+This plugin requires Grunt `~0.4.1`
+
+If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
+
+```shell
+npm install grunt-angular-gettext --save-dev
+```
+
+Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
+
+```js
+grunt.loadNpmTasks('grunt-angular-gettext');
+```
+
+## The "nggettext_extract" task
+
+Extracts translations from your Angular.JS templates and generates a gettext-compatible `.pot` file.
+
+In your project's Gruntfile, add a section named nggettext_extract` to the data object passed into `grunt.initConfig()`.
+
+```js
+grunt.initConfig({
+ nggettext_extract: {
+ pot: {
+ 'po/myApp.pot': ['src/views/*.html']
+ },
+ },
+})
+```
+
+## Contributing
+All code lives in the `src` folder and is written in CoffeeScript. Try to stick to the style conventions used in existing code.
+
+Tests can be run using `grunt test`. A convenience command to automatically run the tests is also available: `grunt watch`. Please add test cases when adding new functionality: this will prove that it works and ensure that it will keep working in the future.
+
+## License
+
+ (The MIT License)
+
+ Copyright (C) 2013 by Ruben Vermeersch <ruben@savanne.be>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
@@ -0,0 +1,50 @@
+{
+ "name": "grunt-angular-gettext",
+ "description": "Tasks for extracting/compiling angular-gettext strings.",
+ "version": "0.0.0",
+ "homepage": "https://github.com/rubenv/grunt-angular-gettext",
+ "author": {
+ "name": "Ruben Vermeersch",
+ "email": "ruben@savanne.be",
+ "url": "http://savanne.be"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/rubenv/grunt-angular-gettext.git"
+ },
+ "bugs": {
+ "url": "https://github.com/rubenv/grunt-angular-gettext/issues"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/rubenv/grunt-angular-gettext/blob/master/LICENSE"
+ }
+ ],
+ "main": "Gruntfile.js",
+ "engines": {
+ "node": ">= 0.8.0"
+ },
+ "scripts": {
+ "test": "grunt test"
+ },
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-contrib-clean": "~0.4.0",
+ "grunt-contrib-coffee": "~0.7.0",
+ "grunt-contrib-watch": "~0.5.1",
+ "grunt-mocha-cli": "~1.0.6",
+ "grunt-release": "~0.4.0",
+ "coffee-script": "~1.6.3"
+ },
+ "peerDependencies": {
+ "grunt": "~0.4.1"
+ },
+ "keywords": [
+ "gruntplugin"
+ ],
+ "dependencies": {
+ "node-po": "~0.1.2",
+ "jquery": "~1.8.3"
+ }
+}
@@ -0,0 +1,4 @@
+module.exports = (grunt) ->
+ grunt.registerMultiTask 'nggettext_compile', 'Compile strings from .po files', () ->
+ console.log @files
+
@@ -0,0 +1,40 @@
+jquery = require 'jquery'
+po = require 'node-po'
+
+$ = jquery.create()
+
+module.exports = (grunt) ->
+ grunt.registerMultiTask 'nggettext_extract', 'Extract strings from views', () ->
+ @files.forEach (file) ->
+ failed = false
+ catalog = new po()
+
+ strings = {}
+
+ addString = (file, string, plural = null) ->
+ if !strings[string]
+ strings[string] = new po.Item()
+ item = strings[string]
+ item.msgid = string
+ item.references.push(file) if file not in item.references
+ if plural && plural != ''
+ if item.msgid_plural && item.msgid_plural != plural
+ grunt.log.error "Incompatible plural definitions for #{string}: #{item.msgid_plural} / #{plural} (in: #{item.references.join(", ")})"
+ failed = true
+ item.msgid_plural = plural
+ item.msgstr = ["", ""]
+
+ file.src.forEach (input) ->
+ src = grunt.file.read(input)
+ $(src).find('*[translate]').each (index, n) ->
+ node = $(n)
+ return if !node.attr('translate')
+ str = node.html()
+ plural = node.attr('translate-plural')
+ addString(input, str, plural)
+
+ for key, string of strings
+ catalog.items.push(string)
+
+ if !failed
+ grunt.file.write(file.dest, catalog.toString())
@@ -0,0 +1,5 @@
+module.exports = function(grunt) {
+ return grunt.registerMultiTask('nggettext_compile', 'Compile strings from .po files', function() {
+ return console.log(this.files);
+ });
+};
@@ -0,0 +1,62 @@
+var $, jquery, po,
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+jquery = require('jquery');
+
+po = require('node-po');
+
+$ = jquery.create();
+
+module.exports = function(grunt) {
+ return grunt.registerMultiTask('nggettext_extract', 'Extract strings from views', function() {
+ return this.files.forEach(function(file) {
+ var addString, catalog, failed, key, string, strings;
+ failed = false;
+ catalog = new po();
+ strings = {};
+ addString = function(file, string, plural) {
+ var item;
+ if (plural == null) {
+ plural = null;
+ }
+ if (!strings[string]) {
+ strings[string] = new po.Item();
+ }
+ item = strings[string];
+ item.msgid = string;
+ if (__indexOf.call(item.references, file) < 0) {
+ item.references.push(file);
+ }
+ if (plural && plural !== '') {
+ if (item.msgid_plural && item.msgid_plural !== plural) {
+ grunt.log.error("Incompatible plural definitions for " + string + ": " + item.msgid_plural + " / " + plural + " (in: " + (item.references.join(", ")) + ")");
+ failed = true;
+ }
+ item.msgid_plural = plural;
+ return item.msgstr = ["", ""];
+ }
+ };
+ file.src.forEach(function(input) {
+ var src;
+ src = grunt.file.read(input);
+ return $(src).find('*[translate]').each(function(index, n) {
+ var node, plural, str;
+ node = $(n);
+ if (!node.attr('translate')) {
+ return;
+ }
+ str = node.html();
+ plural = node.attr('translate-plural');
+ return addString(input, str, plural);
+ });
+ });
+ for (key in strings) {
+ string = strings[key];
+ catalog.items.push(string);
+ }
+ if (!failed) {
+ return grunt.file.write(file.dest, catalog.toString());
+ }
+ });
+ });
+};
@@ -0,0 +1,79 @@
+assert = require 'assert'
+po = require 'node-po'
+fs = require 'fs'
+grunt = require 'grunt'
+
+describe 'Extract', ->
+ it 'Extracts strings from views', (done) ->
+ assert(fs.existsSync('tmp/test1.pot'))
+
+ po.load 'tmp/test1.pot', (catalog) ->
+ assert.equal(catalog.items.length, 1)
+ assert.equal(catalog.items[0].msgid, 'Hello!')
+ assert.equal(catalog.items[0].msgstr, '')
+ assert.equal(catalog.items[0].references.length, 1)
+ assert.equal(catalog.items[0].references[0], 'test/fixtures/single.html')
+ done()
+
+ it 'Merges multiple views into one .pot', (done) ->
+ assert(fs.existsSync('tmp/test2.pot'))
+
+ po.load 'tmp/test2.pot', (catalog) ->
+ i = catalog.items
+ assert.equal(i.length, 2)
+ assert.equal(i[0].msgid, 'Hello!')
+ assert.equal(i[1].msgid, 'This is a test')
+ done()
+
+ it 'Merges duplicate strings with references', (done) ->
+ assert(fs.existsSync('tmp/test2.pot'))
+
+ po.load 'tmp/test2.pot', (catalog) ->
+ i = catalog.items
+ assert.equal(i.length, 2)
+
+ assert.equal(i[0].msgid, 'Hello!')
+ assert.equal(i[0].references.length, 2)
+ assert.equal(i[0].references[0], 'test/fixtures/single.html')
+ assert.equal(i[0].references[1], 'test/fixtures/second.html')
+
+ assert.equal(i[1].msgid, 'This is a test')
+ assert.equal(i[1].references.length, 1)
+ assert.equal(i[1].references[0], 'test/fixtures/second.html')
+ done()
+
+ it 'Extracts plural strings', (done) ->
+ assert(fs.existsSync('tmp/test3.pot'))
+
+ po.load 'tmp/test3.pot', (catalog) ->
+ i = catalog.items
+ assert.equal(i.length, 1)
+
+ assert.equal(i[0].msgid, 'Bird')
+ assert.equal(i[0].msgid_plural, 'Birds')
+ assert.equal(i[0].msgstr.length, 2)
+ assert.equal(i[0].msgstr[0], '')
+ assert.equal(i[0].msgstr[1], '')
+ done()
+
+ it 'Merges singular and plural strings', (done) ->
+ assert(fs.existsSync('tmp/test4.pot'))
+
+ po.load 'tmp/test4.pot', (catalog) ->
+ i = catalog.items
+ assert.equal(i.length, 1)
+
+ assert.equal(i[0].msgid, 'Bird')
+ assert.equal(i[0].msgid_plural, 'Birds')
+ assert.equal(i[0].msgstr.length, 2)
+ assert.equal(i[0].msgstr[0], '')
+ assert.equal(i[0].msgstr[1], '')
+ done()
+
+ it 'Warns for incompatible plurals', (done) ->
+ grunt.util.spawn {
+ cmd: "grunt",
+ args: ["nggettext_extract:manual"]
+ }, (err) ->
+ assert(!fs.existsSync('tmp/test5.pot'))
+ done(err)
Oops, something went wrong.

0 comments on commit f046cca

Please sign in to comment.