diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 24b8730..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: node_js
-node_js:
- - '8'
- - '6'
-script:
- - npm run test
- - npm run build
-branches:
- only:
- - master
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 0000000..b0e6d1e
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1 @@
+* @hkasemir
\ No newline at end of file
diff --git a/README.md b/README.md
index 80adafd..535dc7f 100644
--- a/README.md
+++ b/README.md
@@ -1,334 +1,19 @@
# fluent-react-utils
String extraction and helper components for using [fluent-react](https://github.com/projectfluent/fluent.js/tree/master/fluent-react) in your projects.
-## Helper Components
-Basic fluent-react makes use of `Localized` components to wrap jsx components, like this:
-```jsx
-export function NotAuthorized() {
- return (
-
-
-
- {/* here is a comment for the localizer */}
- Oops! looks like you're not authorized to use this app.
-
-
-
-
-
- }
- a={}
- button={
- );
-}
-```
-
-This makes for a lot of `Localized` components on the page, and can make it hard
-to visually scan for specific HTML elements. This package comes with standard HTML
-elements already wrapped in `Localized` with their typical `attrs` enabled in the
-`Loc` component. This turns the above into:
-
-```jsx
-import {Loc} from 'fluent-react-utils';
-
-export function NotAuthorized() {
- return (
-
-
- {/* here is a comment for the localizer */}
- Oops! looks like you're not authorized to use this app.
-
-
- ,
- a: ,
- button:
- }}
- >
- {
- 'Try again, go Home or Logout'
- }
-
-
- );
-}
-```
-
-#### Props
-In the `Loc` components you have access to three `l10n` props to describe how
-this message needs to be translated.
-
-##### l10nId (Required)
-The localization key for that message
-
-##### l10nVars
-This is a plain object with the message variables as keys. It's only used if the message has a variable to substitute.
-
-```jsx
-
- {'Welcome, { $name }'}
-
-```
-
-##### l10nJsx
-A plain object with the element alias as the key and a JSX component as the value.
-This is used for any components that are included inline in the message, with the
-alias used in HTML-like syntax to wrap the translated message.
-
-```jsx
-
- }}
->
- {
- 'Go home'
- }
-
-```
-
-### Custom Loc Components
-Your project may have components that would be great to include in the `Loc`
-object, but which are not standard HTML. Say you have a styled `MyButton`
-component, for example.
-
-```jsx
-
-
-
-```
-
-You can make use of two helpers from fluent-react-utils to quickly wrap a
-component in `Localized` and / or add it to the `Loc` object.
-
-#### `makeLocalizedElement(Element[, attrs])`
-
-```js
-const MyLocalizedButton = makeLocalizedElement(MyButton, {label: true})
-```
-
-`MyLocalizedButton` will now have access to the `l10nId`, `l10nVars`, and
-`l10nJsx` props.
-
-
-#### `augmentLoc(customElements)`
-In order for your custom elements to be recognized by the string extraction tool,
-they need to be prefixed by `Loc.` (or a custom name of your choice -
-see information about the `.l10nrc` file).
+This is a mono-repo containing two packages:
+## [fluent-react-components](./packages/components)
+Helper components to write cleaner jsx with fluent-react.
-```js
-// my-utils
-import {augmentLoc} from 'fluent-react-utils';
+## [fluent-react-extract](./packages/extraction)
+CLI for extracting strings for localization into ftl files.
-const customElements = {
- MyButton: MyLocalizedButton
-};
-export const Loc = augmentLoc(customElements);
+# Contributing
-// elsewhere
+To get started developing locally, install dependencies and build the packages using
-import {Loc} from 'my-utils';
-
-...
-
- Look, a button!
-
-
```
-
-## String Extraction
-Get default messages from your source code so that you don't have to switch
-context to manage translatable messages
-
-Uses the [fluent-syntax](https://github.com/projectfluent/fluent.js/tree/master/fluent-syntax) serializer
-and [Babel parser](https://github.com/babel/babel/tree/master/packages/babel-parser) to
-create an AST for your React code to pull out default messages and format them in
-FTL.
-
-### How to Use
-```sh
-l10n extract [--pattern '...'] [--outputDir '...']
-```
-This will run through all files matching the file pattern, parse the code into an
-AST, locate all the `Localized` or `Loc.X` (`Loc.` is the default, but this can
-be customized, see `.l10nrc` information below) helper components and pull the id,
-messages, and comments for that component into a fresh `data.ftl` file located
-in the specified output directory.
-
-#### Example
-```jsx
-// imports
-
-export function NotAuthorized() {
- return (
-
-
- {/* here is a comment for the localizer */}
- Oops! looks like you're not authorized to use this app.
-
-
- ,
- a: ,
- button:
- }}
- >
- {
- 'Try again, go Home or Logout'
- }
-
-
- );
-}
+$ lerna bootstrap
```
-
-Running the localization script on this file would result in the `data.ftl` below:
-```
-# here is a comment for the localizer
-NotAuthorized_oopsMessage = Oops! looks like you're not authorized to use this app.
-NotAuthorized_warningImg =
- .alt = warning sign
-NotAuthorized_possibleActions = Try again, go Home or Logout
-```
-
-*NOTE*: adding comments along with the children of a component will extract this
-out as a comment to the localizer. This can be helpful for leaving tips about
-context of the message to make translation easier.
-
-### .l10nrc File
-In order to run the extraction based on your project's custom needs, a `.l10nrc`
-file is supported. Possible values of this file:
-
-#### `customElementsPath`
-If you use the custom elements as described above, if they include any attributes
-(i.e. `label` on the `MyButton` component), they need to be included to tell the
-extraction scripts which attributes to look for. The format for this is a json object
-with the component names as keys, and an object of their allowed (or explicitly
-disallowed) attributes. For example:
-
-```json
-// custom-elements.json
-{
- "MyButton": {"label": true}
-}
-```
-It is recommended that this record of custom element attributes is held in a json
-file that is pulled into any file defining the `attrs` of that element in the React
-code.
-```js
-import {augmentLoc, makeLocalizedElement} from 'fluent-react-utils';
-import customAttrs from './custom-elements.json';
-
-const customElements = {
- MyButton: makeLocalizedElement(MyButton, customAttrs.MyButton)
-};
-
-export const Loc = augmentLoc(customElements);
-```
-
-The value for `customElementsPath` is the path to the `custom-elements.json` file
-from the project root.
-
-For example:
-```json
-{
- "customElementsPath": "./src/app/utils/custom-elements.json",
-}
-```
-
-#### `shorthandName`
-By default, this is `Loc`, but if your project prefers not to use the same name
-as this library's `Loc` utility, you can update this in the `.l10nrc` file.
-
-```js
-// my-utils
-import {augmentLoc, makeLocalizedElement} from 'fluent-react-utils';
-import customAttrs from './custom-elements.json';
-
-const customElements = {
- MyButton: makeLocalizedElement(MyButton, customAttrs.MyButton)
-};
-
-export const L = augmentLoc(customElements);
-
-// elsewhere
-
-import {L} from 'my-utils';
-
-...
-
- Look, a button!
-
-
-```
-
-```json
-{
- "shorthandName": "L",
-}
-```
-
-#### `filePattern`
-In case your project always extracts the same file pattern, this can be defined
-in `.l10nrc` as opposed to passing it into the cli every time.
-```json
-{
- "filePattern": "./src/app/**/*.{js,jsx}",
-}
-```
-
-#### `outputDir`
-The location you want the string extraction script to write its results.
-```json
-{
- "outputDir": "./public/locales/new-strings/",
-}
-```
-
-## future work:
-- message deduplication with interface
- - decide which message to keep, or to create a new l10nId and write back to file
-- compare string extraction output with production files
- - provide no reference warnings (may indicate obsolete string)
diff --git a/lerna.json b/lerna.json
new file mode 100644
index 0000000..89763cc
--- /dev/null
+++ b/lerna.json
@@ -0,0 +1,6 @@
+{
+ "packages": [
+ "packages/*"
+ ],
+ "version": "0.1.0"
+}
diff --git a/package.json b/package.json
index 7be21a4..71c7fc8 100644
--- a/package.json
+++ b/package.json
@@ -2,16 +2,8 @@
"name": "fluent-react-utils",
"version": "0.1.0",
"description": "Utilities for fluent-react",
- "main": "./lib/index.js",
"scripts": {
- "clean": "rimraf lib",
- "test": "npm run lint && npm run cover",
- "test:prod": "cross-env BABEL_ENV=production npm run test",
- "test:only": "mocha --require babel-core/register --require babel-polyfill --recursive",
- "cover": "istanbul cover _mocha -- --require babel-core/register --require babel-polyfill --recursive",
- "lint": "eslint src test",
- "build": "cross-env BABEL_ENV=production babel src --out-dir lib",
- "prepublish": "npm run clean && npm run test && npm run build"
+ "build": "lerna bootstrap"
},
"keywords": [
"udacity",
@@ -31,48 +23,6 @@
"type": "git",
"url": "https://github.com/udacity/fluent-react-utils"
},
- "bin": {
- "l10n": "lib/cli.js"
- },
- "files": [
- "lib",
- "src"
- ],
"license": "Apache-2.0",
- "devDependencies": {
- "babel-cli": "^6.26.0",
- "babel-eslint": "^8.2.1",
- "babel-plugin-add-module-exports": "^0.2.1",
- "babel-plugin-transform-object-rest-spread": "^6.26.0",
- "babel-polyfill": "^6.26.0",
- "babel-preset-env": "^1.7.0",
- "babel-preset-es2015": "^6.24.1",
- "babel-preset-minify": "^0.3.0",
- "babel-preset-react": "^6.24.1",
- "chai": "^4.1.2",
- "cross-env": "^5.1.3",
- "enzyme": "^3.6.0",
- "enzyme-adapter-react-16": "^1.5.0",
- "eslint": "^4.16.0",
- "eslint-config-airbnb": "^16.1.0",
- "eslint-plugin-import": "^2.7.0",
- "eslint-plugin-jsx-a11y": "^6.0.2",
- "eslint-plugin-react": "^7.4.0",
- "fluent-react": "^0.8.1",
- "istanbul": "^1.0.0-alpha",
- "mocha": "^5.0.0",
- "prop-types": "^15.6.2",
- "react": "^16.5.2",
- "react-dom": "^16.5.2",
- "rimraf": "^2.6.2"
- },
- "dependencies": {
- "@babel/parser": "^7.1.0",
- "babylon-walk": "^1.0.2",
- "fluent-syntax": "^0.8.1",
- "glob": "^7.1.3",
- "jsx-ast-utils": "^2.0.1",
- "mkdirp": "^0.5.1",
- "yargs": "^12.0.2"
- }
+ "dependencies": {}
}
diff --git a/.babelrc b/packages/components/.babelrc
similarity index 100%
rename from .babelrc
rename to packages/components/.babelrc
diff --git a/.eslintrc b/packages/components/.eslintrc
similarity index 100%
rename from .eslintrc
rename to packages/components/.eslintrc
diff --git a/packages/components/README.md b/packages/components/README.md
new file mode 100644
index 0000000..a2ac457
--- /dev/null
+++ b/packages/components/README.md
@@ -0,0 +1,167 @@
+# Fluent React Components
+
+Basic fluent-react makes use of `Localized` components to wrap jsx components, like this:
+
+```jsx
+export function NotAuthorized() {
+ return (
+
+
+
+ {/* here is a comment for the localizer */}
+ Oops! looks like you're not authorized to use this app.
+
+ );
+}
+```
+
+This makes for a lot of `Localized` components on the page, and can make it hard
+to visually scan for specific HTML elements. This package comes with standard HTML
+elements already wrapped in `Localized` with their typical `attrs` enabled in the
+`Loc` component. This turns the above into:
+
+```jsx
+import {Loc} from 'fluent-react-utils';
+
+export function NotAuthorized() {
+ return (
+
+
+ {/* here is a comment for the localizer */}
+ Oops! looks like you're not authorized to use this app.
+
+
+ ,
+ a: ,
+ button:
+ }}
+ >
+ {
+ 'Try again, go Home or Logout'
+ }
+
+
+ );
+}
+```
+
+### Props
+In the `Loc` components you have access to three `l10n` props to describe how
+this message needs to be translated.
+
+#### l10nId (Required)
+The localization key for that message
+
+#### l10nVars
+This is a plain object with the message variables as keys. It's only used if the message has a variable to substitute.
+
+```jsx
+
+ {'Welcome, { $name }'}
+
+```
+
+#### l10nJsx
+A plain object with the element alias as the key and a JSX component as the value.
+This is used for any components that are included inline in the message, with the
+alias used in HTML-like syntax to wrap the translated message.
+
+```jsx
+
+ }}
+>
+ {
+ 'Go home'
+ }
+
+```
+
+## Custom Loc Components
+Your project may have components that would be great to include in the `Loc`
+object, but which are not standard HTML. Say you have a styled `MyButton`
+component, for example.
+
+```jsx
+
+
+
+```
+
+You can make use of two helpers from fluent-react-utils to quickly wrap a
+component in `Localized` and / or add it to the `Loc` object.
+
+### `makeLocalizedElement(Element[, attrs])`
+
+```js
+const MyLocalizedButton = makeLocalizedElement(MyButton, {label: true})
+```
+
+`MyLocalizedButton` will now have access to the `l10nId`, `l10nVars`, and
+`l10nJsx` props.
+
+
+### `augmentLoc(customElements)`
+In order for your custom elements to be recognized by the string extraction tool,
+they need to be prefixed by `Loc.` (or a custom name of your choice -
+see information about the `.l10nrc` file).
+
+```js
+// my-utils
+import {augmentLoc} from 'fluent-react-utils';
+
+const customElements = {
+ MyButton: MyLocalizedButton
+};
+
+export const Loc = augmentLoc(customElements);
+
+// elsewhere
+
+import {Loc} from 'my-utils';
+
+...
+
+ Look, a button!
+
+
+```
\ No newline at end of file
diff --git a/examples/components.jsx b/packages/components/examples/components.jsx
similarity index 100%
rename from examples/components.jsx
rename to packages/components/examples/components.jsx
diff --git a/examples/project-file-loc.jsx b/packages/components/examples/project-file-loc.jsx
similarity index 100%
rename from examples/project-file-loc.jsx
rename to packages/components/examples/project-file-loc.jsx
diff --git a/examples/project-file-localized.jsx b/packages/components/examples/project-file-localized.jsx
similarity index 100%
rename from examples/project-file-localized.jsx
rename to packages/components/examples/project-file-localized.jsx
diff --git a/examples/project-file-t.jsx b/packages/components/examples/project-file-t.jsx
similarity index 100%
rename from examples/project-file-t.jsx
rename to packages/components/examples/project-file-t.jsx
diff --git a/packages/components/package.json b/packages/components/package.json
new file mode 100644
index 0000000..af50a4f
--- /dev/null
+++ b/packages/components/package.json
@@ -0,0 +1,68 @@
+{
+ "name": "fluent-react-components",
+ "version": "0.1.0",
+ "description": "Utility components for fluent-react",
+ "main": "./lib/index.js",
+ "scripts": {
+ "clean": "rimraf lib",
+ "test": "npm run lint && npm run cover",
+ "test:prod": "cross-env BABEL_ENV=production npm run test",
+ "test:only": "mocha --require babel-core/register --require babel-polyfill --recursive",
+ "cover": "istanbul cover _mocha -- --require babel-core/register --require babel-polyfill --recursive",
+ "lint": "eslint src test",
+ "build": "cross-env BABEL_ENV=production babel src --out-dir lib",
+ "prepublish": "npm run clean && npm run test && npm run build"
+ },
+ "keywords": [
+ "udacity",
+ "fluent",
+ "localization",
+ "l10n",
+ "ftl",
+ "translate",
+ "translation",
+ "fluent-react",
+ "internationalization",
+ "i18n",
+ "components",
+ "react"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/udacity/fluent-react-utils"
+ },
+ "files": [
+ "lib",
+ "src"
+ ],
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "babel-cli": "^6.26.0",
+ "babel-eslint": "^8.2.1",
+ "babel-plugin-add-module-exports": "^0.2.1",
+ "babel-plugin-transform-object-rest-spread": "^6.26.0",
+ "babel-polyfill": "^6.26.0",
+ "babel-preset-env": "^1.7.0",
+ "babel-preset-es2015": "^6.24.1",
+ "babel-preset-minify": "^0.3.0",
+ "babel-preset-react": "^6.24.1",
+ "chai": "^4.1.2",
+ "cross-env": "^5.1.3",
+ "enzyme": "^3.6.0",
+ "enzyme-adapter-react-16": "^1.5.0",
+ "eslint": "^4.16.0",
+ "eslint-config-airbnb": "^16.1.0",
+ "eslint-plugin-import": "^2.7.0",
+ "eslint-plugin-jsx-a11y": "^6.0.2",
+ "eslint-plugin-react": "^7.4.0",
+ "fluent-react": "^0.8.1",
+ "istanbul": "^1.0.0-alpha",
+ "lerna": "^3.4.3",
+ "mocha": "^5.0.0",
+ "prop-types": "^15.6.2",
+ "react": "^16.5.2",
+ "react-dom": "^16.5.2",
+ "rimraf": "^2.6.2"
+ },
+ "dependencies": {}
+}
diff --git a/src/components/Loc.js b/packages/components/src/Loc.js
similarity index 91%
rename from src/components/Loc.js
rename to packages/components/src/Loc.js
index ea55e3c..d7a6472 100644
--- a/src/components/Loc.js
+++ b/packages/components/src/Loc.js
@@ -1,5 +1,5 @@
import { makeLocalizedElement } from './make-localized-element';
-import { STANDARD_ELEMENT_TYPES } from '../extraction/constants';
+import { STANDARD_ELEMENT_TYPES } from '../../../shared/constants';
export const Loc = {
A: makeLocalizedElement('a'),
diff --git a/src/components/index.js b/packages/components/src/index.js
similarity index 100%
rename from src/components/index.js
rename to packages/components/src/index.js
diff --git a/src/components/make-localized-element.jsx b/packages/components/src/make-localized-element.jsx
similarity index 100%
rename from src/components/make-localized-element.jsx
rename to packages/components/src/make-localized-element.jsx
diff --git a/src/components/pseudolocalize.js b/packages/components/src/pseudolocalize.js
similarity index 100%
rename from src/components/pseudolocalize.js
rename to packages/components/src/pseudolocalize.js
diff --git a/test/components/Loc.test.js b/packages/components/test/Loc.test.js
similarity index 77%
rename from test/components/Loc.test.js
rename to packages/components/test/Loc.test.js
index 2aa4c5d..b6631e8 100644
--- a/test/components/Loc.test.js
+++ b/packages/components/test/Loc.test.js
@@ -1,7 +1,7 @@
import { assert, expect } from 'chai';
-import { MyComponent } from '../../examples/components';
-import { augmentLoc, Loc } from '../../src/components/Loc';
-import { makeLocalizedElement } from '../../lib/components/make-localized-element';
+import { MyComponent } from '../examples/components';
+import { augmentLoc, Loc } from '../src/Loc';
+import { makeLocalizedElement } from '../src/make-localized-element';
describe('augmentLoc', () => {
it('Augments the Loc object with a custom element', () => {
diff --git a/test/components/make-localized-element.test.js b/packages/components/test/make-localized-element.test.js
similarity index 96%
rename from test/components/make-localized-element.test.js
rename to packages/components/test/make-localized-element.test.js
index ea907f1..060288f 100644
--- a/test/components/make-localized-element.test.js
+++ b/packages/components/test/make-localized-element.test.js
@@ -3,7 +3,7 @@ import { Localized } from 'fluent-react/compat';
import { assert, expect } from 'chai';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
-import { formatVars, makeLocalizedElement } from '../../src/components/make-localized-element';
+import { formatVars, makeLocalizedElement } from '../src/make-localized-element';
Enzyme.configure({ adapter: new Adapter() });
diff --git a/test/components/pseudolocalize.test.js b/packages/components/test/pseudolocalize.test.js
similarity index 83%
rename from test/components/pseudolocalize.test.js
rename to packages/components/test/pseudolocalize.test.js
index ce540e3..6f56242 100644
--- a/test/components/pseudolocalize.test.js
+++ b/packages/components/test/pseudolocalize.test.js
@@ -1,5 +1,5 @@
import { assert } from 'chai';
-import { pseudolocalize } from '../../src';
+import { pseudolocalize } from '../src';
describe('pseudolocalize', () => {
it('should transform a message', () => {
diff --git a/packages/extraction/.babelrc b/packages/extraction/.babelrc
new file mode 100644
index 0000000..b9a56e2
--- /dev/null
+++ b/packages/extraction/.babelrc
@@ -0,0 +1,18 @@
+{
+ "env": {
+ "development": {
+ "presets": ["env", "react", "es2015"],
+ "plugins": [
+ "add-module-exports",
+ "transform-object-rest-spread"
+ ]
+ },
+ "production": {
+ "presets": ["env", "react", "es2015", "minify"],
+ "plugins": [
+ "add-module-exports",
+ "transform-object-rest-spread"
+ ]
+ }
+ }
+}
diff --git a/packages/extraction/.eslintrc b/packages/extraction/.eslintrc
new file mode 100644
index 0000000..4ccec45
--- /dev/null
+++ b/packages/extraction/.eslintrc
@@ -0,0 +1,21 @@
+{
+ "parser": "babel-eslint",
+ "extends": "airbnb",
+ "env": {
+ "mocha": true
+ },
+ "rules": {
+ "comma-dangle": ["error", "only-multiline"],
+ "consistent-return": "off",
+ "import/prefer-default-export": "off",
+ "import/no-extraneous-dependencies": "off",
+ "import/no-unresolved": "off",
+ "import/extensions": "off",
+ "jsx-a11y/alt-text": "off",
+ "jsx-a11y/anchor-has-content": "off",
+ "jsx-a11y/anchor-is-valid": "off",
+ "jsx-a11y/heading-has-content": "off",
+ "no-console": "off",
+ "react/jsx-filename-extension": "off"
+ }
+}
diff --git a/packages/extraction/README.md b/packages/extraction/README.md
new file mode 100644
index 0000000..755f0e0
--- /dev/null
+++ b/packages/extraction/README.md
@@ -0,0 +1,166 @@
+
+# Fluent React Extract
+
+Get default messages from your source code so that you don't have to switch
+context to manage translatable messages
+
+Uses the [fluent-syntax](https://github.com/projectfluent/fluent.js/tree/master/fluent-syntax) serializer
+and [Babel parser](https://github.com/babel/babel/tree/master/packages/babel-parser) to
+create an AST for your React code to pull out default messages and format them in
+FTL.
+
+### How to Use
+```sh
+l10n extract [--pattern '...'] [--outputDir '...']
+```
+This will run through all files matching the file pattern, parse the code into an
+AST, locate all the `Localized` or `Loc.X` (`Loc.` is the default, but this can
+be customized, see `.l10nrc` information below) helper components and pull the id,
+messages, and comments for that component into a fresh `data.ftl` file located
+in the specified output directory.
+
+### Example
+```jsx
+// imports
+
+export function NotAuthorized() {
+ return (
+
+
+ {/* here is a comment for the localizer */}
+ Oops! looks like you're not authorized to use this app.
+
+
+ ,
+ a: ,
+ button:
+ }}
+ >
+ {
+ 'Try again, go Home or Logout'
+ }
+
+
+ );
+}
+```
+
+Running the localization script on this file would result in the `data.ftl` below:
+```
+# here is a comment for the localizer
+NotAuthorized_oopsMessage = Oops! looks like you're not authorized to use this app.
+NotAuthorized_warningImg =
+ .alt = warning sign
+NotAuthorized_possibleActions = Try again, go Home or Logout
+```
+
+*NOTE*: adding comments along with the children of a component will extract this
+out as a comment to the localizer. This can be helpful for leaving tips about
+context of the message to make translation easier.
+
+## .l10nrc File
+In order to run the extraction based on your project's custom needs, a `.l10nrc`
+file is supported. Possible values of this file:
+
+### `customElementsPath`
+If you use the custom elements as described above, if they include any attributes
+(i.e. `label` on the `MyButton` component), they need to be included to tell the
+extraction scripts which attributes to look for. The format for this is a json object
+with the component names as keys, and an object of their allowed (or explicitly
+disallowed) attributes. For example:
+
+```json
+// custom-elements.json
+{
+ "MyButton": {"label": true}
+}
+```
+It is recommended that this record of custom element attributes is held in a json
+file that is pulled into any file defining the `attrs` of that element in the React
+code.
+```js
+import {augmentLoc, makeLocalizedElement} from 'fluent-react-utils';
+import customAttrs from './custom-elements.json';
+
+const customElements = {
+ MyButton: makeLocalizedElement(MyButton, customAttrs.MyButton)
+};
+
+export const Loc = augmentLoc(customElements);
+```
+
+The value for `customElementsPath` is the path to the `custom-elements.json` file
+from the project root.
+
+For example:
+```json
+{
+ "customElementsPath": "./src/app/utils/custom-elements.json",
+}
+```
+
+### `shorthandName`
+By default, this is `Loc`, but if your project prefers not to use the same name
+as this library's `Loc` utility, you can update this in the `.l10nrc` file.
+
+```js
+// my-utils
+import {augmentLoc, makeLocalizedElement} from 'fluent-react-utils';
+import customAttrs from './custom-elements.json';
+
+const customElements = {
+ MyButton: makeLocalizedElement(MyButton, customAttrs.MyButton)
+};
+
+export const L = augmentLoc(customElements);
+
+// elsewhere
+
+import {L} from 'my-utils';
+
+...
+
+ Look, a button!
+
+
+```
+
+```json
+{
+ "shorthandName": "L",
+}
+```
+
+### `filePattern`
+In case your project always extracts the same file pattern, this can be defined
+in `.l10nrc` as opposed to passing it into the cli every time.
+```json
+{
+ "filePattern": "./src/app/**/*.{js,jsx}",
+}
+```
+
+### `outputDir`
+The location you want the string extraction script to write its results.
+```json
+{
+ "outputDir": "./public/locales/new-strings/",
+}
+```
+
+# Future Work:
+- Message deduplication with interface
+ - decide which message to keep, or to create a new l10nId and write back to file
+- Compare string extraction output with production files
+ - provide no reference warnings (may indicate obsolete string)
diff --git a/packages/extraction/examples/components.jsx b/packages/extraction/examples/components.jsx
new file mode 100644
index 0000000..28bbdac
--- /dev/null
+++ b/packages/extraction/examples/components.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export function MyComponent(props) {
+ return (
+
+
Widget for {props.label}
+
+
+ );
+}
+
+MyComponent.propTypes = {
+ label: PropTypes.string.isRequired,
+ imageSrc: PropTypes.string.isRequired
+};
diff --git a/packages/extraction/examples/project-file-loc.jsx b/packages/extraction/examples/project-file-loc.jsx
new file mode 100644
index 0000000..dc88ab8
--- /dev/null
+++ b/packages/extraction/examples/project-file-loc.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { Link } from 'react-router';
+import { signOut } from 'utils';
+import warningImg from 'assets/images';
+import { Loc } from '../src';
+
+export function NotAuthorized() {
+ return (
+
+
+ {/* here is a comment */}
+ Oops! looks like you are not authorized to use this app.
+
+
+ ,
+ a: ,
+ button:
+ }}
+ >
+ {'Try again, go Home or Logout'}
+
+
+ );
+}
diff --git a/packages/extraction/examples/project-file-localized.jsx b/packages/extraction/examples/project-file-localized.jsx
new file mode 100644
index 0000000..cb332ea
--- /dev/null
+++ b/packages/extraction/examples/project-file-localized.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { Localized } from 'fluent-react/compat';
+import { Link } from 'react-router';
+import { signOut } from 'utils';
+import warningImg from 'assets/images';
+
+export function NotAuthorized() {
+ return (
+
+
+
+ {/* here is a comment */}
+ Oops! looks like you are not authorized to use this app.
+
+ );
+}
diff --git a/packages/extraction/examples/project-file-t.jsx b/packages/extraction/examples/project-file-t.jsx
new file mode 100644
index 0000000..279f581
--- /dev/null
+++ b/packages/extraction/examples/project-file-t.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { Link } from 'react-router';
+import { signOut, T } from 'utils';
+import warningImg from 'assets/images';
+
+export function NotAuthorized() {
+ return (
+
+
+ {/* here is a comment */}
+ Oops! looks like you are not authorized to use this app.
+
+
+ ,
+ a: ,
+ button:
+ }}
+ >
+ {'Try again, go Home or Logout'}
+
+