Search code examples
javascriptreactjsinternationalizationlinguijs

Language Switcher with Lingui (i18n), I want the language chosen to stay throughout the app even when refreshed


I am trying out Lingui for the i18n of an app. I created a language switcher based on the documentation and tutorial, but I wanted to know how should I set it up so that each time I choose a language in the app it stays throughout the app even when refreshed.

At the moment I can switch it and change pages but everytime I refresh it goes back to English.

here are my files:

index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import { I18nProvider } from "@lingui/react";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

async function loadMessages(language) {
    return await import(`@lingui/loader!./locales/${language}/messages.json`);
}

const LocalizedApp = () => {
    const [catalogs, setCatalogs] = useState({});
    const [language, setLanguage] = useState("");

    async function handleLanguageChange(language) {
        const newCatalog = await loadMessages(language);

        const newCatalogs = { ...catalogs, [language]: newCatalog };

        setCatalogs(newCatalogs);
        setLanguage(language);
    }

    return (
        <BrowserRouter>
            <I18nProvider language={language} catalogs={catalogs}>
                <App
                    language={language}
                    onLanguageChange={handleLanguageChange}
                />
            </I18nProvider>
        </BrowserRouter>
    );
};

ReactDOM.render(<LocalizedApp />, document.getElementById("root"));

App.js

import React from "react";
import "./styles/App.css";
import { Switch, Route } from "react-router-dom";
import { Trans } from "@lingui/macro";
import Home from "./Home.js";
import About from "./About.js";
import Contact from "./Contact.js";
import Navigation from "./Navigation.js";
import LanguageSelector from "./LanguageSelector";

const Main = () => (
    <Switch>
        <Route exact path="/" component={Home}></Route>
        <Route exact path="/about" component={About}></Route>
        <Route exact path="/contact" component={Contact}></Route>
    </Switch>
);

const App = ({ language, onLanguageChange }) => {
    return (
        <div className="App">
            <Trans id="navigation.title">
                <h1 style={{ margin: 26 }}>Playground</h1>
            </Trans>
            <Navigation />
            <header className="App-header">
                <Main />
                <LanguageSelector
                    language={language}
                    onChangeLangage={onLanguageChange}
                />
            </header>
        </div>
    );
};

export default App;

languageSelector.js

import React from "react";

const LanguageSelector = ({ language, onChangeLangage }) => {
    const handleChange = (event) => {
        event.preventDefault();

        onChangeLangage(event.target.value);
    };

    return (
        <div className="select">
            <select onChange={handleChange} value={language}>
                <option value="en">English</option>
                <option value="fr">Français</option>
                <option value="es">Español</option>
            </select>
        </div>
    );
};

export default LanguageSelector;

Solution

  • You could store your language on localStorage. LocalStorage API allows you to persist your language upon multiple page refreshes. It is the browser way of persisting values.

    Since localStorage stores as key:value pair. You could store your language value with a key and use the same key to retrieve the value.

    const LANGUAGE_KEY = 'language';
    
    const LocalizedApp = () => {
        const [catalogs, setCatalogs] = useState({});
        const [language, setLanguage] = useState("");
    
        async function handleLanguageChange(language) {
            const newCatalog = await loadMessages(language);
    
            const newCatalogs = { ...catalogs, [language]: newCatalog };
    
    
            localStorage.setItem(LANGUAGE_KEY, language);
            setCatalogs(newCatalogs);
            setLanguage(language);
        }
    
        React.useEffect(() => {
          const persistedLanguage = localStorage.getItem(LANGUAGE_KEY)
          if (language !== persistedLanguage) {
            setLanguage(persistedLanguage);
          }
        }, [])
    
        return (
            <BrowserRouter>
                <I18nProvider language={language} catalogs={catalogs}>
                    <App
                        language={language}
                        onLanguageChange={handleLanguageChange}
                    />
                </I18nProvider>
            </BrowserRouter>
        );
    };