动态切换语言并重新渲染 react-native 应用程序

Posted

技术标签:

【中文标题】动态切换语言并重新渲染 react-native 应用程序【英文标题】:Dynamically toggle language and re-render react-native app 【发布时间】:2021-10-01 00:28:03 【问题描述】:

我正在通过阅读一些博客并尝试在使用 Drawer(主页和关于屏幕)、堆栈(主页 -> 设置)和选项卡(主页和关于屏幕)导航的测试应用程序上复制这些概念来学习 react-native。到目前为止,一切顺利。

我正在使用 'react-native-localize'、'i18n-js' 和 'lodash.memoize' 来制作应用程序的多语言。在启动过程中,应用程序成功地从设备设置中确定了当前的区域设置,并根据区域设置显示正确的内容。

但是,我希望能够通过按设置屏幕上的切换语言按钮来动态更改它。我不知道如何更改语言环境并使整个应用程序(抽屉菜单选项名称、底部选项卡名称和所有屏幕文本内容)重新呈现和显示来自新语言环境的文本。有人可以帮帮我吗?

App.js

import * as i18n from './src/utils/i18n';

const App = () => 

  const [locale, setLocale] = useState(i18n.DEFAULT_LANGUAGE);
  const localizationContext = useMemo(
    () => (
      t: (scope, options) => i18n.t(scope, locale, ...options),
      locale,
      setLocale
    ),
    [locale],
  );

  const handleLocalizationChange = useCallback(
    (newLocale) => 
      const newSetLocale = i18n.setI18nConfig(newLocale);
      setLocale(newSetLocale);
    ,
    [locale],
  );

  useEffect(() => 
    handleLocalizationChange();

    RNLocalize.addEventListener('change', handleLocalizationChange);
    return () => 
      RNLocalize.removeEventListener('change', handleLocalizationChange);
    ;
  , []);
 
  return (
   <LocalizationContext.Provider value=localizationContext>
      <NavigationContainer>
        <DrawerNavigator localizationChange=handleLocalizationChange/>
      </NavigationContainer>
    </LocalizationContext.Provider>
  );
;

export default App;

i18n.js

import I18nManager from 'react-native';
import * as RNLocalize from 'react-native-localize';
import i18n from 'i18n-js';
import memoize from 'lodash.memoize';

export const DEFAULT_LANGUAGE = 'en';

export const translationGetters = 
  'en': () => require('../locales/en.json'),
  'es': () => require('../locales/es.json'),
;

export const translate = memoize(
  (key, config) => i18n.t(key, config),
  (key, config) => (config ? key + JSON.stringify(config) : key),
);

export const t = translate;

export const setI18nConfig = (codeLang = null) => 
  // Fallback if no available language fits
  const fallback = languageTag: DEFAULT_LANGUAGE, isRTL: false;
  const lang = codeLang ? languageTag: codeLang, isRTL: false : null;
  
  const languageTag, isRTL = lang
    ? lang
    : RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
      fallback;

  // Enables fallbacks
  i18n.fallbacks = true;

  // Clear translation cache
  translate.cache.clear();

  // Update layout direction
  I18nManager.forceRTL(isRTL);

  // Set i18n-js config
  i18n.translations = [languageTag]: translationGetters[languageTag]();
  i18n.locale = languageTag;
  
  return languageTag;
;

DrawerNavigation.js

import React,  useContext  from "react";

import  AboutStackNavigator  from "./StackNavigator";
import TabNavigator from "./TabNavigator";

import  createDrawerNavigator  from "@react-navigation/drawer";

import LocalizationContext from '../providers/LocalizationContext';

const Drawer = createDrawerNavigator();

const DrawerNavigator = () => 
  const t = useContext(LocalizationContext);
  
  return (
    <Drawer.Navigator
      drawerContentOptions=
        activeTintColor: 'gray',
        inactiveTintColor: 'gray',
      
    >
      <Drawer.Screen 
        name="Home" 
        component= TabNavigator  
        options=
          title: t('title_home')
         
      />
      <Drawer.Screen 
        name="About" 
        component= AboutStackNavigator  
        options=
          title: t('title_about')
         
      />
    </Drawer.Navigator>
  );
;

export default DrawerNavigator;

StackNavigator.js

import React,  useContext  from "react";
import  createStackNavigator  from "@react-navigation/stack";

import Home from "../screens/Home";
import About from "../screens/About";
import Settings from "../screens/Settings";

import LocalizationContext from '../providers/LocalizationContext';

const Stack = createStackNavigator();

const MainStackNavigator = () => 
  const t = useContext(LocalizationContext);
  return (
    <Stack.Navigator screenOptions=screenOptionStyle>
      <Stack.Screen name="Home" component= Home  options= headerShown:false  />
      <Stack.Screen name="About" component= About  options= title: t('title_about') />
      <Stack.Screen name="Settings" component= Settings  options= title: t('title_settings') />
    </Stack.Navigator>
  );
;

const AboutStackNavigator = () => 
  const t = useContext(LocalizationContext);
  return (
    <Stack.Navigator screenOptions=screenOptionStyle>
      <Stack.Screen name="About" component= About  options= title: t('title_about')  />
    </Stack.Navigator>
  );
;

const SettingsStackNavigator = () => 
  const t = useContext(LocalizationContext);
  return (
    <Stack.Navigator screenOptions=screenOptionStyle>
      <Stack.Screen name="Settings" component= Settings  options= title: t('title_settings')  />
    </Stack.Navigator>
  );
;

const screenOptionStyle = 
  headerStyle: 
    backgroundColor: 'white',
  ,
  headerTintColor: "gray",
  headerBackTitle: "Back",
;

export  
  MainStackNavigator, 
  AboutStackNavigator, 
  SettingsStackNavigator 
;

TabNavigator.js

import React,  useContext  from 'react';

import  createBottomTabNavigator  from '@react-navigation/bottom-tabs';

import  MainStackNavigator, AboutStackNavigator  from './StackNavigator';

import LocalizationContext from '../providers/LocalizationContext';

const Tab = createBottomTabNavigator();

const BottomTabNavigator = () => 
  const t = useContext(LocalizationContext);

  return (
    <Tab.Navigator
      tabBarOptions=
        activeTintColor: 'black',
        inactiveTintColor: 'gray',
        activeBackgroundColor: 'white',
        inactiveBackgroundColor: 'white',
        labelStyle: 
          fontSize: 12,
        ,
       >
      <Tab.Screen name="Home" component= MainStackNavigator  options= title: t('title_home')  />
      <Tab.Screen name="About" component= AboutStackNavigator  options= title: t('title_about'), headerShown:false  />
    </Tab.Navigator>
  );


export default BottomTabNavigator;

Home.js

import React,  useContext  from "react";
import  View, SafeAreaView, StyleSheet, Text, StatusBar  from "react-native";
import  Header  from 'react-native-elements';

import LocalizationContext from '../providers/LocalizationContext';

const Home = ( navigation ) => 
  const t = useContext(LocalizationContext);
  
  return (
    <SafeAreaView style=styles.container>
      <StatusBar barStyle="dark-content" backgroundColor='white' />
        <Header
          statusBarProps= barStyle: 'dark-content', backgroundColor: 'gray' 
          placement="center"
          leftComponent= icon: 'menu', color: 'white', onPress: () => navigation.openDrawer() 
          centerComponent= text: 'My App', style: styles.centerComponent 
          rightComponent= icon: 'settings', color: 'white', onPress: () => navigation.navigate("Settings") 
          containerStyle= backgroundColor: 'gray', justifyContent: 'space-around' 
        /> 
        <View style=styles.center>
          <Text>t('text_home')</Text>
        </View>
      </SafeAreaView>
  );
;

const styles = StyleSheet.create(
  center: 
    flex: 1,
    backgroundColor: 'white',
    justifyContent: "center",
    alignItems: "center",
    textAlign: "center",
  ,
  container: 
    flex: 1,
    backgroundColor: 'white',
  ,
  centerComponent: 
    color: 'white', 
    fontWeight: 'bold', 
    fontSize: 20
  ,
    
);

export default Home;

Settings.js

import React,  useContext, useState  from "react";
import  View, StyleSheet, Text, StatusBar, Button  from "react-native";

import LocalizationContext from '../providers/LocalizationContext';

const Settings = () => 
  const t = useContext(LocalizationContext);

  const [locale, setLocale] = useState('en');

  const toggleLanguage = (locale) => 
    setLocale(locale);
    console.log(locale);
  ;

  return (
    <View style=styles.center>
      <StatusBar barStyle="dark-content" backgroundColor='white' />
      <View style=styles.center>
          <Text>t('text_setings')</Text>
          <Button onPress=() => toggleLanguage(locale == "es" ? "en" : "es") title=locale == "es" ? "EN" : "ES" />
        </View>
    </View>
  );
;

const styles = StyleSheet.create(
  center: 
    flex: 1,
    backgroundColor: 'white',
    justifyContent: "center",
    alignItems: "center",
    textAlign: "center",
  ,
);

export default Settings;

【问题讨论】:

【参考方案1】:

要允许更改语言显示,您可以使用以下方法(假设您要显示英语、法语和德语):

    使用以下内容创建一个 globals.js(如果需要,添加更多项目):
module.exports = 

eunit:["Eldery Unit", "Unité des personnes âgées", "Senioreneinheit"],      
skeysearch:["Search by Name", "Recherche par nom", "Suche mit Name"],       
sstatus: ["Status", "Statut", "Status"]

;

    在您的 js 页面顶部添加以下行:
GLOBAL = require('./globals');
    在要显示不同语言的地方,使用以下命令:
GLOBAL.skeysearch[this.state.lang]
    根据您的需要更改语言状态。 (比如点击一个按钮), 所以,
this.state.lang=0 for English 
this.state.lang=1 for French
this.state.lang=2 for German

【讨论】:

以上是关于动态切换语言并重新渲染 react-native 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

React-native,动态渲染按钮点击

如何使用 redux 让根组件在 react-native 中重新渲染(开源项目)

为啥组件在状态更改后不重新渲染。在 react-native 函数组件中

第 005 期 Vue 运行时性能优化之减少渲染组件的次数

vuetab按钮切换动态数据间隙按钮位置掉低的问题

向 uitableviewcell 发送新值并重新渲染