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

react-intl-po

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-intl-po - npm Package Compare versions

Comparing version 2.0.2 to 2.1.0

test/po/mcs-ctxt.zh-CN.po

11

CHANGELOG.md

@@ -6,2 +6,13 @@ # react-intl-po

## [v2.1.0]
> Jul 17, 2017
* feat(contexts): Allow user to specify msgctxt with `-c` arguments. ([@Sand1929](https://github.com/Sand1929)in [#84])
## [v2.0.2]
> Mar 02, 2017
* fix(potFormater): Escape quotes in msgId ([@jonbretman](https://github.com/jonbretman) in [#70])
* chore(Jest): update jest to 19.
## [v2.0.1]

@@ -8,0 +19,0 @@ > Feb 12, 2017

4

lib/cli.js

@@ -10,6 +10,6 @@ #!/usr/bin/env node

_commander2.default.command('json2pot <srcPatterns>').option('-o, --output <path>', 'The output pathname of `.pot` file to be translated').option('-k, --message-key [key]', 'Translation message key (default key is `defaultMessage`)').action(require('./extractAndWritePOTFromMessagesSync'));
_commander2.default.command('json2pot <srcPatterns>').option('-o, --output <path>', 'The output pathname of `.pot` file to be translated').option('-k, --message-key [key]', 'Translation message key (default key is `defaultMessage`)').option('-c, --message-context [context]', 'Translation message context (defaults to no context)').action(require('./extractAndWritePOTFromMessagesSync'));
_commander2.default.command('po2json <srcPatterns>').option('-m, --messages-pattern <path>', 'The pattern of *json* files extracted from *babel-plugin-react-intl*').option('-o, --output <path>', 'The output pathname of a file / directory').option('-k, --message-key [key]', 'Translation message key (default key is `defaultMessage`)').action(require('./filterPOAndWriteTranslateSync'));
_commander2.default.command('po2json <srcPatterns>').option('-m, --messages-pattern <path>', 'The pattern of *json* files extracted from *babel-plugin-react-intl*').option('-o, --output <path>', 'The output pathname of a file / directory').option('-k, --message-key [key]', 'Translation message key (default key is `defaultMessage`)').option('-c, --message-context [context]', 'Translation message context (defaults to no context)').action(require('./filterPOAndWriteTranslateSync'));
_commander2.default.parse(process.argv);

@@ -49,3 +49,4 @@ 'use strict';

result += (0, _flowRight2.default)(_potFormater2.default, // 2. return formated string
_readAllMessageAsObjectSync2.default)(srcPatterns, messageKey);
_readAllMessageAsObjectSync2.default // 1. return messages object
)(srcPatterns, messageKey);

@@ -52,0 +53,0 @@ _fs2.default.writeFileSync(output, result);

@@ -27,5 +27,5 @@ 'use strict';

var _flatten = require('lodash/flatten');
var _flattenDeep = require('lodash/flattenDeep');
var _flatten2 = _interopRequireDefault(_flatten);
var _flattenDeep2 = _interopRequireDefault(_flattenDeep);

@@ -58,5 +58,11 @@ var _flowRight = require('lodash/flowRight');

var getTranslationTableContext = function getTranslationTableContext(messageContext, message) {
return messageContext ? message[messageContext] + '\x04' : '';
};
function filterPOAndWriteTranslateSync(srcPatterns, _ref) {
var _ref$messageKey = _ref.messageKey,
messageKey = _ref$messageKey === undefined ? 'defaultMessage' : _ref$messageKey,
_ref$messageContext = _ref.messageContext,
messageContext = _ref$messageContext === undefined ? '' : _ref$messageContext,
messagesPattern = _ref.messagesPattern,

@@ -66,5 +72,11 @@ output = _ref.output;

var translationTable = (0, _readAllPOAsObjectSync2.default)(srcPatterns);
var messageList = (0, _flowRight2.default)(_flatten2.default, // 3. return flatten object values
_values2.default, // 2. return object values
_readAllMessageAsObjectSync2.default)(messagesPattern, messageKey);
var messageList = (0, _flowRight2.default)(_flattenDeep2.default, // 4. return flattened values
function (objects) {
return objects.map(function (o) {
return (0, // 3. return values
_values2.default)(o);
});
}, _values2.default, // 2. return context objects
_readAllMessageAsObjectSync2.default // 1. return message object
)(messagesPattern, messageKey, messageContext);

@@ -74,3 +86,3 @@ var locales = Object.keys(translationTable);

return _defineProperty({}, locale, (0, _toObjectBy2.default)(messageList, function (message) {
return _defineProperty({}, message.id, translationTable[locale][message[messageKey]]);
return _defineProperty({}, message.id, translationTable[locale]['' + getTranslationTableContext(messageContext, message) + message[messageKey]]);
}));

@@ -77,0 +89,0 @@ });

@@ -61,2 +61,13 @@ 'use strict';

/**
* Formatting POT contexts
* @param {String} messageContext
* @return {String}
*
* @author Sandy Suh
*/
var potContextsFormater = function potContextsFormater(messageContext) {
return messageContext ? 'msgctxt ' + JSON.stringify(messageContext) + '\n' : '';
};
/**
* Formatting POT comments

@@ -74,3 +85,5 @@ * @param {Object} messageObject

.sort().map(function (id) {
return potCommentsFormater(messageObject[id]) + 'msgid ' + JSON.stringify(id) + '\nmsgstr ""\n';
return Object.keys(messageObject[id]).map(function (context) {
return '' + potCommentsFormater(messageObject[id][context]) + potContextsFormater(context) + 'msgid ' + JSON.stringify(id) + '\nmsgstr ""\n';
}).join('\n');
}).join('\n');

@@ -77,0 +90,0 @@ };

@@ -15,5 +15,5 @@ 'use strict';

var _mergeWith = require('lodash/mergeWith');
var _mergeWith2 = require('lodash/mergeWith');
var _mergeWith2 = _interopRequireDefault(_mergeWith);
var _mergeWith3 = _interopRequireDefault(_mergeWith2);

@@ -28,3 +28,3 @@ var _isArray = require('lodash/isArray');

var customizer = function customizer(accValue, objectValue) {
var concatCustomizer = function concatCustomizer(accValue, objectValue) {
if (!(0, _isArray2.default)(accValue)) return objectValue;

@@ -35,4 +35,8 @@

var mergeCustomizer = function mergeCustomizer(accValue, objectValue) {
return (0, _mergeWith3.default)(accValue, objectValue, concatCustomizer);
};
// hint: Use defaultMessage as key by default
var indexBy = function indexBy(messageKey) {
var indexBy = function indexBy(messageKey, messageContext) {
return function (_ref) {

@@ -42,3 +46,3 @@ var messages = _ref.messages,

return messages.reduce(function (acc, message) {
return _extends({}, acc, _defineProperty({}, message[messageKey], acc[message[messageKey]] ? acc[message[messageKey]].concat([_extends({}, message, { filename: filename })]) : [_extends({}, message, { filename: filename })]));
return _extends({}, acc, _defineProperty({}, message[messageKey], (0, _mergeWith3.default)(acc[message[messageKey]], _defineProperty({}, messageContext ? message[messageContext] : '', [_extends({}, message, { filename: filename })]), concatCustomizer)));
}, {});

@@ -61,2 +65,3 @@ };

var messageKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'defaultMessage';
var messageContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';

@@ -68,7 +73,7 @@ return (0, _glob.sync)(srcPatterns)

})
// 2. convert message list to object by messageKey
.map(indexBy(messageKey))
// 2. convert message list to nested objects by messageKey and messageContext
.map(indexBy(messageKey, messageContext))
// 3. aggregate objects (merge and concat)
.reduce(function (acc, object) {
return (0, _mergeWith2.default)(acc, object, customizer);
return (0, _mergeWith3.default)(acc, object, mergeCustomizer);
}, {});

@@ -75,0 +80,0 @@ }

{
"name": "react-intl-po",
"version": "2.0.2",
"version": "2.1.0",
"description": "Extract POT from react-intl and convert back to json.",

@@ -50,3 +50,3 @@ "author": "Michael Hsu",

"babel-register": "^6.18.0",
"codecov": "^1.0.1",
"codecov": "^2.1.0",
"eslint": "^3.13.0",

@@ -53,0 +53,0 @@ "jest": "^19.0.2",

@@ -31,4 +31,8 @@ # react-intl-po

[peerDependency]: https://david-dm.org/evenchange4/react-intl-po#info=peerDependencies
[![Greenkeeper badge](https://badges.greenkeeper.io/evenchange4/react-intl-po.svg)](https://greenkeeper.io/)
## Demo
Standalone example based on Create-React-App: https://github.com/evenchange4/react-intl-po-example
## Installation

@@ -62,7 +66,8 @@

| **Arguments** | **Description** |
| ------------------ | ---------------------------------------------------------------------- |
| `srcPatterns` | The pattern of *.json* files extracted from *babel-plugin-react-intl* |
| `output (-o)` | The output pathname of *.pot* file to be translated |
| `message-key (-k)` | [Optional] Translation message key (default key is `defaultMessage`) |
| **Arguments** | **Description** |
| ------------------ | ---------------------------------------------------------------------- |
| `srcPatterns` | The pattern of *.json* files extracted from *babel-plugin-react-intl* |
| `output (-o)` | The output pathname of *.pot* file to be translated |
| `message-key (-k)` | [Optional] Translation message key (default key is `defaultMessage`) |
| `message-context (-c)` | [Optional] Translation message context (defaults to no context) |

@@ -93,2 +98,3 @@ ### po2json

| `message-key (-k)` | [Optional] Translation message key (default key is `defaultMessage`) |
| `message-context (-c)` | [Optional] Translation message context (defaults to no context) |

@@ -107,2 +113,20 @@

#### Option 1 (Recommended):
Set the `message-context (-c)` to `'id'` of message object from *babel-plugin-react-intl* (there is no context by default).
The advantage of this option over Option 2 (below) is that PO file editors that provide features such as translation suggestions or error-checking often expect the message key to be `defaultMessage`.
```
$ rip po2json './node_modules/mcs-translation/po/mcs-public*.po' \
-m './_translations/src/**/*.json' \
-o './translations' \
-c 'id'
$ rip po2json './node_modules/mcs-translation/po/mcs-public*.po' \`
-m './_translations/src/**/*.json' \
-o './translations.json' \
-c 'id'
```
#### Option 2:
Set the `message-key (-k)` to `'id'` of message object from *babel-plugin-react-intl* (default key is `'defaultMessage'`). ([#41](https://github.com/evenchange4/react-intl-po/pull/41))

@@ -109,0 +133,0 @@

@@ -9,2 +9,3 @@ #!/usr/bin/env node

.option('-k, --message-key [key]', 'Translation message key (default key is `defaultMessage`)')
.option('-c, --message-context [context]', 'Translation message context (defaults to no context)')
.action(require('./extractAndWritePOTFromMessagesSync'));

@@ -20,4 +21,5 @@

.option('-k, --message-key [key]', 'Translation message key (default key is `defaultMessage`)')
.option('-c, --message-context [context]', 'Translation message context (defaults to no context)')
.action(require('./filterPOAndWriteTranslateSync'));
program.parse(process.argv);

@@ -7,3 +7,3 @@ /* eslint-disable no-console */

import values from 'lodash/values';
import flatten from 'lodash/flatten';
import flattenDeep from 'lodash/flattenDeep';
import flowRight from 'lodash/flowRight';

@@ -16,10 +16,14 @@ import toObjectBy from 'to-object-by';

const getTranslationTableContext = (messageContext, message) =>
(messageContext ? `${message[messageContext]}\u0004` : '');
function filterPOAndWriteTranslateSync(srcPatterns,
{ messageKey = 'defaultMessage', messagesPattern, output }) {
{ messageKey = 'defaultMessage', messageContext = '', messagesPattern, output }) {
const translationTable = readAllPOAsObjectSync(srcPatterns);
const messageList = flowRight(
flatten, // 3. return flatten object values
values, // 2. return object values
readAllMessageAsObjectSync, // 1. return message object
)(messagesPattern, messageKey);
flattenDeep, // 4. return flattened values
objects => objects.map(o => values(o)), // 3. return values
values, // 2. return context objects
readAllMessageAsObjectSync, // 1. return message object
)(messagesPattern, messageKey, messageContext);

@@ -29,3 +33,3 @@ const locales = Object.keys(translationTable);

[locale]: toObjectBy(messageList, message => ({
[message.id]: translationTable[locale][message[messageKey]],
[message.id]: translationTable[locale][`${getTranslationTableContext(messageContext, message)}${message[messageKey]}`],
})),

@@ -32,0 +36,0 @@ }));

@@ -49,2 +49,12 @@ /**

/**
* Formatting POT contexts
* @param {String} messageContext
* @return {String}
*
* @author Sandy Suh
*/
const potContextsFormater = messageContext =>
(messageContext ? `msgctxt ${JSON.stringify(messageContext)}\n` : '');
/**
* Formatting POT comments

@@ -62,5 +72,9 @@ * @param {Object} messageObject

.sort()
.map(id => `${potCommentsFormater(messageObject[id])}msgid ${JSON.stringify(id)}\nmsgstr ""\n`)
.map(id =>
Object.keys(messageObject[id])
.map(context => `${potCommentsFormater(messageObject[id][context])}${potContextsFormater(context)}msgid ${JSON.stringify(id)}\nmsgstr ""\n`)
.join('\n'),
)
.join('\n');
export default potFormater;

@@ -6,3 +6,3 @@ import fs from 'fs';

const customizer = (accValue, objectValue) => {
const concatCustomizer = (accValue, objectValue) => {
if (!isArray(accValue)) return objectValue;

@@ -13,9 +13,14 @@

const mergeCustomizer = (accValue, objectValue) =>
mergeWith(accValue, objectValue, concatCustomizer);
// hint: Use defaultMessage as key by default
const indexBy = messageKey => ({ messages, filename }) =>
const indexBy = (messageKey, messageContext) => ({ messages, filename }) =>
messages.reduce((acc, message) => ({
...acc,
[message[messageKey]]: acc[message[messageKey]]
? acc[message[messageKey]].concat([{ ...message, filename }])
: [{ ...message, filename }],
[message[messageKey]]: mergeWith(
acc[message[messageKey]],
{ [messageContext ? message[messageContext] : '']: [{ ...message, filename }]},
concatCustomizer,
),
}), {});

@@ -34,12 +39,12 @@

function readAllMessageAsObjectSync(srcPatterns, messageKey = 'defaultMessage') {
function readAllMessageAsObjectSync(srcPatterns, messageKey = 'defaultMessage', messageContext = '') {
return globSync(srcPatterns)
// 1. read messages
.map(filename => ({ filename, messages: JSON.parse(fs.readFileSync(filename, 'utf8')) }))
// 2. convert message list to object by messageKey
.map(indexBy(messageKey))
// 2. convert message list to nested objects by messageKey and messageContext
.map(indexBy(messageKey, messageContext))
// 3. aggregate objects (merge and concat)
.reduce((acc, object) => mergeWith(acc, object, customizer), {});
.reduce((acc, object) => mergeWith(acc, object, mergeCustomizer), {});
}
export default readAllMessageAsObjectSync;

@@ -25,3 +25,3 @@ import fs from 'fs';

it('should optput currect filter merged file with id as messageKey', () => {
it('should output correct filter merged file with id as messageKey', () => {
const messagesPattern = './test/messages/**/*.json';

@@ -33,1 +33,9 @@ const output = './test/temp/translations-id.json';

});
it('should output correct filter merged file with id as messageContext', () => {
const messagesPattern = './test/messages/**/*.json';
const output = './test/temp/translations-ctxt.json';
filterPOAndWriteTranslateSync('./test/po/mcs-ctxt.*.po', { messageContext: 'id', messagesPattern, output });
expect(JSON.parse(fs.readFileSync(output, 'utf8'))).toMatchSnapshot();
});

@@ -10,16 +10,18 @@ import potFormater from '../src/potFormater';

potFormater({
'Go to MCS website': [
{
id: 'App.errorButton',
description: 'Click error Button',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/App/App.json',
},
{
id: 'NotFound.errorButton',
description: 'Click error Button',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/NotFound/messages.json',
},
],
'Go to MCS website': {
'': [
{
id: 'App.errorButton',
description: 'Click error Button',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/App/App.json',
},
{
id: 'NotFound.errorButton',
description: 'Click error Button',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/NotFound/messages.json',
},
],
},
}),

@@ -32,9 +34,11 @@ ).toMatchSnapshot();

potFormater({
'Go to MCS website': [
{
id: 'NotFound.errorButton',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/NotFound/messages.json',
},
],
'Go to MCS website': {
'': [
{
id: 'NotFound.errorButton',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/NotFound/messages.json',
},
],
},
}),

@@ -47,10 +51,12 @@ ).toMatchSnapshot();

potFormater({
'NotFound.errorButton': [
{
id: 'NotFound.errorButton',
description: 'My description\nis\nquite\nlong.',
defaultMessage: 'This is\nmultiline',
filename: './messages/src/containers/NotFound/messages.json',
},
],
'NotFound.errorButton': {
'': [
{
id: 'NotFound.errorButton',
description: 'My description\nis\nquite\nlong.',
defaultMessage: 'This is\nmultiline',
filename: './messages/src/containers/NotFound/messages.json',
},
],
},
}),

@@ -63,12 +69,39 @@ ).toMatchSnapshot();

potFormater({
'This is "quoted"': [
{
id: 'NotFound.errorButton',
description: 'My description\nis\nquite\nlong.',
defaultMessage: 'This is "quoted"',
filename: './messages/src/containers/NotFound/messages.json',
},
],
'This is "quoted"': {
'': [
{
id: 'NotFound.errorButton',
description: 'My description\nis\nquite\nlong.',
defaultMessage: 'This is "quoted"',
filename: './messages/src/containers/NotFound/messages.json',
},
],
},
}),
).toMatchSnapshot();
});
it('should return pot formatted string, with message context', () => {
expect(
potFormater({
'Go to MCS website': {
'App.errorButton': [
{
id: 'App.errorButton',
description: 'Click error Button',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/App/App.json',
},
],
'NotFound.errorButton': [
{
id: 'NotFound.errorButton',
description: 'Click error Button',
defaultMessage: 'Go to MCS website',
filename: './messages/src/containers/NotFound/messages.json',
},
],
},
}),
).toMatchSnapshot();
});

@@ -30,1 +30,11 @@ import readAllMessageAsObjectSync from '../src/readAllMessageAsObjectSync';

});
it('should return messages object with id as context', () => {
expect(
readAllMessageAsObjectSync(
'./test/messages/**/*.json',
undefined,
'id',
),
).toMatchSnapshot();
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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