Code Monkey home page Code Monkey logo

i18next-example-typescript's Introduction

i18next-example-typescript

In this example we are going to start form a simple login application and add multilanguage support.

Scenarios that we are going to cover:

  • Translate markup text.
  • Translate text generated by javascript.
  • User interpolation.

More samples coming soon:

  • Split language resources in json files.
  • Use namespaces.

In the future we will incorporate more samples.

About folder structure:

  • 00_start: Starting point (no multilanguage).

  • 01_basic_translastion: application supporting mulilanguage (english / spanish).

  • 02_change_language: added tu buttons to change the preffered language on the fly.

Each project (except 00 start) includes in its subfolder a Readme.md file with an step by step guide to reproduce it.

Additional resources:

Official React Guide: https://react.i18next.com/guides/quick-start.

Steps

  • Let's start by installing the react-i18next library.
npm install react-i18next i18next --save
  • Create a new file i18n.js containing the following content.

./src/i18n.ts

import i18n from "i18next";
import { initReactI18next } from "react-i18next";

// the translations
// (tip move them in a JSON file and import them)
const resources = {
  en: {
    translation: {
      login: "Login",
      "Invalid login or password, please type again":
        "Invalid login or password, please type again",
      "error, review the fields": "error, review the fields"
    }
  },
  es: {
    translation: {
      login: "Introduzca credenciales",
      "Invalid login or password, please type again":
        "Usuario o clave no validos, porfavor intentelo de nuevo",
      "error, review the fields": "Error, revise los campos por favor"
    }
  }
};

i18n
  .use(initReactI18next) // passes i18n down to react-i18next
  .init({
    resources,
    lng: "en",

    keySeparator: false, // we do not use keys in form messages.welcome

    interpolation: {
      escapeValue: false // react already safes from xss
    }
  });

export default i18n;

The interesting part here is by i18n.use(initReactI18next) we pass the i18n instance to react-i18next which will make it available for all the components via the context api.

Now let's import this fail in our main.tsx

./src/main.tsx

import * as React from "react";
import { withStyles, createStyles, WithStyles } from "@material-ui/core/styles";
+ import './i18n';
  • Let's start translating the heading of the login panel, to do that we will make use of a hook that i18n provides.

./src/pages/login/loginPage.tsx

// (...)
+ import { useTranslation } from 'react-i18next';

// (...)

const LoginPageInner = (props: Props) => {
+  const { t, i18n } = useTranslation();
  const { loginInfo, setLoginInfo } = useLogin();

// (...)

  return (
    <>
      <Card className={classes.card}>
-        <CardHeader title="Login" />
+        <CardHeader title={t('login')} />

        <CardContent>
          <LoginForm
            onLogin={onLogin}
            onUpdateField={onUpdateLoginField}
            loginInfo={loginInfo}
            loginFormErrors={loginFormErrors}
          />
        </CardContent>
      </Card>
      <NotificationComponent
-        message="Invalid login or password, please type again"
+        message={t('Invalid login or password, please type again')}
        show={showLoginFailedMessage}
        onClose={() => setShowLoginFailedMessage(false)}
      />
    </>
  );
};

If you are using class based components react i18next exposes an HOC for you to get access to t.

  • So far so good, let's check now how can we add multilanguage support to a literal that is injected via javascript.

./src/pages/login/loginPage.tsx

  const onLogin = () => {
    loginFormValidation.validateForm(loginInfo).then(formValidationResult => {
      if (formValidationResult.succeeded) {
        if (isValidLogin(loginInfo)) {
          loginContext.updateLogin(loginInfo.login);
          props.history.push("/pageB");
        } else {
          setShowLoginFailedMessage(true);
        }
      } else {
-        alert("error, review the fields");
+         alert(t("error, review the fields");
      }
    });
  };

That was nice, let's give a try now to interpolation, in pageB we are showing a message like:

<h3>Login: {props.login}</h3>

We don't need to concatenate translated strings, we can directly include the variables in the string.

  • Let's define the entry in the our root i18next.ts file.

./src/i18n.ts

const resources = {
  en: {
    translation: {
      login: "Login",
      "Invalid login or password, please type again":
        "Invalid login or password, please type again",
      "error, review the fields": "error, review the fields rrr",
+           "login plus username": "Usuario: {{username}}"

    }
  },
  es: {
    translation: {
      login: "Introduzca credenciales",
      "Invalid login or password, please type again":
        "Usuario o clave no validos, porfavor intentelo de nuevo",
      "error, review the fields": "Error, revise los campos por favor",
+     "login plus username": "Usuario: {username}",
    }
  }
};

To reach this page you have to enter as valid username and password keys admin and test

  • Let's use this on the pageB

./src/pages/b/pageB.tsx

import * as React from "react"
import { Link } from 'react-router-dom';
import { SessionContext, withSessionContext } from '../../common/'
+ import { useTranslation } from 'react-i18next';


interface Props {
  login : string;
}

- const PageBInner = (props : Props) =>
+ const PageBInner = (props : Props) => {
+   const { t, i18n } = useTranslation();
+   return (
    <>
      <h2>Hello from page B</h2>
      <br />
      <br />
-      <h3>Login: {props.login}</h3>
+      <h3>t({login plus username}, {username: props.login})</h3>
    <Link to="/">Navigate to Login</Link>
   </>
+ )
+ }

export const PageB = withSessionContext(PageBInner);
  • To wrap up this example let's translate the inline validation that appear below each input field.

  • In the loginForm on each textFieldForm we are informing a friendly error message, instead of using that, let's use the type of the validation error.

./src/pages/login/loginForm.tsx

      <TextFieldForm
        label="Name"
        name="login"
        value={loginInfo.login}
        onChange={onUpdateField}
-        error={loginFormErrors.login.errorMessage}
+        loginFormErrors.login.succeeded ? "" : loginFormErrors.login.type
      />
      <TextFieldForm
        label="Password"
        name="password"
        value={loginInfo.password}
        onChange={onUpdateField}
-        error={loginFormErrors.password.errorMessage}
+        error={loginFormErrors.password.succeeded ? "" : loginFormErrors.password.type}
      />
  • Now if we run the application we will see just the type of the error being shown (not very friendly).
npm start
  • Let's add translation keys for that validation errors.

./src/i18n.ts

const resources = {
  en: {
    translation: {
      login: "Login",
      "Invalid login or password, please type again":
        "Invalid login or password, please type again",
      "error, review the fields": "error, review the fields rrr",
      "login plus username": "Usuario: {{username}}",
+      "REQUIRED": "Mandatory field",
    }
  },
  es: {
    translation: {
      login: "Introduzca credenciales",
      "Invalid login or password, please type again":
        "Usuario o clave no validos, porfavor intentelo de nuevo",
      "error, review the fields": "Error, revise los campos por favor",
      "login plus username": "Usuario: {{username}}"
+      "REQUIRED": "Campo obligatorio",
    }
  }
};
  • Let's add i18n translator helper to loginForm, and properly translate the text.

./src/pages/login/loginForm.tsx

+ import { useTranslation } from "react-i18next";

export const LoginForm = (props: Props) => {
+  const { t, i18n } = useTranslation();
  const { onLogin, onUpdateField, loginInfo, loginFormErrors } = props;

// (...)

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        justifyContent: "center"
      }}
    >
      <TextFieldForm
        label="Name"
        name="login"
        value={loginInfo.login}
        onChange={onUpdateField}
        error={
-          loginFormErrors.login.succeeded ? "" : loginFormErrors.login.type
+          loginFormErrors.login.succeeded ? "" : t(loginFormErrors.login.type)

        }
      />
      <TextFieldForm
        label="Password"
        name="password"
        value={loginInfo.password}
        onChange={onUpdateField}
        error={
          loginFormErrors.password.succeeded
            ? ""
-            : loginFormErrors.password.type
+            : t(loginFormErrors.password.type)
        }
      />

Excercise: Could you add multilanguage support to the login button?

i18next-example-typescript's People

Contributors

brauliodiez avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.