Skip to content

Commit

Permalink
feat: initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
avaragado authored Mar 21, 2017
1 parent 3f19c67 commit d487824
Show file tree
Hide file tree
Showing 196 changed files with 25,954 additions and 7 deletions.
25 changes: 25 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"presets": [
[
"env",
{
"node": 6
}
]
],

"plugins": [
"transform-runtime",
"transform-flow-strip-types",
"transform-object-rest-spread",
"inline-package-json"
],
"env": {
// jest needs this
"test": {
"plugins": [
"transform-es2015-modules-commonjs"
]
}
}
}
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
; http://EditorConfig.org

root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[package.json]
indent_size = 2
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
flow-typed/*
dist/*
flow-coverage/*
coverage/*
114 changes: 114 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
module.exports = {
root: true,

extends: [
'airbnb',
'plugin:flowtype/recommended',
'plugin:jest/recommended',
],

plugins: [
'flowtype',
'jest',
],

env: {
'jest': true,
},

// overrides the airbnb ruleset
rules: {
// 4-space indent
'indent': ['error', 4, { SwitchCase: 1 }],

// require space before function opening parenthesis
'space-before-function-paren': ['error', 'always'],

// allow console methods
'no-console': 'off',

// quote all or no props in an object, disallow mixing
'quote-props': ['error', 'consistent'],

// never assign to a fn param, but allow assignment to its props
'no-param-reassign': ['error', { 'props': false }],

// allow padded blocks
'padded-blocks': 'off',

// enforce braces
'curly': ['error', 'all'],

// check that when we import default from our own code, there's a default export
'import/default': 'error',

// check that named imports exist in the exports
'import/named': 'error',

// check that wildcard imports '* as foo' exist when dereferenced
'import/namespace': 'error',

// check that external modules are referenced directly in package.json
// as dependencies, devDependencies or optionalDependencies.
'import/no-extraneous-dependencies': ['error', {
'devDependencies': true,
'optionalDependencies': true,
}],

// disallow use of exported name as name of default import,
// as it's likely you missed some brackets.
'import/no-named-as-default': 'error',

// imports always come first
'import/imports-first': ['error', ''],

// disallow use of exported name as property on the default export,
// as this is likely to confuse.
'import/no-named-as-default-member': 'error',

// ensure imports are in a consistent order:
'import/order': ['error', {
'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
}],

// must separate imports from rest of code
'import/newline-after-import': 'error',

// import must include extensions for all files except these
"import/extensions": [
"error",
"always",
{
"js": "never",
"jsx": "never",
"es": "never"
}
],

// allow dynamic requires
"import/no-dynamic-require": 'off',

// allow 'require' anywhere
'global-require': 'off',

'no-underscore-dangle': ['error', {
'allowAfterThis': false,
'allow': [
'__', // for Ramda's R.__
],
}],

'no-warning-comments': [
'warn', {
'terms': ['::TODO::'],
'location': 'start',
}
],

'generator-star-spacing': ['error', { 'before': true, 'after': true }],
},

// add as they're encountered
globals: {
},
};
26 changes: 26 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# for third-party modules that use flow, you need to let flow do its thing:
# so you shouldn't ignore the entirety of node_modules.
# however, you might have to adjust the [ignore] etc sections HERE
# to account for what those modules need. for example, if a module
# uses a magic marker to ignore certain flow errors, you need to include
# that magic string HERE too.
[ignore]
<PROJECT_ROOT>/dist/.*

# error in a json file
<PROJECT_ROOT>/node_modules/conventional-changelog-core/.*

# error in src/lib/flow.js
<PROJECT_ROOT>/node_modules/flow-coverage-report/.*

[include]

[libs]
flow-typed/

[options]
# we import eg config files via variable
module.ignore_non_literal_requires=true

# used by flow-coverage-report
suppress_comment=.*\\$FLOW_FIXME
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
/dist/
/flow-coverage/
/coverage/
npm-debug.log
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 David Smith

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# riw

riw ("`react-intl` workflow") is a set of command-line tools and a library to help you work with `react-intl` in a React app. Use it to:

- Define target locales for your app: the locales into which you translate the app.
- Extract `react-intl` message descriptors from your React components, directly or indirectly.
- Check for duplicates in your `react-intl` message descriptor ids.
- Manage translations for each target locale.
- Generate JSON files for your translations, to include in your app.

This project is not associated with the `react-intl` project.

The word "riw" seems to be Welsh for slope or hill, and rhymes with the English word "drew".

There's an example repository, [`riw-example`](https://github.com/avaragado/riw-example), showing (in its commit history) how to migrate a simple React app with hard-coded strings to `react-intl`, and then how to use riw with it.


## Which problems doesn't riw solve?

- riw doesn't perform any automated text translation or interface with any translators or translation services. It tells you which messages need translating, lets you update its translations database with the translations once you have them, and produces shippable, `react-intl`-compatible JSON files for each locale you want to support.

- riw doesn't provide a mechanism for generating unique `react-intl` message descriptor ids. How you define these depends on your app's requirements. However, it does let you identify any duplicate ids. ([See the FAQ](doc/faq.md) for a possible naming scheme.)

- riw doesn't import the generated JSON locale files into your app or plug them into `react-intl`'s `IntlProvider`. You implement this behaviour yourself.


## Assumptions

riw assumes you're familiar with `react-intl`, and that your app already uses a build system of some kind (for example, webpack).


## TL;DR

1. `yarn add --dev riw`
1. Add to `package.json`:
```json5
"riw": {
"defaultLocale": "en-US", // locale of the source strings
"targetLocales": ["fr-FR", "pt-BR", ...], // other locales the app should support
}
```
1. `yarn run riw db init` – initialise empty db at `src/locale/riw-db.json`
1. `yarn run riw app translate` – outputs `src/locale/[locale].json` and `src/locale/TODO-untranslated.json` (might need to add a `.babelrc` in your app)
1. Update your app to import strings from `src/locale/[locale].json` for each target locale, and plug them into `react-intl`'s `IntlProvider` at the appropriate time.
1. LOOP:
1. Translate everything in the `TODO-untranslated.json` file. Meanwhile, keep developing your app in the usual way.
1. `yarn run riw db import TODO-with-translations.json` if you have a file of them in the right format, or
1. `yarn run riw db update <opts...>` to update the db string by string.
1. `yarn run riw app translate`
1. Go to LOOP.

Check everything into source control. There are no temporary files.

## More information

- [Installing, configuring and using riw](doc/tutorial.md)
- [Configuration settings](doc/config.md)
- [FAQ/troubleshooting](doc/faq.md)
- [Using riw programmatically](doc/library.md)
- [Example repository showing how to add react-intl and riw to a React app](https://github.com/avaragado/riw-example)
114 changes: 114 additions & 0 deletions doc/config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# riw configuration

## Location

You can place riw configuration in:

- **Either** a configuration file of your choosing (which you specify with the `--config` option whenever you run the `riw` command)
- **Or** the file `.riw-config.js` at the root of your package (in the same directory as your `package.json`)
- **Or** under the `riw` key in your `package.json`

The `riw` command looks for configuration in the order shown above. If you include configuration in more than one location, only the first configuration found is used.

Your configuration settings override the built-in defaults. To see the full configuration in use, including your overrides, use the `riw print-config` command (with the `--config` option if necessary).


## Configuration file type

If you use a standalone configuration file (either `.riw-config.js` or one you specify using `--config`), riw expects this to be a node module that exports an object.

For the `package.json` file's `riw` key, you may use only JSON data.


## Configuration options

For options with type `Path` or `Glob`, the string value is a filesystem path. Relative paths are treated as relative to the configuration file.

### `defaultLocale`

- Type: `LocaleId`
- Default value: `en-US`

The locale id that riw assigns to every `react-intl` message descriptor's `defaultMessage`.

### `targetLocales`

- Type: `LocaleId[]`
- Default value: `[]`

The locales you want to translate to for this app. The riw translations database may contain locales not in this list (because apps can share databases).

### `translationsDatabaseFile`

- Type: `Path`
- Default value: `src/locale/riw-db.json`

The filesystem path to the translations database used by riw. Multiple apps can share the same translations database, with different target locales.

### `sourceDirs`

- Type: `Glob[]`
- Default value: `['src/**/*.js']`
- Ignored if `inputMode` is not `source`.

Array of glob patterns identifying your source files.

When `inputMode` is `source`, riw parses all files matching this pattern looking for `react-intl` message descriptors to translate. (riw uses `babel-plugin-react-intl` to perform the parsing.)


### `collateDir`

- Type: `Path`
- Default value: `tmp/babel-plugin-react-intl`
- Ignored if `inputMode` is not `json`.

The filesystem path to a directory containing JSON files (in any tree structure). Each file is assumed to contain the output of `babel-plugin-react-intl`: an array of `react-intl` message descriptors.

When `inputMode` is `json`, riw collates these JSON files for translation and does not read your source files.


### `inputMode`

- Type: `source` | `json`
- Default value: `source`

How riw should locate the `react-intl` message descriptors to translate.

- Use `source` and set `sourceDirs` if you want riw to extract message descriptors from your source files using `babel-plugin-react-intl`.
- Use `json` and set `collateDir` if you want riw to use message descriptors already extracted from your source files by another process, for example webpack.

### `translationsOutputFile`

- Type: `Path`
- Default value: `src/locale/[locale].json`
- Ignored if `outputMode` is `no-file`.

The filesystem path template that identifies where riw saves translations. Use the placeholder `[locale]` literally: riw replaces this as necessary.

- When `outputMode` is `file-per-locale`, riw replaces `[locale]` with the appropriate locale id.
- When `outputMode` is `single-file`, riw replaces `[locale]` with the literal string `locales`.


### `todoFile`

- Type: `Path`
- Default value: `src/locale/TODO-untranslated.json`
- Ignored if `outputMode` is `no-file`.

The filesystem path that identifies where riw saves message descriptor and locale data for messages that still need to be translated into some or all of your target locales.


### `outputMode`

- Type: `single-file` | `file-per-locale` | `no-file`
- Default value: `file-per-locale`

How riw outputs translated strings for your app.

riw processes your app's `react-intl` message descriptors (found according to `inputMode`) and the configured translations database to discover matching translations. This setting determines whether and how riw should write those translations to disk.

- Use `single-file` and set `translationsOutputFile` if you want riw to save translations for all locales in one file. This option is best if your app ships with every locale embedded statically (for example, an app built with Electron).
- Use `file-per-locale` and set `translationsOutputFile` if you want riw to save translations for each locale in a separate file. This option is best if your app loads locale information on demand (for example, a web app).
- Use `no-file` and ignore `translationsOutputFile` if you don't want riw to save the translations. This option is best if you're using the riw API directly.

If `outputMode` is `single-file` or `file-per-locale`, riw saves message descriptor and locale data for untranslated messages in the configured `todoFile`. If `outputMode` is `no-file`, this data is not saved to a file.
Loading

0 comments on commit d487824

Please # to comment.