简体   繁体   English

React Native & i18n 在路由到另一个屏幕后返回默认语言

[英]React Native & i18n returns to default language after routing to another screen

I'm using React Native with i18n language manager, and I'm trying to create language choice on first app launch.我正在将 React Native 与 i18n 语言管理器一起使用,并且我正在尝试在首次应用启动时创建语言选择。

首屏启动

The language selection screen does work, after choosing language the component re-renders and execute the correct language.语言选择屏幕确实有效,在选择语言后组件重新渲染并执行正确的语言。 (Assuming I selected English, the buttons string is in English) (假设我选择了英文,按钮字符串是英文的)

重新渲染

But after signing in to the app the language changes, and I can't really understand why.但是登录到应用程序后,语言发生了变化,我真的不明白为什么。 (Here suppose to be in English, instead displays the Hebrew string) (这里假设是英文,而是显示希伯来语字符串)

在此处输入图像描述

Here is App.js file, I have used Async Storage to check if the app has launched before (If didn't show language selection, if did use the saved language choice).这是 App.js 文件,我使用Async Storage检查该应用程序之前是否已启动(如果没有显示语言选择,是否使用了保存的语言选择)。

import React, {useEffect, useState} from "react";
import Login from "./login.js";
import Register from "./register.js";
import Dashboard from "./dashboard.js";
import i18n from "./translation.js";
import { NavigationContainer, useNavigation } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { Text, View, Button, I18nManager } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";



const Stack = createStackNavigator();
const HAS_LAUNCHED = "hasLaunched";
const ENGLISH = "en";
const HEBREW = "he";


//Save the language as AsyncStorage for other times the user will open the app
async function setAppLaunched(en) {
  AsyncStorage.setItem(HAS_LAUNCHED, "true");
  AsyncStorage.setItem(en ? ENGLISH : HEBREW, "true");
  if(await AsyncStorage.getItem(HEBREW)){
    i18n.locale = "he";
    I18nManager.forceRTL(true);
  }
  else{
    i18n.locale = "en";
    I18nManager.forceRTL(false);
  }
}


//If first launch show this screen
function CheckIfFirstLaunch({ onSelect }) {
  const navigation = useNavigation();

  const selectLaunched = (value) => {
    if(value){
      i18n.locale = "en";
      I18nManager.forceRTL(false);
    }
    else{
      i18n.locale = "he";
      I18nManager.forceRTL(true);
    }
    setAppLaunched(value);
    onSelect();
    navigation.navigate('Login');
  };


  return (
    <View>
        <Text>Choose Language</Text>
        <Button onPress={() => selectLaunched(false)} title="Hebrew"/>
        <Button onPress={() => selectLaunched(true)} title="English"/>
    </View>
  );
}

export default function App() {
  const [selected, setSelected] = useState(false);
  const verifyHasLaunched = async () => {
    try {
      const hasLaunched = await AsyncStorage.getItem(HAS_LAUNCHED);
      console.log(await AsyncStorage.getItem(HAS_LAUNCHED));
      if(hasLaunched){
        setSelected(true);
      }
      else{
        setSelected(false);
      }
    } catch (err) {
      setSelected(false);
    }
  };

  useEffect(() => verifyHasLaunched, []);


  if(selected){
    const verifyLang = async () => {
      const lang = await AsyncStorage.getItem('he');
      if(lang != null){
        i18n.locale = "he";
        I18nManager.forceRTL(true);
      }
      else{
        i18n.locale = "en";
        I18nManager.forceRTL(false);
      }
   };
   () => verifyLang;
  }

  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{headerShown: false}} initialRouteName={selected ? "Login" : "Language"}>
        <Stack.Screen name="Language" >
          {props => (<CheckIfFirstLaunch {...props} onSelect={() => setSelected(true)} />)}
        </Stack.Screen>
        <Stack.Screen name="Login" component={Login} />
        <Stack.Screen name="Register" component={Register} />
        <Stack.Screen name="Dashboard" component={Dashboard} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

translation.js翻译.js

import i18n from 'i18n-js';
import en from './locale/en.json';
import he from './locale/he.json';

i18n.defaultLocale = 'en';
i18n.fallbacks = true;
i18n.translations = { en, he };


export default i18n;

I have debugged the values from AsyncStorage and received the correct values.我已经调试了AsyncStorage中的值并收到了正确的值。

As it seems, the Async Storage saves the language data for the re-render of App.js file, but the I18n reset his settings after screen routing.看起来, Async Storage保存了重新渲染App.js文件的语言数据,但 I18n 在屏幕路由后重置了他的设置。 Why is that?这是为什么?

How to set language for the entire app on first app launch using React Native?如何在第一次使用 React Native 启动应用程序时为整个应用程序设置语言?

Codesandbox 代码沙盒

I've forked your sandbox https://codesandbox.io/s/xenodochial-mclean-ctk5p?file=/src/App.js我已经分叉了你的沙箱https://codesandbox.io/s/xenodochial-mclean-ctk5p?file=/src/App.js

There are several changes.有几个变化。

The problem came from the fact that each time you selected a language you were setting it as a key in the storage.问题来自这样一个事实,即每次您选择一种语言时,您都将其设置为存储中的键。

Once you've selected English, reloaded and selected Hebrew you get both keys in the storage like this一旦您选择了英语,重新加载并选择了希伯来语,您就可以像这样在存储中获得两个键

{'he': true, 'en': true}

At this point this part always sets the lang to Hebrew cause indeed there is such key ('he' is true).在这一点上,这部分总是将 lang 设置为希伯来语,因为确实有这样的键(“他”是真的)。

 const verifyLang = async () => {
      const lang = await AsyncStorage.getItem('he');
      if(lang != null){
        i18n.locale = "he";
        I18nManager.forceRTL(true);
       }

What I changed is that we no longer set each language as a key.我改变的是我们不再将每种语言都设置为键。 Instead we pass down through selectLaunched the languge itself.相反,我们通过selectLaunched传递语言本身。 Then we save it in a lang key in the storage.然后我们将它保存在存储中的lang键中。 This way the lang key always has the correct language stored - 'he' or 'en'.这样, lang键始终存储正确的语言 - 'he' 或 'en'。

The verifyLang can be removed as it's no longer needed. verifyLang可以删除,因为它不再需要。 Hope this resolves your issue.希望这能解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM