javascript - 根据用户选择更新 React Native 语言
问题描述
我正在使用I18n创建多语言应用程序。
我创建了“首次启动”屏幕,为用户提供选择他喜欢的语言的选项,它工作正常但有问题。
一旦我选择语言,App()
组件更新,它显示登录组件(initialRouteName="Login"
)。但是默认情况下语言仍然是英语,只有当我进入另一个屏幕时它才能工作或快速刷新登录屏幕。
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.clear()
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 selectLaunched = (value) => {
setAppLaunched(value);
onSelect();
};
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);
setSelected(hasLaunched != null);
} catch (err) {
setSelected(false);
}
};
useEffect(() => verifyHasLaunched, []);
if (!selected){
return <CheckIfFirstLaunch onSelect={() => setSelected(true)} />;
}
else{
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="Login">
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Dashboard" component={Dashboard} />
</Stack.Navigator>
</NavigationContainer>
);
}
我想知道既然我已经更新了我的组件,那么语言也应该更新,不是吗?
以下是一些屏幕截图,可以直观地解释我的问题所在。
如何使用 I18n 插件根据用户选择更新 React Native 应用程序?
编辑
调试结果:
selectedLaunched(value)
- value 正确返回布尔值。
检查setAppLaunched(en)
if 语句以查看是否正确响应,它确实如此。
selected
state 也可以正常工作,并在NavigationContainer
组件设置为 true 后立即渲染组件。
解决方案
CheckIfFirstLaunch 启动屏幕也应该在 NavigationContainer 内,它在导航容器之外可能是问题的原因,您的所有屏幕都应该在 NavigationContainer 内。
对初始路由使用状态,
const [initialRoute, setRouteState] = useState('CheckIfFirstLaunch');
然后在您的条件更新状态中
if (!selected){
setRouteState('CheckIfFirstLaunch);
return <CheckIfFirstLaunch onSelect={() => setSelected(true)} />;
}
else{
setRouteState('Login');
}
然后有条件地设置你的初始路线,
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}} initialRouteName{initialRoute}">
<Stack.Screen name="CheckIfFirstLaunch" component={CheckIfFirstLaunch} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Dashboard" component={Dashboard} />
</Stack.Navigator>
</NavigationContainer>
);
您可以将其他应用程序屏幕保留在单独的堆栈中
const AppStack = createStackNavigator();
function MyAppStack() {
<APPStack.Screen name="Login" component={Login} />
<APPStack.Screen name="Register" component={Register} />
<APPStack.Screen name="Dashboard" component={Dashboard} />
}
然后主 navigationContainer 为
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}} initialRouteName="Login">
<Stack.Screen name="CheckIfFirstLaunch" component={CheckIfFirstLaunch} />
<Stack.Screen name="Login" component={MyAppStack} />
</Stack.Navigator>
</NavigationContainer>
然后最后在选择语言时将其存储到 asyncStorage 您的语言,即“en”以及您是否选择了一种语言
AsyncStorage.setItem("languageSelected",true)
并导航到登录屏幕。
除了在 App Lauch 上,如果已经选择了语言,您可以使用 Asyncstorage 而不是 isSelected 状态进行检查
const langSelected = await AsyncStorage.getItem('languageSelected');
if(langSelected) {
setInitialRoute('Login')
// check which language has been Selected
const lang = await AsyncStorage.getItem('he');
if(lang != null){
i18n.locale = "he";
I18nManager.forceRTL(true);
}
else{
i18n.locale = "en";
I18nManager.forceRTL(false);
}
} else {
setInitialRoute('CheckIfFirstScreen')
}
完整的虚拟代码
// CheckIfFirstLaunch screen component
export function CheckIfFirstLaunch(props) {
//set default language on button selection
setDefaultLanguage = (lang) => {
//set default language language
i18n.locale = lang;
//If Hebrew switch to RTL
if(lang === "he") {
I18nManager.forceRTL(true);
}
AsyncStorage.setItem("language",lang)
props.navigation.navigate("Login")
}
return (
<View>
<Text>Choose Language</Text>
<Button onPress={() => setDefaultLanguage("he")} title="Hebrew"/>
<Button onPress={() => setDefaultLanguage("en")} title="English"/>
</View>
);
}
const Stack = createStackNavigator();
export default function App() {
//intial default route set FirstLaunch Screen
const [initialAppRoute, setInitialRoute] = useState("CheckIfFirstLaunch");
// a loading state to check if react has checked for data from asyncStorage
const [dataLoaded, setDataLoaded] = useState("false");
//verify if language has been selected
const verifyHasLaunched = async () => {
try {
//get language from asyncStorage
const lang = await AsyncStorage.getItem("language");
// if language value stored in asyncStorage
if(hasLaunched) {
// if language is hebrew do this else do that
if(lang === 'he'){
i18n.locale = "he";
I18nManager.forceRTL(true);
}
else{
i18n.locale = "en";
I18nManager.forceRTL(false);
}
// set initial route to Login
setInitialRoute(initialAppRoute:'Login')
}else {
// else initial route should language screen
setInitialRoute(initialAppRoute:'CheckIfFirstLaunch')
}
} catch (err) {
// if error do something here
}
};
useEffect(() => verifyHasLaunched, []);
return (
{dataLoaded ?
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}} initialRouteName={initialAppRoute}">
<Stack.Screen name="CheckIfFirstLaunch" component={CheckIfFirstLaunch} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Dashboard" component={Dashboard} />
</Stack.Navigator>
</Stack.Navigator>
</NavigationContainer>
:
// or keep loading loader until react has checked for data from asyncStorage
null
}
);
}