Socket
Socket
Sign inDemoInstall

gettext-parser

Package Overview
Dependencies
Maintainers
2
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gettext-parser - npm Package Compare versions

Comparing version 6.0.0 to 7.0.0

.gitattributes

96

lib/poparser.js

@@ -6,11 +6,14 @@ const encoding = require('encoding');

module.exports.parse = parse;
module.exports.stream = stream;
/**
* Parses a PO object into translation table
*
* @param {Buffer|String} buffer PO object
* @param {String} [defaultCharset] Default charset to use
* @return {Object} Translation object
* @typedef {{ defaultCharset?: string, validation?: boolean }} Options
* @param {string | Buffer} input PO object
* @param {Options} [options] Optional options with defaultCharset and validation
*/
module.exports.parse = function (buffer, defaultCharset) {
const parser = new Parser(buffer, defaultCharset);
function parse (input, options = {}) {
const parser = new Parser(input, options);

@@ -23,8 +26,8 @@ return parser.parse();

*
* @param {String} [defaultCharset] Default charset to use
* @param {String} [options] Stream options
* @return {Stream} Transform stream
* @typedef {{ defaultCharset: strubg, validation: boolean }} Options
* @param {Options} [options] Optional options with defaultCharset and validation
* @param {import('readable-stream').TransformOptions} [transformOptions] Optional stream options
*/
module.exports.stream = function (defaultCharset, options) {
return new PoParserTransform(defaultCharset, options);
function stream (options = {}, transformOptions = {}) {
return new PoParserTransform(options, transformOptions);
};

@@ -36,7 +39,9 @@

*
* @typedef {{ defaultCharset?: string, validation?: boolean }} Options
* @constructor
* @param {Buffer|String} fileContents PO object
* @param {String} [defaultCharset] Default charset to use
* @param {string | Buffer} fileContents PO object
* @param {Options} options Options with defaultCharset and validation
*/
function Parser (fileContents, defaultCharset = 'iso-8859-1') {
function Parser (fileContents, { defaultCharset = 'iso-8859-1', validation = false }) {
this._validation = validation;
this._charset = defaultCharset;

@@ -384,2 +389,6 @@

if (lastNode) {
if (this._validation && 'msgid_plural' in lastNode) {
throw new SyntaxError(`Multiple msgid_plural error: entry "${lastNode.msgid}" in "${lastNode.msgctxt || ''}" context has multiple msgid_plural declarations.`);
}
lastNode.msgid_plural = tokens[i].value;

@@ -412,2 +421,37 @@ }

/**
* Validate token
*
* @param {Object} token Parsed token
* @param {Object} translations Translation table
* @param {string} msgctxt Message entry context
* @param {number} nplurals Number of epected plural forms
* @throws Will throw an error if token validation fails
*/
Parser.prototype._validateToken = function (
{
msgid = '',
msgid_plural = '', // eslint-disable-line camelcase
msgstr = []
},
translations,
msgctxt,
nplurals
) {
if (!this._validation) {
return;
}
if (msgid in translations[msgctxt]) {
throw new SyntaxError(`Duplicate msgid error: entry "${msgid}" in "${msgctxt}" context has already been declared.`);
// eslint-disable-next-line camelcase
} else if (msgid_plural && msgstr.length !== nplurals) {
// eslint-disable-next-line camelcase
throw new RangeError(`Plural forms range error: Expected to find ${nplurals} forms but got ${msgstr.length} for entry "${msgid_plural}" in "${msgctxt}" context.`);
// eslint-disable-next-line camelcase
} else if (!msgid_plural && msgstr.length !== 1) {
throw new RangeError(`Translation string range error: Extected 1 msgstr definitions associated with "${msgid}" in "${msgctxt}" context, found ${msgstr.length}.`);
}
};
/**
* Compose a translation table from tokens object

@@ -424,2 +468,3 @@ *

};
let nplurals = 1;
let msgctxt;

@@ -452,4 +497,7 @@

table.headers = sharedFuncs.parseHeader(tokens[i].msgstr[0]);
nplurals = sharedFuncs.parseNPluralFromHeadersSafely(table.headers, nplurals);
}
this._validateToken(tokens[i], table.translations, msgctxt, nplurals);
table.translations[msgctxt][tokens[i].msgid] = tokens[i];

@@ -481,13 +529,9 @@ }

*
* @typedef {{ defaultCharset: strubg, validation: boolean }} Options
* @constructor
* @param {String} [defaultCharset] Default charset to use
* @param {String} [options] Stream options
* @param {Options} options Optional options with defaultCharset and validation
* @param {import('readable-stream').TransformOptions} transformOptions Optional stream options
*/
function PoParserTransform (defaultCharset, options) {
if (!options && defaultCharset && typeof defaultCharset === 'object') {
options = defaultCharset;
defaultCharset = undefined;
}
this.defaultCharset = defaultCharset;
function PoParserTransform (options, transformOptions) {
this.options = options;
this._parser = false;

@@ -499,5 +543,5 @@ this._tokens = {};

this.initialTreshold = options.initialTreshold || 2 * 1024;
this.initialTreshold = transformOptions.initialTreshold || 2 * 1024;
Transform.call(this, options);
Transform.call(this, transformOptions);
this._writableState.objectMode = false;

@@ -532,3 +576,3 @@ this._readableState.objectMode = true;

this._parser = new Parser(chunk, this.defaultCharset);
this._parser = new Parser(chunk, this.options);
} else if (this._cacheSize) {

@@ -586,3 +630,3 @@ // this only happens if we had an uncompleted 8bit sequence from the last iteration

if (!this._parser && chunk) {
this._parser = new Parser(chunk, this.defaultCharset);
this._parser = new Parser(chunk, this.options);
}

@@ -589,0 +633,0 @@

module.exports.parseHeader = parseHeader;
module.exports.parseNPluralFromHeadersSafely = parseNPluralFromHeadersSafely;
module.exports.generateHeader = generateHeader;

@@ -8,2 +9,3 @@ module.exports.formatCharset = formatCharset;

// see https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html
const PLURAL_FORMS = 'Plural-Forms';
const HEADERS = new Map([

@@ -19,3 +21,3 @@ ['project-id-version', 'Project-Id-Version'],

['content-transfer-encoding', 'Content-Transfer-Encoding'],
['plural-forms', 'Plural-Forms']
['plural-forms', PLURAL_FORMS]
]);

@@ -25,2 +27,4 @@

const PLURAL_FORM_HEADER_NPLURALS_REGEX = /nplurals\s*=\s*(?<nplurals>\d+)/;
/**

@@ -51,2 +55,22 @@ * Parses a header string into an object of key-value pairs

/**
* Attempts to safely parse 'nplurals" value from "Plural-Forms" header
*
* @param {Object} [headers = {}] An object with parsed headers
* @returns {number} Parsed result
*/
function parseNPluralFromHeadersSafely (headers = {}, fallback = 1) {
const pluralForms = headers[PLURAL_FORMS];
if (!pluralForms) {
return fallback;
}
const {
groups: { nplurals } = { nplurals: '' + fallback }
} = pluralForms.match(PLURAL_FORM_HEADER_NPLURALS_REGEX) || {};
return parseInt(nplurals, 10) || fallback;
}
/**
* Joins a header object of key value pairs into a header string

@@ -135,2 +159,3 @@ *

* Comparator function for comparing msgid
*
* @param {Object} object with msgid prev

@@ -137,0 +162,0 @@ * @param {Object} object with msgid next

{
"name": "gettext-parser",
"description": "Parse and compile gettext po and mo files to/from json, nothing more, nothing less",
"version": "6.0.0",
"version": "7.0.0",
"author": "Andris Reinman",

@@ -26,15 +26,15 @@ "contributors": [

"dependencies": {
"content-type": "^1.0.4",
"content-type": "^1.0.5",
"encoding": "^0.1.13",
"readable-stream": "^4.1.0",
"readable-stream": "^4.3.0",
"safe-buffer": "^5.2.1"
},
"devDependencies": {
"chai": "^4.3.6",
"eslint": "^8.21.0",
"chai": "^4.3.7",
"eslint": "^8.39.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"mocha": "^10.0.0"
"eslint-plugin-promise": "^6.1.1",
"mocha": "^10.2.0"
},

@@ -41,0 +41,0 @@ "keywords": [

@@ -14,3 +14,2 @@ gettext-parser [![ci](https://github.com/smhg/gettext-parser/actions/workflows/ci.yml/badge.svg)](https://github.com/smhg/gettext-parser/actions/workflows/ci.yml)

### Parse PO files

@@ -20,3 +19,3 @@

gettextParser.po.parse(input[, defaultCharset]) → Object
gettextParser.po.parse(input[, options]) → Object

@@ -26,4 +25,11 @@ Where

* **input** is a *po* file as a Buffer or an unicode string. Charset is converted to unicode from other encodings only if the input is a Buffer, otherwise the charset information is discarded
* **defaultCharset** is the charset to use if charset is not defined or is the default `"CHARSET"` (applies only if *input* is a Buffer)
* **options** is an optional object with the following optional properties:
* **defaultCharset** is the charset to use if charset is not defined or is the default `"CHARSET"` (applies only if *input* is a Buffer)
* **validation** is a flag to turn on PO source file validation. The validation makes sure that:
* there is exactly zero or one `msgid_plural` definition per translation entry; a `Multiple msgid_plural error` error gets thrown otherwise.
* there are no duplicate entries with exact `msgid` values; a `Duplicate msgid error` error gets thrown otherwise.
* the number of plural forms matches exactly the number from `nplurals` defined in `Plural-Forms` header for entries that have plural forms; a `Plural forms range error` error gets thrown otherwise.
* the number of `msgstr` matches exacty the one (if `msgid_plural` is not defined) or the number from `nplurals` (if `msgid_plural` is defined); a `Translation string range error` error gets thrown otherwise.
Method returns gettext-parser specific translation object (see below)

@@ -43,8 +49,8 @@

gettextParser.po.createParseStream([defaultCharset][, streamOptions]) → Transform Stream
gettextParser.po.createParseStream([options][, transformOptions]) → Transform Stream
Where
* **defaultCharset** is the charset to use if charset is not defined or is the default `"CHARSET"`
* **streamOptions** are the standard stream options
* **options** is an optional object, same as in `parse`. See [Parse PO files](#parse-po-files) section for details.
* **transformOptions** are the standard stream options.

@@ -87,2 +93,4 @@ **Example**

###
### Parse MO files

@@ -89,0 +97,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