Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 2 #21

Merged
merged 38 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1d939fc
Update packages, remove redux
Nov 19, 2018
a4767e3
Add simple translate JSX function
Nov 19, 2018
09e72a4
Add translation function
Nov 19, 2018
056b1bf
Add plural translation functions
Nov 19, 2018
17bf62c
Split into multiple components
Nov 19, 2018
97f1c60
Clean up
Nov 19, 2018
a26e674
Add multiline and context translation and more cleanup
Nov 19, 2018
e47574e
Add support for translation options and fix multi-line
Nov 19, 2018
9e00624
Delete old code
Nov 19, 2018
628869d
Fix bug with regex on matching obj data
Nov 19, 2018
5a88135
Update packages
Dec 11, 2018
ddabed6
Callback test
Jan 23, 2019
062359c
Add poc for parsing dom-like elements in translations
Jan 30, 2019
f168a9d
Split parser into own folder
Jan 31, 2019
64d9a80
Messy redux-like store
Jan 31, 2019
6f129f1
Minor cleanups and refactor
Jan 31, 2019
c7e91b5
Split into more components and add withTranslate hoc"
Jan 31, 2019
21fc06d
Update packages and move files to main
Jan 31, 2019
2bb5e88
Update example package
Jan 31, 2019
739b072
Working-ish example project
Feb 1, 2019
da49baf
Move things around, add tests and whitelists
Feb 1, 2019
977f512
Improve documentation
Feb 1, 2019
82e1511
Minor fixes
Feb 1, 2019
aa6b53e
Merge branch 'master' into v2
Feb 1, 2019
622f1c9
Add support for more types
Feb 1, 2019
846ad19
Add type for with translate
Feb 1, 2019
70deeb2
Fix type for withTranslate HoC
Feb 4, 2019
e47d6a1
Simplify the Omit type
Feb 4, 2019
53e9fff
Use Provider instead of contextType to fix hoist issues
Feb 4, 2019
b6b1167
Fix example and other minor things
Feb 4, 2019
58bc9cf
Upgrade packages, remove void tags, add hook
Mar 4, 2019
b5e3768
Use next tag instead of local file
Mar 4, 2019
6a5723a
Remove example dir and add example to README
Aug 8, 2019
3c75329
Fix export script not working with this.props.x
Aug 8, 2019
f40b4f8
Fix translation type
Aug 8, 2019
b711283
Ensure subscriber exists before unsubscribing
Aug 8, 2019
85f5e78
Update snapshots
Aug 8, 2019
0d270bd
Bump next version
Aug 8, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 145 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
# @connectedcars/react-i18n

Work in progress.

## Todo
- [ ] fuzzy translations
- [ ] improve documentation

## Installation

`npm install @connectedcars/react-i18n`
Expand All @@ -28,6 +22,42 @@ Translate text containing a variable:

`t('This {word} is in a translated sentence.', { word: 'Variable'})`

Translate plurals (`n` is injected into the data object, but can be overwritten):

`tn(count, '{n} time', '{n} times')`

Multiple lines are also supported using template strings (however, **DO NOT** use `${}` variables!):

```
t(`Foo
bar
baz`)
```

*Please note, however, that these translations will not be rendered on multiple lines in HTML!*

Translate with React:

```
// Use `tnx` for plurals with JSX!
tx(`
<p>Hello, <strong>{name}</strong><p>
<p>Today is {day}</p>
`, {
p: content => <p>{content}</p>,
strong: content => <strong>{content}</strong>,
name: 'John Doe',
day: 'Monday'
})
```

*Please note, by default translations are in strict mode which means an error will be thrown on undefined types*
*Please note, it is possible to add a whitelist/default by setting `jsxWhitelist` on the `I18nPovider`.*

You can also add a context to your translations:

`t('Hello', null, 'context here')`

## Import and Export

First you need to set up the import and export scripts in your `package.json`
Expand All @@ -41,6 +71,7 @@ First you need to set up the import and export scripts in your `package.json`

...
```

Then you can run the following commands:
* `npm run export` creates a POT file with the extracted translations in `./locales/template.pot`
* `npm run import` creates a json file containing your all your translations in `./src/translations.json`
Expand All @@ -50,4 +81,111 @@ Then you can run the following commands:
To get output for CI, add the following script:
```
"ci-translation": "i18n-translation-status"
```
```

## Example
```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import {
I18nStore,
I18nProvider,
I18nContext,
I18nConsumer,
useTranslate,
withTranslate,
} from '@connectedcars/react-i18n'
import './index.css'

const translations = {
"da": {
"": {
"content-type": "text/plain; charset=UTF-8",
"project-id-version": "",
"pot-creation-date": "",
"po-revision-date": "",
"language-team": "",
"mime-version": "1.0",
"content-transfer-encoding": "8bit",
"x-generator": "Poedit 2.0.6",
"last-translator": "",
"plural-forms": "nplurals=2; plural=(n != 1);",
"language": "da"
},
"Hello {name}": [
null,
"Hej {name}"
],
"Set language to <lang />": [
null,
"Skift sprog til <lang />"
]
}
}

const store = new I18nStore({
translations,
locale: 'da',
})

class ExampleA extends React.Component {
static contextType = I18nContext

render() {
return <div>{this.context.t('Hello {name}', { name: 'World' })}</div>
}
}

class ExampleB extends React.Component {
render() {
return (
<I18nConsumer>
{i18n => {
return <div>{i18n.t('Hello {name}', { name: 'World' })}</div>
}}
</I18nConsumer>
)
}
}

const ExampleC = withTranslate(props => {
return <div>{props.t('Hello {name}', { name: 'World' })}</div>
})

const ExampleD: React.FC = props => {
const { tx } = useTranslate()

return (
<div>
{tx('<strong>Hello</strong> there <link>test</link>', {
strong: content => <strong>{content}</strong>,
link: content => <a href="https://example.com">{content}</a>
})}
</div>
)
}

const ToggleLocale: React.FC = () => {
const { tx, setLocale, locale } = useTranslate()
const swapLocale = locale === 'da' ? 'en' : 'da'

return (
<button onClick={() => setLocale(swapLocale)}>
{tx('Set language to <lang />', {
lang: (content, attr) => <strong>{swapLocale}</strong>,
})}
</button>
)
}

ReactDOM.render(
<I18nProvider store={store}>
<ExampleA />
<ExampleB />
<ExampleC />
<ExampleD />
<ToggleLocale />
</I18nProvider>,
document.getElementById('root')
)
```
42 changes: 34 additions & 8 deletions bin/export.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,57 @@
#!/usr/bin/env node
const { GettextExtractor, JsExtractors, HtmlExtractors } = require('gettext-extractor')
const { GettextExtractor, JsExtractors } = require('gettext-extractor')

let extractor = new GettextExtractor()

const content = {
trimWhiteSpace: true,
preserveIndentation: false
}

extractor
.createJsParser([
JsExtractors.callExpression(['t', 'props.t', '[this].context.t'], {
JsExtractors.callExpression(['t', '[this].props.t', '[this].context.t'], {
arguments: {
text: 0,
// data
context: 2,
},
content,
}),

JsExtractors.callExpression(['tn', '[this].props.tn', '[this].context.tn'], {
arguments: {
// count
text: 1,
textPlural: 2,
// data
context: 4,
},
content,
}),

JsExtractors.callExpression(['tx', '[this].props.tx', '[this].context.tx'], {
arguments: {
text: 0,
// data
context: 2
}
context: 2,
},
content,
}),

JsExtractors.callExpression(['tn', 'props.tn', '[this].context.tn'], {
JsExtractors.callExpression(['tnx', '[this].props.tnx', '[this].context.tnx'], {
arguments: {
// count
text: 1,
textPlural: 2,
// data
context: 4
}
context: 4,
},
content,
})
])
.parseFilesGlob('./src/**/*.@(ts|js|tsx|jsx)')

extractor.savePotFile('./locales/template.pot')

extractor.printStats()

1 change: 0 additions & 1 deletion example/.gitignore

This file was deleted.

14 changes: 0 additions & 14 deletions example/README.md

This file was deleted.

27 changes: 0 additions & 27 deletions example/locales/da.po

This file was deleted.

17 changes: 0 additions & 17 deletions example/locales/template.pot

This file was deleted.

Loading