├── .npmignore ├── test ├── fixtures │ ├── line_numbers.html │ ├── ejs.ejs │ ├── comments2.html │ ├── erb.erb │ ├── custom-attribute.html │ ├── context.html │ ├── module.js │ ├── delim.html │ ├── quotes.html │ ├── complete │ │ ├── README.md │ │ └── issue23.html │ ├── empty.html │ ├── js-in-script-tags │ │ ├── no-type.html │ │ ├── not-javascript.html │ │ └── type-javascript.html │ ├── jsp.jsp │ ├── php.php │ ├── tag.tag │ ├── template-literal-separated.js │ ├── strip.html │ ├── issue_188.html │ ├── line_numbers.js │ ├── second.html │ ├── custom.js_extension │ ├── escaped-quotes.html │ ├── custom_module.js │ ├── custom_method.js │ ├── duplicate-comments.html │ ├── tapestry.tml │ ├── comments.html │ ├── source.js │ ├── filter-custom.html │ ├── filter.html │ ├── single.html │ ├── custom.extension │ ├── custom_marker_name.js │ ├── inline-templates.html │ ├── multifilter-custom.html │ ├── multifilter.html │ ├── translate-element.html │ ├── context-custom.html │ ├── concat.js │ ├── es6-export.js │ ├── merge.html │ ├── ts.tsx │ ├── escaped_quotes-custom.html │ ├── escaped_quotes.html │ ├── corrupt.html │ ├── filter-custom-standard-attribute.html │ ├── filter-in-multiple-expression-attributes-custom.html │ ├── issue_188.ts │ ├── plural.html │ ├── filter-in-multiple-expression-attributes.html │ ├── es6-import.js │ ├── bind-once.html │ ├── multifilter-custom-standard-attribute.html │ ├── custom_marker_name_plural.js │ ├── multi-line-comments.js │ ├── escaped_quotes-custom-standard-attribute.html │ ├── filter-data-attributes.html │ ├── ts.ts │ ├── filter-in-multiple-expression-attributes-custom-standard-attribute.html │ ├── entities.html │ ├── sort.html │ ├── deeppath_catalog.js │ ├── deeppath_catalog_invalid.js │ ├── template-literal-component.js │ ├── DecoratedClassWithProperties.ts │ ├── es6-dynamic-import.js │ ├── custom_marker_names.js │ ├── catalog.js │ ├── ngif.html │ ├── no_delimiter.html │ ├── source-property.js │ ├── depth │ │ └── fr.po │ ├── custom_marker_names_plural.js │ ├── obsolete.po │ ├── es6-class.js │ ├── empty.po │ ├── fuzzy.po │ ├── data.html │ ├── context.po │ ├── fr.po │ ├── nl.po │ ├── inconvertible_html_entities.po │ ├── comments.js │ ├── comments.ts │ ├── widget.html │ └── convertible_html_entities.po ├── utils.js ├── extract_template_literal.js ├── extract_quotes.js ├── issue_188.js ├── extract_javascript_custom_module_method.js ├── extract_multiline.js ├── extract_complete.js ├── extract_plurals.js ├── extract_line_numbers.js ├── extract_custom_filters.js ├── extract_filters.js ├── extract_comments.js ├── extract_extensions.js ├── extract_custom_filter_standard_attribute.js ├── extract_javascript.js ├── extract_regex.js ├── compile.js └── extract.js ├── .gitignore ├── index.js ├── .travis.yml ├── .jshintrc ├── LICENSE ├── package.json ├── .jscs.json ├── Gruntfile.js ├── README.md └── lib ├── compile.js └── extract.js /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | tmp 3 | Gruntfile.coffee 4 | .npmignore 5 | -------------------------------------------------------------------------------- /test/fixtures/line_numbers.html: -------------------------------------------------------------------------------- 1 |
Line 1
2 | -------------------------------------------------------------------------------- /test/fixtures/ejs.ejs: -------------------------------------------------------------------------------- 1 | <%# EJS comment %> 2 | EJS Link 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | .idea 3 | *.iml 4 | /node_modules 5 | /tmp 6 | /test/fixtures/*.mo 7 | .project 8 | -------------------------------------------------------------------------------- /test/fixtures/comments2.html: -------------------------------------------------------------------------------- 1 |

Translate this

2 | -------------------------------------------------------------------------------- /test/fixtures/erb.erb: -------------------------------------------------------------------------------- 1 | <%# ERB comment %> 2 | <% @foo %> 3 | message 4 | -------------------------------------------------------------------------------- /test/fixtures/custom-attribute.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | -------------------------------------------------------------------------------- /test/fixtures/context.html: -------------------------------------------------------------------------------- 1 |
Hello!
2 |
Hello!
3 | -------------------------------------------------------------------------------- /test/fixtures/module.js: -------------------------------------------------------------------------------- 1 | define(['angular'], function (angular) { 2 | return angular.module('myApp', []); 3 | }) -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Compiler: require('./lib/compile'), 3 | Extractor: require('./lib/extract') 4 | }; 5 | -------------------------------------------------------------------------------- /test/fixtures/delim.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | [['Hello'|translate]] 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/fixtures/quotes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello "world"!

4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "node" 5 | 6 | before_script: 7 | - npm install -g grunt-cli 8 | -------------------------------------------------------------------------------- /test/fixtures/complete/README.md: -------------------------------------------------------------------------------- 1 | These are larger examples, coming from real applications. They mainly serve as 2 | regression tests. 3 | -------------------------------------------------------------------------------- /test/fixtures/empty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/js-in-script-tags/no-type.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/jsp.jsp: -------------------------------------------------------------------------------- 1 | <%--JSP comment--%> 2 | <%@ attribute url="www.test.com" required="true" %> 3 | message 4 | -------------------------------------------------------------------------------- /test/fixtures/php.php: -------------------------------------------------------------------------------- 1 |

  • 2 | Play 3 | 4 |
  • 5 | -------------------------------------------------------------------------------- /test/fixtures/tag.tag: -------------------------------------------------------------------------------- 1 | <%--JSP comment--%> 2 | <%@ attribute url="www.test.com" required="true" %> 3 | message 4 | -------------------------------------------------------------------------------- /test/fixtures/template-literal-separated.js: -------------------------------------------------------------------------------- 1 | // template.js 2 | export default ` 3 |
    4 |

    Hi

    5 |
    `; -------------------------------------------------------------------------------- /test/fixtures/strip.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    4 | Hello! 5 |

    6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/issue_188.html: -------------------------------------------------------------------------------- 1 | constructor 2 | {{'constructor'|translate}} 3 | constructor 4 | -------------------------------------------------------------------------------- /test/fixtures/line_numbers.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettext, gettextCatalog) { 2 | gettext('Line number 2'); 3 | }); 4 | -------------------------------------------------------------------------------- /test/fixtures/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    Hello!

    4 |

    This is a test

    5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/custom.js_extension: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("customController", function (gettext) { 2 | var myString = gettext("Hello custom"); 3 | }); 4 | -------------------------------------------------------------------------------- /test/fixtures/escaped-quotes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/custom_module.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (LabelService) { 2 | var myString = LabelService.getString("Hello"); 3 | }); 4 | -------------------------------------------------------------------------------- /test/fixtures/js-in-script-tags/not-javascript.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/js-in-script-tags/type-javascript.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/custom_method.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettextCatalog) { 2 | var myString = gettextCatalog.getTranslation("Hello"); 3 | }); 4 | -------------------------------------------------------------------------------- /test/fixtures/duplicate-comments.html: -------------------------------------------------------------------------------- 1 |

    Translate this

    2 |

    Translate this

    3 | -------------------------------------------------------------------------------- /test/fixtures/tapestry.tml: -------------------------------------------------------------------------------- 1 | 2 |

    Bonjour from HelloWorld component.

    3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/comments.html: -------------------------------------------------------------------------------- 1 |

    Translate this

    2 |

    And this

    3 | -------------------------------------------------------------------------------- /test/fixtures/source.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettext) { 2 | var myString = gettext("Hello"); 3 | gettext(); // Should be ignored. 4 | }); 5 | -------------------------------------------------------------------------------- /test/fixtures/filter-custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{'Second'|trans}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/filter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{'Second'|translate}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/single.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    Hello!

    4 |

    Hello!

    5 | polo 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/custom.extension: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    Custom file!

    4 |

    This is a test to show support for custom extensions

    5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/custom_marker_name.js: -------------------------------------------------------------------------------- 1 | window.__ = function(str) { return str; }; 2 | 3 | angular.module("myApp").controller("customController", function (gettext) { 4 | var myString = __("Hello custom"); 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/inline-templates.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/multifilter-custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{'World'|trans|lowercase}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/multifilter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{'Second'|translate|lowercase}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/translate-element.html: -------------------------------------------------------------------------------- 1 | 1: message 2 | 3 | 2: message with comment and plural 4 | 5 | -------------------------------------------------------------------------------- /test/fixtures/context-custom.html: -------------------------------------------------------------------------------- 1 |
    2 | CrazyMe! 3 | CrazyYou! 4 |
    Hello1!
    5 |
    Hello2!
    6 |
    7 | -------------------------------------------------------------------------------- /test/fixtures/concat.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettext) { 2 | var myString = gettext("Hello" + " one concat!"); 3 | var myString = gettext("Hello" + " two " + "concat!"); 4 | }); 5 | -------------------------------------------------------------------------------- /test/fixtures/es6-export.js: -------------------------------------------------------------------------------- 1 | export function exportTest() { 2 | return gettext('Hi from an ES6 export!') 3 | } 4 | 5 | export default function exportTestDefault() { 6 | return gettext('Hi from an ES6 export default!'); 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/merge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    Bird

    4 |
    Bird
    5 |

    Bird

    6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/ts.tsx: -------------------------------------------------------------------------------- 1 | const Test = () => ( 2 |
    3 |

    {gettext("Hello World")}

    4 |

    5 | {gettext(`One 6 | Two 7 | Three`)} 8 |

    9 |
    10 | ); 11 | -------------------------------------------------------------------------------- /test/fixtures/escaped_quotes-custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/escaped_quotes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/corrupt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    Bird
    4 |
    Bird
    5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/filter-custom-standard-attribute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{'Second'|trans}} 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/filter-in-multiple-expression-attributes-custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/fixtures/issue_188.ts: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", (gettext, gettextCatalog) => { 2 | var simpleString: string = gettext("constructor"); 3 | var catalogString: string = gettextCatalog.getString("constructor"); 4 | }); 5 | -------------------------------------------------------------------------------- /test/fixtures/plural.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    Bird
    4 |
    Hobbit
    5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/filter-in-multiple-expression-attributes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/fixtures/es6-import.js: -------------------------------------------------------------------------------- 1 | import exportTestDefault, { exportTest } from './es6-export'; 2 | 3 | const fromDefaultExport = exportTestDefault(); // should be ignored 4 | const fromExport = exportTest(); // should be ignored 5 | gettext('Hi from ES6 file with import!'); 6 | -------------------------------------------------------------------------------- /test/fixtures/bind-once.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 | -------------------------------------------------------------------------------- /test/fixtures/multifilter-custom-standard-attribute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{'World'|trans|lowercase}} 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/custom_marker_name_plural.js: -------------------------------------------------------------------------------- 1 | window._n = function(n, str, plural) { return n === 1 ? str : plursal; }; 2 | 3 | angular.module("myApp").controller("customController", function (gettext) { 4 | var myString = _n(1, "Hello custom singular", "Hello custom plural"); 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/multi-line-comments.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettext) { 2 | /// B 3 | /// A 4 | gettext('0'); 5 | 6 | /// A 7 | /// B 8 | gettext('0'); 9 | 10 | /// B 11 | /// A 12 | gettext('1'); 13 | }); 14 | -------------------------------------------------------------------------------- /test/fixtures/escaped_quotes-custom-standard-attribute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/filter-data-attributes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/ts.ts: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", (gettext) => { 2 | var myString: string = gettext("Hello"); 3 | var longString: string = gettext(`One 4 | Two 5 | Three`); 6 | var castedVar: any = gettext("Casted"); 7 | gettext(); // Should be ignored. 8 | }); 9 | -------------------------------------------------------------------------------- /test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/entities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    & & ' ' > > < < " "

    4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/sort.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    a

    4 |

    c

    5 |

    b

    6 |

    d

    7 |

    d

    8 |

    d

    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/fixtures/deeppath_catalog.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettextCatalog) { 2 | var obj = { 3 | gettextCatalog: gettextCatalog }; 4 | var myString = obj.gettextCatalog.getString("Hello"); 5 | var myString2 = obj.gettextCatalog.getPlural(3, "Bird", "Birds"); 6 | }); 7 | -------------------------------------------------------------------------------- /test/fixtures/deeppath_catalog_invalid.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettextCatalog) { 2 | var obj = {[ 3 | gettextCatalog: gettextCatalog }; 4 | var myString = obj.gettextCatalog.getString("Hello"); 5 | var myString2 = obj.gettextCatalog.getPlural(3, "Bird", "Birds"); 6 | }); 7 | -------------------------------------------------------------------------------- /test/fixtures/template-literal-component.js: -------------------------------------------------------------------------------- 1 | class MyLiteralController { 2 | /* @ngInject */ 3 | constructor() {} 4 | } 5 | 6 | export const MyLiteralComponent = { 7 | controller: MyLiteralController, 8 | bindings: {}, 9 | template: ` 10 |
    11 |

    Hi

    12 |
    13 | `, 14 | }; 15 | -------------------------------------------------------------------------------- /test/fixtures/DecoratedClassWithProperties.ts: -------------------------------------------------------------------------------- 1 | function CustomDecorator(value: string) { 2 | return function (target) { } 3 | } 4 | 5 | @CustomDecorator('CustomValue') 6 | export class DecoratedClassWithProperties { 7 | protected a: string; 8 | 9 | constructor(gettext) { 10 | this.a = gettext("A Hello"); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test/fixtures/es6-dynamic-import.js: -------------------------------------------------------------------------------- 1 | 2 | async function run () { 3 | const { default: exportTestDefault, exportTest } = await import('./es6-export') 4 | const fromDefaultExport = exportTestDefault(); // should be ignored 5 | const fromExport = exportTest(); // should be ignored 6 | gettext('Hi from ES6 file with dynamic import!'); 7 | } 8 | 9 | run() 10 | -------------------------------------------------------------------------------- /test/fixtures/custom_marker_names.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("customController", function (gettext) { 2 | var myString = gettext("Hello default"); 3 | // Should be ignored. 4 | gettext(); 5 | 6 | showError("Hello first custom"); 7 | showSuccess("Hello second custom"); 8 | 9 | function showError(str) { } 10 | function showSuccess(str) { } 11 | }); 12 | -------------------------------------------------------------------------------- /test/fixtures/catalog.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettextCatalog) { 2 | var myString = gettextCatalog.getString("Hello"); 3 | var myString2 = gettextCatalog.getString("Hello2", null, "Context"); 4 | var myString3 = gettextCatalog.getPlural(3, "Bird", "Birds"); 5 | var myString4 = gettextCatalog.getPlural(3, "Bird2", "Birds2", null, "Context2"); 6 | }); 7 | -------------------------------------------------------------------------------- /test/fixtures/ngif.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
  • Show {{trackcount}} song...
  • 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/fixtures/no_delimiter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Upload {{count}} file 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/source-property.js: -------------------------------------------------------------------------------- 1 | var HelloController = function (gettext) { 2 | this.gettext = gettext; 3 | 4 | this.someProperties = [ 5 | this.gettext("Hello"), 6 | this.gettext("World"), 7 | ]; 8 | }; 9 | 10 | HelloController.prototype.someFunction = function () { 11 | return this.gettext("Hello world"); 12 | }; 13 | 14 | angular.module("myApp").controller("helloController", HelloController); 15 | -------------------------------------------------------------------------------- /test/fixtures/depth/fr.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: fr\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=n>1;\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | msgid "Goodbye!" 16 | msgstr "Au revoir!" 17 | -------------------------------------------------------------------------------- /test/fixtures/custom_marker_names_plural.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("customController", function (gettext) { 2 | var myString = gettext("Hello default"); 3 | // Should be ignored. 4 | gettext(); 5 | 6 | showErrors(1, "Hello first custom singular", "Hello first custom plural"); 7 | showSuccesses(1, "Hello second custom singular", "Hello second custom plural"); 8 | 9 | function showError(str) { } 10 | function showSuccess(str) { } 11 | }); 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "boss": true, 11 | "eqnull": true, 12 | "node": true, 13 | "strict": true, 14 | "white": true, 15 | "indent": 4, 16 | "predef": [ 17 | "$", 18 | "angular", 19 | "describe", 20 | "it", 21 | "before", 22 | "beforeEach", 23 | "after", 24 | "afterEach" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var PO = require('pofile'); 4 | var fs = require('fs'); 5 | var Extractor = require('..').Extractor; 6 | 7 | function testExtract(filenames, options) { 8 | var extractor = new Extractor(options); 9 | filenames.forEach(function (filename) { 10 | extractor.parse(filename, fs.readFileSync(filename, 'utf8')); 11 | }); 12 | 13 | return PO.parse(extractor.toString()); 14 | } 15 | 16 | module.exports = { 17 | testExtract: testExtract 18 | }; 19 | -------------------------------------------------------------------------------- /test/fixtures/obsolete.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/single.html 16 | msgid "Hello!" 17 | msgstr "Hallo!" 18 | 19 | #~ msgid "Hello \"world\"" 20 | #~ msgstr "Hallo \"wereld\"" 21 | -------------------------------------------------------------------------------- /test/fixtures/es6-class.js: -------------------------------------------------------------------------------- 1 | class TestController { 2 | classProperty = 1; 3 | 4 | constructor(gettext) { 5 | var myString = gettext("Hi from an ES6 class!"); 6 | 7 | this.bindedMethod = ::this.method; 8 | 9 | const component = ( 10 | 11 | <> 12 | {gettext("Hi from a fragment!")}; 13 | 14 | 15 | ); 16 | 17 | const a = { a: 1 }; 18 | const b = { b: 2 }; 19 | 20 | const c = { ...a, ...b }; 21 | } 22 | 23 | @test 24 | method () { } 25 | } 26 | -------------------------------------------------------------------------------- /test/fixtures/empty.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/single.html test/fixtures/second.html 16 | msgid "Hello!" 17 | msgstr "" 18 | 19 | #: test/fixtures/second.html 20 | msgid "This is a test" 21 | msgstr "Dit is een test" 22 | -------------------------------------------------------------------------------- /test/fixtures/fuzzy.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/single.html test/fixtures/second.html 16 | #, fuzzy 17 | msgid "Hello!" 18 | msgstr "Dag!" 19 | 20 | #: test/fixtures/second.html 21 | msgid "This is a test" 22 | msgstr "Dit is een test" 23 | -------------------------------------------------------------------------------- /test/fixtures/data.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    1: Hello!

    4 |

    2: with comment

    5 |

    3: with data-comment

    6 |

    4: translate with data-comment

    7 |

    8 | 5: translate with data-plural 9 |

    10 |

    11 | 6: data-translate with data-plural 12 |

    13 | 14 | 15 | -------------------------------------------------------------------------------- /test/fixtures/context.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/context.html 16 | msgid "Hello!" 17 | msgstr "Hallo!" 18 | 19 | #: test/fixtures/context.html 20 | msgctxt "male" 21 | msgid "Hello!" 22 | msgstr "Hallo (male)!" 23 | 24 | msgid "Goodbye" 25 | msgstr "Vaarwel" 26 | 27 | msgctxt "female" 28 | msgid "Ciao" 29 | msgstr "Ciao (female)" 30 | -------------------------------------------------------------------------------- /test/fixtures/fr.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: fr\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=n>1;\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/single.html test/fixtures/second.html 16 | msgid "Hello!" 17 | msgstr "Bonjour!" 18 | 19 | #: test/fixtures/second.html 20 | msgid "This is a test" 21 | msgstr "Ceci est un test" 22 | 23 | #: test/fixtures/plural.html 24 | msgid "Bird" 25 | msgid_plural "Birds" 26 | msgstr[0] "Oiseau" 27 | msgstr[1] "Oiseaux" 28 | -------------------------------------------------------------------------------- /test/fixtures/nl.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/single.html test/fixtures/second.html 16 | msgid "Hello!" 17 | msgstr "Hallo!" 18 | 19 | #: test/fixtures/second.html 20 | msgid "This is a test" 21 | msgstr "Dit is een test" 22 | 23 | #: test/fixtures/plural.html 24 | msgid "Bird" 25 | msgid_plural "Birds" 26 | msgstr[0] "Vogel" 27 | msgstr[1] "Vogels" 28 | 29 | #: test/fixtures/quotes.html 30 | msgid "Hello \"world\"" 31 | msgstr "Hallo \"wereld\"" 32 | -------------------------------------------------------------------------------- /test/fixtures/inconvertible_html_entities.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/html_entities.html 16 | msgid "non-breaking space" 17 | msgstr "harde spatie" 18 | 19 | #: test/fixtures/html_entities.html 20 | msgid "greater > than" 21 | msgstr "groter > dan" 22 | 23 | #: test/fixtures/html_entities.html 24 | msgid "less < than" 25 | msgstr "kleiner < dan" 26 | 27 | #: test/fixtures/html_entities.html 28 | msgid "and &" 29 | msgstr "en <" 30 | -------------------------------------------------------------------------------- /test/extract_template_literal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting template literal', function () { 7 | it('should work with separated template', function () { 8 | var files = [ 9 | 'test/fixtures/template-literal-separated.js' 10 | ]; 11 | var catalog = testExtract(files); 12 | 13 | assert.equal(catalog.items.length, 1); 14 | assert.equal(catalog.items[0].msgid, 'Hi'); 15 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/template-literal-separated.js:4']); 16 | }); 17 | 18 | it('should work with components template', function () { 19 | var files = [ 20 | 'test/fixtures/template-literal-component.js' 21 | ]; 22 | var catalog = testExtract(files); 23 | 24 | assert.equal(catalog.items.length, 1); 25 | assert.equal(catalog.items[0].msgid, 'Hi'); 26 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/template-literal-component.js:11']); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015 Ruben Vermeersch 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/fixtures/comments.js: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", function (gettext, gettextCatalog) { 2 | /// This is a comment 3 | var myString = gettext("0: Translate this"); 4 | 5 | /// This is two part comment 6 | /// Second part 7 | var myString = gettext("1: Two Part Comment"); 8 | 9 | /** 10 | * Please ignore this comment ///gettext 11 | Thank You 12 | */ 13 | var myString = gettext("2: No comment"); 14 | 15 | /// Plural Comments 16 | var myString = gettextCatalog.getPlural(2, "3: Bird", "Birds"); 17 | 18 | /// gettextCatalog.getString() comment 19 | var myString = gettextCatalog.getString("4: gettextCatalog.getString comment"); 20 | 21 | var array = [ 22 | /// gettext inside array 23 | gettext('5: gettext inside array'), 24 | 25 | /// gettextCatalog inside array 26 | gettextCatalog.getString('6: gettextCatalog inside array'), 27 | 28 | /// gettextCatalog(gettext) inside array 29 | gettextCatalog.getString(gettext('7: gettextCatalog(gettext) inside array')) 30 | ]; 31 | 32 | /// Comment with no translations, ignore this comment too 33 | }); 34 | -------------------------------------------------------------------------------- /test/extract_quotes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting strings containing quotes', function () { 7 | it('works on HTML', function () { 8 | var files = [ 9 | 'test/fixtures/quotes.html' 10 | ]; 11 | var catalog = testExtract(files); 12 | 13 | assert.equal(catalog.items.length, 1); 14 | assert.equal(catalog.items[0].msgid, 'Hello "world"!'); 15 | assert.equal(catalog.items[0].msgstr, ''); 16 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/quotes.html:3']); 17 | }); 18 | 19 | it('does not escape single quotes', function () { 20 | var files = [ 21 | 'test/fixtures/escaped-quotes.html' 22 | ]; 23 | var catalog = testExtract(files); 24 | 25 | assert.equal(catalog.items.length, 1); 26 | assert.equal(catalog.items[0].msgid, "'These quotes' should not be escaped."); 27 | assert.equal(catalog.items[0].msgstr, ''); 28 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/escaped-quotes.html:3']); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/fixtures/comments.ts: -------------------------------------------------------------------------------- 1 | angular.module("myApp").controller("helloController", (gettext, gettextCatalog) => { 2 | /// This is a comment 3 | let myString0 = gettext("0: Translate this"); 4 | 5 | /// This is two part comment 6 | /// Second part 7 | let myString1 = gettext("1: Two Part Comment"); 8 | 9 | /** 10 | * Please ignore this comment ///gettext 11 | Thank You 12 | */ 13 | let myString2 = gettext("2: No comment"); 14 | 15 | /// Plural Comments 16 | let myString3 = gettextCatalog.getPlural(2, "3: Bird", "Birds"); 17 | 18 | /// gettextCatalog.getString() comment 19 | let myString4 = gettextCatalog.getString("4: gettextCatalog.getString comment"); 20 | 21 | let array = [ 22 | /// gettext inside array 23 | gettext('5: gettext inside array'), 24 | 25 | /// gettextCatalog inside array 26 | gettextCatalog.getString('6: gettextCatalog inside array'), 27 | 28 | /// gettextCatalog(gettext) inside array 29 | gettextCatalog.getString(gettext('7: gettextCatalog(gettext) inside array')) 30 | ]; 31 | 32 | /// Comment with no translations, ignore this comment too 33 | }); 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-gettext-tools", 3 | "description": "Tools for extracting/compiling angular-gettext strings.", 4 | "version": "2.5.3", 5 | "homepage": "http://angular-gettext.rocketeer.be/", 6 | "author": { 7 | "name": "Ruben Vermeersch", 8 | "email": "ruben@rocketeer.be", 9 | "url": "http://rocketeer.be" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/rubenv/angular-gettext-tools.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/rubenv/angular-gettext-tools/issues" 17 | }, 18 | "license": "MIT", 19 | "main": "index.js", 20 | "engines": { 21 | "node": ">= 0.10.0" 22 | }, 23 | "scripts": { 24 | "test": "grunt test" 25 | }, 26 | "devDependencies": { 27 | "grunt": "~1.5.2", 28 | "grunt-bump": "^0.8.0", 29 | "grunt-contrib-clean": "~0.6.0", 30 | "grunt-contrib-jshint": "~3.2.0", 31 | "grunt-contrib-watch": "~1.1.0", 32 | "grunt-jscs": "^3.0.1", 33 | "grunt-mocha-cli": "^7.0.0", 34 | "sinon": "^1.17.4" 35 | }, 36 | "keywords": [ 37 | "angular", 38 | "gettext" 39 | ], 40 | "dependencies": { 41 | "@babel/parser": "^7.4.3", 42 | "binary-search": "^1.2.0", 43 | "cheerio": "^1.0.0-rc.12", 44 | "lodash": "^4.17.5", 45 | "pofile": "~1.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/issue_188.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var fs = require('fs'); 5 | var Extractor = require('..').Extractor; 6 | var testExtract = require('./utils').testExtract; 7 | 8 | describe('Extract', function () { 9 | it('Extract "constructor" from HTML', function () { 10 | var files = [ 11 | 'test/fixtures/issue_188.html' 12 | ]; 13 | var catalog = testExtract(files); 14 | 15 | assert.equal(catalog.items.length, 1); 16 | assert.equal(catalog.items[0].msgid, 'constructor'); 17 | assert.equal(catalog.items[0].msgstr, ''); 18 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/issue_188.html:1', 'test/fixtures/issue_188.html:2', 'test/fixtures/issue_188.html:3']); 19 | }); 20 | 21 | it('Extract "constructor" from TypeScript', function () { 22 | var files = [ 23 | 'test/fixtures/issue_188.ts' 24 | ]; 25 | var catalog = testExtract(files); 26 | 27 | assert.equal(catalog.items.length, 1); 28 | assert.equal(catalog.items[0].msgid, 'constructor'); 29 | assert.equal(catalog.items[0].msgstr, ''); 30 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/issue_188.ts:2', 'test/fixtures/issue_188.ts:3']); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/extract_javascript_custom_module_method.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting from Javascript using both a custom module and custom methods', function () { 7 | it('supports a custom module name', function () { 8 | var files = [ 9 | 'test/fixtures/custom_module.js' 10 | ]; 11 | var catalog = testExtract(files, { 12 | moduleName: 'LabelService' 13 | }); 14 | 15 | assert.equal(catalog.items.length, 1); 16 | assert.equal(catalog.items[0].msgid, 'Hello'); 17 | assert.equal(catalog.items[0].msgstr, ''); 18 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/custom_module.js:2']); 19 | }); 20 | 21 | it('supports a custom method name', function () { 22 | var files = [ 23 | 'test/fixtures/custom_method.js' 24 | ]; 25 | var catalog = testExtract(files, { 26 | moduleMethodString: 'getTranslation' 27 | }); 28 | 29 | assert.equal(catalog.items.length, 1); 30 | assert.equal(catalog.items[0].msgid, 'Hello'); 31 | assert.equal(catalog.items[0].msgstr, ''); 32 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/custom_method.js:2']); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/extract_multiline.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var assert = require("assert"); 4 | var PO = require("pofile"); 5 | var fs = require("fs"); 6 | var Extractor = require("..").Extractor; 7 | 8 | function testExtract(filenames, options) { 9 | var extractor = new Extractor(options); 10 | filenames.forEach(function (filename) { 11 | extractor.parse(filename, fs.readFileSync(filename, "utf8")); 12 | }); 13 | return PO.parse(extractor.toString()); 14 | } 15 | 16 | describe("Extract (multi-line HTML)", function () { 17 | it("Issue 122", function () { 18 | var files = ["test/fixtures/widget.html"]; 19 | var catalog = testExtract(files); 20 | 21 | var i = 0; 22 | 23 | function assertString(string, line, plural) { 24 | line = line ? ":" + line : ""; 25 | 26 | assert.equal(catalog.items[i].msgid, string); 27 | assert.equal(catalog.items[i].msgid_plural, plural); 28 | assert.equal(catalog.items[i].references.length, 1); 29 | assert.equal(catalog.items[i].references[0], "test/fixtures/widget.html" + line); 30 | i++; 31 | } 32 | 33 | assert.equal(catalog.items.length, 2); 34 | assertString("Available for {{$count}} {{datatype}} ({{($count / total * 100) | number:2}}%)", 1, "Available for {{$count}} {{datatypePlural}} ({{($count / total * 100) | number:2}}%)"); 35 | assertString("No data", 1); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /.jscs.json: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"], 3 | "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], 4 | "requireParenthesesAroundIIFE": true, 5 | "requireSpacesInFunctionExpression": { 6 | "beforeOpeningCurlyBrace": true 7 | }, 8 | "requireSpacesInAnonymousFunctionExpression": { 9 | "beforeOpeningRoundBrace": true 10 | }, 11 | "disallowSpacesInNamedFunctionExpression": { 12 | "beforeOpeningRoundBrace": true 13 | }, 14 | "disallowSpacesInFunctionDeclaration": { 15 | "beforeOpeningRoundBrace": true 16 | }, 17 | "disallowMixedSpacesAndTabs": true, 18 | "disallowMultipleVarDecl": true, 19 | "requireSpacesInsideObjectBrackets": "all", 20 | "disallowDanglingUnderscores": true, 21 | "disallowSpaceAfterObjectKeys": true, 22 | "requireCommaBeforeLineBreak": true, 23 | "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], 24 | "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], 25 | "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], 26 | "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], 27 | "requireSpacesInConditionalExpression": true, 28 | "validateQuoteMarks": { "mark": true, "escape": true }, 29 | "validateIndentation": 4, 30 | "disallowTrailingWhitespace": true, 31 | "disallowKeywordsOnNewLine": ["else"], 32 | "requireCapitalizedConstructors": true, 33 | "safeContextKeyword": "self", 34 | "requireDotNotation": true, 35 | "disallowYodaConditions": true 36 | } 37 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.loadNpmTasks('grunt-contrib-clean'); 3 | grunt.loadNpmTasks('grunt-contrib-jshint'); 4 | grunt.loadNpmTasks('grunt-contrib-watch'); 5 | grunt.loadNpmTasks('grunt-jscs'); 6 | grunt.loadNpmTasks('grunt-mocha-cli'); 7 | grunt.loadNpmTasks('grunt-bump'); 8 | 9 | grunt.initConfig({ 10 | jshint: { 11 | all: ['{lib,test}/**/*.js', 'index.js', '!test/fixtures/*.js'], 12 | options: { 13 | jshintrc: '.jshintrc' 14 | } 15 | }, 16 | 17 | jscs: { 18 | src: { 19 | options: { 20 | config: '.jscs.json' 21 | }, 22 | files: { 23 | src: ['*.js', '{lib,test}/**/*.js', '!test/fixtures/*.js'] 24 | } 25 | } 26 | }, 27 | 28 | clean: { 29 | tmp: ['tmp'] 30 | }, 31 | 32 | watch: { 33 | test: { 34 | files: ['lib/**.js', 'test/**/*.{js,coffee}'], 35 | tasks: ['test'] 36 | } 37 | }, 38 | 39 | mochacli: { 40 | spec: { 41 | options: { 42 | reporter: 'spec' 43 | } 44 | } 45 | }, 46 | 47 | bump: { 48 | options: { 49 | files: ['package.json'], 50 | commitFiles: ['-a'], 51 | pushTo: 'origin' 52 | } 53 | } 54 | }); 55 | 56 | grunt.registerTask('default', ['test']); 57 | grunt.registerTask('build', ['clean', 'jshint', 'jscs']); 58 | grunt.registerTask('test', ['build', 'mochacli']); 59 | }; 60 | -------------------------------------------------------------------------------- /test/extract_complete.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var assert = require("assert"); 4 | var PO = require("pofile"); 5 | var fs = require("fs"); 6 | var Extractor = require("..").Extractor; 7 | 8 | function testExtract(filenames, options) { 9 | var extractor = new Extractor(options); 10 | filenames.forEach(function (filename) { 11 | extractor.parse(filename, fs.readFileSync(filename, "utf8")); 12 | }); 13 | return PO.parse(extractor.toString()); 14 | } 15 | 16 | describe("Extract (regression tests)", function () { 17 | it("Issue 23", function () { 18 | var files = ["test/fixtures/complete/issue23.html"]; 19 | var catalog = testExtract(files); 20 | 21 | var i = 0; 22 | 23 | function assertString(string, line) { 24 | line = line ? ":" + line : ""; 25 | 26 | assert.equal(catalog.items[i].msgid, string); 27 | assert.equal(catalog.items[i].msgid_plural, null); 28 | assert.equal(catalog.items[i].references.length, 1); 29 | assert.equal(catalog.items[i].references[0], "test/fixtures/complete/issue23.html" + line); 30 | i++; 31 | } 32 | 33 | assert.equal(catalog.items.length, 17); 34 | assertString("(Show on map)", 3); 35 | assertString("Add", 3); 36 | assertString("Address", 1); 37 | assertString("All", 3); 38 | assertString("Birth date", 3); 39 | assertString("Cancel", 3); 40 | assertString("Communications", 3); 41 | assertString("E-mail", 3); 42 | assertString("Enter your message here...", 3); 43 | assertString("Log", 3); 44 | assertString("Order", 3); 45 | assertString("Orders", 3); 46 | assertString("Personal details", 1); 47 | assertString("Preferences", 3); 48 | assertString("Remarks", 3); 49 | assertString("Statistics", 3); 50 | assertString("Subscribed to", 3); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /test/extract_plurals.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting plurals', function () { 7 | it('works on HTML', function () { 8 | var files = [ 9 | 'test/fixtures/plural.html' 10 | ]; 11 | var catalog = testExtract(files); 12 | 13 | var i = catalog.items; 14 | assert.equal(i.length, 1); 15 | 16 | assert.equal(i[0].msgid, 'Bird'); 17 | assert.equal(i[0].msgid_plural, 'Birds'); 18 | assert.deepEqual(i[0].msgstr, ['', '']); 19 | }); 20 | 21 | it('merges singular and plural strings', function () { 22 | var files = [ 23 | 'test/fixtures/merge.html' 24 | ]; 25 | var catalog = testExtract(files); 26 | 27 | var i = catalog.items; 28 | assert.equal(i.length, 1); 29 | 30 | assert.equal(i[0].msgid, 'Bird'); 31 | assert.equal(i[0].msgid_plural, 'Birds'); 32 | assert.deepEqual(i[0].msgstr, ['', '']); 33 | }); 34 | 35 | it('warns for incompatible plurals', function () { 36 | var files = [ 37 | 'test/fixtures/corrupt.html' 38 | ]; 39 | assert.throws(function () { 40 | testExtract(files); 41 | }); 42 | }); 43 | 44 | it('works with custom attributes', function () { 45 | var files = [ 46 | 'test/fixtures/plural.html' 47 | ]; 48 | var catalog = testExtract(files, { 49 | attributes: ['custom-attr'] 50 | }); 51 | 52 | var i = catalog.items; 53 | assert.equal(i.length, 2); 54 | 55 | assert.equal(i[0].msgid, 'Bird'); 56 | assert.equal(i[0].msgid_plural, 'Birds'); 57 | assert.deepEqual(i[0].msgstr, ['', '']); 58 | 59 | assert.equal(i[1].msgid, 'Hobbit'); 60 | assert.equal(i[1].msgid_plural, 'Hobbits'); 61 | assert.deepEqual(i[1].msgstr, ['', '']); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/extract_line_numbers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting line numbers', function () { 7 | it('works on Javascript', function () { 8 | var files = [ 9 | 'test/fixtures/line_numbers.js' 10 | ]; 11 | var catalog = testExtract(files); 12 | 13 | assert.equal(catalog.items[0].msgid, 'Line number 2'); 14 | assert.equal(catalog.items[0].msgstr, ''); 15 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/line_numbers.js:2']); 16 | }); 17 | 18 | it('works on HTML', function () { 19 | var files = [ 20 | 'test/fixtures/line_numbers.html' 21 | ]; 22 | var catalog = testExtract(files); 23 | 24 | assert.equal(catalog.items[0].msgid, 'Line 1'); 25 | assert.equal(catalog.items[0].msgstr, ''); 26 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/line_numbers.html:1']); 27 | }); 28 | 29 | 30 | it('works on Typescript', function () { 31 | var files = [ 32 | 'test/fixtures/DecoratedClassWithProperties.ts' 33 | ]; 34 | var catalog = testExtract(files); 35 | 36 | assert.equal(catalog.items[0].msgid, 'A Hello'); 37 | assert.equal(catalog.items[0].msgstr, ''); 38 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/DecoratedClassWithProperties.ts:10']); 39 | }); 40 | 41 | it("doesn't extract line numbers from JavaScript if lineNumbers: false", function () { 42 | var files = [ 43 | 'test/fixtures/line_numbers.js' 44 | ]; 45 | var catalog = testExtract(files, { lineNumbers: false }); 46 | 47 | assert.equal(catalog.items[0].msgid, 'Line number 2'); 48 | assert.equal(catalog.items[0].msgstr, ''); 49 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/line_numbers.js']); 50 | }); 51 | 52 | it("doesn't extract line numbers from HTML if lineNumbers: false", function () { 53 | var files = [ 54 | 'test/fixtures/line_numbers.html' 55 | ]; 56 | var catalog = testExtract(files, { lineNumbers: false }); 57 | 58 | assert.equal(catalog.items[0].msgid, 'Line 1'); 59 | assert.equal(catalog.items[0].msgstr, ''); 60 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/line_numbers.html']); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/fixtures/widget.html: -------------------------------------------------------------------------------- 1 |

    {{options.caption}}

    {{options.remark}}
    Available for {{$count}} {{datatype}} ({{($count / total * 100) | number:2}}%)
    {{sticker.key}}
    {{sticker.value}}
    {{col.caption}}
    {{row[col.id]}}
    {{'No data' | translate}}
    2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-gettext-tools 2 | 3 | > Tools for extracting/compiling angular-gettext strings. 4 | 5 | Used to construct build tools for [`angular-gettext`](https://github.com/rubenv/angular-gettext). 6 | 7 | [![Build Status](https://travis-ci.org/rubenv/angular-gettext-tools.png?branch=master)](https://travis-ci.org/rubenv/angular-gettext-tools) 8 | 9 | Implementations: 10 | 11 | * [Grunt plugin](https://github.com/rubenv/grunt-angular-gettext) 12 | * [Gulp plugin](https://github.com/gabegorelick/gulp-angular-gettext) 13 | * [CLI utility](https://github.com/huston007/angular-gettext-cli) 14 | * [Webpack loader (compilation)](https://github.com/princed/angular-gettext-loader) 15 | * [Webpack plugin (compilation and extraction)](https://github.com/augusto-altman/angular-gettext-plugin) 16 | 17 | Check the website for usage instructions: [http://angular-gettext.rocketeer.be/](http://angular-gettext.rocketeer.be/). 18 | 19 | ## Options 20 | 21 | All options and defaults are displayed below: 22 | 23 | ```JSON 24 | { 25 | "startDelim": "{{", 26 | "endDelim": "}}", 27 | "markerName": "gettext", 28 | "markerNames": [], 29 | "markerNamePlural": null, 30 | "markerNamesPlural": [], 31 | "moduleName": "gettextCatalog", 32 | "moduleMethodString": "getString", 33 | "moduleMethodPlural": "getPlural", 34 | "attribute": "translate", 35 | "attributes": [], 36 | "lineNumbers": true, 37 | "filterName": "translate", 38 | "format": "javascript", 39 | "defaultLanguage": false, 40 | "requirejs": false 41 | } 42 | ``` 43 | 44 | ## License 45 | 46 | (The MIT License) 47 | 48 | Copyright (C) 2013-2015 by Ruben Vermeersch 49 | 50 | Permission is hereby granted, free of charge, to any person obtaining a copy 51 | of this software and associated documentation files (the "Software"), to deal 52 | in the Software without restriction, including without limitation the rights 53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54 | copies of the Software, and to permit persons to whom the Software is 55 | furnished to do so, subject to the following conditions: 56 | 57 | The above copyright notice and this permission notice shall be included in 58 | all copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 66 | THE SOFTWARE. 67 | -------------------------------------------------------------------------------- /test/fixtures/convertible_html_entities.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: nl\n" 4 | "MIME-Version: 1.0\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | "Content-Transfer-Encoding: 8bit\n" 7 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 8 | "Project-Id-Version: \n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "X-Generator: Poedit 1.5.7\n" 14 | 15 | #: test/fixtures/html_entities.html 16 | msgid "dots…" 17 | msgstr "puntjes…" 18 | 19 | #: test/fixtures/html_entities.html 20 | msgid "cents ¢, pounds £ and euros €" 21 | msgstr "centen ¢, ponden £ and euro’s €" 22 | 23 | #: test/fixtures/html_entities.html 24 | msgid "«double» and ‹single› guillemets" 25 | msgstr "«dubbel» en ‹enkele› guillemets" 26 | 27 | #: test/fixtures/html_entities.html 28 | msgid "copyright © and registered ® trade ™ marks" 29 | msgstr "kopierecht © en geregistreerde ® handels ™ merken" 30 | 31 | #: test/fixtures/html_entities.html 32 | msgid "§ sections and paragraphs¶" 33 | msgstr "§ secties en paragrafen¶" 34 | 35 | #: test/fixtures/html_entities.html 36 | msgid "hot 10° cold" 37 | msgstr "heet ° koud" 38 | 39 | #: test/fixtures/html_entities.html 40 | msgid "± greater ≥ or less than ≤" 41 | msgstr "± groter ≥ of kleiner dan ≤" 42 | 43 | #: test/fixtures/html_entities.html 44 | msgid "not ≠ or approximately ≈ equal" 45 | msgstr "niet ≠ of ongeveer ≈ gelijk" 46 | 47 | #: test/fixtures/html_entities.html 48 | msgid "middle · dot" 49 | msgstr "middel · punt" 50 | 51 | #: test/fixtures/html_entities.html 52 | msgid "en – and em — dash" 53 | msgstr "gedachte– of aandachts— streepje" 54 | 55 | #: test/fixtures/html_entities.html 56 | msgid "‘single’ ‘quotes‚" 57 | msgstr "‘enkele’ ‘aanhalingstekens‚" 58 | 59 | #: test/fixtures/html_entities.html 60 | msgid "“double” “quotes„" 61 | msgstr "“dubbele” “aanhalingstekens„" 62 | 63 | #: test/fixtures/html_entities.html 64 | msgid "† dagger ‡" 65 | msgstr "† obelisk ‡" 66 | 67 | #: test/fixtures/html_entities.html 68 | msgid "• bullet" 69 | msgstr "• opsommingsteken" 70 | 71 | #: test/fixtures/html_entities.html 72 | msgid "10′23″" 73 | msgstr "10′23″ tijd" 74 | 75 | #: test/fixtures/html_entities.html 76 | msgid "square root ² and to the power of ³" 77 | msgstr "kwadraat ² en to de macht ³" 78 | 79 | #: test/fixtures/html_entities.html 80 | msgid "fraction two ½ three ⅓ four ¼ and three fourths ¾" 81 | msgstr "helft ½ derde ⅓ kwart ¼ en drie-vierde ¾" 82 | 83 | -------------------------------------------------------------------------------- /test/fixtures/complete/issue23.html: -------------------------------------------------------------------------------- 1 |

    Personal details

    {{titles[contact.customertitleid]}} {{contact.firstname}} {{contact.middlename}} {{contact.lastname}}
    {{address.type}}{{'Address'|translate}}{{address.street1}} {{address.street2}}
    2 | {{address.zip}} {{address.city}}
    3 | {{address.country}} (Show on map)
    Birth date{{contact.birthdate}}
    E-mail{{contact.email}}
    {{phone.type}}{{phone.number}}
    Subscribed to{{newsletters[nl]}}
    Preferences{{newsletterpreferences[pref]}}

    Statistics

    {{section.caption}}

    {{stat.key}}{{stat.value}}
    Order  4 | {{item.content}}
    {{item.content}}
    {{item.content}}
    5 | -------------------------------------------------------------------------------- /test/extract_custom_filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting custom filters', function () { 7 | 8 | it('works for the simple case', function () { 9 | var files = [ 10 | 'test/fixtures/filter-custom.html' 11 | ]; 12 | var catalog = testExtract(files, { 13 | attribute: 'trans' 14 | }); 15 | 16 | assert.equal(catalog.items.length, 2); 17 | assert.equal(catalog.items[0].msgid, 'Hello'); 18 | assert.equal(catalog.items[0].msgstr, ''); 19 | assert.equal(catalog.items[0].references.length, 1); 20 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter-custom.html:3']); 21 | 22 | assert.equal(catalog.items[1].msgid, 'Second'); 23 | assert.equal(catalog.items[1].msgstr, ''); 24 | assert.equal(catalog.items[1].references.length, 1); 25 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter-custom.html:4']); 26 | }); 27 | 28 | it('works for concatenated filter strings', function () { 29 | var files = [ 30 | 'test/fixtures/multifilter-custom.html' 31 | ]; 32 | var catalog = testExtract(files, { 33 | attribute: 'trans' 34 | }); 35 | 36 | assert.equal(catalog.items.length, 2); 37 | assert.equal(catalog.items[0].msgid, 'Hello'); 38 | assert.equal(catalog.items[0].msgstr, ''); 39 | assert.equal(catalog.items[0].references.length, 1); 40 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/multifilter-custom.html:3']); 41 | 42 | assert.equal(catalog.items[1].msgid, 'World'); 43 | assert.equal(catalog.items[1].msgstr, ''); 44 | assert.equal(catalog.items[1].references.length, 1); 45 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/multifilter-custom.html:4']); 46 | }); 47 | 48 | it('works on filter strings using escaped quotes', function () { 49 | var files = [ 50 | 'test/fixtures/escaped_quotes-custom.html' 51 | ]; 52 | var catalog = testExtract(files, { 53 | attribute: 'trans' 54 | }); 55 | 56 | assert.equal(catalog.items.length, 2); 57 | assert.equal(catalog.items[0].msgid, 'Hello'); 58 | assert.equal(catalog.items[0].msgstr, ''); 59 | assert.equal(catalog.items[0].references.length, 1); 60 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/escaped_quotes-custom.html:3']); 61 | 62 | assert.equal(catalog.items[1].msgid, 'World'); 63 | assert.equal(catalog.items[1].msgstr, ''); 64 | assert.equal(catalog.items[1].references.length, 1); 65 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/escaped_quotes-custom.html:4']); 66 | }); 67 | 68 | it('works on filter strings in multiple expression attributes', function () { 69 | var files = [ 70 | 'test/fixtures/filter-in-multiple-expression-attributes-custom.html' 71 | ]; 72 | var catalog = testExtract(files, { 73 | attribute: 'trans' 74 | }); 75 | 76 | assert.equal(catalog.items.length, 4); 77 | 78 | assert.equal(catalog.items[0].msgid, 'expr1'); 79 | assert.equal(catalog.items[0].msgstr, ''); 80 | assert.equal(catalog.items[0].references.length, 1); 81 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom.html:3']); 82 | 83 | assert.equal(catalog.items[1].msgid, 'expr2'); 84 | assert.equal(catalog.items[1].msgstr, ''); 85 | assert.equal(catalog.items[1].references.length, 1); 86 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom.html:3']); 87 | 88 | assert.equal(catalog.items[2].msgid, 'expr3'); 89 | assert.equal(catalog.items[2].msgstr, ''); 90 | assert.equal(catalog.items[2].references.length, 1); 91 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom.html:3']); 92 | 93 | assert.equal(catalog.items[3].msgid, 'expr4'); 94 | assert.equal(catalog.items[3].msgstr, ''); 95 | assert.equal(catalog.items[3].references.length, 1); 96 | assert.deepEqual(catalog.items[3].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom.html:3']); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /test/extract_filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting filters', function () { 7 | 8 | it('works for the simple case', function () { 9 | var files = [ 10 | 'test/fixtures/filter.html' 11 | ]; 12 | var catalog = testExtract(files); 13 | 14 | assert.equal(catalog.items.length, 2); 15 | assert.equal(catalog.items[0].msgid, 'Hello'); 16 | assert.equal(catalog.items[0].msgstr, ''); 17 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter.html:3']); 18 | 19 | assert.equal(catalog.items[1].msgid, 'Second'); 20 | assert.equal(catalog.items[1].msgstr, ''); 21 | assert.equal(catalog.items[1].references.length, 1); 22 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter.html:4']); 23 | }); 24 | 25 | it('works for concatenated filter strings', function () { 26 | var files = [ 27 | 'test/fixtures/multifilter.html' 28 | ]; 29 | var catalog = testExtract(files); 30 | 31 | assert.equal(catalog.items.length, 2); 32 | assert.equal(catalog.items[0].msgid, 'Hello'); 33 | assert.equal(catalog.items[0].msgstr, ''); 34 | assert.equal(catalog.items[0].references.length, 1); 35 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/multifilter.html:3']); 36 | 37 | assert.equal(catalog.items[1].msgid, 'Second'); 38 | assert.equal(catalog.items[1].msgstr, ''); 39 | assert.equal(catalog.items[1].references.length, 1); 40 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/multifilter.html:4']); 41 | }); 42 | 43 | it('works on filter strings using escaped quotes', function () { 44 | var files = [ 45 | 'test/fixtures/escaped_quotes.html' 46 | ]; 47 | var catalog = testExtract(files); 48 | 49 | assert.equal(catalog.items.length, 2); 50 | assert.equal(catalog.items[0].msgid, 'Hello'); 51 | assert.equal(catalog.items[0].msgstr, ''); 52 | assert.equal(catalog.items[0].references.length, 1); 53 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/escaped_quotes.html:3']); 54 | 55 | assert.equal(catalog.items[1].msgid, 'World'); 56 | assert.equal(catalog.items[1].msgstr, ''); 57 | assert.equal(catalog.items[1].references.length, 1); 58 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/escaped_quotes.html:4']); 59 | }); 60 | 61 | it('works on filter strings in multiple expression attributes', function () { 62 | var files = [ 63 | 'test/fixtures/filter-in-multiple-expression-attributes.html' 64 | ]; 65 | var catalog = testExtract(files); 66 | 67 | assert.equal(catalog.items.length, 4); 68 | 69 | assert.equal(catalog.items[0].msgid, 'expr1'); 70 | assert.equal(catalog.items[0].msgstr, ''); 71 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter-in-multiple-expression-attributes.html:3']); 72 | 73 | assert.equal(catalog.items[1].msgid, 'expr2'); 74 | assert.equal(catalog.items[1].msgstr, ''); 75 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter-in-multiple-expression-attributes.html:3']); 76 | 77 | assert.equal(catalog.items[2].msgid, 'expr3'); 78 | assert.equal(catalog.items[2].msgstr, ''); 79 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/filter-in-multiple-expression-attributes.html:3']); 80 | 81 | assert.equal(catalog.items[3].msgid, 'expr4'); 82 | assert.equal(catalog.items[3].msgstr, ''); 83 | assert.deepEqual(catalog.items[3].references, ['test/fixtures/filter-in-multiple-expression-attributes.html:3']); 84 | }); 85 | 86 | it('works for the data attribute case', function () { 87 | var files = [ 88 | 'test/fixtures/filter-data-attributes.html' 89 | ]; 90 | var catalog = testExtract(files); 91 | 92 | assert.equal(catalog.items.length, 4); 93 | 94 | assert.equal(catalog.items[0].msgid, 'label1'); 95 | assert.equal(catalog.items[0].msgstr, ''); 96 | assert.equal(catalog.items[0].references.length, 1); 97 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter-data-attributes.html:3']); 98 | 99 | assert.equal(catalog.items[1].msgid, 'label2'); 100 | assert.equal(catalog.items[1].msgstr, ''); 101 | assert.equal(catalog.items[1].references.length, 1); 102 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter-data-attributes.html:4']); 103 | 104 | assert.equal(catalog.items[2].msgid, 'label3'); 105 | assert.equal(catalog.items[2].msgstr, ''); 106 | assert.equal(catalog.items[2].references.length, 1); 107 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/filter-data-attributes.html:5']); 108 | 109 | assert.equal(catalog.items[3].msgid, 'label4'); 110 | assert.equal(catalog.items[3].msgstr, ''); 111 | assert.equal(catalog.items[3].references.length, 1); 112 | assert.deepEqual(catalog.items[3].references, ['test/fixtures/filter-data-attributes.html:6']); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /test/extract_comments.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting comments', function () { 7 | it('works on HTML', function () { 8 | var files = [ 9 | 'test/fixtures/comments.html' 10 | ]; 11 | var catalog = testExtract(files); 12 | 13 | var i = catalog.items; 14 | assert.equal(i.length, 1); 15 | 16 | assert.equal(i[0].msgid, 'Translate this'); 17 | assert.deepEqual(i[0].extractedComments, ['This is a comment']); 18 | }); 19 | 20 | it('works on Javascript', function () { 21 | var files = [ 22 | 'test/fixtures/comments.js' 23 | ]; 24 | var catalog = testExtract(files); 25 | 26 | var i = catalog.items; 27 | 28 | assert.equal(i.length, 8); 29 | 30 | assert.equal(i[0].msgid, '0: Translate this'); 31 | assert.deepEqual(i[0].extractedComments, ['This is a comment']); 32 | 33 | assert.equal(i[1].msgid, '1: Two Part Comment'); 34 | assert.deepEqual(i[1].extractedComments, ['This is two part comment, Second part']); 35 | 36 | assert.equal(i[2].msgid, '2: No comment'); 37 | assert.deepEqual(i[2].extractedComments, []); 38 | 39 | assert.equal(i[3].msgid, '3: Bird'); 40 | assert.deepEqual(i[3].extractedComments, ['Plural Comments']); 41 | 42 | assert.equal(i[4].msgid, '4: gettextCatalog.getString comment'); 43 | assert.deepEqual(i[4].extractedComments, ['gettextCatalog.getString() comment']); 44 | 45 | assert.equal(i[5].msgid, '5: gettext inside array'); 46 | assert.deepEqual(i[5].extractedComments, ['gettext inside array']); 47 | 48 | assert.equal(i[6].msgid, '6: gettextCatalog inside array'); 49 | assert.deepEqual(i[6].extractedComments, ['gettextCatalog inside array']); 50 | 51 | assert.equal(i[7].msgid, '7: gettextCatalog(gettext) inside array'); 52 | assert.deepEqual(i[7].extractedComments, ['gettextCatalog(gettext) inside array']); 53 | }); 54 | 55 | it('works on Typescript', function () { 56 | var files = [ 57 | 'test/fixtures/comments.ts' 58 | ]; 59 | var catalog = testExtract(files); 60 | 61 | var i = catalog.items; 62 | 63 | assert.equal(i.length, 8); 64 | 65 | assert.equal(i[0].msgid, '0: Translate this'); 66 | assert.deepEqual(i[0].extractedComments, ['This is a comment']); 67 | 68 | assert.equal(i[1].msgid, '1: Two Part Comment'); 69 | assert.deepEqual(i[1].extractedComments, ['This is two part comment, Second part']); 70 | 71 | assert.equal(i[2].msgid, '2: No comment'); 72 | assert.deepEqual(i[2].extractedComments, []); 73 | 74 | assert.equal(i[3].msgid, '3: Bird'); 75 | assert.deepEqual(i[3].extractedComments, ['Plural Comments']); 76 | 77 | assert.equal(i[4].msgid, '4: gettextCatalog.getString comment'); 78 | assert.deepEqual(i[4].extractedComments, ['gettextCatalog.getString() comment']); 79 | 80 | assert.equal(i[5].msgid, '5: gettext inside array'); 81 | assert.deepEqual(i[5].extractedComments, ['gettext inside array']); 82 | 83 | assert.equal(i[6].msgid, '6: gettextCatalog inside array'); 84 | assert.deepEqual(i[6].extractedComments, ['gettextCatalog inside array']); 85 | 86 | assert.equal(i[7].msgid, '7: gettextCatalog(gettext) inside array'); 87 | assert.deepEqual(i[7].extractedComments, ['gettextCatalog(gettext) inside array']); 88 | }); 89 | 90 | it('merges duplicate comments', function () { 91 | var files = [ 92 | 'test/fixtures/duplicate-comments.html' 93 | ]; 94 | var catalog = testExtract(files); 95 | 96 | var i = catalog.items; 97 | assert.equal(i.length, 1); 98 | 99 | assert.equal(i[0].msgid, 'Translate this'); 100 | assert.deepEqual(i[0].extractedComments, ['This is a comment']); 101 | }); 102 | 103 | it('Should order multi-line JS comments', function () { 104 | var files = [ 105 | 'test/fixtures/multi-line-comments.js' 106 | ]; 107 | var catalog = testExtract(files); 108 | 109 | var i = catalog.items; 110 | assert.equal(i.length, 2); 111 | 112 | assert.equal(i[0].msgid, '0'); 113 | assert.equal(i[0].extractedComments.length, 2); 114 | assert.equal(i[0].extractedComments[0], 'A, B'); 115 | assert.equal(i[0].extractedComments[1], 'B, A'); 116 | 117 | assert.equal(i[1].msgid, '1'); 118 | assert.equal(i[1].extractedComments.length, 1); 119 | assert.equal(i[1].extractedComments[0], 'B, A'); 120 | }); 121 | 122 | it('extracts custom attribute comments from HTML', function () { 123 | var files = [ 124 | 'test/fixtures/comments.html' 125 | ]; 126 | var catalog = testExtract(files, { 127 | attributes: ['custom-attr'] 128 | }); 129 | 130 | var i = catalog.items; 131 | assert.equal(i.length, 2); 132 | 133 | assert.equal(i[0].msgid, 'And this'); 134 | assert.deepEqual(i[0].extractedComments, ['This is a custom attribute comment']); 135 | 136 | assert.equal(i[1].msgid, 'Translate this'); 137 | assert.deepEqual(i[1].extractedComments, ['This is a comment']); 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /test/extract_extensions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting files with different extensions', function () { 7 | it('supports custom HTML file extensions', function () { 8 | var files = [ 9 | 'test/fixtures/custom.extension' 10 | ]; 11 | var catalog = testExtract(files, { 12 | extensions: { 13 | extension: 'html' 14 | } 15 | }); 16 | 17 | assert.equal(catalog.items.length, 2); 18 | assert.equal(catalog.items[0].msgid, 'Custom file!'); 19 | assert.equal(catalog.items[0].msgstr, ''); 20 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/custom.extension:3']); 21 | }); 22 | 23 | it('supports custom JS file extensions', function () { 24 | var files = [ 25 | 'test/fixtures/custom.js_extension' 26 | ]; 27 | var catalog = testExtract(files, { 28 | extensions: { 29 | js_extension: 'js' 30 | } 31 | }); 32 | 33 | assert.equal(catalog.items.length, 1); 34 | assert.equal(catalog.items[0].msgid, 'Hello custom'); 35 | assert.equal(catalog.items[0].msgstr, ''); 36 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/custom.js_extension:2']); 37 | }); 38 | 39 | it('supports PHP files', function () { 40 | var files = [ 41 | 'test/fixtures/php.php' 42 | ]; 43 | var catalog = testExtract(files); 44 | 45 | assert.equal(catalog.items.length, 1); 46 | assert.equal(catalog.items[0].msgid, 'Play'); 47 | assert.equal(catalog.items[0].msgstr, ''); 48 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/php.php:2']); 49 | }); 50 | 51 | it('supports EJS files', function () { 52 | var files = [ 53 | 'test/fixtures/ejs.ejs' 54 | ]; 55 | var catalog = testExtract(files); 56 | 57 | assert.equal(catalog.items.length, 1); 58 | assert.equal(catalog.items[0].msgid, 'EJS Link'); 59 | assert.equal(catalog.items[0].msgstr, ''); 60 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/ejs.ejs:2']); 61 | }); 62 | 63 | it('supports ERB files', function () { 64 | var files = [ 65 | 'test/fixtures/erb.erb' 66 | ]; 67 | var catalog = testExtract(files); 68 | 69 | assert.equal(catalog.items.length, 1); 70 | assert.equal(catalog.items[0].msgid, 'message'); 71 | assert.equal(catalog.items[0].msgstr, ''); 72 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/erb.erb:3']); 73 | }); 74 | 75 | it('supports JSP .jsp files', function () { 76 | var files = [ 77 | 'test/fixtures/jsp.jsp' 78 | ]; 79 | var catalog = testExtract(files); 80 | 81 | assert.equal(catalog.items.length, 1); 82 | assert.equal(catalog.items[0].msgid, 'message'); 83 | assert.equal(catalog.items[0].msgstr, ''); 84 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/jsp.jsp:3']); 85 | }); 86 | it('supports JSP .tag files', function () { 87 | var files = [ 88 | 'test/fixtures/tag.tag' 89 | ]; 90 | var catalog = testExtract(files); 91 | 92 | assert.equal(catalog.items.length, 1); 93 | assert.equal(catalog.items[0].msgid, 'message'); 94 | assert.equal(catalog.items[0].msgstr, ''); 95 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/tag.tag:3']); 96 | }); 97 | 98 | 99 | it('supports tapestry files', function () { 100 | var files = [ 101 | 'test/fixtures/tapestry.tml' 102 | ]; 103 | var catalog = testExtract(files); 104 | 105 | assert.equal(catalog.items.length, 1); 106 | assert.equal(catalog.items[0].msgid, 'Bonjour from HelloWorld component.'); 107 | assert.equal(catalog.items[0].msgstr, ''); 108 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/tapestry.tml:2']); 109 | }); 110 | 111 | it('supports TypeScript files', function () { 112 | var files = [ 113 | 'test/fixtures/ts.ts' 114 | ]; 115 | var catalog = testExtract(files); 116 | 117 | assert.equal(catalog.items.length, 3); 118 | assert.equal(catalog.items[0].msgid, 'Casted'); 119 | assert.equal(catalog.items[0].msgstr, ''); 120 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/ts.ts:6']); 121 | 122 | assert.equal(catalog.items[1].msgid, 'Hello'); 123 | assert.equal(catalog.items[1].msgstr, ''); 124 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/ts.ts:2']); 125 | 126 | assert.equal(catalog.items[2].msgid, 'One\nTwo\nThree'); 127 | assert.equal(catalog.items[2].msgstr, ''); 128 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/ts.ts:3']); 129 | }); 130 | 131 | it('supports TypeScript .tsx files', function () { 132 | var files = [ 133 | 'test/fixtures/ts.tsx' 134 | ]; 135 | var catalog = testExtract(files); 136 | 137 | assert.equal(catalog.items.length, 2); 138 | assert.equal(catalog.items[0].msgid, 'Hello World'); 139 | assert.equal(catalog.items[0].msgstr, ''); 140 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/ts.tsx:3']); 141 | 142 | assert.equal(catalog.items[1].msgid, 'One\nTwo\nThree'); 143 | assert.equal(catalog.items[1].msgstr, ''); 144 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/ts.tsx:5']); 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /lib/compile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var po = require('pofile'); 4 | var _ = require('lodash'); 5 | 6 | var formats = { 7 | javascript: { 8 | addLocale: function (locale, strings) { 9 | return ' gettextCatalog.setStrings(\'' + locale + '\', ' + JSON.stringify(strings) + ');\n'; 10 | }, 11 | format: function (locales, options) { 12 | var angular = 'angular'; 13 | if (options.browserify) { 14 | angular = 'require(\'angular\')'; 15 | } 16 | var module = angular + '.module(\'' + options.module + '\')' + 17 | '.run([\'gettextCatalog\', function (gettextCatalog) {\n' + 18 | '/* jshint -W100 */\n' + 19 | locales.join('') + 20 | '/* jshint +W100 */\n'; 21 | if (options.defaultLanguage) { 22 | module += 'gettextCatalog.currentLanguage = \'' + options.defaultLanguage + '\';\n'; 23 | } 24 | module += '}]);'; 25 | 26 | if (options.requirejs) { 27 | return 'define([\'angular\', \'' + options.modulePath + '\'], function (angular) {\n' + module + '\n});'; 28 | } 29 | 30 | return module; 31 | } 32 | }, 33 | json: { 34 | addLocale: function (locale, strings) { 35 | return { 36 | name: locale, 37 | strings: strings 38 | }; 39 | }, 40 | format: function (locales, options) { 41 | var result = {}; 42 | locales.forEach(function (locale) { 43 | if (!result[locale.name]) { 44 | result[locale.name] = {}; 45 | } 46 | _.assign(result[locale.name], locale.strings); 47 | }); 48 | return JSON.stringify(result); 49 | } 50 | } 51 | }; 52 | 53 | var noContext = '$$noContext'; 54 | 55 | var Compiler = (function () { 56 | function Compiler(options) { 57 | this.options = _.extend({ 58 | format: 'javascript', 59 | ignoreFuzzyString: true, 60 | module: 'gettext' 61 | }, options); 62 | } 63 | 64 | Compiler.browserConvertedHTMLEntities = { 65 | 'hellip': '…', 66 | 'cent': '¢', 67 | 'pound': '£', 68 | 'euro': '€', 69 | 'laquo': '«', 70 | 'raquo': '»', 71 | 'rsaquo': '›', 72 | 'lsaquo': '‹', 73 | 'copy': '©', 74 | 'reg': '®', 75 | 'trade': '™', 76 | 'sect': '§', 77 | 'deg': '°', 78 | 'plusmn': '±', 79 | 'para': '¶', 80 | 'middot': '·', 81 | 'ndash': '–', 82 | 'mdash': '—', 83 | 'lsquo': '‘', 84 | 'rsquo': '’', 85 | 'sbquo': '‚', 86 | 'ldquo': '“', 87 | 'rdquo': '”', 88 | 'bdquo': '„', 89 | 'dagger': '†', 90 | 'Dagger': '‡', 91 | 'bull': '•', 92 | 'prime': '′', 93 | 'Prime': '″', 94 | 'asymp': '≈', 95 | 'ne': '≠', 96 | 'le': '≤', 97 | 'ge': '≥', 98 | 'sup2': '²', 99 | 'sup3': '³', 100 | 'frac12': '½', 101 | 'frac14': '¼', 102 | 'frac13': '⅓', 103 | 'frac34': '¾' 104 | }; 105 | 106 | Compiler.hasFormat = function (format) { 107 | return formats.hasOwnProperty(format); 108 | }; 109 | 110 | Compiler.prototype.convertPo = function (inputs) { 111 | var format = formats[this.options.format]; 112 | var ignoreFuzzyString = this.options.ignoreFuzzyString; 113 | var locales = []; 114 | 115 | inputs.forEach(function (input) { 116 | var catalog = po.parse(input); 117 | 118 | if (!catalog.headers.Language) { 119 | throw new Error('No Language header found!'); 120 | } 121 | 122 | var strings = {}; 123 | for (var i = 0; i < catalog.items.length; i++) { 124 | var item = catalog.items[i]; 125 | var ctx = item.msgctxt || noContext; 126 | var msgid = item.msgid; 127 | 128 | var convertedEntity; 129 | var unconvertedEntity; 130 | var unconvertedEntityPattern; 131 | 132 | for ( unconvertedEntity in Compiler.browserConvertedHTMLEntities ) { 133 | convertedEntity = Compiler.browserConvertedHTMLEntities[ unconvertedEntity ]; 134 | unconvertedEntityPattern = new RegExp( '&' + unconvertedEntity + ';?', 'g' ); 135 | msgid = msgid.replace( unconvertedEntityPattern, convertedEntity ); 136 | } 137 | 138 | var nonEmptyUpToDateStr = item.msgstr[0].length > 0 && !item.obsolete; 139 | var useNonFuzzyStrOnly = ignoreFuzzyString && !item.flags.fuzzy; 140 | 141 | if (nonEmptyUpToDateStr && (useNonFuzzyStrOnly || !ignoreFuzzyString)) { 142 | if (!strings[msgid]) { 143 | strings[msgid] = {}; 144 | } 145 | 146 | // Add array for plural, single string for signular. 147 | strings[msgid][ctx] = item.msgstr.length === 1 ? item.msgstr[0] : item.msgstr; 148 | } 149 | } 150 | 151 | // Strip context from strings that have no context. 152 | for (var key in strings) { 153 | if (Object.keys(strings[key]).length === 1 && strings[key][noContext]) { 154 | strings[key] = strings[key][noContext]; 155 | } 156 | } 157 | 158 | locales.push(format.addLocale(catalog.headers.Language, strings)); 159 | }); 160 | 161 | return format.format(locales, this.options); 162 | }; 163 | 164 | return Compiler; 165 | })(); 166 | 167 | module.exports = Compiler; 168 | -------------------------------------------------------------------------------- /test/extract_custom_filter_standard_attribute.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var testExtract = require('./utils').testExtract; 5 | 6 | describe('Extracting custom filters but standard attribute', function () { 7 | 8 | it('works for the simple case', function () { 9 | var files = [ 10 | 'test/fixtures/filter-custom-standard-attribute.html' 11 | ]; 12 | var catalog = testExtract(files, { 13 | filterName: 'trans' 14 | }); 15 | 16 | assert.equal(catalog.items.length, 3); 17 | 18 | assert.equal(catalog.items[0].msgid, 'Hello'); 19 | assert.equal(catalog.items[0].msgstr, ''); 20 | assert.equal(catalog.items[0].references.length, 1); 21 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter-custom-standard-attribute.html:4']); 22 | 23 | assert.equal(catalog.items[1].msgid, 'Label'); 24 | assert.equal(catalog.items[1].msgstr, ''); 25 | assert.equal(catalog.items[1].references.length, 1); 26 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter-custom-standard-attribute.html:3']); 27 | 28 | assert.equal(catalog.items[2].msgid, 'Second'); 29 | assert.equal(catalog.items[2].msgstr, ''); 30 | assert.equal(catalog.items[2].references.length, 1); 31 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/filter-custom-standard-attribute.html:5']); 32 | }); 33 | 34 | it('works for concatenated filter strings', function () { 35 | var files = [ 36 | 'test/fixtures/multifilter-custom-standard-attribute.html' 37 | ]; 38 | var catalog = testExtract(files, { 39 | filterName: 'trans' 40 | }); 41 | 42 | assert.equal(catalog.items.length, 3); 43 | 44 | assert.equal(catalog.items[0].msgid, 'Hello'); 45 | assert.equal(catalog.items[0].msgstr, ''); 46 | assert.equal(catalog.items[0].references.length, 1); 47 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/multifilter-custom-standard-attribute.html:4']); 48 | 49 | assert.equal(catalog.items[1].msgid, 'Label'); 50 | assert.equal(catalog.items[1].msgstr, ''); 51 | assert.equal(catalog.items[1].references.length, 1); 52 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/multifilter-custom-standard-attribute.html:3']); 53 | 54 | assert.equal(catalog.items[2].msgid, 'World'); 55 | assert.equal(catalog.items[2].msgstr, ''); 56 | assert.equal(catalog.items[2].references.length, 1); 57 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/multifilter-custom-standard-attribute.html:5']); 58 | }); 59 | 60 | it('works on filter strings using escaped quotes', function () { 61 | var files = [ 62 | 'test/fixtures/escaped_quotes-custom-standard-attribute.html' 63 | ]; 64 | var catalog = testExtract(files, { 65 | filterName: 'trans' 66 | }); 67 | 68 | assert.equal(catalog.items.length, 3); 69 | 70 | assert.equal(catalog.items[0].msgid, 'Hello'); 71 | assert.equal(catalog.items[0].msgstr, ''); 72 | assert.equal(catalog.items[0].references.length, 1); 73 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/escaped_quotes-custom-standard-attribute.html:4']); 74 | 75 | assert.equal(catalog.items[1].msgid, 'Label'); 76 | assert.equal(catalog.items[1].msgstr, ''); 77 | assert.equal(catalog.items[1].references.length, 1); 78 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/escaped_quotes-custom-standard-attribute.html:3']); 79 | 80 | assert.equal(catalog.items[2].msgid, 'World'); 81 | assert.equal(catalog.items[2].msgstr, ''); 82 | assert.equal(catalog.items[2].references.length, 1); 83 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/escaped_quotes-custom-standard-attribute.html:5']); 84 | }); 85 | 86 | it('works on filter strings in multiple expression attributes', function () { 87 | var files = [ 88 | 'test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html' 89 | ]; 90 | var catalog = testExtract(files, { 91 | filterName: 'trans' 92 | }); 93 | 94 | assert.equal(catalog.items.length, 5); 95 | 96 | assert.equal(catalog.items[0].msgid, 'Label'); 97 | assert.equal(catalog.items[0].msgstr, ''); 98 | assert.equal(catalog.items[0].references.length, 1); 99 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html:3']); 100 | 101 | assert.equal(catalog.items[1].msgid, 'expr1'); 102 | assert.equal(catalog.items[1].msgstr, ''); 103 | assert.equal(catalog.items[1].references.length, 1); 104 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html:4']); 105 | 106 | assert.equal(catalog.items[2].msgid, 'expr2'); 107 | assert.equal(catalog.items[2].msgstr, ''); 108 | assert.equal(catalog.items[2].references.length, 1); 109 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html:4']); 110 | 111 | assert.equal(catalog.items[3].msgid, 'expr3'); 112 | assert.equal(catalog.items[3].msgstr, ''); 113 | assert.equal(catalog.items[3].references.length, 1); 114 | assert.deepEqual(catalog.items[3].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html:4']); 115 | 116 | assert.equal(catalog.items[4].msgid, 'expr4'); 117 | assert.equal(catalog.items[4].msgstr, ''); 118 | assert.equal(catalog.items[4].references.length, 1); 119 | assert.deepEqual(catalog.items[4].references, ['test/fixtures/filter-in-multiple-expression-attributes-custom-standard-attribute.html:4']); 120 | }); 121 | }); 122 | -------------------------------------------------------------------------------- /test/extract_javascript.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var sinon = require('sinon'); 5 | var testExtract = require('./utils').testExtract; 6 | 7 | describe('Extracting from Javascript', function () { 8 | it('supports gettext()', function () { 9 | var files = [ 10 | 'test/fixtures/source.js' 11 | ]; 12 | var catalog = testExtract(files); 13 | 14 | assert.equal(catalog.items.length, 1); 15 | assert.equal(catalog.items[0].msgid, 'Hello'); 16 | assert.equal(catalog.items[0].msgstr, ''); 17 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/source.js:2']); 18 | }); 19 | 20 | it('supports this.gettext()', function () { 21 | var files = [ 22 | 'test/fixtures/source-property.js' 23 | ]; 24 | var catalog = testExtract(files); 25 | 26 | assert.equal(catalog.items.length, 3); 27 | assert.equal(catalog.items[0].msgid, 'Hello'); 28 | assert.equal(catalog.items[0].msgstr, ''); 29 | assert.equal(catalog.items[1].msgid, 'Hello world'); 30 | assert.equal(catalog.items[1].msgstr, ''); 31 | assert.equal(catalog.items[2].msgid, 'World'); 32 | assert.equal(catalog.items[2].msgstr, ''); 33 | 34 | assert.equal(catalog.items[0].references.length, 1); 35 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/source-property.js:5']); 36 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/source-property.js:11']); 37 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/source-property.js:6']); 38 | }); 39 | 40 | it('supports gettextCatalog.getString()', function () { 41 | var files = [ 42 | 'test/fixtures/catalog.js' 43 | ]; 44 | var catalog = testExtract(files); 45 | 46 | assert.equal(catalog.items.length, 4); 47 | 48 | assert.equal(catalog.items[0].msgid, 'Hello2'); 49 | assert.equal(catalog.items[0].msgstr, ''); 50 | assert.equal(catalog.items[0].msgctxt, 'Context'); 51 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/catalog.js:3']); 52 | 53 | assert.equal(catalog.items[1].msgid, 'Bird2'); 54 | assert.equal(catalog.items[1].msgid_plural, 'Birds2'); 55 | assert.equal(catalog.items[1].msgstr.length, 2); 56 | assert.equal(catalog.items[1].msgstr[0], ''); 57 | assert.equal(catalog.items[1].msgstr[1], ''); 58 | assert.equal(catalog.items[1].msgctxt, 'Context2'); 59 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/catalog.js:5']); 60 | 61 | assert.equal(catalog.items[2].msgid, 'Bird'); 62 | assert.equal(catalog.items[2].msgid_plural, 'Birds'); 63 | assert.equal(catalog.items[2].msgstr.length, 2); 64 | assert.equal(catalog.items[2].msgstr[0], ''); 65 | assert.equal(catalog.items[2].msgstr[1], ''); 66 | assert.deepEqual(catalog.items[2].references, ['test/fixtures/catalog.js:4']); 67 | 68 | assert.equal(catalog.items[3].msgid, 'Hello'); 69 | assert.equal(catalog.items[3].msgstr, ''); 70 | assert.deepEqual(catalog.items[3].references, ['test/fixtures/catalog.js:2']); 71 | }); 72 | 73 | it('supports foo.gettextCatalog.getString()', function () { 74 | var files = [ 75 | 'test/fixtures/deeppath_catalog.js' 76 | ]; 77 | var catalog = testExtract(files); 78 | 79 | assert.equal(catalog.items[0].msgid, 'Bird'); 80 | assert.equal(catalog.items[0].msgid_plural, 'Birds'); 81 | assert.equal(catalog.items[0].msgstr.length, 2); 82 | assert.equal(catalog.items[0].msgstr[0], ''); 83 | assert.equal(catalog.items[0].msgstr[1], ''); 84 | assert.deepEqual(catalog.items[0].references, ['test/fixtures/deeppath_catalog.js:5']); 85 | assert.equal(catalog.items.length, 2); 86 | assert.equal(catalog.items[1].msgid, 'Hello'); 87 | assert.equal(catalog.items[1].msgstr, ''); 88 | assert.deepEqual(catalog.items[1].references, ['test/fixtures/deeppath_catalog.js:4']); 89 | }); 90 | 91 | describe('invalid javascript', function () { 92 | beforeEach(function () { 93 | sinon.stub(console, 'warn', function () { 94 | // respect the rule of silence 95 | }); 96 | }); 97 | 98 | afterEach(function () { 99 | console.warn.restore(); 100 | }); 101 | 102 | it('should not throw an exception', function () { 103 | var files = [ 104 | 'test/fixtures/deeppath_catalog_invalid.js' 105 | ]; 106 | testExtract(files); 107 | }); 108 | }); 109 | 110 | describe('from HTML