retranslate
Advanced tools
Comparing version 0.4.1 to 1.0.0
MIT License | ||
Copyright (c) 2017 Uku Markus Tammet | ||
Copyright (c) 2018 Uku Markus Tammet | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
108
package.json
{ | ||
"name": "retranslate", | ||
"description": "Real simple translations for react.", | ||
"main": "build/retranslate.js", | ||
"version": "0.4.1", | ||
"main": "dist/retranslate.js", | ||
"version": "1.0.0", | ||
"license": "MIT", | ||
@@ -11,2 +11,5 @@ "bugs": { | ||
}, | ||
"files": [ | ||
"dist/" | ||
], | ||
"keywords": [ | ||
@@ -25,45 +28,53 @@ "react", | ||
"devDependencies": { | ||
"babel-core": "6.17.0", | ||
"babel-eslint": "7.1.1", | ||
"babel-jest": "17.0.2", | ||
"babel-loader": "6.2.7", | ||
"babel-plugin-transform-react-remove-prop-types": "^0.2.11", | ||
"babel-preset-react-app": "^2.0.1", | ||
"case-sensitive-paths-webpack-plugin": "1.1.4", | ||
"chalk": "1.1.3", | ||
"coveralls": "^2.11.15", | ||
"dotenv": "2.0.0", | ||
"enzyme": "^2.7.0", | ||
"eslint": "3.9.1", | ||
"eslint-config-airbnb": "^13.0.0", | ||
"eslint-loader": "1.6.0", | ||
"eslint-plugin-import": "2.2.0", | ||
"eslint-plugin-jsx-a11y": "2.2.3", | ||
"eslint-plugin-react": "6.6.0", | ||
"filesize": "3.3.0", | ||
"fs-extra": "0.30.0", | ||
"gzip-size": "3.0.0", | ||
"jest": "17.0.2", | ||
"json-loader": "0.5.4", | ||
"path-exists": "2.1.0", | ||
"publish": "^0.6.0", | ||
"react": "^15.4.2", | ||
"react-addons-test-utils": "^15.4.2", | ||
"react-dev-utils": "^0.4.2", | ||
"react-dom": "^15.4.2", | ||
"recursive-readdir": "2.1.0", | ||
"strip-ansi": "3.0.1", | ||
"webpack": "1.14.0", | ||
"webpack-manifest-plugin": "1.1.0" | ||
"@babel/core": "^7.0.0-rc.1", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-rc.1", | ||
"@babel/preset-env": "^7.0.0-rc.1", | ||
"@babel/preset-react": "^7.0.0-rc.2", | ||
"babel-core": "^7.0.0-bridge.0", | ||
"babel-jest": "^23.4.2", | ||
"babel-loader": "^8.0.0-beta.4", | ||
"coveralls": "^3.0.2", | ||
"enzyme": "^3.4.4", | ||
"enzyme-adapter-react-16": "^1.2.0", | ||
"eslint": "^5.4.0", | ||
"eslint-config-airbnb": "^17.1.0", | ||
"eslint-config-prettier": "^3.0.1", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.1", | ||
"eslint-plugin-prettier": "^2.6.2", | ||
"eslint-plugin-react": "^7.11.1", | ||
"husky": "^0.14.3", | ||
"jest": "^23.5.0", | ||
"lint-staged": "^7.2.2", | ||
"prettier": "^1.14.2", | ||
"prettier-eslint-cli": "^4.7.1", | ||
"prop-types": "^15.6.1", | ||
"react": "^16.4.0", | ||
"react-dom": "^16.4.0", | ||
"webpack": "^4.17.0", | ||
"webpack-cli": "^3.1.0" | ||
}, | ||
"peerDependencies": { | ||
"react": "^15.4.2", | ||
"react-dom": "^15.4.2" | ||
"react": "^16.4.0" | ||
}, | ||
"scripts": { | ||
"build": "node scripts/build.js", | ||
"test": "node scripts/test.js --env=jsdom", | ||
"coverage": "node scripts/test.js --env=jsdom --coverage" | ||
"precommit": "lint-staged", | ||
"test": "npm run lint && npm run check-format && jest --env=jsdom", | ||
"coverage": "jest --env=jsdom --coverage", | ||
"test:watch": "jest --env=jsdom --watch", | ||
"lint": "eslint src", | ||
"check-format": "prettier-eslint \"src/**/*.js\" --list-different", | ||
"format": "prettier-eslint \"src/**/*.js\" --write", | ||
"build": "webpack -p" | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"prettier-eslint \"src/**/*.js\" --write", | ||
"git add" | ||
] | ||
}, | ||
"jest": { | ||
"setupFiles": [ | ||
"<rootDir>/setupEnzyme.js" | ||
], | ||
"collectCoverageFrom": [ | ||
@@ -83,22 +94,3 @@ "src/**/*.{js,jsx}" | ||
] | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"react-app" | ||
], | ||
"plugins": [ | ||
"transform-react-remove-prop-types" | ||
] | ||
}, | ||
"eslintConfig": { | ||
"extends": "airbnb", | ||
"env": { | ||
"jest": true | ||
}, | ||
"rules": { | ||
"react/jsx-filename-extension": 0, | ||
"import/prefer-default-export": 0, | ||
"import/no-extraneous-dependencies": 0 | ||
} | ||
} | ||
} |
122
README.md
@@ -1,3 +0,3 @@ | ||
retranslate | ||
=========== | ||
# retranslate | ||
[![CircleCI](https://circleci.com/gh/Tankenstein/retranslate/tree/master.svg?style=shield)](https://circleci.com/gh/Tankenstein/retranslate/tree/master) [![Coverage Status](https://coveralls.io/repos/github/Tankenstein/retranslate/badge.svg)](https://coveralls.io/github/Tankenstein/retranslate) | ||
@@ -10,82 +10,90 @@ | ||
First, install retranslate using | ||
+ npm: `npm install --save retranslate` | ||
+ or yarn: `yarn add retranslate` | ||
```javascript | ||
import { Message, Provider as TranslationProvider, withTranslations } from 'retranslate'; | ||
- npm: `npm install --save retranslate` | ||
- or yarn: `yarn add retranslate` | ||
import SomeComponent from './someComponent'; | ||
import { getLanguage } from './config'; // some functionality to select a language, in this example, hopefully returning en or et. | ||
import { version } from '../../package.json'; | ||
Then, start importing and using the following components and functions: | ||
// You can import these from a json file that tools like crowdin can use, like | ||
// import enTranslations from './translations.en.json'; | ||
// import etTranslations from './translations.et.json'; | ||
const translations = { | ||
en: { | ||
'main.heading': 'retranslate #{{ versionNumber }}', | ||
'main.subtitle': 'Real simple translations for react.', | ||
'current.language': 'Your current language is {{ currentLanguage }}', | ||
'bold.thing': 'This <b>text</b> is bold', | ||
}, | ||
et: { | ||
'main.heading': 'retranslate #{{ versionNumber }}', | ||
'main.subtitle': 'Väga lihtsad tõlked reactile.', | ||
'current.language': 'Teie hetke keel on {{ language }}', | ||
'bold.thing': 'See <b>tekst</b> on tumedam', | ||
}, | ||
}; | ||
### Provider | ||
// You can use the withTranslations higher-order component to get a hold of the current language and the translate function. | ||
const LanguageShower = withTranslations(({ translations: { translate, language } }) => ( | ||
<p>{translate('current.language', { currentLanguage: language })}</p> | ||
)); | ||
retranslate is configured using the `Provider`. You pass `Provider` `messages`, a `language` and a `fallbackLanguage` (just in case). Wrap your application with `Provider` to make retranslate work. The `Provider` takes an optional argument `wrapperElement`, which can be used to configure which element is used to render the provider. | ||
// withTranslations is also available through a render prop with <WithTranslations> | ||
const AnotherLanguageShower = () => ( | ||
<WithTranslations>{({ translate, language }) =>( | ||
<p>{translate('current.language', { currentLanguage: language })}</p> | ||
)}</WithTranslations> | ||
) | ||
Example use: | ||
```javascript | ||
import { Provider as TranslationProvider } from 'retranslate'; | ||
const App = () => ( | ||
<TranslationProvider messages={translations} language={getLanguage()} fallbackLanguage="en"> | ||
<h1><Message params={{ versionNumber: version }}>main.heading</Message></h1> | ||
<SomeComponent /> // this can also use the Message component, since there is a Provider up the tree. | ||
<Message className="lead" data-toggle="popover">main.subtitle</Message> // you can pass props to the generated span containing the translation | ||
<Message dangerouslyTranslateInnerHTML="bold.thing" /> // this does not escape HTML. Dangerous to use, be careful. | ||
<LanguageShower /> | ||
<AnotherLanguageShower /> | ||
</TranslationProvider> | ||
<TranslationProvider | ||
messages={{ | ||
en: { key: 'I am a translation in english with a parameter here: {{ parameter }}' }, | ||
et: { key: 'Ma olen eestikeelne tõlge, parameetriga siin: {{ parameter }}' }, | ||
}} | ||
language="en" | ||
fallbackLanguage="en" | ||
> | ||
// ... your app goes here | ||
</Provider> | ||
); | ||
``` | ||
### Provider | ||
### Message | ||
retranslate is configured using the `Provider`. You pass `Provider` `messages`, a `language` and a `fallbackLanguage` (just in case). Wrap your application with `Provider` to make retranslate work. The `Provider` takes an optional argument `wrapperElement`, which can be used to configure which element is used to render the provider. This can either be a string | ||
to use a DOM element (e.g. `<Provider wrapperElement="span">`) or some react element (e.g. `<Provider wrapperElement={React.Fragment}>`). | ||
retranslate uses `Message` to actually translate your messages. It uses the children you give it as the key to use to get translations. You can make it not escape the html of the translation, by passing the key in a prop called `dangerouslyTranslateInnerHTML` rather than the children. To add variables, pass them as a map in the `params` prop. You can use react components as variables out of the box. | ||
### Message | ||
Example use: | ||
retranslate uses `Message` to actually translate your messages. It uses the children you give it as the key to use to get translations. | ||
```javascript | ||
import { Message } from 'retranslate'; | ||
// assuming there is a key called "greeting" and a provider somewhere up the tree. | ||
const Greeting = ({ name }) => <Message params={{ name }}>greeting</Message>; | ||
``` | ||
When the translation is not found, even in the fallback language, the translation key itself will be rendered. | ||
### withTranslations | ||
`withTranslations` is a higher order component that you can use to access translation functionality and language manually. | ||
You get access to a `translate` function, a `translateAsParts` function and the current `language`. The translate function takes a message key and template parameters, and returns a string translation. When using this function, react components passed as parameters will not work, and they'll be stringified. The other function, translateAsParts, returns the internal representation of translation parts. These translation parts have both a value and a property called `dangerous`. If `dangerous` is true, it's a resolved template parameter and you should take special care with it (as these are dynamic). | ||
Example use: | ||
```javascript | ||
import { withTranslations } from 'retranslate'; | ||
const GreetingWithLanguage = withTranslations(({ translations: { translate, language } }) => | ||
translate('greeting', { name: 'someName', language /* parameters */ }), | ||
); | ||
``` | ||
### WithTranslations | ||
`WithTranslations` is a component, similar to the `withTranslations` HOC. Instead of exposing internal functionality as a hoc, it exposes it to a function as a child. | ||
Example use: | ||
```javascript | ||
import { WithTranslations } from 'retranslate'; | ||
const Greeting = ({ name }) => ( | ||
<WithTranslations> | ||
{translations => | ||
translations.translate('greeting', { name })) | ||
} | ||
</WithTranslations> | ||
); | ||
``` | ||
## Potential questions | ||
+ Async loading | ||
- Async loading | ||
I don't want to build this into retranslate. I would keep handling this on the application side. | ||
+ Logic in templates, such as `{{ thing + 1 }}` | ||
- Plurals | ||
I would not like to do this, as it makes the whole application harder to test and maintain. | ||
+ Plurals | ||
This is something that will be worked on. | ||
+ Compiled templates for even better performance | ||
- Compiled templates for even better performance | ||
@@ -96,4 +104,4 @@ Also something that will probably be worked on. | ||
Use the `test` and `build` script to test the library. Make a pull request, and it will be automatically checked by CircleCI, Coveralls, and @Tankenstein. When you make a production code change, make sure to increment the version in `package.json` according to semver. As your branch is merged, a release will automatically be made. | ||
Use the `test:build` script to test the library. Make a pull request, and it will be automatically checked by CircleCI, Coveralls, and @Tankenstein. When you make a production code change, make sure to increment the version in `package.json` according to semver. As your branch is merged, a release will automatically be made. | ||
retranslate is licensed under MIT. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1
27
106
38327
5
27