So here is what happens with Android:
On iOS works by the well.
I saw there are some libraries out there to listen for locale changes, restart the app, etc. I think we could include a solution directly here so we have everything in one dependency.
I also tried react-native-restart and it is not actually working for me so I am working in a solution right now. It restarts the app but not the bundle. I think maybe we won't need to refresh the bundle if we can export some method to the update locale for this library?
Would you accept a PR which such functionality here?
Thanks!
Ok, I found a way to do this without the need of react-native-locale-listener and react-native-restart, will post it soon.
@ferrannp I know. I made a better lib for the react-community org: https://github.com/react-community/react-native-languages
You can listen for languages changes on Android, and use the i18n library of your choice (including i18n-js, like on this project - but also format.js, i18next, etc)
import ReactNativeLanguages from 'react-native-languages';
import I18nJs from 'i18n-js';
I18nJs.locale = ReactNativeLanguages.language;
ReactNativeLanguages.addEventListener('change', ({ language }) => {
I18nJs.locale = language;
});
OR
import ReactNativeLanguages from 'react-native-languages';
import i18next from 'i18next';
i18next.init({
lng: ReactNativeLanguages.language,
initImmediate: false,
});
ReactNativeLanguages.addEventListener('change', ({ language }) => {
i18next.changeLanguage(language);
});
Should do the trick, and is way easier.
Actually, if we need to add this functionality in this project, I will only add react-native-languages as a dependency...And I don't really like the fact that it is tied to i18n-js. I prefer work on a generic package and write more documentation for the different i18n libs (soon!)
Hey !
Thanks for your answer, I did not know about that package. So I actually wrote about this https://blog.callstack.io/react-native-handling-language-changes-on-android-the-right-way-c883056a8f5c
And I just fixed my case in the native side. Basically:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
String locale = newConfig.locale.toString();
if (!MainActivity.currentLocale.equals(locale)) {
MainActivity.currentLocale = locale;
final ReactInstanceManager instanceManager = getReactInstanceManager();
instanceManager.recreateReactContextInBackground();
}
}
Works well for me :). Not sure if we could add this to your package as optional...? Or maybe in the README?
@ferrannp If I do something like this, I will deprecate this package in favor of https://github.com/react-community/react-native-languages
Just found following post on the issue by same @ferrannp :)
Worked for me, don't forget the imports!
https://blog.callstack.io/react-native-handling-language-changes-on-android-the-right-way-c883056a8f5c
if you want to follow @ferrannp tutorial you may missed some import
So full MainActivity.java will be look like this
import com.facebook.react.ReactActivity;
import android.content.res.Configuration;
import com.facebook.react.ReactInstanceManager;
import android.os.Bundle;
public class MainActivity extends ReactActivity {
static String currentLocale;
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "ServiceNode";
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivity.currentLocale = getResources().getConfiguration().locale.toString();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
String locale = newConfig.locale.toString();
if (!MainActivity.currentLocale.equals(locale)) {
MainActivity.currentLocale = locale;
final ReactInstanceManager instanceManager = getReactInstanceManager();
instanceManager.recreateReactContextInBackground();
}
}
}
@milon87 Or just:
yarn add react-native-languages i18n-js
react-native link react-native-languages
import Languages from 'react-native-languages'
import I18n from 'i18n-js'
import en from '../locales/en'
import fr from '../locales/fr'
I18n.locale = Languages.language
I18n.fallbacks = true
I18n.translations = { en, fr }
Languages.addEventListener('change', ({ language }) => {
I18n.locale = language
})
export default I18n
100% compatible API 馃槃
EDIT: If you want to memoize the results:
import Languages from 'react-native-languages'
import I18n from 'i18n-js'
import memoize from 'lodash.memoize'
import en from '../locales/en'
import fr from '../locales/fr'
// use JS Map as memoization cache
ld.memoize.Cache = Map
I18n.locale = Languages.language
I18n.fallbacks = true
I18n.translations = { en, fr }
export const t = memoize(I18n.t)
export const l = memoize(I18n.l)
export const p = memoize(I18n.p)
Languages.addEventListener('change', ({ language }) => {
t.cache.clear()
l.cache.clear()
p.cache.clear()
I18n.locale = language
})
export default { t, l, p }
hmm... why just not use something like that in some root component?
state = {
isSettingLang: true;
}
componentWillMount() {
getLanguages().then(langs => {
I18n.locale = langs[0];
this.setState({ isSettingLang: false });
});
}
render() {
if(this.state.isSettingLang) return <SomeLoadingComponent />
return <RestApplication />
}
How about changing the language in in-app settings? Should I re-render the whole app? Cause when I navigate back, the language isn't changed because the scene doesn't re-render!!
How about changing the language in in-app settings? Should I re-render the whole app? Cause when I navigate back, the language isn't changed because the scene doesn't re-render!!
@zoontek I am facing the same issue, any suggestion?
I think, you can create a custom text component that will updating on languange change in app, and use it everywhere localization is needed. Like with redux container or any way your prefer.
Btw, native implementation mostly work with locale of device and restarting application when it changes.
If I change the language (i18n.locale) in one route of a stack, it does not change the language for already opened stacks.Someone please tell me what should i do here.
If I change the language (i18n.locale) in one route of a stack, it does not change the language for already opened stacks.Someone please tell me what should i do here.
i have the same problem, did you resolve?
I still didn't get the exact solution. But, i used react-native-restart to restart the whole app.
If I change the language (i18n.locale) in one route of a stack, it does not change the language for already opened stacks.Someone please tell me what should i do here.
I have the same problem with my app, any one can help
@melaku468 reload your top level component (a state update is enough)
@zoontek can you help me with this, how to update state ?
Here is my index.js
`import * as RNLocalize from 'react-native-localize';
import I18n from 'i18n-js';
import memoize from 'lodash.memoize';
import {I18nManager,
AsyncStorage} from 'react-native';
import en from './en';
import or from './or';
import tg from './tg';
import sl from './sl';
const locales = RNLocalize.getLocales();
if (Array.isArray(locales)) {
I18n.locale = locales[0].languageTag;
}
I18n.fallbacks = true;
I18n.translations = {
default: en,
'en-US': en,
en,
or,
tg,
sl,
};
export default I18n;
SettingScreen.js
onChangeLanguage(languageSelected){
this.setState({
languageSelected
})
I18n.locale = languageSelected
}
class DropdownLanguage extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
iosHeader={''}
style={{ width: width,
}}
selectedValue={this.props.language}
onValueChange={this.props.onChangeLanguage.bind(this)}
>
{listLanguage.map((languageItem, i) => {
return
})}
) }}`
Most helpful comment
@milon87 Or just:
100% compatible API 馃槃
EDIT: If you want to memoize the results: