动态切换语言并重新渲染 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 应用程序的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 redux 让根组件在 react-native 中重新渲染(开源项目)