[英]Updating React Native language by user choice
我正在使用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 正確返回 boolean 值。
檢查setAppLaunched(en)
if 語句以查看是否正確響應,它確實如此。
selected
的 state 也可以正常工作,並在NavigationContainer
組件設置為 true 后立即呈現。
CheckIfFirstLaunch 啟動屏幕也應該在 NavigationContainer 內,它在導航容器之外可能是問題的原因,您的所有屏幕都應該在 NavigationContainer 內。
使用 state 進行初始路由,
const [initialRoute, setRouteState] = useState('CheckIfFirstLaunch');
然后在你的條件內更新 state
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>
<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 state 進行檢查
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
}
);
}
正如我所看到的,初始路由是登錄,因此默認情況下它會以英文呈現。 首次啟動時選擇語言的彈出窗口會呈現在登錄屏幕本身上。 因此,一旦您 select 使用不同的語言,它就會更新該語言,但組件不會重新呈現,因為沒有 state 更新。 這就是語言在導航到其他屏幕或快速重新加載時更新的原因。 可以實施兩種解決方案:-
問題是嘗試使用async
函數和使用await
更改語言,這導致語言僅在第二個屏幕后更改。 所以在那種情況下,我只是將語言切換向后移動了一步。
我將其移至const selectLaunched = (value) =>
async function setAppLaunched(en)
const selectLaunched = (value) => {
if(!value){
i18n.locale = "he";
I18nManager.forceRTL(true);
}
else{
i18n.locale = "en";
I18nManager.forceRTL(false);
}
setAppLaunched(value);
onSelect();
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.