xgettext-handlebars
v0.0.6
Published
Extract translatable strings from Handlebars templates
Downloads
4
Maintainers
Readme
xgettext-handlebars
Extract translatable strings from Handlebars templates.
Warning
This code is unstable and going through a major rewrite.
Usage
var xgettext = require('xgettext-handlebars');
xgettext('{{gettext "Hello World!"}}', {
// optional options
});
Features
Basic extraction
{{gettext "Hello World!"}}
Plurals
{{ngettext "boat" "boats" numBoats}}
gettext documentation on plural forms
Contexts
Necessary to disambiguate things like homonyms:
{{pgettext "noun" "file"}}
gettext documentation on contexts
Domains
Useful for splitting your translation catalogs up:
{{dgettext "plugin_catalog" "Hello World!"}}
gettext documentation on domains
Extracted comments
Useful for providing instructions to your localizers. Comments are extracted from Handlebars subexpressions:
{{gettext "Hi %s" (gettext-comment "%s is a variable")}}
gettext documentation on extracted comments
Options
filename
Filename the Handlebars string came from. Used in references.
// no filename, so references are non-existent or not very helpful
// (if they only have column number)
xgettext('{{gettext "Hi"}}');
// this would generate a reference in your PO entry that's actually useful
xgettext('{{gettext "Hi"}}', {filename: foo.js});
identifiers
Set of identifiers to extract. Defaults to every function in the standard gettext API, plus a common shorthand version of each function:
{
gettext: ['msgid'],
_: ['msgid'],
dgettext: ['domain', 'msgid'],
d_: ['domain', 'msgid'],
dcgettext: ['domain', 'msgid', 'category'],
dc_: ['domain', 'msgid', 'category'],
ngettext: ['msgid', 'msgid_plural', 'n'],
n_: ['msgid', 'msgid_plural', 'n'],
dngettext: ['domain', 'msgid', 'msgid_plural', 'n'],
dn_: ['domain', 'msgid', 'msgid_plural', 'n'],
dcngettext: ['domain', 'msgid', 'msgid_plural', 'n', 'category'],
dcn_: ['domain', 'msgid', 'msgid_plural', 'n', 'category'],
pgettext: ['msgctxt', 'msgid'],
p_: ['msgctxt', 'msgid'],
dpgettext: ['domain', 'msgctxt', 'msgid'],
dp_: ['domain', 'msgctxt', 'msgid'],
npgettext: ['msgctxt', 'msgid', 'msgid_plural', 'n'],
np_: ['msgctxt', 'msgid', 'msgid_plural', 'n'],
dnpgettext: ['domain', 'msgctxt', 'msgid', 'msgid_plural', 'n'],
dnp_: ['domain', 'msgctxt', 'msgid', 'msgid_plural', 'n'],
dcnpgettext: ['domain', 'msgctxt', 'msgid', 'msgid_plural', 'n', 'category'],
dcnp_: ['domain', 'msgctxt', 'msgid', 'msgid_plural', 'n', 'category']
}
Each key in identifiers
indicates a Handlebars helper to extract, while the value indicates
the order of expected PO fields for that helper. For example,
npgettext: ['msgctxt', 'msgid', 'msgid_plural']
indicates that the npgettext
handlebars helper takes arguments of the form
{{npgettext "context" "string" "plural"}}
.
The default identifiers
assumes you're using helpers that match the gettext API, but you
can customize it to fit your needs. See the Examples section for more info.
While identifiers
allows for a large amount of freedom, there are some limits. Since
xgettext-handlebars
can't do much without knowing a string's message ID, each
extracted identifier must declare a msgid
. For example, the following will
throw an Error:
xgettext('{{gettext "Hi"}}', {
identifiers: {
// error, no msgid specified
i18n: ['string']
}
});
Similarly, if you want strings with the same msgid to be distinguished by
their contexts, use msgctxt
. Otherwise, contexts won't work. Likewise,
domain parameters should be called domain
.
Finally, you should name your plural message ID msgid_plural
. Otherwise, xgettext-handlebars
can't warn you about mismatched plural definitions like the following:
{{ngettext "goose" "goose"}}
{{ngettext "goose" "geese"}}
{{! error, should we use "goose" or "geese"? }}
defaultDomain
Optional string indicating the default domain. Defaults to messages
.
commentIdentifiers
Optional array of strings indicating names of subexpressions to extract
comments from. Defaults to ['gettext-comment']
.
Return value
The xgettext
function returns an object representing the set of extracted
messages.
{
"messages": { // messages are grouped under domain, which defaults to "messages"
msgid1: {
msgid: "msgid1", // useful when you have context
extractedComments: [
// Extracted comments are different from translator comments.
// Extracted comments come from the developers who put them in the
// code. Translator comments are added to PO files by translators.
"TRANSLATORS: please listen to me"
],
references: [ // list of all the places this msgid is used
{
// whatever you passed in as the `filename` option
filename: undefined
// see https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API
start: {
line: 1,
column: 0
},
end: {
line: 2,
column: 15
}
}
// there can be more references if this msigd appears multiple times
]
},
// plural messages have a msgid_plural field
boat: {
msgid: "boat",
msgid_plural: "boats",
references: [/* ...you get the idea...*/],
extractedComments: []
},
// Messages with context are stored as keys prefixed by their context
// and a separator. This is the same technique Jed uses.
"context\u0004msgid1": {
msgid: "msgid1",
msgctxt: "context",
references: [/* ... */]
}
},
"another domain": {
// if you define multiple domains in your strings, which you can do by
// using the dgettext family of functions, you'll get multiple domains in your ouput
}
}
Examples
Changing field order
Changing the field order is useful if your helpers' signatures don't match the
gettext API. For example, if your Handlebars helper ngettext
expects the plural
form to be passed first, initialize xgettext-handlebars
like so:
xgettext('{{gettext "boats" "boat"}}', {
identifiers: {
ngettext: ['msgid_plural', 'msgid']
// declare other identifiers as needed
}
});
Custom identifiers
You can define totally new identifiers to extract, for example:
xgettext('{{i18n "Hi"}}', {
identifiers: {
i18n: ['msgid']
}
});
Not that identifiers
overrides the built-in default identifiers. If you want to
add a new identifier to the existing set use xgettext.DEFAULT_IDENTIFIERS
:
xgettext('{{i18n "Hi"}}', {
identifiers: Object.assign({i18n: ['msgid']}, xgettext.DEFAULT_IDENTIFIERS)
});
Custom fields
You don't have to limit yourself to extracting gettext fields. For example, let's say you mark the gender of your strings (a field gettext doesn't otherwise support):
xgettext('{{i18n-gender "You" "female"}}', {
identifiers: {
'i18n-gender': ['msgid', 'gender']
}
});
The return value will include the gender
field in its output for this message:
{
msgid: 'You',
gender: 'female'
// other fields not shown
}
Ignoring arguments
xgettext-handlebars
ignores any extra arguments it encounters.
Take this example, using the default config for gettext
(['msgid']
):
{{! ignored will be ignored, only "message" will be extracted}}
{{gettext "message" ignored}}
Skipping arguments
Ignoring non-trailing arguments is also possible. Let's say you want to extract something of the form
{{i18n variable "Hi %s"}}
The first parameter to i18n
is a variable and shouldn't be extracted, while
the second field, the msgid, is what we actually care about. We can use
xgettext-handlebar's support for custom fields to ignore fields we don't want:
xgettext('{{i18n variable "Hi %s"}}', {
identifiers: {
i18n: ['parameter', 'msgid']
}
});
Note that the parameter will still technically be extracted, it's just in a field nothing uses. Here's the extracted message for the above example:
{
msgid: 'Hi %s',
parameter: 'variable'
}
License
MIT