Skip to content
This repository has been archived by the owner on Jun 8, 2019. It is now read-only.

Commit

Permalink
Merge pull request #73 from yahoo/src-meta
Browse files Browse the repository at this point in the history
Add extractSourceLocation option
  • Loading branch information
ericf authored Sep 3, 2016
2 parents e491de9 + 4f9f8fc commit 0d00e71
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 9 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ The default message descriptors for the app's default language will be extracted
{
"plugins": [
["react-intl", {
"messagesDir": "./build/messages/",
"enforceDescriptions": true
"messagesDir": "./build/messages/"
}]
]
}
Expand All @@ -35,7 +34,9 @@ The default message descriptors for the app's default language will be extracted

- **`messagesDir`**: The target location where the plugin will output a `.json` file corresponding to each component from which React Intl messages were extracted. If not provided, the extracted message descriptors will only be accessible via Babel's API.

- **`enforceDescriptions`**: Whether or not message declarations _must_ contain a `description` to provide context to translators. Defaults to: `false`.
- **`enforceDescriptions`**: Whether message declarations _must_ contain a `description` to provide context to translators. Defaults to: `false`.

- **`extractSourceLocation`**: Whether the metadata about the location of the message in the source file should be extracted. If `true`, then `file`, `start`, and `end` fields will exist for each extracted message descriptors. Defaults to `false`.

- **`moduleSourceName`**: The ES6 module source name of the React Intl package. Defaults to: `"react-intl"`, but can be changed to another name/path to React Intl.

Expand Down
3 changes: 3 additions & 0 deletions scripts/build-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const baseDir = p.resolve(`${__dirname}/../test/fixtures`);

const fixtures = [
'defineMessages',
['extractSourceLocation', {
extractSourceLocation: true,
}],
'FormattedHTMLMessage',
'FormattedMessage',
['moduleSourceName', {
Expand Down
14 changes: 11 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export default function () {
}

function storeMessage({id, description, defaultMessage}, path, state) {
const {opts, reactIntl} = state;
const {file, opts, reactIntl} = state;

if (!(id && defaultMessage)) {
throw path.buildCodeFrameError(
Expand All @@ -134,7 +134,15 @@ export default function () {
);
}

reactIntl.messages.set(id, {id, description, defaultMessage});
let loc;
if (opts.extractSourceLocation) {
loc = {
file: p.relative(process.cwd(), file.opts.filename),
...path.node.loc,
};
}

reactIntl.messages.set(id, {id, description, defaultMessage, ...loc});
}

function referencesImport(path, mod, importedNames) {
Expand Down Expand Up @@ -257,7 +265,7 @@ export default function () {

// Evaluate the Message Descriptor values, then store it.
descriptor = evaluateMessageDescriptor(descriptor);
storeMessage(descriptor, path, state);
storeMessage(descriptor, messageObj, state);
}

if (referencesImport(callee, moduleSourceName, FUNCTION_NAMES)) {
Expand Down
13 changes: 13 additions & 0 deletions test/fixtures/extractSourceLocation/actual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, {Component} from 'react';
import {FormattedMessage} from 'react-intl';

export default class Foo extends Component {
render() {
return (
<FormattedMessage
id='foo.bar.baz'
defaultMessage='Hello World!'
/>
);
}
}
45 changes: 45 additions & 0 deletions test/fixtures/extractSourceLocation/expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _reactIntl = require('react-intl');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Foo = function (_Component) {
_inherits(Foo, _Component);

function Foo() {
_classCallCheck(this, Foo);

return _possibleConstructorReturn(this, (Foo.__proto__ || Object.getPrototypeOf(Foo)).apply(this, arguments));
}

_createClass(Foo, [{
key: 'render',
value: function render() {
return _react2.default.createElement(_reactIntl.FormattedMessage, {
id: 'foo.bar.baz',
defaultMessage: 'Hello World!'
});
}
}]);

return Foo;
}(_react.Component);

exports.default = Foo;
15 changes: 15 additions & 0 deletions test/fixtures/extractSourceLocation/expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"id": "foo.bar.baz",
"defaultMessage": "Hello World!",
"file": "test/fixtures/extractSourceLocation/actual.js",
"start": {
"line": 7,
"column": 12
},
"end": {
"line": 10,
"column": 14
}
}
]
31 changes: 28 additions & 3 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const skipTests = [
'.babelrc',
'.DS_Store',
'enforceDescriptions',
'extractSourceLocation',
'moduleSourceName',
'icuSyntax',
];
Expand Down Expand Up @@ -49,7 +50,9 @@ describe('options', () => {
const fixtureDir = path.join(fixturesDir, 'enforceDescriptions');

try {
transform(path.join(fixtureDir, 'actual.js'));
transform(path.join(fixtureDir, 'actual.js'), {
enforceDescriptions: true,
});
assert(false);
} catch (e) {
assert(e);
Expand Down Expand Up @@ -83,6 +86,30 @@ describe('options', () => {
console.error(e);
assert(false);
}

// Check message output
const expectedMessages = fs.readFileSync(path.join(fixtureDir, 'expected.json'));
const actualMessages = fs.readFileSync(path.join(fixtureDir, 'actual.json'));
assert.equal(trim(actualMessages), trim(expectedMessages));
});

it('respects extractSourceLocation', () => {
const fixtureDir = path.join(fixturesDir, 'extractSourceLocation');

try {
transform(path.join(fixtureDir, 'actual.js'), {
extractSourceLocation: true,
});
assert(true);
} catch (e) {
console.error(e);
assert(false);
}

// Check message output
const expectedMessages = fs.readFileSync(path.join(fixtureDir, 'expected.json'));
const actualMessages = fs.readFileSync(path.join(fixtureDir, 'actual.json'));
assert.equal(trim(actualMessages), trim(expectedMessages));
});
});

Expand All @@ -99,13 +126,11 @@ describe('errors', () => {
assert(/Expected .* but "\." found/.test(e.message));
}
});

});


const BASE_OPTIONS = {
messagesDir: baseDir,
enforceDescriptions: true,
};

function transform(filePath, options = {}) {
Expand Down

0 comments on commit 0d00e71

Please sign in to comment.