bc-gettext-utils v1.1.1
Bulletcode gettext utilities
bc-gettext-utils is a toolset for Node.js which helps creating and updating translations in a format compatible with gettext .po and .mo files. It extracts translatable strings from JavaScript, .NET and PHP source files and merges extracted translations with existing ones.
In order to load and save translations in .po and .mo formats, use the gettext-parser library.
Usage
Install using npm:
npm install bc-gettext-utilsExtract translations
Use the extractors collection of functions to extract translatable strings from source files, e.g.:
const { translationBuilder, extractors } = require( 'bc-gettext-utils' );
const builder = translationBuilder();
builder.add( file, extractors.js( text, [options] ) );
builder.add( file, extractors.vue( text, [options] ) );
builder.add( file, extractors.cs( text, [options] ) );
builder.add( file, extractors.cshtml( text, [options] ) );
builder.add( file, extractors.xaml( text, [options] ) );
builder.add( file, extractors.php( text, [options] ) );
const translations = builder.translations;
const count = builder.count;Where:
fileis the path of the source file to be included in the commentstextis the source file contents as a UTF-8 stringoptionsis the optional configuration object (see below)
Available extractors:
extractors.js- JavaScript filesextractors.vue- Vue single-file componentsextractors.cs- C# filesextractors.cshtml- Razor pages and MVC viewsextractors.xaml- XAML filesextractors.php- PHP files
The object returned by builder.translations follows the format used by gettext-parser, e.g.:
{
"": {
"example": {
"msgid": "example",
"msgstr": [ "" ],
"comments": {
"reference": "/path/to/file:123"
}
}
},
"context": {
"another example": {
"msgctxt": "context",
"msgid": "another example",
"msgstr": [ "" ],
"comments": {
"reference": "/path/to/file:256"
}
}
}
}The number of extracted unique messages is available as builder.count.
JavaScript and C
The following functions or methods are recognized in JavaScript and C# code:
_( "text" );
_p( "context", "text" );
_n( "text", "plural text" );
_pn( "context", "text", "plural text" );Additional arguments are ignored. The names of these functions can be customized by passing additional options to the extractor, for example:
builder.add( file, extractors.js( text, file, {
string: '_',
particularString: '_p',
pluralString: '_n',
particularPluralString: '_pn',
} ) );Multiple names can be specified by passing an array.
Note that string literals must be used for the extraction to work. In JavaScript, 'single quoted' and "double quoted" strings are supported. In C#, "regular" and @"verbatim" string literals can be used.
Concatenation of multiple string literals using the + operator is also supported:
_( "this is a long text\n"
+ "and this is another line" );In C#, translatable strings are also extracted from the Display attribute and the ErrorMessage property of validation attributes, for example:
[Required( ErrorMessage = "This field is required." )]
[Display( Name = "First Name" )]
public string FirstName { get; set; }The names of the attribute and property can be customized by passing additional options to the extractor, for example:
builder.add( file, extractors.cs( text, file, {
displayAttribute: 'Display',
errorMessageProperty: 'ErrorMessage',
} ) );Vue
In Vue single-file components, translatable strings can be placed in the following locations:
- text interpolation using the "Mustache" syntax:
<p>{{ _( 'text' ) }}</p> - attribute bindings:
<a v-bind:title="_( 'text' )"> - shorthand attribute bindings:
<a :title="_( 'text' )"> - the
<script>block
Razor
In Razor .cshtml files, translatable strings are extracted from:
- Razor expressions:
@_( "text" ) - Razor code blocks:
@{ string title = _( "text" ); } - control structures - conditionals, loops, etc.:
@if ( a > 0 ) { title = _( "text" ); } - the
@functionsdirective
XAML
In XAML files, by default, translatable strings are extracted from i18n:Translate, i18n:Format and i18n:MultiFormat markup extensions, for example:
<Label Content="{i18n:Translate text}"/><Label Content="{i18n:Translate "hello, world", Context=context}"/><Label Content="{Binding Count, Converter={i18n:Format 'a dog', PluralText='{0} dogs'}}"/>
The element syntax is also supported:
<Label>
<Label.Content>
<i18n:Translate Context="context">another example</i18n:Translate>
</Label.Content>
</Label>The names of extensions and their attributes can be customized by passing additional options to the extractor, for example:
builder.add( file, extractors.xaml( text, file, {
extensions: [ 'i18n:Translate', 'i8n:Format', 'i8n:MultiFormat' ],
textAttribute: 'Text',
pluralTextAttribute: 'PluralText',
contextAttribute: 'Context',
} ) );PHP
In PHP files, translatable strings are extracted from code blocks starting with <?php or <?=.
The order of arguments can be changed to support WordPress internationalization functions, by setting the reverseContext option to true:
builder.add( file, extractors.php( text, file, {
string: [ '__', '_e', 'esc_html__', 'esc_html_e', 'esc_attr__', 'esc_attr_e' ],
particularString: [ '_x', '_ex', 'esc_html_x', 'esc_attr_x' ],
pluralString: '_n',
particularPluralString: '_nx',
reverseContext: true,
} ) );Merge translations
The following function can be used to merge existing, already translated messages, with newly extracted translations:
const { mergeTranslations } = require( 'bc-gettext-utils' );
const { translations, added, updated, deleted } = mergeTranslations( existingTranslations, newTranslations );The existingTranslations, newTranslations and the returned translations all follow the format used by gettext-parser.
In addition to the merged translations, this function returns the following information:
addedthe number of new translations which were not included in existing translations and have been addedupdatethe number of translations which existed before, but the reference or plural string has been updateddeletedthe number of existing translations which were not included in new translations and have been removed
The existing translations, translator comments and flags are preserved.
Normalize plurals
The following function can be used to normalize plurals in merged translations:
const { normalizePlurals } = require( 'bc-gettext-utils' );
const normalizedTranslations = normalizePlurals( translations, 2 );It ensures that the plural messages contain the specified number of translated strings, and singular messages contain exactly one translated string.
Sort translations
Use the compareReference function to sort translations by file path and line number. This can be used when creating a .po file using gettext-parser:
const { compareReference } = require( 'bc-gettext-utils' );
const gettextParser = require( 'gettext-parser' );
const data = { headers, translations };
const output = gettextParser.po.compile( data, { sort: compareReference } );