Home > Net >  How to create a sort of Context Template for different parents components in react native?
How to create a sort of Context Template for different parents components in react native?

Time:10-15

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

  • Related