I wanted to Internationalize my react native app only using redux, but for the sake of brevity I'm going to elude the part relative to redux since the whole app is working perfectly fine. for each screen component of the app, I create a context to wrap the screen component and pass down all the strings related to the screen
So i created the context in a separate file that I'm exporting as Language:
import React, { useContext, createContext } from "react";
import { useSelector } from "react-redux";
import { getTranslation } from "../../../redux/reducers/translation/selector/selector";
import {language} from "./Util";
export const Context = createContext();
export const useLanguageContext = () => {
return useContext(Context);
};
export default function Language({ children }) {
const translation = useSelector(getTranslation);
const lang = language(translation.lang);
return <Context.Provider value={lang}>{children}</Context.Provider>;
}
translation.lang
is the current language grabbed from redux that I pass to the language
function to get the strings related to the screen accordingly. in this case it's going to be the Entrance screen. Here is the logic for the language
function:
import french from "../../../i18n/french/auth/entrance/i18n";
import english from "../../../i18n/english/auth/entrance/i18n";
import spanish from "../../../i18n/spanish/auth/entrance/i18n";
import wolof from "../../../i18n/wolof/auth/entrance/i18n";
export const language = (translation) => {
switch (translation) {
case "french":
return french;
case "english":
return english;
case "spanish":
return spanish;
case "wolof":
return wolof;
default:
return french;
}
};
and I wrap the Entrance screen with the context like this
import React from "react";
import { View } from "react-native";
import { Slider, Button } from "../../../components/organisms/auth/Entrance";
import Language from "../../../utils/language/context";
import { styles } from "./Style";
export default function Entrance() {
return (
<Language>
<View style={styles.container}>
<Slider />
<Button />
</View>
</Language>
);
}
And finally, from a child component like Button, I can retrieve the language object passed through like this
import React from "react";
import { Text, TouchableOpacity } from "react-native";
import { useNavigation } from "@react-navigation/native";
import { useLanguageContext } from "../../../../../../utils/language/context";
import { styles } from "./Style";
export default function Button() {
const lang = useLanguageContext();
const navigation = useNavigation();
return (
<TouchableOpacity
style={styles.container}
onPress={() => {
navigation.navigate("LoginNavigator");
}}
>
<Text style={styles.text}>{lang.login}</Text>
</TouchableOpacity>
);
}
Now all of this is working perfectly fine but the main problem is I'm going to have a lot of screens and don't want to be repeating this process of creating a context for each and every screen. Isn't there a neater way to create a sort of Context template that I can use for the different screens instead of creating one for each screen?
CodePudding user response:
If the purpose of this implementation is to separate the translations for each screen, then you could pass a property to the context provider that works on only grabbing the translations for the screen you want.
A cool tip that makes it easier to import the languages instead of importing each one individually is to create an index file that exports it from one entry, for example:
Instead of having
import french from "../../../i18n/french/auth/entrance/i18n";
import english from "../../../i18n/english/auth/entrance/i18n";
import spanish from "../../../i18n/spanish/auth/entrance/i18n";
import wolof from "../../../i18n/wolof/auth/entrance/i18n";
Create an index file inside ../../../i18n/french/auth
that exports the translations for a specific screen like so
export * as entrance from "./entrance/i18n"
export * as login from "./login/i18n"
// etc
Then, from each language folder, an index file to export the related translations from one place
export * from "./auth"
export * from "./home"
// etc
That way it can be accessed like so, where the screen is the name of the screen to grab the translations for, and the translation is the language
import french from "../../../i18n/french"
// other languages
export const language = (screen, translation) => {
switch (translation) {
case "french":
return french[screen];
// other languages
default:
return french[screen];
}
};
Hope you find this helpful!
CodePudding user response:
I try something quite simple and didn't expect it to work
Now in the Context file, I'm passing the language
function as a props to each screen the Context will wrap
import React, { useContext, createContext } from "react";
import { useSelector } from "react-redux";
import { getTranslation } from "../../../redux/reducers/translation/selector/selector";
export const Context = createContext();
export const useLanguageContext = () => {
return useContext(Context);
};
export default function Language({ children, language }) {
const translation = useSelector(getTranslation);
const lang = language(translation.lang);
return <Context.Provider value={lang}>{children}</Context.Provider>;
}
and then inside each Screen, I'll import the language function and wrap it with the Context like this:
import React from "react";
import { View } from "react-native";
import { Slider, Buttons } from "../../../components/organisms/auth/Entrance";
import Language from "../../../utils/language/context";
import { styles } from "./Style";
import { language } from "./Utils";
export default function Entrance() {
return (
<Language language={language}>
<View style={styles.container}>
<Slider />
<Buttons />
</View>
</Language>
);
}
And it worked. @Ibrahim thanks for your answer i'll try to structure the translations folder as you mentioned