Extracts translatable strings from source. Identical to xgettext but for template languages.

Last update: Apr 9, 2022

xgettext-template CI

Extracts translatable strings from source. Identical to xgettext(1) but for template languages.

Template language support

React's JSX and Pug are todos (PRs are much appreciated).

Installation

$ npm install -g xgettext-template

Usage

$ xgettext-template [OPTION] [INPUTFILE]...

Options

Input file location:
  -f, --files-from  get list of input files from FILE
  -D, --directory   add DIRECTORY to list for input files search[default: ["."]]

Output file location:
  -o, --output  write output to specified file          [default: "messages.po"]

Choice of input file language:
  -L, --language  recognise the specified language
                  (Handlebars, Swig, Volt, EJS, Nunjucks)

Input file interpretation:
  --from-code  encoding of input files                        [default: "ascii"]

Operation mode:
  -j, --join-existing  join messages with existing file         [default: false]

Language specific options:
  -k, --keyword  look for WORD as an additional keyword

Output details:
  --force-po     write PO file even if empty                    [default: false]
  --no-location  do not write '#: filename:line' lines          [default: false]
  -s, --sort-output  generate sorted output                     [default: false]

Informative output:
  -h, --help     display this help and exit                            [boolean]
  -V, --version  output version information and exit                   [boolean]

More information about each option can be found in the xgettext manual.

In Poedit

Go to File - Preferences... in Poedit and add a new parser in the Parsers tab:

Poedit parser configuration

Please note that in this Windows example you have to use xgettext-template.cmd. The .cmd extension should not be there on *nix platforms.

General workflow

In the following Handlebars example translatable content is passed to helpers (_ and ngettext):

<button>{{_ "Sign in"}}</button>

<p>{{count}} {{ngettext "country" "countries" count}}</p>

With Handlebars, this requires helpers being registered:

Handlebars.registerHelper('_', function(msgid) {
  return i18n.gettext(msgid);
});

Handlebars.registerHelper('ngettext', function(msgid, plural, count) {
  return i18n.ngettext(msgid, plural, count);
});

What this i18n object refers to is up to you. Some (client/server) options are:

xgettext-template parses the strings above out of your templates into gettext's PO files. These PO files are then translated and compiled to binary MO files using applications like Poedit. The MO files are passed as input the i18n library (above).

Development

  • Clone repository and run npm install.
  • Have your editor run eslint or run npm run lint to lint.
  • Run npm test to run tests.

Note

xgettext-template initial development was founded by Dijiwan.

GitHub

https://github.com/gmarty/xgettext
Comments
  • 1. Unable to execute handlebars-xgettext from Poedit

    On Mac OSX 10.9 / Poedit v1.5.7, I installed handlebars-xgetttext globally via npm and configured the parser in Poedit as instructed in the readme, however when I run an update on my catalog, I get the following error:

    20:43:32: Cannot execute program: handlebars-xgettext --force-po -o "/var/folders/kr/t4b6rm9x14b_qccxmvklplc80000gn/T/poeditzpgIds/5extracted.pot" --from-code=UTF-8 -k_ -kgettext -kgettext_noop "client/templates/application.hbs" 20:43:32: Entries in the catalog are probably incorrect. 20:43:32: Updating the catalog failed. Click on 'Details >>' for details."

    Attached is a screenshot of my parser settings for handlebars. screen shot 2013-11-24 at 8 50 18 pm

    And the contents of the template file (it just a test file) that is listed in the error message is:

    <h1>{{someText}}</h1>
    <button class="btn btn-primary">{{_ 'Save'}}</button>
    <button class="btn btn-danger">{{_ 'Delete'}}</button>
    <button class="btn btn-default">{{_ 'Cancel'}}</button>
    {{outlet}}
    

    Any ideas on what would be causing this error?

    Reviewed by billdami at 2013-11-25 01:54
  • 2. Add Parser to module.export

    There should be public method to parse already loaded templates.

    At the moment one can parse templates with handlebars-xgettext.parse(files, options, callback) but it reads a file from the fs. In the case the content of the file is already loaded there is no way to parse it using public API.

    Reviewed by JustBlackBird at 2014-08-13 12:07
  • 3. [NFR] Swig template parser

    Here is my plea.

    I'm making a open source framework to merge Phalcon PHP and Nodejs Webpack tech. Its working out pretty well but I'd much prefer to use Swig templates to match the Volt templates on the server but I decided to use Handlebars one because your xgettext parser was the only functioning thing that I found anywhere - for anything actually. An island of sanity if you will.

    If adding this is just some simple thing for you guys then feel free to rock the code.


    I need a template parser for yanking out gettext strings from both Volt and Swig [Django family] templates.

    In my Phalcon based Webird system I'm using Volt for server templates and Handlebars for front templates. The reason that I'm using Handlebars templates is that it is very difficult to find an xgettext template parser that is capable of pulling out strings in plural form and the Handlebars ecosystem is more mature in this way.

    So I think that it would be amazing to be able to write templates in the same syntax for both the server and front end and Swig is much more modern than Handlebars in regards to its packaging.

    Here is a good starting point if someone would like to do it with nodejs;

    The generalized wrapper: xgettext-template

    The Handlebars implementation: xgettext-handlebars

    So you can see that it is very little code in the Handlebars wrapper since the heavy liftiing is being done by the parser. I'd do it myself but its not my forte.

    Well my head is pretty full with this project and I can't write all of the tools myself. My idea about this is to combine the superior Nodejs (with webpack) front end environment with the superior Phalcon back end environment. The localization strings are already well shared between the browser and server and the idea is that you can create tech with PHP and JS and have it integrate well. Perhaps you would want to use Volt views for a more Admin type interface to save R&D time and your app uses some fancy JS tech that takes 20x longer to develop. So then the templates would be the same and I'm trying to standardize constants and helpers in as much as possible so that they are mostly compatible between both environments.

    Additionally, one kind of current bummer is that the Volt templates must be compiled into PHP before the strings can be extracted with xgettext. Its not terrible, but could be better.

    So that is my plan and if you are capable of writing a Swig/Volt xgettext implementation in less time than it takes to read my long (mostly irrelevant) words then please get on top of that.

    Reviewed by dschissler at 2014-11-18 18:57
  • 4. New method pgettext() not recognizing by Poedit

    I've implemented method pgettext() in my gettext adapter to handle context and I would like to Poedit recognize pgettext() in .volt files. I've added this keyword in Catalogoue->Properties->Keywords, it works for *.php file only, it doesn't work for *.volt.

    Should I add something extra to extractor's settings or somewhere else?

    Reviewed by Zaszczyk at 2016-11-09 15:19
  • 5. Ignore additional parameters

    Modify pattern to ignore additional parameter:

    Example:

    <tag id='test' placeholder='{{_ "Hello World %s" param1="bla"}}'></tag>
    

    At the moment handlbars-xgettext ignore the complete line because of param1="bla"

    I change parser.js pattern:

    // old
    this.pattern = new RegExp('\\{\\{(?:' + keywords.join('|') + ') "((?:\\\\.|[^"\\\\])*)" ?\\}\\}', 'gm');
    // new
    this.pattern = new RegExp('\\{\\{(?:' + keywords.join('|') + ') "((?:\\\\.|[^"\\\\])*)".*?\\}\\}', 'gm');
                                                                                           ++
    
    Reviewed by rottmann at 2013-09-06 16:40
  • 6. Not working through Poedit

    Hi there,

    Thanks for your work!

    I'm facing a problem, maybe related to my environment, but I perfectly run the command in my terminal (and it is working) but it throws me an error when ran through Poedit :( Did you already experienced this problem?

    I'm running Poedit 1.6.10 (2957)

    And my error is :

    Unable to run the program : xgettext-template --force-po -o "/var/folders/wt/5t32_hfj4f3fnsgc5q8svcsw0000gp/T/poeditZGIuaE/0extracted.pot" -k "_t" -k "_n:1,2" "../app/templates/application.hbs" "../app/templates/catch-all.hbs" "../app/templates/components/content-editable.hbs" "../app/templates/components/editable-item.hbs" "../app/templates/components/google-connect-button.hbs" "../app/templates/components/sync-button.hbs" "../app/templates/components/ui-button.hbs" "../app/templates/components/ui-icon.hbs" "../app/templates/components/ui-meter.hbs" "../app/templates/components/vertical-navigation.hbs" "../app/templates/flash.hbs" "../app/templates/google-connect.hbs" "../app/templates/index.hbs" "../app/templates/loading.hbs" "../app/templates/login.hbs" "../app/templates/meeting/agenda/notes.hbs"

    My question is: is it a permission-related problem with my global install of xgettext-template or is it a problem with Poedit?

    Thanks

    Reviewed by guillaumepotier at 2014-11-19 11:15
  • 7. Error: Lexical error on line 1. Unrecognized text.

    Working on Mac when creating folders it also creates a bunch of extra invisible files such as .DS_Store, these files then gets included by the xgettext package and obviously throws an error because they are invalid handlebars files.

    Could the -D parameter references and parse only .hbs or .handlebars files?

    Had to clear extra files using the commands described inside https://github.com/mikeal/tako/issues/4 but then as soon as something is modified, the file gets created again

    // Of course create an extention-language mapping array for the other supported languages: Swig, Volt and EJS
    if (options.directory) {
      readdirp({root: options.directory, fileFilter: ['*.hbs', '*.handlebars']}, function(err, res) {
        if (err) {
          throw err;
        }
    
        parseFiles(res.files.map(function (file) {
          return file.fullPath;
        }), output);
      });
    } else {
    
    Reviewed by tombertrand at 2016-07-07 20:32
  • 8. I've forked and published some competing and complementary packages

    github

    npm

    • ~~xgettext-template-dschissler~~ [Use github for all]

    The npm package xgettext-template-dschissler links to the github commits for the gettext-volt and gettext-swig packages.

    I'll admit that my gettext-volt regexs are not super great but they do handle a variety of Volt uses that the xgettext-swig one doesn't consider. I forked these since these uses are not valid for Swig and Nunjuck.

    Here is my test Volt template to demonstrate the different types of uses. My code is working against my larger code base.

    {{ t('Single Quote.')}}
    {{t("Double Quote.") }}
    
    {{n("Singular.", "Plural", n) }}
    
    {{ link_to('features/angular', this.translate.gettext('Angular'), 'class':'btn btn-primary') }}
    
    {{ submit_button(t('Change Password'), "class": "btn btn-primary") }}
    
    {{ link_to('signin', t('Signin')) }}
    
    {{ link_to("admin/users/create", "<i class='glyphicon glyphicon-plus-sign'></i> " ~ t('Create User'), "class": "btn btn-primary pull-right") }}
    
    
    Reviewed by dschissler at 2015-01-14 06:35
  • 9. Plural form extraction is not working for me

    Here is the handlebar markup.

    singular: {{_t "hb_msg"}}
    <br>
    plural: {{_n "hb_msg" "hb_msgs" n}}
    

    I have POedit setup the same as in the documentation.

    Here are the keywords:

    _t
    _n:1,2
    

    Your plural example is strange to me since I've never seen a default _ function that is setup as plural.

    <!-- and a simple plural example: -->
    <p>{{count}} {{_ "country" "countries" count}}</p>
    

    It just doesn't seem to figure out the plural form but it can figure out the singular form.

    Reviewed by dschissler at 2014-08-01 21:15
  • 10. Adding support for CLI flags and a new option

    I need to change the prefix for the tabs on the fly to use it on a slightly different situation (parsing some metadata files), and I went ahead and added the CLI flag support that was marked as a todo using optimist. It's working perfectly generating code both from templates and metadata files into the same .po file.

    Reviewed by trodrigues at 2012-07-27 10:33
  • 11. status check

    I would just like to check if you are interested in extending this? Of course I want to offer to try to contribute. If you have completely abandoned this component for some reason however it could prevent some wasted time ;)

    Reviewed by smhg at 2013-05-23 16:31
  • 12. Make `--files-from` work like in gettext

    Currently the file list supplied via --files-from is split at each line feed \n: https://github.com/gmarty/xgettext/blob/2a23cf592728bf98acda2b53f0ad1b01eae3b735/index.js#L195-L201

    This leads to problems with lists generated by programs that produce "Windows linebreaks" (CR LF, \r\n).

    This is why I suggest changing the current behaviour and making line splitting work like in GNU gettext: https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/file-list.c?id=b26729c67cffb2403d8a20b44606f5a08cb901b5#n68

    What is done is basically this:

    1. Get next line from the file.
    2. Remove trailing new line \n
    3. Remove any of: Tab \t, space (I'm not sure this is actually a good idea) and \r from the end of the string.
    Reviewed by sareyko at 2018-09-13 10:05
  • 13. Does anyone want to work on getting gettext-volt to understand contexts?

    Hello I am the creator and maintainer of gettext-volt. At the time that I created gettext-volt the umbrella xgettext-template project didn't support "contexts" and so I didn't add it. Admittedly, I don't exactly understand what they are used for but others have asked for them and apparently they must be useful or necessary.

    So if anyone would like to help out we have been accumulating some donation funds over at https://opencollective.com/phalcon and at the moment we have thousands of dollars its going up at a consistent rate. I don't control those funds but I created the original Patreon effort and I can help to push for someone getting paid to improve this, if money is a motivating factor. Just submit the pay funding request and we can take it from there. Its not necessary to even run Phalcon or Volt but just to parse out the templates and there are already some tests there.

    Thanks.

    Reviewed by dschissler at 2017-08-22 03:35
  • 14. Remove parser dependencies

    It sounds like a good idea to no longer list parsers as dependencies as it lowers maintenance updates.

    Requirements:

    • Take a look at approach of eslint/babel/...
    • Less focus on Poedit in Readme, more on npm/gulp/grunt/... integration.
    • Validate parser at runtime.
    Reviewed by smhg at 2017-01-09 16:50
  • 15. Additional options

    It seems like a good idea to have this discussion here as it can be useful to others.

    @eldarc wrote:

    I also wanted to ask you about some feature additions for xgettext-template. I would love to have the cleanup of strings that are not anymore in the source files. If I were to code this as a new parameter (for example --cleanup) would it have a chance to be merged?

    I would love this feature because I'm using this with Gulp. I have it setup for live watching. Every time there is a change in the template files, gulp will automatically call xgettext-template and extract strings. It would be great for the developer not to worry about temporary strings in the .po files. When the extraction is done, a new gulp task will use all those strings and translations to render static pages for every language.

    Also, is it possible to add a parameter --write-sync to make sure files are written synchronously? It's a bit of a problem to control it in gulp. It moves on to the next task, and that task could require files which should be written in the previous task.

    Also, it would be great to make an export to be used with gulp (or any other node app). For example, a function which will take an object with options and run xgettext-template. This could be also explained in the README.

    Reviewed by smhg at 2016-12-20 13:27
List of 77 languages for Laravel Framework 4, 5, 6, 7 and 8, Laravel Jetstream , Laravel Fortify, Laravel Cashier and Laravel Nova.

Laravel Lang In this repository, you can find the lang files for the Laravel Framework 4/5/6/7/8, Laravel Jetstream , Laravel Fortify, Laravel Cashier

May 28, 2022
🗓 A library to help you work with dates in multiple languages, based on Carbon.

Date This date library extends Carbon with multi-language support. Methods such as format, diffForHumans, parse, createFromFormat and the new timespan

May 24, 2022
75 languages support for Laravel 5 application based on Laravel-Lang/lang.

Laravel-lang 75 languages support for Laravel 5 application based on Laravel-Lang/lang. Features Laravel 5+ && Lumen support. Translations Publisher.

May 19, 2022
Mar 12, 2022
Making multiple identical function calls has the same effect as making a single function call.

Making multiple identical function calls has the same effect as making a single function call.

Oct 16, 2021
🌐 A minimalist languages library that made plugins support multiple languages.

libLanguages · libLanguages is a PocketMine-MP library for making plugins support multiple languages. Easy To Learn: Just declare it in onEnable() fun

May 1, 2022
Extracts information about web pages, like youtube videos, twitter statuses or blog articles.
Extracts information about web pages, like youtube videos, twitter statuses or blog articles.

Essence is a simple PHP library to extract media information from websites, like youtube videos, twitter statuses or blog articles. If you were alread

Apr 16, 2022
PropertyInfo extracts information about PHP class' properties using metadata of popular sources.

PropertyInfo Component The PropertyInfo component extracts information about PHP class' properties using metadata of popular sources. Resources Docume

May 19, 2022
Small tool that extracts witness data from Helium miner logs.

Helium Miner Logs Analyzer Small tool that extracts witness data from Helium miner logs. It currently works for the Pisces 100 and miner version miner

May 20, 2022
Doctrine2 behavioral extensions, Translatable, Sluggable, Tree-NestedSet, Timestampable, Loggable, Sortable

Doctrine Behavioral Extensions This package contains extensions for Doctrine ORM and MongoDB ODM that offer new functionality or tools to use Doctrine

May 18, 2022
Doctrine2 behavioral extensions, Translatable, Sluggable, Tree-NestedSet, Timestampable, Loggable, Sortable

Doctrine Behavioral Extensions This package contains extensions for Doctrine ORM and MongoDB ODM that offer new functionality or tools to use Doctrine

May 23, 2022
Making Eloquent models translatable
Making Eloquent models translatable

A trait to make Eloquent models translatable This package contains a trait to make Eloquent models translatable. Translations are stored as json. Ther

May 16, 2022
This module integrates Silverstripe CMS with Google Translate API and then allows content editors to use automatic translation for every translatable field.
This module integrates Silverstripe CMS with Google Translate API and then allows content editors to use automatic translation for every translatable field.

Autotranslate This module integrates Silverstripe CMS with Google Translate API and then allows content editors to use automatic translation for every

Jan 3, 2022
Blade Snip allows you to use parts of a blade template multiple times. Basically partials, but inline.

Blade Snip Blade Snip allows you to use parts of a blade template multiple times. Basically partials, but inline: <div class="products"> @snip('pr

Mar 17, 2022
PHP Template Attribute Language — template engine for XSS-proof well-formed XHTML and HTML5 pages

PHPTAL - Template Attribute Language for PHP Requirements If you want to use the builtin internationalisation system (I18N), the php-gettext extension

Apr 14, 2022
Is an Extension of Laravel View Class which compiles String Template on the fly. It automatically detects changes on your string template and recompiles it if needed.

Laravel-fly-view Is an Extension of Laravel View Class which compiles String Template on the fly. It automatically detects changes on your string temp

Aug 15, 2021
PaaS template based on production template using platform.sh

Shopware for Platform.sh This template builds Shopware on Platform.sh using Composer. To get started on Platform.sh, please visit https://docs.platfor

May 2, 2022
Textpattern-plugin-template - A template for building plugins for Textpattern CMS.

Plugin template for Textpattern CMS Developer documentation Refer to the Textpattern plugin development documentation, and notably the Plugin template

Apr 17, 2022
:globe_with_meridians: List of all countries with names and ISO 3166-1 codes in all languages and data formats.
:globe_with_meridians: List of all countries with names and ISO 3166-1 codes in all languages and data formats.

symfony upgrade fixer • twig gettext extractor • wisdom • centipede • permissions handler • extraload • gravatar • locurro • country list • transliter

May 25, 2022