Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-gettext

Package Overview
Dependencies
Maintainers
2
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-gettext - npm Package Compare versions

Comparing version 1.1.0 to 2.0.0-rc.0

362

lib/gettext.js
'use strict';
var get = require('lodash.get');
var plurals = require('./plurals');
var gettextParser = require('gettext-parser');

@@ -9,79 +9,157 @@ module.exports = Gettext;

/**
* Gettext function
* Creates and returns a new Gettext instance.
*
* @constructor
* @param {Object} options A set of options
* @param {Boolean} options.debug Whether to output debug info into the
* console.
* @return {Object} A Gettext instance
*/
function Gettext() {
this.domains = {};
this._currentDomain = false;
function Gettext(options) {
options = options || {};
this.catalogs = {};
this.locale = null;
this.domain = 'messages';
this.listeners = [];
// Set debug flag
if ('debug' in options) {
this.debug = options.debug === true;
}
else if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV) {
this.debug = process.env.NODE_ENV !== 'production';
}
else {
this.debug = false;
}
}
/**
* Adds a gettext to the domains list. If default textdomain is not set, uses it
* as default
* Adds an event listener.
*
* @param {String} domain Case insensitive language identifier (domain)
* @param {Buffer} fileContents Translations file (*.mo) contents as a Buffer object
* @param {String} eventName An event name
* @param {Function} callback An event handler function
*/
Gettext.prototype.addTextdomain = function(domain, file) {
domain = this._normalizeDomain(domain);
var translation;
Gettext.prototype.on = function(eventName, callback) {
this.listeners.push({
eventName: eventName,
callback: callback
});
};
if (file && file.translations) {
translation = file;
}
else if (file && typeof file !== 'string') {
translation = gettextParser.mo.parse(file, 'utf-8');
}
/**
* Removes an event listener.
*
* @param {String} eventName An event name
* @param {Function} callback A previously registered event handler function
*/
Gettext.prototype.off = function(eventName, callback) {
this.listeners = this.listeners.filter(function(listener) {
return (
listener.eventName === eventName &&
listener.callback === callback
) === false;
});
};
if (!translation) {
translation = gettextParser.po.parse(file || '', 'utf-8');
/**
* Emits an event to all registered event listener.
*
* @param {String} eventName An event name
* @param {any} eventData Data to pass to event listeners
*/
Gettext.prototype.emit = function(eventName, eventData) {
for (var i = 0; i < this.listeners.length; i++) {
var listener = this.listeners[i];
if (listener.eventName === eventName) {
listener.callback(eventData);
}
}
};
// We do not want to parse and compile stuff from unknown sources
// so we only use precompiled plural definitions
var pluralsInfo = plurals[this._normalizeDomain(domain, true)];
if (pluralsInfo && translation.headers) {
translation.headers['plural-forms'] = pluralsInfo.pluralsText;
translation.pluralsFunc = pluralsInfo.pluralsFunc;
} else {
// default plurals to EN rules
translation.pluralsFunc = plurals.en.pluralsFunc;
/**
* Logs a warning to the console if debug mode is enabled.
*
* @ignore
* @param {String} message A warning message
*/
Gettext.prototype.warn = function(message) {
if (this.debug) {
console.warn(message);
}
this.domains[domain] = translation;
this.emit('error', message);
};
if (!this._currentDomain) {
this._currentDomain = domain;
/**
* Stores a set of translations in the set of gettext
* catalogs.
*
* @example
* gt.addTranslations('sv-SE', 'messages', translationsObject)
*
* @param {String} locale A locale string
* @param {String} domain A domain name
* @param {Object} translations An object of gettext-parser JSON shape
*/
Gettext.prototype.addTranslations = function(locale, domain, translations) {
if (!this.catalogs[locale]) {
this.catalogs[locale] = {};
}
this.catalogs[locale][domain] = translations;
};
/**
* Changes the current default textdomain
* Sets the locale to get translated messages for.
*
* @param {String} [domain] Case insensitive language identifier
* @return {String} cuurent textdomain
* @example
* gt.setLocale('sv-SE')
*
* @param {String} locale A locale
*/
Gettext.prototype.textdomain = function(updatedDomain) {
if (!arguments.length) {
return this._currentDomain;
Gettext.prototype.setLocale = function(locale) {
if (!locale) {
this.warn('You called setLocale() with an empty value, which makes little sense.');
return;
}
updatedDomain = this._normalizeDomain(updatedDomain);
if (this._currentDomain !== updatedDomain && this.domains.hasOwnProperty(updatedDomain)) {
this._currentDomain = updatedDomain;
return true;
} else {
return false;
if (!this.catalogs[locale]) {
this.warn('You called setLocale() with "' + locale + '", but no translations for that locale has been added.');
return;
}
this.locale = locale;
};
/**
* Sets the default gettext domain.
*
* @example
* gt.setTextDomain('domainname')
*
* @param {String} domain A gettext domain name
*/
Gettext.prototype.setTextDomain = function(domain) {
if (!domain) {
this.warn('You called setTextDomain() with an empty `domain` value, which is not allowed.');
return;
}
this.domain = domain;
};
/**
* Translates a string using the default textdomain
*
* @param {String} msgid String to be translated
* @return {String} translation or the original string if no translation was found
* @example
* gt.gettext('Some text')
*
* @param {String} msgid String to be translated
* @return {String} Translation or the original string if no translation was found
*/
Gettext.prototype.gettext = function(msgid) {
return this.dnpgettext(this._currentDomain, '', msgid);
return this.dnpgettext(this.domain, '', msgid);
};

@@ -92,5 +170,8 @@

*
* @param {String} domain Case insensitive language identifier
* @param {String} msgid String to be translated
* @return {String} translation or the original string if no translation was found
* @example
* gt.dgettext('domainname', 'Some text')
*
* @param {String} domain A gettext domain name
* @param {String} msgid String to be translated
* @return {String} Translation or the original string if no translation was found
*/

@@ -104,9 +185,12 @@ Gettext.prototype.dgettext = function(domain, msgid) {

*
* @param {String} msgid String to be translated
* @param {String} msgidPlural If no translation was found, return this on count!=1
* @param {Number} count Number count for the plural
* @return {String} translation or the original string if no translation was found
* @example
* gt.ngettext('One thing', 'Many things', numberOfThings)
*
* @param {String} msgid String to be translated when count is not plural
* @param {String} msgidPlural String to be translated when count is plural
* @param {Number} count Number count for the plural
* @return {String} Translation or the original string if no translation was found
*/
Gettext.prototype.ngettext = function(msgid, msgidPlural, count) {
return this.dnpgettext(this._currentDomain, '', msgid, msgidPlural, count);
return this.dnpgettext(this.domain, '', msgid, msgidPlural, count);
};

@@ -117,7 +201,10 @@

*
* @param {String} domain Case insensitive language identifier
* @param {String} msgid String to be translated
* @param {String} msgidPlural If no translation was found, return this on count!=1
* @param {Number} count Number count for the plural
* @return {String} translation or the original string if no translation was found
* @example
* gt.dngettext('domainname', 'One thing', 'Many things', numberOfThings)
*
* @param {String} domain A gettext domain name
* @param {String} msgid String to be translated when count is not plural
* @param {String} msgidPlural String to be translated when count is plural
* @param {Number} count Number count for the plural
* @return {String} Translation or the original string if no translation was found
*/

@@ -131,8 +218,11 @@ Gettext.prototype.dngettext = function(domain, msgid, msgidPlural, count) {

*
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {String} translation or the original string if no translation was found
* @example
* gt.pgettext('sports', 'Back')
*
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {String} Translation or the original string if no translation was found
*/
Gettext.prototype.pgettext = function(msgctxt, msgid) {
return this.dnpgettext(this._currentDomain, msgctxt, msgid);
return this.dnpgettext(this.domain, msgctxt, msgid);
};

@@ -143,6 +233,9 @@

*
* @param {String} domain Case insensitive language identifier
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {String} translation or the original string if no translation was found
* @example
* gt.dpgettext('domainname', 'sports', 'Back')
*
* @param {String} domain A gettext domain name
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {String} Translation or the original string if no translation was found
*/

@@ -154,12 +247,15 @@ Gettext.prototype.dpgettext = function(domain, msgctxt, msgid) {

/**
* Translates a plural string from a specifi context using the default textdomain
* Translates a plural string from a specific context using the default textdomain
*
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @param {String} msgidPlural If no translation was found, return this on count!=1
* @param {Number} count Number count for the plural
* @return {String} translation or the original string if no translation was found
* @example
* gt.npgettext('sports', 'Back', '%d backs', numberOfBacks)
*
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated when count is not plural
* @param {String} msgidPlural String to be translated when count is plural
* @param {Number} count Number count for the plural
* @return {String} Translation or the original string if no translation was found
*/
Gettext.prototype.npgettext = function(msgctxt, msgid, msgidPlural, count) {
return this.dnpgettext(this._currentDomain, msgctxt, msgid, msgidPlural, count);
return this.dnpgettext(this.domain, msgctxt, msgid, msgidPlural, count);
};

@@ -170,8 +266,11 @@

*
* @param {String} domain Case insensitive language identifier
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @param {String} msgidPlural If no translation was found, return this on count!=1
* @param {Number} count Number count for the plural
* @return {String} translation or the original string if no translation was found
* @example
* gt.dnpgettext('domainname', 'sports', 'Back', '%d backs', numberOfBacks)
*
* @param {String} domain A gettext domain name
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @param {String} msgidPlural If no translation was found, return this on count!=1
* @param {Number} count Number count for the plural
* @return {String} Translation or the original string if no translation was found
*/

@@ -183,3 +282,2 @@ Gettext.prototype.dnpgettext = function(domain, msgctxt, msgid, msgidPlural, count) {

domain = this._normalizeDomain(domain);
msgctxt = msgctxt || '';

@@ -191,6 +289,13 @@

if (!this.locale) {
this.warn('You need to set a locale using setLocale(locale) before getting translated messages.');
return defaultTranslation;
}
translation = this._getTranslation(domain, msgctxt, msgid);
if (translation) {
if (typeof count === 'number') {
index = this.domains[domain].pluralsFunc(count);
var pluralsFunc = plurals[Gettext.getLanguageCode(this.locale)].pluralsFunc;
index = pluralsFunc(count);
if (typeof index === 'boolean') {

@@ -205,2 +310,6 @@ index = index ? 1 : 0;

}
else {
this.warn('No translation was found for msgid "' + msgid + '" in msgctxt "' + msgctxt + '" and domain "' + domain + '"');
}
return defaultTranslation;

@@ -210,8 +319,12 @@ };

/**
* Retrieves comments object for a translation
* Retrieves comments object for a translation. The comments object
* has the shape `{ translator, extracted, reference, flag, previous }`.
*
* @param {String} domain Case insensitive language identifier
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {Object} comments object or false if not found
* @example
* const comment = gt.getComment('domainname', 'sports', 'Backs')
*
* @param {String} domain A gettext domain name
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {Object} Comments object or false if not found
*/

@@ -221,4 +334,2 @@ Gettext.prototype.getComment = function(domain, msgctxt, msgid) {

domain = this._normalizeDomain(domain);
translation = this._getTranslation(domain, msgctxt, msgid);

@@ -235,41 +346,56 @@ if (translation) {

*
* @param {String} domain Case insensitive language identifier
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {Object} translation object or false if not found
* @private
* @param {String} domain A gettext domain name
* @param {String} msgctxt Translation context
* @param {String} msgid String to be translated
* @return {Object} Translation object or false if not found
*/
Gettext.prototype._getTranslation = function(domain, msgctxt, msgid) {
var translation;
msgctxt = msgctxt || '';
domain = this._normalizeDomain(domain);
if (this.domains.hasOwnProperty(domain)) {
if (this.domains[domain].translations && this.domains[domain].translations[msgctxt]) {
if ((translation = this.domains[domain].translations[msgctxt][msgid])) {
return translation;
}
}
}
return get(this.catalogs, [this.locale, domain, 'translations', msgctxt, msgid]);
};
return false;
/**
* Returns the language code part of a locale
*
* @example
* Gettext.getLanguageCode('sv-SE')
* // -> "sv"
*
* @param {String} locale A case-insensitive locale string
* @returns {String} A language code
*/
Gettext.getLanguageCode = function(locale) {
return locale.split(/[\-_]/)[0].toLowerCase();
};
/**
* Normalizes textdomain value
* This function will be removed in the final 2.0.0 release.
*
* @param {String} domain Textdomain
* @param {Boolean} [isShort] If true then returns only language
* @returns {String} Normalized textdomain
* @deprecated
*/
Gettext.prototype._normalizeDomain = function(domain, isShort) {
var parts = (domain || '').toString().split('.').shift().split(/[\-_]/);
var language = (parts.shift() || '').toLowerCase();
var locale = (parts.join('-') || '').toUpperCase();
Gettext.prototype.addTextdomain = function() {
if (isShort) {
return language;
} else {
return [].concat(language || []).concat(locale || []).join('_');
}
// TODO(alexanderwallin): Add instructions for file i/o
console.error('addTextdomain() is deprecated.\n\n' +
'* To add translations, use addTranslations()\n' +
'* To set the default domain, use setTextDomain()\n' +
'\n' +
'To read more about the migration from node-gettext v1 to v2, ' +
'see https://github.com/alexanderwallin/node-gettext/#migrating-from-1x-to-2x');
};
/**
* This function will be removed in the final 2.0.0 release.
*
* @deprecated
*/
Gettext.prototype.textdomain = function() {
console.error('textdomain() is deprecated.\n\n' +
'* To set the current locale, use setLocale()\n' +
'* To set the default domain, use setTextDomain()\n' +
'\n' +
'To read more about the migration from node-gettext v1 to v2, ' +
'see https://github.com/alexanderwallin/node-gettext/#migrating-from-1x-to-2x');
};
{
"name": "node-gettext",
"description": "Gettext client for Node.js to use .mo files for I18N",
"version": "1.1.0",
"description": "A JavaScript implementation of gettext, a localization framework",
"version": "2.0.0-rc.0",
"author": "Andris Reinman",
"maintainers": [
{
"name": "andris",
"email": "andris@node.ee"
"name": "Alexander Wallin",
"email": "office@alexanderwallin.com"
}
],
"homepage": "http://github.com/andris9/node-gettext",
"homepage": "http://github.com/alexanderwallin/node-gettext",
"repository": {
"type": "git",
"url": "http://github.com/andris9/node-gettext.git"
"url": "http://github.com/alexanderwallin/node-gettext.git"
},
"scripts": {
"test": "grunt"
"test": "grunt",
"docs": "jsdoc2md -f lib/gettext.js -t docs/README.template.md --partial docs/templates/*.hbs --param-list-format list > README.md"
},
"main": "./lib/gettext",
"main": "./lib/gettext.js",
"files": [
"lib",
"test"
],
"licenses": [
{
"type": "MIT",
"url": "http://github.com/andris9/node-gettext/blob/master/LICENSE"
"url": "http://github.com/alexanderwallin/node-gettext/blob/master/LICENSE"
}
],
"dependencies": {
"gettext-parser": "^1.1.2"
"lodash.get": "^4.4.2"
},

@@ -36,3 +41,5 @@ "devDependencies": {

"grunt-mocha-test": "^0.12.7",
"mocha": "^2.4.5"
"jsdoc-to-markdown": "^2.0.1",
"mocha": "^2.4.5",
"sinon": "^1.17.7"
},

@@ -45,5 +52,7 @@ "engine": {

"l10n",
"gettext",
"mo"
"internationalization",
"localization",
"translation",
"gettext"
]
}

@@ -1,129 +0,360 @@

# node-gettext
**node-gettext** is a Node.JS module to use .MO and .PO files.
<p align="center">
<img src="docs/node-gettext-logo.png" width="160" height="160" />
</p>
**NB!** If you just want to parse or compile mo/po files, check out [gettext-parser](https://github.com/andris9/gettext-parser).
<h1 align="center">
node-gettext
</h1>
## Features
[![Build Status](https://travis-ci.org/alexanderwallin/node-gettext.svg?branch=master)](http://travis-ci.org/alexanderwallin/node-gettext)
[![npm version](https://badge.fury.io/js/node-gettext.svg)](https://badge.fury.io/js/node-gettext)
* Load binary *MO* or source *PO* files
* Supports contexts and plurals
**`node-gettext`** is a JavaScript implementation of [gettext](https://www.gnu.org/software/gettext/gettext.html), a localization framework.
[![Build Status](https://secure.travis-ci.org/andris9/node-gettext.png)](http://travis-ci.org/andris9/node-gettext)
If you just want to parse or compile mo/po files, check out [gettext-parser](https://github.com/smhg/gettext-parser).
## Support node-gettext development
**NOTE:** This is the README for v2 of node-gettext, which introduces many braking changes and is currently in alpha. You can find the [README for v1 here](https://github.com/alexanderwallin/node-gettext/blob/master/docs/v1/README.md).
[![Donate to author](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DB26KWR2BQX5W)
* [Features](#features)
* [Installation](#installation)
* [Usage](#usage)
* [Migrating from v1 to v2](#migrating-from-v1-to-v2)
* [API](#api)
* [License](#license)
* [See also](#see-also)
## Features
* Supports domains, contexts and plurals
* Supports .json, .mo and .po files with the help of [gettext-parser](https://github.com/smhg/gettext-parser)
* Ships with plural forms for 136 languages
* Change locale or domain on the fly
* Useful error messages enabled by a `debug` option
* Emits events for internal errors, such as missing translations
## Installation
npm install node-gettext
```sh
npm install --save node-gettext
```
## Usage
### Create a new Gettext object
```js
import Gettext from 'node-gettext'
import swedishTranslations from './translations/sv-SE.json'
var Gettext = require("node-gettext");
const gt = new Gettext()
gt.addTranslations('sv-SE', 'messages', swedishTranslations)
gt.setLocale('sv-SE')
var gt = new Gettext();
gt.gettext('The world is a funny place')
// -> "Världen är en underlig plats"
```
### Add a language
### Error events
*addTextdomain(domain, file)*
```js
// Add translations etc...
Language data needs to be in the Buffer format - it can be either contents of a *MO* or *PO* file.
gt.on('error', error => console.log('oh nose', error))
gt.gettext('An unrecognized message')
// -> 'oh nose', 'An unrecognized message'
```
*addTextdomain(domain[, fileContents])*
Load from a *MO* file
## Migrating from v1 to v2
var fileContents = fs.readFileSync("et.mo");
gt.addTextdomain("et", fileContents);
Version 1 of `node-gettext` confused domains with locales, which version 2 has corrected. `node-gettext` also no longer parses files or file paths for you, but accepts only ready-parsed JSON translation objects.
or load from a *PO* file
Here is a full list of all breaking changes:
var fileContents = fs.readFileSync("et.po");
gt.addTextdomain("et", fileContents);
* `textdomain(domain)` is now `setLocale(locale)`
* `dgettext`, `dngettext`, `dpgettext` and `dnpgettext` does not treat the leading `domain` argument as a locale, but as a domain. To get a translation from a certain locale you need to call `setLocale(locale)` beforehand.
* A new `setTextDomain(domain)` has been introduced
* `addTextdomain(domain, file)` is now `addTranslations(locale, domain, translations)`
* `addTranslations(locale, domain, translations)` **only accepts a JSON object with the [shape described in the `gettext-parser` README](https://github.com/smhg/gettext-parser#data-structure-of-parsed-mopo-files)**. To load translations from .mo or .po files, use [gettext-parser](https://github.com/smhg/gettext-parser), and it will provide you with valid JSON objects.
* `_currentDomain` is now `domain`
* `domains` is now `catalogs`
* The instance method `__normalizeDomain(domain)` has been replaced by a static method `Gettext.getLanguageCode(locale)`
Plural rules are automatically detected from the language code
gt.addTextdomain("et");
gt.setTranslation("et", false, "hello!", "tere!");
## API
### Check or change default language
<a name="Gettext"></a>
*textdomain(domain)*
## Gettext
<a name="new_Gettext_new"></a>
gt.textdomain("et");
### new Gettext(options)
Creates and returns a new Gettext instance.
The function also returns the current texdomain value
**Returns**: <code>Object</code> - A Gettext instance
**Params**
var curlang = gt.textdomain();
- `options`: <code>Object</code> - A set of options
- `.debug`: <code>Boolean</code> - Whether to output debug info into the
console.
## Translation methods
<a name="Gettext+on"></a>
### Load a string from default language file
### gettext.on(eventName, callback)
Adds an event listener.
*gettext(msgid)*
**Params**
var greeting = gt.gettext("Hello!");
- `eventName`: <code>String</code> - An event name
- `callback`: <code>function</code> - An event handler function
### Load a string from a specific language file
<a name="Gettext+off"></a>
*dgettext(domain, msgid)*
### gettext.off(eventName, callback)
Removes an event listener.
var greeting = gt.dgettext("et", "Hello!");
**Params**
### Load a plural string from default language file
- `eventName`: <code>String</code> - An event name
- `callback`: <code>function</code> - A previously registered event handler function
*ngettext(msgid, msgid_plural, count)*
<a name="Gettext+emit"></a>
gt.ngettext("%d Comment", "%d Comments", 10);
### gettext.emit(eventName, eventData)
Emits an event to all registered event listener.
### Load a plural string from a specific language file
**Params**
*dngettext(domain, msgid, msgid_plural, count)*
- `eventName`: <code>String</code> - An event name
- `eventData`: <code>any</code> - Data to pass to event listeners
gt.dngettext("et", "%d Comment", "%d Comments", 10)
<a name="Gettext+addTranslations"></a>
### Load a string of a specific context
### gettext.addTranslations(locale, domain, translations)
Stores a set of translations in the set of gettext
catalogs.
*pgettext(msgctxt, msgid)*
**Params**
gt.pgettext("menu items", "File");
- `locale`: <code>String</code> - A locale string
- `domain`: <code>String</code> - A domain name
- `translations`: <code>Object</code> - An object of gettext-parser JSON shape
### Load a string of a specific context from specific language file
**Example**
```js
gt.addTranslations('sv-SE', 'messages', translationsObject)
```
<a name="Gettext+setLocale"></a>
*dpgettext(domain, msgctxt, msgid)*
### gettext.setLocale(locale)
Sets the locale to get translated messages for.
gt.dpgettext("et", "menu items", "File");
**Params**
### Load a plural string of a specific context
- `locale`: <code>String</code> - A locale
*npgettext(msgctxt, msgid, msgid_plural, count)*
**Example**
```js
gt.setLocale('sv-SE')
```
<a name="Gettext+setTextDomain"></a>
gt.npgettext("menu items", "%d Recent File", "%d Recent Files", 3);
### gettext.setTextDomain(domain)
Sets the default gettext domain.
### Load a plural string of a specific context from specific language file
**Params**
*dnpgettext(domain, msgctxt, msgid, msgid_plural, count)*
- `domain`: <code>String</code> - A gettext domain name
gt.dnpgettext("et", "menu items", "%d Recent File", "%d Recent Files", 3);
**Example**
```js
gt.setTextDomain('domainname')
```
<a name="Gettext+gettext"></a>
### Get comments for a translation (if loaded from PO)
### gettext.gettext(msgid) ⇒ <code>String</code>
Translates a string using the default textdomain
*getComment(domain, msgctxt, msgid)*
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
gt.getComment("et", "menu items", "%d Recent File");
- `msgid`: <code>String</code> - String to be translated
Returns an object in the form of `{translator: "", extracted: "", reference: "", flag: "", previous: ""}`
**Example**
```js
gt.gettext('Some text')
```
<a name="Gettext+dgettext"></a>
## Advanced handling
### gettext.dgettext(domain, msgid) ⇒ <code>String</code>
Translates a string using a specific domain
If you need the translation object for a domain, for example `et_EE`, you can access it from `gt.domains.et_EE`.
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
If you want modify it and compile it to *mo* or *po*, checkout [gettext-parser](https://github.com/andris9/gettext-parser) module.
- `domain`: <code>String</code> - A gettext domain name
- `msgid`: <code>String</code> - String to be translated
**Example**
```js
gt.dgettext('domainname', 'Some text')
```
<a name="Gettext+ngettext"></a>
### gettext.ngettext(msgid, msgidPlural, count) ⇒ <code>String</code>
Translates a plural string using the default textdomain
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
- `msgid`: <code>String</code> - String to be translated when count is not plural
- `msgidPlural`: <code>String</code> - String to be translated when count is plural
- `count`: <code>Number</code> - Number count for the plural
**Example**
```js
gt.ngettext('One thing', 'Many things', numberOfThings)
```
<a name="Gettext+dngettext"></a>
### gettext.dngettext(domain, msgid, msgidPlural, count) ⇒ <code>String</code>
Translates a plural string using a specific textdomain
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
- `domain`: <code>String</code> - A gettext domain name
- `msgid`: <code>String</code> - String to be translated when count is not plural
- `msgidPlural`: <code>String</code> - String to be translated when count is plural
- `count`: <code>Number</code> - Number count for the plural
**Example**
```js
gt.dngettext('domainname', 'One thing', 'Many things', numberOfThings)
```
<a name="Gettext+pgettext"></a>
### gettext.pgettext(msgctxt, msgid) ⇒ <code>String</code>
Translates a string from a specific context using the default textdomain
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
- `msgctxt`: <code>String</code> - Translation context
- `msgid`: <code>String</code> - String to be translated
**Example**
```js
gt.pgettext('sports', 'Back')
```
<a name="Gettext+dpgettext"></a>
### gettext.dpgettext(domain, msgctxt, msgid) ⇒ <code>String</code>
Translates a string from a specific context using s specific textdomain
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
- `domain`: <code>String</code> - A gettext domain name
- `msgctxt`: <code>String</code> - Translation context
- `msgid`: <code>String</code> - String to be translated
**Example**
```js
gt.dpgettext('domainname', 'sports', 'Back')
```
<a name="Gettext+npgettext"></a>
### gettext.npgettext(msgctxt, msgid, msgidPlural, count) ⇒ <code>String</code>
Translates a plural string from a specific context using the default textdomain
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
- `msgctxt`: <code>String</code> - Translation context
- `msgid`: <code>String</code> - String to be translated when count is not plural
- `msgidPlural`: <code>String</code> - String to be translated when count is plural
- `count`: <code>Number</code> - Number count for the plural
**Example**
```js
gt.npgettext('sports', 'Back', '%d backs', numberOfBacks)
```
<a name="Gettext+dnpgettext"></a>
### gettext.dnpgettext(domain, msgctxt, msgid, msgidPlural, count) ⇒ <code>String</code>
Translates a plural string from a specifi context using a specific textdomain
**Returns**: <code>String</code> - Translation or the original string if no translation was found
**Params**
- `domain`: <code>String</code> - A gettext domain name
- `msgctxt`: <code>String</code> - Translation context
- `msgid`: <code>String</code> - String to be translated
- `msgidPlural`: <code>String</code> - If no translation was found, return this on count!=1
- `count`: <code>Number</code> - Number count for the plural
**Example**
```js
gt.dnpgettext('domainname', 'sports', 'Back', '%d backs', numberOfBacks)
```
<a name="Gettext+getComment"></a>
### gettext.getComment(domain, msgctxt, msgid) ⇒ <code>Object</code>
Retrieves comments object for a translation. The comments object
has the shape `{ translator, extracted, reference, flag, previous }`.
**Returns**: <code>Object</code> - Comments object or false if not found
**Params**
- `domain`: <code>String</code> - A gettext domain name
- `msgctxt`: <code>String</code> - Translation context
- `msgid`: <code>String</code> - String to be translated
**Example**
```js
const comment = gt.getComment('domainname', 'sports', 'Backs')
```
<a name="Gettext+addTextdomain"></a>
### ~~gettext.addTextdomain()~~
***Deprecated***
This function will be removed in the final 2.0.0 release.
<a name="Gettext+textdomain"></a>
### ~~gettext.textdomain()~~
***Deprecated***
This function will be removed in the final 2.0.0 release.
<a name="Gettext.getLanguageCode"></a>
### Gettext.getLanguageCode(locale) ⇒ <code>String</code>
Returns the language code part of a locale
**Returns**: <code>String</code> - A language code
**Params**
- `locale`: <code>String</code> - A case-insensitive locale string
**Example**
```js
Gettext.getLanguageCode('sv-SE')
// -> "sv"
```
## License
MIT
## See also
* [gettext-parser](https://github.com/smhg/gettext-parser) - Parsing and compiling gettext translations between .po/.mo files and JSON
* [react-gettext-parser](https://github.com/lagetse/react-gettext-parser) - Extracting gettext translatable strings from JS(X) code
* [narp](https://github.com/lagetse/narp) - Workflow CLI tool that syncs translations between your app and Transifex

@@ -6,2 +6,3 @@ 'use strict';

var fs = require('fs');
var sinon = require('sinon');

@@ -12,69 +13,64 @@ var expect = chai.expect;

describe('Gettext', function() {
var gt;
var jsonFile;
describe('#_normalizeDomain', function() {
it('should normalize domain key', function() {
var gt = new Gettext();
beforeEach(function() {
gt = new Gettext({ debug: false });
jsonFile = JSON.parse(fs.readFileSync(__dirname + '/fixtures/latin13.json'));
});
expect(gt._normalizeDomain('ab-cd_ef.utf-8')).to.equal('ab_CD-EF');
expect(gt._normalizeDomain('ab-cd_ef', true)).to.equal('ab');
describe('#getLanguageCode', function() {
it('should normalize locale string', function() {
expect(Gettext.getLanguageCode('ab-cd_ef.utf-8')).to.equal('ab');
expect(Gettext.getLanguageCode('ab-cd_ef')).to.equal('ab');
});
});
describe('#addTextdomain', function() {
describe('#addTranslations', function() {
it('should store added translations', function() {
gt.addTranslations('et-EE', 'messages', jsonFile);
it('Should add from a mo file', function() {
var gt = new Gettext();
var moFile = fs.readFileSync(__dirname + '/fixtures/latin13.mo');
expect(gt.catalogs['et-EE']).to.exist;
expect(gt.catalogs['et-EE'].messages).to.exist;
expect(gt.catalogs['et-EE'].messages.charset).to.equal('iso-8859-13');
});
gt.addTextdomain('et-EE', moFile);
it('should store added translations on a custom domain', function() {
gt.addTranslations('et-EE', 'mydomain', jsonFile);
expect(gt.domains.et_EE).to.exist;
expect(gt.domains.et_EE.charset).to.equal('iso-8859-13');
expect(gt.catalogs['et-EE'].mydomain).to.exist;
expect(gt.catalogs['et-EE'].mydomain.charset).to.equal('iso-8859-13');
});
});
it('Should add from a po file', function() {
var gt = new Gettext();
var poFile = fs.readFileSync(__dirname + '/fixtures/latin13.po');
describe('#setLocale', function() {
it('should have no default locale', function() {
expect(gt.locale).to.equal(null);
});
gt.addTextdomain('et-EE', poFile);
expect(gt.domains.et_EE).to.exist;
expect(gt.domains.et_EE.charset).to.equal('iso-8859-13');
it ('should not accept a locale that has no translations', function() {
gt.setLocale('de-AT');
expect(gt.locale).to.equal(null);
});
it('Should add from a json file', function() {
var gt = new Gettext();
var jsonFile = JSON.parse(fs.readFileSync(__dirname + '/fixtures/latin13.json'));
gt.addTextdomain('et-EE', jsonFile);
expect(gt.domains.et_EE).to.exist;
expect(gt.domains.et_EE.charset).to.equal('iso-8859-13');
it('should change locale if translations exist', function() {
gt.addTranslations('et-EE', 'messages', jsonFile);
gt.setLocale('et-EE');
expect(gt.locale).to.equal('et-EE');
});
});
describe('#textdomain', function() {
it('should set default domain', function() {
var gt = new Gettext();
var moFile = fs.readFileSync(__dirname + '/fixtures/latin13.mo');
describe('#setTextDomain', function() {
it('defaults to "messages"', function() {
expect(gt.domain).to.equal('messages');
});
expect(gt.textdomain()).to.be.false;
gt.addTextdomain('et-EE', moFile);
expect(gt.textdomain()).to.equal('et_EE');
gt.addTextdomain('cd-EE', moFile);
expect(gt.textdomain()).to.equal('et_EE');
it('does not accept an empty value', function() {
gt.setTextDomain('');
expect(gt.domain).to.equal('messages');
});
it('should change default domain', function() {
var gt = new Gettext();
var moFile = fs.readFileSync(__dirname + '/fixtures/latin13.mo');
expect(gt.textdomain()).to.be.false;
gt.addTextdomain('et-EE', moFile);
expect(gt.textdomain()).to.equal('et_EE');
gt.addTextdomain('cd-EE', moFile);
expect(gt.textdomain()).to.equal('et_EE');
gt.textdomain('cd_EE');
expect(gt.textdomain()).to.equal('cd_EE');
it('accepts and stores a non-empty domain name', function() {
gt.setTextDomain('mydomain');
expect(gt.domain).to.equal('mydomain');
});

@@ -84,33 +80,22 @@ });

describe('Resolve translations', function() {
var gt;
beforeEach(function() {
gt = new Gettext();
var poFile = fs.readFileSync(__dirname + '/fixtures/latin13.po');
gt.addTextdomain('et-EE', poFile);
gt.addTranslations('et-EE', 'messages', jsonFile);
gt.setLocale('et-EE');
});
describe('#dnpgettext', function() {
it('should return default singular', function() {
expect(gt.dnpgettext('et_EE', '', '0 matches', 'multiple matches', 1)).to.equal('0 matches');
});
it('should return default plural', function() {
expect(gt.dnpgettext('et_EE', '', '0 matches', 'multiple matches', 100)).to.equal('multiple matches');
});
it('should return singular match from default context', function() {
expect(gt.dnpgettext('et_EE', '', 'o2-1', 'o2-2', 1)).to.equal('t2-1');
expect(gt.dnpgettext('messages', '', 'o2-1', 'o2-2', 1)).to.equal('t2-1');
});
it('should return plural match from default context', function() {
expect(gt.dnpgettext('et_EE', '', 'o2-1', 'o2-2', 2)).to.equal('t2-2');
expect(gt.dnpgettext('messages', '', 'o2-1', 'o2-2', 2)).to.equal('t2-2');
});
it('should return singular match from selected context', function() {
expect(gt.dnpgettext('et_EE', 'c2', 'co2-1', 'co2-2', 1)).to.equal('ct2-1');
expect(gt.dnpgettext('messages', 'c2', 'co2-1', 'co2-2', 1)).to.equal('ct2-1');
});
it('should return plural match from selected context', function() {
expect(gt.dnpgettext('et_EE', 'c2', 'co2-1', 'co2-2', 2)).to.equal('ct2-2');
expect(gt.dnpgettext('messages', 'c2', 'co2-1', 'co2-2', 2)).to.equal('ct2-2');
});

@@ -131,3 +116,3 @@

it('should return singular from default context', function() {
expect(gt.dgettext('et-ee', 'o2-1')).to.equal('t2-1');
expect(gt.dgettext('messages', 'o2-1')).to.equal('t2-1');
});

@@ -144,3 +129,3 @@ });

it('should return plural from default context', function() {
expect(gt.dngettext('et-ee', 'o2-1', 'o2-2', 2)).to.equal('t2-2');
expect(gt.dngettext('messages', 'o2-1', 'o2-2', 2)).to.equal('t2-2');
});

@@ -157,3 +142,3 @@ });

it('should return singular from selected context', function() {
expect(gt.dpgettext('et-ee', 'c2', 'co2-1')).to.equal('ct2-1');
expect(gt.dpgettext('messages', 'c2', 'co2-1')).to.equal('ct2-1');
});

@@ -170,3 +155,3 @@ });

it('should return comments object', function() {
expect(gt.getComment('et-ee', '', 'test')).to.deep.equal({
expect(gt.getComment('messages', '', 'test')).to.deep.equal({
translator: 'Normal comment line 1\nNormal comment line 2',

@@ -181,2 +166,42 @@ extracted: 'Editors note line 1\nEditors note line 2',

});
});
describe('Unresolvable transaltions', function() {
beforeEach(function() {
gt.addTranslations('et-EE', 'messages', jsonFile);
});
it('should pass msgid until a locale is set', function() {
expect(gt.gettext('o2-1')).to.equal('o2-1');
gt.setLocale('et-EE');
expect(gt.gettext('o2-1')).to.equal('t2-1');
});
it('should pass unresolved singular message when count is 1', function() {
expect(gt.dnpgettext('messages', '', '0 matches', 'multiple matches', 1)).to.equal('0 matches');
});
it('should pass unresolved plural message when count > 1', function() {
expect(gt.dnpgettext('messages', '', '0 matches', 'multiple matches', 100)).to.equal('multiple matches');
});
});
describe('Events', function() {
var errorListener;
beforeEach(function() {
errorListener = sinon.spy();
gt.on('error', errorListener);
});
it('should notify a registered listener of error events', function() {
gt.emit('error', 'Something went wrong');
expect(errorListener.callCount).to.equal(1);
});
it('should deregister a previously registered event listener', function() {
gt.off('error', errorListener);
gt.emit('error', 'Something went wrong');
expect(errorListener.callCount).to.equal(0);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc