#Using i18next with SolidJS (Language Switcher)

15 messages · Page 1 of 1 (latest)

humble venture
#

Hello everyone! I'm new to SolidJS (but worked with React/Next before) and I wanted to implement i18next in a very basic app that I have that shows weather data.

The main thing is **I don't want to use any third-party i18n libraries for SolidJS (like solid-i18next etc) but want to use just the plain old i18next **(https://www.i18next.com/).

Normal translations are implemented but now I want to add a LanguageSwitcher component that can toggle between the en and the es locale. Here's my current code:

// LanguageSwitcher.jsx

import i18next from "i18next";

const LanguageSwitcher = () => {
  function handleLanguageChange(event) {
    i18next.changeLanguage(event.target.value);
  }

  return (
    <div>
      <label htmlFor="language-switcher">
        <select id="language-switcher" onChange={handleLanguageChange}>
          <option value="en">{i18next.t("english_label")}</option>
          <option value="es">{i18next.t("spanish_label")}</option>
        </select>
      </label>
    </div>
  );
};

export default LanguageSwitcher;

And here's my i18next config in App.js:

// App.jsx

createEffect(() => {
    i18next
      .use(Backend)
      .init({
        lng: "en",
        debug: true,
        interpolation: {
          escapeValue: false,
        },
        fallbackLng: false,
        ns: "translations",
        backend: {
          loadPath: "./../locales/{{lng}}/{{ns}}.json",
        },
      })
      .then(() => setIsReady(true))
      .catch((err) => console.error(err));
  });

When I choose a different locale like es, i18next does work and logs this to console:

i18next: languageChanged es

But the issue is that I don't see it reflected on the UI. I know this issue is related to SolidJS state changes but I wasn’t able to get how to make it work. Please let me know 😄

vale reef
#

You could do something like this I think. You need a signal in there somewhere so it knows to update.

const LanguageSwitcher = () => {
  const [t, setTranslator] = createSignal(i18next.t);

  function handleLanguageChange(event: any) {
    setTranslator(() => i18next.getFixedT(event.target.value, null));
  }

  const translate = (label: string) => {
    const translator = t();
    return translator(label);
  };

  return (
    <div>
      <label htmlFor="language-switcher">
        <select id="language-switcher" onChange={handleLanguageChange}>
          <option value="en">{translate("english_label")}</option>
          <option value="es">{translate("spanish_label")}</option>
        </select>
      </label>
    </div>
  );
};
humble venture
vale reef
#

Is that not just missing translations?

humble venture
#

Well somehow yes that's the case.

But the translations are already loading before we try to invoke handleLanguageChange as it says in console:

loaded namespace translations for language en

And we also see it on the dropdown label. But when we change language, it stops fetching the translations...

vale reef
#

Ah, when I was playing around I wasn't loading languages dynamically, I'm guessing you just still need to use changeLanguage. But then use the callback to update the signal.

Maybe something like:

  i18next.changeLanguage(event.target.value, (err, t) => {
    if (err) return console.log('something went wrong loading', err);
    setTranslator(() => t);
  });
}```
#

The docs aren't very clear if the "t" in the callback works the same as getFixedT but if not you could call getFixedT instead

humble venture
#

Hmm so what I see is that when I use this:

function handleLanguageChange(event) {
    i18next.changeLanguage(event.target.value, (err, t) => {
      if (err) return console.log("something went wrong loading", err);
      setTranslator(() => t);
    });
  }

Then it does load the translations on the dropdown. It works the same as this what I had before (without a signal):

function handleLanguageChange(event) {
    i18next.changeLanguage(event.target.value);
}

But the thing is the translation is not happening at app-level! The other component like the heading etc dont' change. For example when I switch to Spanish, the heading should change from "SolidJS Weather App" to "Aplicación meteorológica SolidJS" and same with the form label/button.

vale reef
#

Yeah, you'll need to use a context provider or something to pass the translation function around to all parts of your app

humble venture
#

Is there something we need to do like having a I18nextProvider or something? Or like a custom hook like useI18next?

vale reef
#

Although one of the nice things about Solid.js is that state can just be global. I'd definitely be tempted in this case to just make a global signal and not bother with the context API at all.

#

Although not if you're using SSR

humble venture
#

Hey @vale reef! Just resumed this project...

By "global signal" you mean we can use Stores? Like this Stores without Context? https://www.solidjs.com/tutorial/stores_nocontext

Let me know I'm very new to this so was seeking help on how to work by passing i18n throughout the app....

vale reef
#

Yeah that’s what I was thinking of