fill-pot-po
Advanced tools
Comparing version
{ | ||
"name": "fill-pot-po", | ||
"version": "1.0.8", | ||
"version": "2.0.0", | ||
"description": "Create pre-filled PO files from POT file, using previous PO files.", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
224
readme.md
@@ -10,3 +10,3 @@ # fill-pot-po | ||
```sh | ||
```bash | ||
npm install --save-dev fill-pot-po | ||
@@ -16,6 +16,32 @@ ``` | ||
## Example usage | ||
## Usage | ||
### Basic - Asynchronous using callback (recommended default) | ||
The `fill-pot-po` module exports an asynchronous and a synchronous method. | ||
Depending on the chosen method, the result and the handling of the result is slightly different (see examples below). | ||
### 1. Asynchronous (recommended) | ||
### `fillPotPo( cb, options )` | ||
Processes the POT files and found PO files in parallel. | ||
<table> | ||
<tr> | ||
<td><strong>cb</strong></td> | ||
<td><code>required</code></td> | ||
<td><code>function</code> Callback function, with one argument containing the results (see <a href="#Results-Async-mode">Results</a>).</td> | ||
</tr> | ||
<tr> | ||
<td rowspan="2"><strong>options</strong></td> | ||
<td rowspan="2"><code>optional</code></td> | ||
<td><code>object</code> Options object (see <a href="#Options">Options</a>).</td> | ||
</tr> | ||
<tr> | ||
<td><code>string|array</code> Alternatively, a glob string or array can be provided that will be used as <strong>options.poSources</strong>. All other options will have their default values.</td> | ||
</tr> | ||
</table> | ||
#### Example | ||
```js | ||
@@ -25,48 +51,72 @@ const fillPotPo = require('fill-pot-po'); | ||
const cb = results => { | ||
// See `results` section | ||
// ... | ||
}; | ||
fillPotPo( cb, { | ||
// See `options` section | ||
} ); | ||
fillPotPo( cb, options ); | ||
``` | ||
### Basic - Synchronous | ||
### 2. Synchronous | ||
```js | ||
const fillPotPo = require('fill-pot-po').sync; | ||
### `fillPotPoSync( options )` | ||
const results = fillPotPo( { | ||
// See `options` section | ||
} ); | ||
Processes the POT files and found PO files in series (slower). | ||
// See `results` section | ||
<table> | ||
<tr> | ||
<td rowspan="2"><strong>options</strong></td> | ||
<td rowspan="2"><code>optional</code></td> | ||
<td><code>object</code> Options object (see <a href="#Options">Options</a>).</td> | ||
</tr> | ||
<tr> | ||
<td><code>string|array</code> Alternatively, a glob string or array can be provided that will be used as <strong>options.poSources</strong>. All other options will have their default values.</td> | ||
</tr> | ||
<tr> | ||
<td colspan="2"><strong><em>returns</em></strong></td> | ||
<td><code>array</code> Results array on success (see <a href="#Results-Sync-mode">Results</a>).</td> | ||
</tr> | ||
<tr> | ||
<td colspan="2"><strong><em>throws</em></strong></td> | ||
<td><code>PluginError</code> On error ;)</td> | ||
</tr> | ||
</table> | ||
``` | ||
#### Example | ||
```js | ||
const fillPotPoSync = require('fill-pot-po').sync; | ||
## Results array | ||
The array available as the first argument of the callback function or as returned from the synchronous version of `fill-pot-po`. | ||
The results array has two items: | ||
try { | ||
const results = fillPotPoSync( options ); | ||
### results[0] | ||
`boolean` True on success, false on error. | ||
//... | ||
} catch ( error ) { | ||
console.log( error ); | ||
} | ||
### results[1] (on error) | ||
`string` Error message. | ||
``` | ||
### results[1] (on success) | ||
`array` The generated PO files. Each is an array with: | ||
> [0] `string` filename\ | ||
> [1] `Buffer` file contents | ||
## Options | ||
## Options | ||
### potSources | ||
`string|array` | ||
> The POT files to process. Can be a path or glob string, or an array of paths/globs. | ||
`string|Vinyl|array` | ||
> The POT files to process. Can be a path or glob string, a Vinyl object, an array of strings or an array of Vinyl objects. | ||
Default: `['**/*.pot', '!node_modules/**']` | ||
### srcDir | ||
### Options related to locating PO files | ||
#### poSources | ||
`string|array` | ||
> The PO source files to use. Can be a path or glob string, or an array of paths/globs. | ||
> | ||
> By default, or if falsy, the module will look for PO files with filenames like `{text-domain}-{locale}.po` or `{locale}.po` if `domainInPOPath` is set to false. | ||
> | ||
> `{text-domain}` is either the POT filename or the value set in the `domain` option. | ||
> | ||
> See also `domainInPOPath`, `domainFromPOTPath` and `domain`. | ||
Default: `null` | ||
#### srcDir | ||
`string` | ||
@@ -79,9 +129,11 @@ > Relative path from current working directory or absolute path to folder where source PO files can be found. | ||
### srcGlobOptions | ||
`object` | ||
> Glob options used when matching PO source files. | ||
#### domainInPOPath | ||
`boolean` | ||
> Match source PO files with the text domain name in the filename. For example: `text-domain-en_EN.po` and `text-domain-nl_NL.po`. | ||
> | ||
> See also `domainFromPOTPath` and `domain`. | ||
Default: `{}` | ||
Default: `true` | ||
### domainFromPOTPath | ||
#### domainFromPOTPath | ||
`boolean` | ||
@@ -94,31 +146,31 @@ > Whether or not to get the text domain from the POT filename (excluding extension). | ||
### domain | ||
#### domain | ||
`string` | ||
> The text domain slug, like `text-domain`. | ||
> | ||
> By default this is the POT filename excluding extension is used to find the right PO source files. | ||
> By default this is the POT filename excluding extension and is used to find the right PO source files. | ||
> | ||
> See also `domainFromPOTPath` and `domainInPOPath`. | ||
> See also `domainInPOPath` and `domainFromPOTPath`. | ||
Default: `''` | ||
### domainInPOPath | ||
`boolean` | ||
> Match source PO files with the text domain name in the filename. For example: `text-domain-en_EN.po` and `text-domain-nl_NL.po`. | ||
> | ||
> See also `domain` and `domainFromPOTPath`. | ||
#### srcGlobOptions | ||
`object` | ||
> Glob options used when matching PO source files. | ||
Default: `true` | ||
Default: `{}` | ||
### poSources | ||
`string|array` | ||
> The PO source files to use. Can be a path or glob string, or an array of paths/globs. | ||
### Options related to output | ||
#### returnPOT | ||
`boolean` | ||
> Whether the plugin should return the source POT file(s) (`true`) or the generated PO file(s) (`false`). | ||
> | ||
> By default, or if falsy, the module will look for PO files with filenames like `{text-domain}-{locale}.po` or `{locale}.po` if `domainInPOPath` is set to `false`. `{text-domain}` is either the POT filename or the value set in the `domain` option. | ||
> By default, it will return the generated PO files. | ||
> | ||
> See also `domainFromPOTPath`, `domain` and `domainInPOPath`. | ||
> _**NOTE**_: If `returnPOT` is `true`, you need to set `writeFiles` to `true` or else no PO files will be generated and the plugin throws an error. | ||
Default: `null` | ||
Default: `false` | ||
### writeFiles | ||
#### writeFiles | ||
`boolean` | ||
@@ -133,3 +185,3 @@ > Whether or not to write the newly generated PO files to disk. | ||
### destDir | ||
#### destDir | ||
`string` | ||
@@ -140,3 +192,11 @@ > (Only if `writeFiles` is `true`) Relative path from current working directory or absolute path to the folder where the PO files should be written. | ||
### wrapLength | ||
#### logResults | ||
`boolean` | ||
> Log results to console. | ||
Default: `false` | ||
### Options related to generating PO content | ||
#### wrapLength | ||
`integer` | ||
@@ -147,3 +207,3 @@ > Line wrapping length excluding quotation marks. The is forwarded as `foldLength` to [`gettext-parser`](https://github.com/smhg/gettext-parser#compile-po-from-a-translation-object). | ||
### defaultContextAsFallback | ||
#### defaultContextAsFallback | ||
`boolean` | ||
@@ -156,3 +216,3 @@ > If a string is not found in the PO source file with a certain context, try searching for the same string without a context and use that. | ||
### appendNonIncludedFromPO | ||
#### appendNonIncludedFromPO | ||
`boolean` | ||
@@ -165,3 +225,3 @@ > Append all translated strings from the source PO file that were not in the POT file. | ||
### includePORevisionDate | ||
#### includePORevisionDate | ||
`boolean` | ||
@@ -172,9 +232,54 @@ > Include a `PO-Revision-Date` header to the PO files with the current timestamp. | ||
### logResults | ||
#### includeGenerator | ||
`boolean` | ||
> Log results to console. | ||
> Include a `X-Generator` header to the PO files. | ||
Default: `false` | ||
Default: `true` | ||
## Results | ||
### Results - Async mode | ||
The first argument of the callback function will be the results array: | ||
#### results[0] | ||
`boolean` True on success, false on error. | ||
#### results[1] (on success) | ||
`array` Array of [Vinyl](https://github.com/gulpjs/vinyl) file objects, depending on the value of `options.returnPOT`: | ||
<ul><table> | ||
<tr> | ||
<td><code>false</code></td> | ||
<td>The generated PO files. <em>(default)</em></td> | ||
</tr> | ||
<tr> | ||
<td><code>true</code></td> | ||
<td>The input POT files.</td> | ||
</tr> | ||
</table> | ||
</ul> | ||
#### results[1] (on error) | ||
`string` Error message. | ||
### Result - Sync mode | ||
#### On success | ||
`array` Returns an array of [Vinyl](https://github.com/gulpjs/vinyl) file objects, depending on the value of `options.returnPOT`: | ||
<ul><table> | ||
<tr> | ||
<td><code>false</code></td> | ||
<td>The generated PO files. <em>(default)</em></td> | ||
</tr> | ||
<tr> | ||
<td><code>true</code></td> | ||
<td>The input POT files.</td> | ||
</tr> | ||
</table> | ||
</ul> | ||
#### On error | ||
On error, `fillPotPoSync()` will throw an error. | ||
## Related | ||
@@ -186,4 +291,5 @@ | ||
## License | ||
MIT © [Philip van Heemstra](https://github.com/vheemstra) |
@@ -14,2 +14,5 @@ 'use strict'; | ||
let pot_input_files = []; | ||
let po_input_files = []; | ||
/** | ||
@@ -62,2 +65,6 @@ * Reads and parses PO file. | ||
if (isVinyl) { | ||
if (options.returnPOT) { | ||
pot_input_files.push(pot_file); | ||
} | ||
const pot_object = gettextParser.po.parse(pot_file.contents); | ||
@@ -67,5 +74,13 @@ resolve([pot_object, po_filepaths]); | ||
// Async - Read and parse POT file | ||
readFile(pot_filepath, (err, file_content) => { | ||
readFile(pot_filepath, (err, pot_content) => { | ||
if (err) reject(err); | ||
const pot_object = gettextParser.po.parse(file_content); | ||
if (options.returnPOT) { | ||
pot_input_files.push(new Vinyl({ | ||
contents: Buffer.from(pot_content), | ||
path: pot_filepath | ||
})); | ||
} | ||
const pot_object = gettextParser.po.parse(pot_content); | ||
resolve([pot_object, po_filepaths]); | ||
@@ -93,3 +108,4 @@ }); | ||
const po_input_files = []; | ||
pot_input_files = []; | ||
po_input_files = []; | ||
@@ -138,5 +154,10 @@ // Process all POT files | ||
if (options.logResults) { | ||
logResults(options._potFiles, po_input_files, pot_results, options.destDir); | ||
logResults(options._potFilenames, po_input_files, pot_results, options.destDir); | ||
} | ||
if (options.returnPOT) { | ||
cb([true, pot_input_files]); | ||
return; | ||
} | ||
// Flatten into array with all PO files | ||
@@ -143,0 +164,0 @@ pot_results = [].concat(...pot_results); |
'use strict'; | ||
const PluginError = require('./plugin-error'); | ||
const { isArray, isObject, isString, isBool, isArrayOfStrings } = require('./utils'); | ||
const { isArray, isObject, isString, isBool, isArrayOfStrings, isArrayOfVinyls } = require('./utils'); | ||
const Vinyl = require('vinyl'); | ||
@@ -32,4 +33,10 @@ // const { sync: matchedSync } = require('matched'); | ||
if (isObject(options)) { | ||
if (typeof options.potSources !== 'undefined' && !isArray(options.potSources)) { | ||
throw new OptionsError('Option potSources should be an array.'); | ||
if ( | ||
typeof options.potSources !== 'undefined' | ||
&& !isString(options.potSources) | ||
&& !isArrayOfStrings(options.potSources) | ||
&& !Vinyl.isVinyl(options.potSources) | ||
&& !isArrayOfVinyls(options.potSources) | ||
) { | ||
throw new OptionsError('Option potSources should be a string or Vinyl object, or an array of those.'); | ||
} | ||
@@ -40,3 +47,4 @@ | ||
&& options.poSources | ||
&& ! (isString(options.poSources) || isArrayOfStrings(options.poSources)) | ||
&& !isString(options.poSources) | ||
&& !isArrayOfStrings(options.poSources) | ||
) { | ||
@@ -69,2 +77,3 @@ throw new OptionsError('Option poSources should be a glob string or glob array.'); | ||
'writeFiles', | ||
'returnPOT', | ||
'domainFromPOTPath', | ||
@@ -75,2 +84,3 @@ 'domainInPOPath', | ||
'includePORevisionDate', | ||
'includeGenerator', | ||
'logResults', | ||
@@ -104,3 +114,13 @@ ]; | ||
function sanitizeAndStandardizeOptionsInput(options) { | ||
if (typeof options.poSources !== 'undefined') { | ||
if (typeof options.potSources !== 'undefined' && options.potSources) { | ||
if (!isArray(options.potSources)) { | ||
options.potSources = [options.potSources]; | ||
} | ||
options.potSources = options.potSources | ||
.map(v => (typeof v === 'string' ? v.trim() : v)) | ||
.filter(v => (typeof v !== 'string' || v.length > 0)) | ||
; | ||
} | ||
if (typeof options.poSources !== 'undefined' && options.poSources) { | ||
// Make array with one or more non-empty strings | ||
@@ -114,6 +134,4 @@ if (!isArray(options.poSources)) { | ||
; | ||
if (0 >= options.poSources.length) { | ||
delete options.poSources; | ||
} | ||
} | ||
if (options.srcDir) { | ||
@@ -129,3 +147,3 @@ // NOTE: all paths starting with a slash are considered absolute paths | ||
} | ||
//TO-REMOVE | ||
if (options.destDir) { | ||
@@ -141,2 +159,3 @@ // NOTE: all paths starting with a slash are considered absolute paths | ||
} | ||
if (options.wrapLength) { | ||
@@ -170,11 +189,12 @@ // Make integer | ||
const defaultOptions = { | ||
// Input-related | ||
potSources: ['**/*.pot', '!node_modules/**'], | ||
poSources: null, | ||
srcDir: '', | ||
srcGlobOptions: {}, | ||
writeFiles: (typeof writeFiles !== 'undefined') ? writeFiles : true, | ||
destDir: '', | ||
domainInPOPath: true, | ||
domainFromPOTPath: true, | ||
domain: '', | ||
domainInPOPath: true, | ||
srcGlobOptions: {}, | ||
// Content-related | ||
wrapLength: 77, | ||
@@ -185,2 +205,7 @@ defaultContextAsFallback: false, | ||
includeGenerator: true, | ||
// Output-related | ||
returnPOT: false, | ||
writeFiles: (typeof writeFiles !== 'undefined') ? writeFiles : true, | ||
destDir: '', | ||
logResults: false, | ||
@@ -204,2 +229,6 @@ }; | ||
if (options.returnPOT && !options.writeFiles) { | ||
throw new OptionsError('If option returnPOT is true, option writeFiles must be true or no PO files will be generated.'); | ||
} | ||
return options; | ||
@@ -206,0 +235,0 @@ } |
@@ -9,2 +9,3 @@ 'use strict'; | ||
const { isString, pathLineSort } = require('./utils'); | ||
const Vinyl = require('vinyl'); | ||
const PluginError = require('./plugin-error'); | ||
@@ -29,3 +30,3 @@ const c = require('ansi-colors'); | ||
// Store POT filepaths for logging | ||
options._potFiles = options.potSources.map(f => (isString(f) ? f : f.path)); | ||
options._potFilenames = options.potSources.map(f => (isString(f) ? f : f.path)); | ||
@@ -92,3 +93,3 @@ if (0 >= options.potSources.length) { | ||
* - Optionally writes content to file | ||
* - Returns filepath and content of new PO file | ||
* - Returns Vinyl file object of the new PO file | ||
* | ||
@@ -100,6 +101,3 @@ * @param {object} pot_object | ||
* | ||
* @return {array} [ | ||
* {string} New PO filepath | ||
* {Buffer} New PO compiled content | ||
* ] | ||
* @return {object} Vinyl file object | ||
*/ | ||
@@ -124,3 +122,6 @@ function generatePO(pot_object, po_object, po_filepath, options) { | ||
// Add Buffer to collection | ||
return [new_po_filepath, new_po_output]; | ||
return new Vinyl({ | ||
contents: Buffer.from(new_po_output), | ||
path: new_po_filepath, | ||
}); | ||
} | ||
@@ -127,0 +128,0 @@ |
@@ -10,2 +10,3 @@ 'use strict'; | ||
let pot_input_files = []; | ||
let po_input_files = []; | ||
@@ -64,6 +65,19 @@ let po_output_files = []; | ||
if (isVinyl) { | ||
if (options.returnPOT) { | ||
pot_input_files.push(pot_file); | ||
} | ||
pot_content = pot_file.contents; | ||
} else { | ||
// Sync - Read and parse POT file | ||
pot_content = readFileSync(pot_filepath).toString(); | ||
// Sync - Read POT file | ||
pot_content = readFileSync(pot_filepath); | ||
if (options.returnPOT) { | ||
pot_input_files.push(new Vinyl({ | ||
contents: Buffer.from(pot_content), | ||
path: pot_filepath | ||
})); | ||
} | ||
pot_content = pot_content.toString(); | ||
} | ||
@@ -91,5 +105,9 @@ const pot_object = gettextParser.po.parse(pot_content); | ||
if (options.logResults) { | ||
logResults(options._potFiles, po_input_files, po_output_files, options.destDir); | ||
logResults(options._potFilenames, po_input_files, po_output_files, options.destDir); | ||
} | ||
if (options.returnPOT) { | ||
return pot_input_files; | ||
} | ||
// Flatten into array with all PO files | ||
@@ -96,0 +114,0 @@ po_output_files = [].concat(...po_output_files); |
'use strict'; | ||
const Vinyl = require('vinyl'); | ||
/** | ||
@@ -72,2 +74,14 @@ * Escape string for literal match in regex. | ||
/** | ||
* Determine if `ar` is an array containing only Vinyl objects or not. | ||
* | ||
* @param {mixed} ar | ||
* | ||
* @return {boolean} | ||
*/ | ||
function isArrayOfVinyls(ar) { | ||
if (!isArray(ar)) return false; | ||
return ar.reduce((r, v) => (Vinyl.isVinyl(v) && r), true); | ||
} | ||
/** | ||
* Array sort callback for file reference strings (optionally with line numbers). | ||
@@ -156,3 +170,4 @@ * e.g. strings like 'some/file_path.js:123' | ||
isArrayOfStrings, | ||
isArrayOfVinyls, | ||
pathLineSort | ||
}; |
40273
13.79%930
7.64%284
59.55%