-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
How does React-Intl recommend allowing users to select a different language? #39
Comments
We haven't written an a specific guide for how we recommend implementing a user-selectable language feature — as that's more application specific. We do provide details on automatically determining the locale. But once we have the locale it can simply be passed as a prop to a React component that uses the I'm not sure if this answers your question… if not, could you provide more details in the issue description? |
Thanks, that’s helpful. I guess what’s odd to me about the ReactIntlMixin “API” is that the top-level usage (which I am following) accepts a "locales" array, as well as a "messages" object. (which seems to work without the top level of the object being a locale, e.g., top level can be "buttons" and "errors", not "en" and "fr")… so… I’m confused by the semantics of passing multiple "locales" but one locale's messages. Maybe I should be adding a top-level locale key? I see from the guide you linked to that I am supposed to chose a locale automatically for the user. But then if I have passed multiple locales to the React-Intl mixin, how does it know which one locale it should be using? |
I see that the React-Intl mixin makes the following available to children thu
But what about the 1 locale that you can actually use at a time? |
@alanhogan all the low level APIs (e.g. Intl.numberFormat()) expect a list of locales to match that with the available locales in the runtime (or the polyfill CLDR data) to compute the most common denominator, more details here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat |
@caridy I think I see. So, correct me if I am wrong, but an optimal implementation might look like:
Yeah? |
|
Right… true. Thanks very much. |
@alanhogan the one vs many confusion is something we can work to fix — I agree that it makes it hard to understand that when the prop's name is Have two props
Essentially the idea would to make |
I think we should stick to |
This should be trivial, since props can be reset with |
@gpbl switching the When you combine the locale data for the Intl.js polyfill, Format.js, and your app's strings it will be large enough that you'll only want to load this data for the user's current locale. Switching the locale on the fly means that you'll need to implement a script loader that makes sure the locale data for the new locale is loaded before re-rendering the page in React. To complicate things more, the Intl.js polyfill should ideally only be loaded in the browsers that actually need it. We're working this make Intl.js available through Polyfill.io. |
@ericf I see what you mean. However it's not an uncommon task to require modules asynchronously, for example with webpack's As for the missing function switchLocale(i18n) {
// Render the component
this.setProps({messages: i18n.messages, locales: i18n.locales});
);
function switchToJapanese() {
if (has('Intl'))
require.ensure(['../i18n/jp'], function(require){
// Now we have loaded japanese data
var jp = require('../i18n/jp');
switchLocale(jp);
});
else
require.ensure(['../i18n/jp-with-intl'], function(require){
var jp = require('../i18n/jp-with-intl'); // Load Intl locale-data as well
switchLocale(jp);
});
} Not sure if there are better ways for doing this, anyway :-) Since I don't believe dynamic requires would work, I need to explicitly specify the requires for each language. I still have to check if polyfills.io may help, but I believe if using web pack it wouldn't. |
Modern browsers (with the exception of Safari) don't need the Intl.js polyfill, and it's pretty large (14kb for the polyfill + data for a locale), so this is why we want to get this on polyfill.io. We feel strongly that you should not |
@ericf I don't see why it shouldn't work – just make sure you "require" the polyfills and the localized strings before mounting the app, or before setting the new props. Here is a working example of what I mean: https://github.com/gpbl/react-locale-hot-switch What could go wrong? Maybe I'm missing an important part of the whole concept :-) @alanhogan is this something can help you too? |
Yes, this is relevant to my interests, as they say on the Internet. Thanks. I’ll be taking a look before long. Alan
|
@gpbl I wasn't saying it's not possible, just qualifying hot-swap locale switching as being complex rather than trivial :) It also never felt like a strong requirement to support hot-swapping locales without reloading the page. But that may be because our apps also support server-side rendering. |
@ericf Actually the reason I landed to hot switching the locale was because my projects also start from a server rendered page. This also comes easy with webpack. When naming the i18n chunks during the build process, we can This way we can have the same URL for different languages. Crawlers will still see the alternate localised domain (e.g. Hot switching the locale is not mandatory but it's nice to have and I still believe requires little effort. Plus it's a benefit for our translators :-) |
ok ok, there is nothing (as far as I can tell) that will prevent you for doing all those things (even though we think those are crazy things jejejeje). The internal cache system used by react-intl will take in consideration the locales, and therefore if you change As for the use of |
Thanks for all the pointers, guys. I have to admit I have a tough time making this work with Safari & webpack. If I use |
@sebastienbarre not being able to use dependencies when a module is being executed seems like a problem with Webpack or how it's being configured. How are you conditionally loading other polyfills your app uses? |
@ericf so far I had bit the bullet and included my polyfills in my vendor chunk, because they were pretty small. |
The Intl polyfill + |
Yes, ultimately when UglifyJS has done its job and the server is gzipping, we are down to much smaller numbers. But I've to admit my surprise when I first tried |
@sebastienbarre my bad: the react-locale-hot-switch app wasn't using the react-intl@latest, which indeed requires |
@gpbl I see. Thanks a lot for the quick reply. It seems the change was made by @ericf in e188cc1.
My gut feeling is that people will use the It's not a huge issue, but the problem here is that it involves loading yet one more chunk, thus requiring yet another round-trip to the server. Performance-wise, you would want to avoid that. Again, thanks for the all the hard work. |
This is like saying I can't access
I would assume Webpack loads the |
Agreed, 3 separate requests wouldn't be too bad, I guess I was curious as to why I suddenly needed an extra one. I'm wholeheartedly with you on this one:
but I think that might be where my confusion is here, I'm not executing any I've to admit I've not have had that issue with other polyfills before, that's why I would put them in my vendor chunk (small so far). No worries, but I figured I might not be the only one bumping into that, might as well document it. |
Hi all, I came across this issue, and while it is old/closed I felt I might see if there's any new perspective from the React Intl team on how to allow users to select another language? |
Hi guys, this is what I came up with with a new React Context API. Pure React solution, no redux required. Tell me what you think: IntlContext.jsx import React from "react";
import Types from "prop-types";
import { IntlProvider, addLocaleData } from "react-intl";
import en from "react-intl/locale-data/en";
import de from "react-intl/locale-data/de";
import deTranslation from "../../lang/de";
import enTranslation from "../../lang/en";
addLocaleData([...en, ...de]);
const { Provider, Consumer } = React.createContext();
class IntlProviderWrapper extends React.Component {
constructor(...args) {
super(...args);
this.switchToEnglish = () =>
this.setState({ locale: "en", messages: enTranslation });
this.switchToDeutsch = () =>
this.setState({ locale: "de", messages: deTranslation });
// pass everything in state to avoid creating object inside render method (like explained in the documentation)
this.state = {
locale: "en",
messages: enTranslation,
switchToEnglish: this.switchToEnglish,
switchToDeutsch: this.switchToDeutsch
};
}
render() {
const { children } = this.props;
const { locale, messages } = this.state;
return (
<Provider value={this.state}>
<IntlProvider
key={locale}
locale={locale}
messages={messages}
defaultLocale="en"
>
{children}
</IntlProvider>
</Provider>
);
}
}
export { IntlProviderWrapper as IntlProvider, Consumer as IntlConsumer }; Main App.jsx component: import { Provider } from "react-redux";
import { IntlProvider } from "./IntlContext";
class App extends Component {
render() {
return (
<Provider store={store}>
<IntlProvider>
...
</IntlProvider>
</Provider>
);
}
} LanguageSwitch.jsx import React from "react";
import { Text, Button } from "native-base";
import { IntlConsumer } from "../IntlContext";
const LanguageSwitch = () => (
<IntlConsumer>
{({ switchToEnglish, switchToDeutsch }) => (
<React.Fragment>
<Button onPress={switchToEnglish}>
<Text>English</Text>
</Button>
<Button onPress={switchToDeutsch}>
<Text>Deutsch</Text>
</Button>
</React.Fragment>
)}
</IntlConsumer>
);
export default LanguageSwitch; @ericf I would like to hear your thoughts. I've put the idea into the repository |
No description provided.
The text was updated successfully, but these errors were encountered: