-
-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Help wanted Using react-intl #1227
Comments
You only need the Babel plugin to generate the translate files which you can do as part of your production build without ejecting although it's a little messy. I'll post how later. |
You can just install the required dependencies, add your own E.g.:
add to the root folder: {
"presets": ["react-app"],
"plugins": [
[
"react-intl", {
"messagesDir": "translations/messages",
"enforceDescriptions": false
}
]
]
} then add to your "translate": "NODE_ENV=production babel ./src >/dev/null" You should be able to run both |
@EnoahNetzach thanks for the answer! How does : "NODE_ENV=production babel ./src >/dev/null" generate the translation? How does it work exactly? Thank you 🙏 |
hi, Internationlization is a pretty important feature for mobile apps these days. Could we have react-intl inbuilt in the create-react flow? Regards |
@firaskrichi it works as intended by react-intl, by using babel's AST to catch translations and replace them (I suggest you to look it up, it's really interesting, if you like to know how exactly it - and in general babel plugins - works!). Moreover what I suggested is simply what the official doc tells to do ;) @arshmakker being that it's easily pluggable, not everybody wants to use i18n, and the specific tool (format.js) is not that reliable if you want to do substantial i18n (@see), I'm not sure at all it would be possible. |
This is a really useful discussion and the information provided by @EnoahNetzach has really helped get react-intl into my create-react-app application. I think it would be exceptionally valuable to have i18n working out-of-the-box with create-react-app (or at least some good documentation explaining how to use it). The main thing that I don't quite understand is how this works with a production build. I've followed the various scripts to combine individual component message files into a single JSON file for the default locale, I've then added a different locale (with translated messages) and updated the IntlProvider locale to be the new locale. When you use If anyone can shed any light on the correct approach to combining the information provided so far in a production story I'd be very grateful. |
@draperd, as a non English native speaker, I find that unfortunately no i18n instrument in js is a "catch all" solution. |
@EnoahNetzach Thanks for your response... I wasn't suggesting that there is a one-size fits all solution, but it would seem that React-Intl is a pretty good fit. I can understand the rationale of not wanting to tie "create-react-app" to a single solution, however a solution of some kind is almost going to be required. Any serious application is going to want to support i18n so I'm simply suggesting that either something is provided by default, or that documentation is provided to assist people in achieving a solution. The information you have previously provided has been invaluable but only as far as the development experience goes. My point is that when I'm ready to ship my finished application I need translation to work in production for multiple locales and I've not been able to find that information anywhere so far. I'll continue to experiment and hopefully find a working solution which I'll then write up, I was just hoping that someone may have already encountered and solved this problem using react-intl. |
Just to follow up my previous comment... what I actually need is a per component solution which I've now managed to achieve using the higher order component pattern. I will write this solution up as soon as I can for anyone that comes across this thread as it might be useful. |
@draperd good! |
As promised... hopefully this might be of use to some people: https://medium.com/@dave.draper20/i18n-per-component-in-react-using-the-higher-order-component-pattern-b04f32e7cd6a#.ewrplesd7 |
For everyone that the suggestion from @EnoahNetzach is not working out of the box I had to put following in my
|
Yep, env var definition and the output indirection to cross-env solves the first part, for the second sincerely I have no idea how to accomplish that on Windows.. |
If you don't want to have to // scripts/translate.js
process.env.NODE_ENV = 'development';
const fs = require('fs');
const path = require('path');
const globSync = require('glob').sync;
const mkdirpSync = require('mkdirp').sync;
const transformFileSync = require('babel-core').transformFileSync;
const paths = require('../config/paths');
//////////////////////////////
// Add to `/config/paths.js`:
// appBuildMessages: .. where to output the messages
//////////////////////////////
globSync(path.join(paths.appSrc, '/**/*.js'))
.map((filename) => {
const result = transformFileSync(filename, {
plugins: ['react-intl']
});
const messages = result.metadata["react-intl"]["messages"];
if (messages.length > 0) {
const relFn = path.relative(paths.appSrc, filename);
const outFilename = path.join(
paths.appBuildMessages,
path.dirname(relFn), `${path.basename(relFn, ".js")}.json`);
mkdirpSync(path.dirname(outFilename));
const outFd = fs.openSync(outFilename, 'w');
fs.write(outFd, JSON.stringify(messages));
}
}); ...
"scripts": {
...,
"translate": "node scripts/translate.js",
} |
I tried the .bablerc solution, but it does not work unless and untill i do an eject, is that just me? |
@EnoahNetzach I tried your solution of using a In my package.json file, I have:
...and am running react 15.5.4, react-scripts 0.9.5, babel-cli 6.24.1, babel-plugin-react-intl 2.3.1, and babel-preset-react-app 2.2.0. My
Have I missed something obvious? |
@cwalv question about your solution: it appears that you're outputting a separate .json file for each .js file in which you find translatable content (if I'm reading your code right). Is there a reason for doing that as opposed to putting all translatable content into a single .json file? I'm just getting into i18n, so I don't know if you're following an accepted practice, or if that's just a personal preference on your part. Thanks! |
@bmueller-sykes, you're right, I only put in half the script. I adapted it from https://github.com/yahoo/react-intl/blob/b82a899a59c762fcc590e1fa824b87da6ad409d9/examples/translations/scripts/translate.js, which adds this to the "plugins": [
["react-intl", {
"messagesDir": "./build/messages/"
}] which creates the .json files when babel runs, similar to how my snippet above does, and then the translate script has a second pass that aggregates separate files into one: // Aggregates the default messages that were extracted from the example app's
// React components via the React Intl Babel plugin. An error will be thrown if
// there are messages in different components that use the same `id`. The result
// is a flat collection of `id: message` pairs for the app's default locale.
const messagesGlob = path.join(paths.appBuildMessages, '**', '*.json');
let defaultMessages = globSync(messagesGlob)
.map((filename) => fs.readFileSync(filename, 'utf8'))
.map((file) => JSON.parse(file))
.reduce((collection, descriptors) => {
descriptors.forEach(({ id, defaultMessage }) => {
if (collection.hasOwnProperty(id)) {
throw new Error(`Duplicate message id: ${id}`);
}
collection[id] = defaultMessage;
});
return collection;
}, {});
// For the purpose of this example a fake locale: `en-UPPER` is created and
// the app's default messages are "translated" into this new "locale" by simply
// UPPERCASING all of the message text. For a real translation this would mean some
// offline process to get the app's messages translated by machine or
// professional translators.
let uppercaseTranslator = new Translator((text) => text.toUpperCase());
let uppercaseMessages = Object.keys(defaultMessages)
.map((id) => [id, defaultMessages[id]])
.reduce((collection, [id, defaultMessage]) => {
collection[id] = uppercaseTranslator.translate(defaultMessage);
return collection;
}, {});
mkdirpSync(LANG_DIR);
fs.writeFileSync(LANG_DIR + 'en-US.json', JSON.stringify(defaultMessages, null, 2));
fs.writeFileSync(LANG_DIR + 'en-UPPER.json', JSON.stringify(uppercaseMessages, null, 2)); |
I released a workaround solution to NPM $ yarn add react-intl-cra --dev
$ react-intl-cra './src/**/*.js' -o messages.json |
Thanks @evenchange4 , that npm package really helped my case. I was struggling with intl after shifting to react-scripts. REgards |
This looks really great! Perhaps we should put it into docs? |
FWIW, I wound up writing a script for this as well, based on the work from above. It runs at the command line, and trolls through everything in the
|
@arshmakker, thank you for trying. If there is any problem please feel free to report it to here currently. Maybe I will move it out to a stand-alone repository later. @gaearon I am happy to send a PR for I18n document improvement. 😀 Update (2017-12-14): Moved it to https://github.com/evenchange4/react-intl-cra |
Thank you @bmueller-sykes. Works like a charm. |
To sum up: it would be nice to have standalone CLI (or API to write one) to extract all translation keys to JSON file. See no reason why |
@stereobooster Thanks for suggestions! I have received some issues in the monorepo, so I moved it to standalone repository https://github.com/evenchange4/react-intl-cra for better issue tracking (after v0.2.12). 🙌 |
@evenchange4 How well does it work in practice? Should we start pointing people towards it? |
@gaearon I use the I notice that babel-plugin-macros have been merged today. I will take some time to try it with this babel-related problem. |
Nice, thanks. |
Currently I am using the |
Here is the macro solution POC: Your code// Component.js
-import {defineMessages} from 'react-Intl';
+import { defineMessages } from 'react-intl.macro';
const messages = defineMessages({
'Component.greet': {
id: 'Component.greet',
defaultMessage: 'Hello, {name}!',
description: 'Greeting to welcome the user to the app',
},
}); Extract messages// package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
+ "extract": "MESSAGE_DIR='./.messages' react-scripts build"
}, Pros and ConsThe ReferencesGitHub: https://github.com/evenchange4/react-intl.macro |
May I know why does
format? If you do
Thanks. |
@EnoahNetzach I have tried with your solution and
Should I install anything else in my project ? What plugin can I reuse and where are they stored ? Did anybody made a workaround ? I dont' get why [
{
"id": "test.action.resetViews",
"defaultMessage": "Reset views",
"filepath": "./src/messages.js"
}
] While I expect {
"test.action.resetViews": "Reset views"
} I want to use react-intl. As @dachinat pointed oput, we need How can I do without ejecting? |
Personnaly, I use the internal script "extract-intl": "babel-node --presets env,stage-0 -- ./internals/scripts/extract-intl.js" |
@noliiva I have placed this react-boilerplate script in a program that you can run through You must have in your + "declinationId": "intl" Then run $ npx rollup-umd-scripts install fr en de ch vi --default=en This will create in your + "translation": {
+ "locale": "en",
+ "locales": [
+ "en",
+ "fr",
+ "de",
+ "ch",
+ "vi"
+ ]
}, You can now extract what's in $ NODE_ENV=production npx rollup-umd-scripts intl extract You can add the following scripts to your + "extract-intl": "NODE_ENV=production npx rollup-umd-scripts intl extract --target=src/i18n/translation",
It's basically the same as evenchange4 except with the standard format for json and without any install. |
I'm following up on the questions asked by @dachinat and @kopax From what I understand, there are two steps:
In the The I didn't think the second step would be so complicated to implement. So far all I've found (outside of this discussion) is this software that provides a GUI to do it. I don't know what it is based on. Did I miss something here or is it really that complicated to have a translations file for each language? |
Looking for a way to extract messages from components localized using react-intl and manage translations effortlessly? The following worked for me: formatjs/babel-plugin-react-intl#108 (comment) |
I was using the same tutorial and couldn't find a tutorial from start => finish without ejecting so wrote one here: https://medium.com/@jamieallen59/using-react-intl-with-create-react-app-6667ee3e19f3. Hope it helps. |
Hey I get error saying ' You must use a intl declination to use this command!' |
@SeunghunSunmoonLee sorry I did a change in that script, you must have in your + "declinationId": "intl" It wont break anymore, otherwise you can fix to an older version. |
@jamieallen59 Your tutorial worked great for me. Thanks. |
@jamieallen59 |
In my case I'm able to use scripts/i18n-extract.sh: #!/bin/bash
lang='en'
npm run i18n:formatjs:extract \
-- 'src/**/*.ts*' --ignore 'src/**/*.d.ts*' \
--out-file src/src-lang/"$lang".json \
--id-interpolation-pattern '[sha512:contenthash:base64:6]' * I define the extension as scripts/i18n-compile.sh: #!/bin/bash
langs=( 'en' 'fr' 'ar' )
if [ "${1:-}" = 'default' ]; then
langs=( 'en' )
fi
for lang in "${langs[@]}"; do
src="src/src-lang/$lang.json"
dest="src/lang/$lang.json"
if [ ! -f "$src" ]; then
echo "[warn] src file not found ($src)"
else
npm run i18n:formatjs:compile -- "$src" --ast --out-file "$dest"
fi
done * In this case I'm considering the languages And in package.json: "scripts": {
"start": "HTTPS=true react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"i18n:dev": "echo '{}' > src/lang/en.json",
"i18n:extract": "bash ./scripts/i18n-extract.sh",
"i18n:compile": "bash ./scripts/i18n-compile.sh",
"i18n:formatjs:extract": "formatjs extract",
"i18n:formatjs:compile": "formatjs compile"
} I only need bash to be installed and everything works fine so far. I can run In smaller projects you can run In development I just run The only thing I haven't achieved was to be able to generate ids (https://formatjs.io/docs/guides/bundler-plugins), and use the generated ids in development (I don't know if this is possible without ejecting and stop using |
Hi all,
I'm following this tutorial https://medium.freecodecamp.com/internationalization-in-react-7264738274a0#.pgfd03878 to use internationalization in my app.
Apparently the integreation is done by modifying the .babelrc file but to do so I have to eject, and I prefer not to.
Is there any way to use React-Intl without ejecting create-react-app?
The text was updated successfully, but these errors were encountered: