Categories
React

react-i18next NPM Package — Translation Component

If we want to add localization to a React app, we can use the react-i18next NPM package to do it.

In this article, we’ll look at how to use the Translation component to render our translations.

Translation (render prop)

The Translation component lets us pass in a function as the render prop to render the translations.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Translation>
        {(t, { i18n }) => <p>{t("Welcome to React")}</p>}
      </Translation>
    </div>
  );
}

to render the translation.

We also have access to the i18n object to let us do things like changing the language:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  },
  fr: {
    translation: {
      "Welcome to React": "Bienvenue dans React et react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Translation>
        {(t, { i18n }) => (
          <p>{i18n.changeLanguage("fr") && t("Welcome to React")}</p>
        )}
      </Translation>
    </div>
  );
}

We change the language on the fly and also render the translation afterward.

Loading Namespaces

We can load namespaces with the ns prop.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation } from "react-i18next";

const resources = {
  en: {
    ns1: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Translation ns="ns1">
        {(t) => <p>{t("Welcome to React")}</p>}
      </Translation>
    </div>
  );
}

We have the ns1 namespace.

And we set the ns prop to 'ns1' so that we can load the translations from there.

We can also pass in an array as the value of ns :

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation } from "react-i18next";

const resources = {
  en: {
    ns1: {
      "Welcome to React": "Welcome to React and react-i18next"
    },
    ns2: {
      Hello: "Hello World"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Translation ns={["ns1", "ns2"]}>
        {(t) => <p>{t("ns2:Hello")}</p>}
      </Translation>
    </div>
  );
}

We load 2 namespaces, and we add the namespace name before the translation key so that the translation will be found.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Translation i18n={i18n}>
        {(t) => <p>{t("Welcome to React")}</p>}
      </Translation>
    </div>
  );
}

We set the i18n prop to the i18n instance we want.

Conclusion

We can use the Translation component from the react-i18next NPM package to load the translations.

Categories
React

react-i18next NPM Package— Loading Translations

If we want to add localization to a React app, we can use the react-i18next NPM package to do it.

In this article, we’ll look at how to load translations.

Loading Namespaces

We can load namespaces with the useTranslation hook.

For instance, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, useTranslation } from "react-i18next";

const resources = {
  en: {
    ns1: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  const { t } = useTranslation("ns1");

  return (
    <div className="App">
      <p>{t("Welcome to React")}</p>
    </div>
  );
}

We load the 'ns1' namespace by passing it in as the argument of the useTranslation hook.

Also, we can pass in multiple namespaces.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, useTranslation } from "react-i18next";

const resources = {
  en: {
    ns1: {
      "Welcome to React": "Welcome to React and react-i18next"
    },
    ns2: {
      Hello: "Hello World"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  const { t } = useTranslation(["ns1", "ns2"]);

  return (
    <div className="App">
      <p>{t("Welcome to React")}</p>
      <p>{t("ns2:Hello")}</p>
    </div>
  );
}

to load both the ns1 and ns2 namespaces.

Any namespace other than the first needs to be prefixed with the namespace name.

Overriding the i18next Instance

We can override the i18next instance with the i18n option.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, useTranslation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  const { t } = useTranslation(undefined, { i18n });

  return (
    <div className="App">
      <p>{t("Welcome to React")}</p>
    </div>
  );
}

We just pass it into the i18n property.

Not using Suspense

We can also disable using the Suspense component for loading translations dynamically.

For example, we can write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, useTranslation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  const { t, i18n, ready } = useTranslation(undefined, { useSuspense: false });

  return (
    <div className="App">
      <p>{ready && t("Welcome to React")}</p>
    </div>
  );
}

to disable using the Suspense component.

If we do that, then we have to check the ready state ourselves as we did with the translation above.

Conclusion

We can pass various arguments into the useTranslation hook to adjust how translations are loaded with the react-i18next NPM package.

Categories
React

Getting Started with Internationalization for React Apps with the react-i18next NPM Package

If we want to add localization to a React app, we can use the react-i18next NPM package to do it.

In this article, we’ll look at how to add the package and add some translations to our apps.

Installation

To install the required packages, we run:

npm install react-i18next i18next --save

i18next provides the translation functionality and react-i18next is the React wrapper for it.

Adding Translations

Once we installed the packages, we have to initialize the library with some configuration and add some translations.

To do that, we write:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",

  keySeparator: false,

  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  return (
    <div className="App">
      <Translation>{(t) => <h1>{t("Welcome to React")}</h1>}</Translation>
    </div>
  );
}

We have the resources object with the translations.

Then we call i18n.use to initialize the react-i18next package.

keySeparator indicates whether we want to add a key separator character.

interpolation lets us change interpolation settings.

escapeValue set to false means we don’t want to escape the input.

lng sets the language.

resources has the translations.

Once we configured it, we can use the Translation component to add our translation.

We just pass in the key for the translation into the object.

Also, we can use the hook to add translations:

import React from "react";
import i18n from "i18next";
import { initReactI18next, Translation, useTranslation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",

  keySeparator: false,

  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  const { t } = useTranslation();

  return (
    <div className="App">
      <h1>{t("Welcome to React")}</h1>
    </div>
  );
}

The t function returns the translated string in both examples.

useTranslation Hook

The useTranslation hook lets us get translations and set the language.

For example, we can write:

import React, { useEffect } from "react";
import i18n from "i18next";
import { initReactI18next, useTranslation } from "react-i18next";

const resources = {
  en: {
    translation: {
      "Welcome to React": "Welcome to React and react-i18next"
    }
  },
  fr: {
    translation: {
      "Welcome to React": "Bienvenue dans React et react-i18next"
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  lng: "en",
  keySeparator: false,
  interpolation: {
    escapeValue: false
  }
});

export default function App() {
  const { t, i18n } = useTranslation();
  useEffect(() => {
    i18n.changeLanguage("fr");
  }, []);

  return (
    <div className="App">
      <p>{t("Welcome to React")}</p>
    </div>
  );
}

We called the changeLanguage method to change the language to French.

So we’ll see the translations displayed.

Conclusion

We can add translations easily to a React app with the react-i18next NPM package.

Categories
JavaScript

Compress Images Before Uploading to a Server with the Compress.js Library

To save time uploading our images, we can compress them before uploading them.

We can do that easily with the Compress.js library.

In this article, we’ll look at how to use the Compress.js library to compress images before uploading.

Installation

The Compress.js library is available as a Node package.

This library is used on the client-side.

To install it, we run:

npm install compress.js --save

Compress Images

We can compress images easily whenever we select an image file.

To do that, we write:

<div>
  <input type='file' id='upload' />
</div>

Then write:

const Compress = require("compress.js");
const compress = new Compress();

compress
  .attach("#upload", {
    size: 4,
    quality: 0.75
  })
  .then((data) => {
    console.log(data);
  });

to watch the file input with ID upload for changes and compress the image that’s selected.

Then data parameter has an array of compressed images.

We can also select multiple images and compress them all at the same time.

For example, we can write:

<div>
  <input type='file' id='upload' multiple />
</div>

Then we write:

const Compress = require("compress.js");
const compress = new Compress();

compress
  .attach("#upload", {
    size: 4,
    quality: 0.75
  })
  .then((data) => {
    console.log(data);
  });

We can also add more configuration by writing:

const upload = document.getElementById("upload");
upload.addEventListener(
  "change",
  function (evt) {
    const files = [...evt.target.files];
    compress
      .compress(files, {
        size: 4,
        quality: 0.75,
        maxWidth: 1920,
        maxHeight: 1920,
        resize: true
      })
      .then((data) => {
        console.log(data);
      });
  },
  false
);

We listen to file input changes with the addEventListener method.

The size is the max size of the file in MB.

quality is the quality of the image with the max being 1.

maxWidth is the max-width of the output image.

maxHeight is the max height of the output image.

resize indicates whether we resize the image or not.

false in the 3rd argument disables capture mode.

File Upload

To do the file upload, we can use the fetch function by writing:

const upload = document.getElementById("upload");
upload.addEventListener(
  "change",
  function (evt) {
    const files = [...evt.target.files];
    compress
      .compress(files, {
        size: 4,
        quality: 0.75,
        maxWidth: 1920,
        maxHeight: 1920,
        resize: true
      })
      .then((imgData) => {
        const formData = new FormData();
        for (const { data, ext } of imgData) {
          const newFile = dataURIToBlob(data, ext);
          formData.append("image", newFile);
        }
        return fetch(
          "https://run.mocky.io/v3/c5189845-2a93-49aa-85c7-70bc64e8af90",
          {
            method: "POST",
            body: formData
          }
        );
      })
      .then((res) => res.text());
  },
  false
);

We compress the files the same way.

Then we append the images to the FormData instance, we created.

To do that, we convert the base64 images back to file objects first.

We did that with the dataURIToBlob method to convert the base64 string to an Uint8Array .

The mimeString is from the ext property of the resolved objects.

Then we loop through that and put and put the data into the Blob constructor.

And then we call fetch with it to send it to the server.

Conclusion

We can compress images before uploading them in a JavaScript browser app with the Compress.js library.

Categories
React

Compression Images Before Upload in a React App with React Image File Resizer

The React Image File Resizer lets us compress and manipulate our images before we upload them.

In this article, we’ll look at how to manipulate our image before uploading in a React app.

Installation

We can install the package by running:

npm i react-image-file-resizer

or

yarn add react-image-file-resizer

Compressing and Manipulating Images

We can compress and manipulate our image that we select from a file input.

To do that, we write:

import React from "react";
import Resizer from "react-image-file-resizer";

const resizeFile = (file) =>
  new Promise((resolve) => {
    Resizer.imageFileResizer(
      file,
      300,
      400,
      "JPEG",
      80,
      0,
      (uri) => {
        resolve(uri);
      },
      "base64"
    );
  });

export default function App() {
  const onChange = async (event) => {
    const file = event.target.files[0];
    const image = await resizeFile(file);
    console.log(image);
  };

  return (
    <div className="App">
      <input onChange={onChange} type="file" />
    </div>
  );
}

We have the resizeFile function that takes the image file and returns the promise to resize and compress the file.

The first argument is the file object.

The 2nd and 3rd are the width and height.

The 4th is the format to convert to.

The 5th is the quality of the image from 0 to 100.

The 6th is the rotation of the image.

The 7th is a function for getting the new image URI.

The 8th is the format.

It takes 2 more arguments for the min-width and height.

In the onChange handler, we get the file from the file input.

Once we did that we can do the upload.

Upload the File

To upload the file, we write:

import React from "react";
import Resizer from "react-image-file-resizer";

const resizeFile = (file) =>
  new Promise((resolve) => {
    Resizer.imageFileResizer(
      file,
      300,
      400,
      "JPEG",
      80,
      0,
      (uri) => {
        resolve(uri);
      },
      "base64"
    );
  });

const dataURIToBlob = (dataURI) => {
  const splitDataURI = dataURI.split(",");
  const byteString =
    splitDataURI[0].indexOf("base64") >= 0
      ? atob(splitDataURI[1])
      : decodeURI(splitDataURI[1]);
  const mimeString = splitDataURI[0].split(":")[1].split(";")[0];

  const ia = new Uint8Array(byteString.length);
  for (let i = 0; i < byteString.length; i++) ia[i] = byteString.charCodeAt(i);

  return new Blob([ia], { type: mimeString });
};

export default function App() {
  const onChange = async (event) => {
    const file = event.target.files[0];
    const image = await resizeFile(file);
    console.log(image);
    const newFile = dataURIToBlob(image);
    const formData = new FormData();
    formData.append("image", newFile);
    const res = await fetch(
      "https://run.mocky.io/v3/c5189845-2a93-49aa-85c7-70bc64e8af90",
      {
        method: "POST",
        body: formData
      }
    );
    const data = await res.text();
    console.log(data);
  };

  return (
    <div className="App">
      <input onChange={onChange} type="file" />
    </div>
  );
}

We added the dataURItoBlob function to convert the base64 string back to a file.

It looks through the byte string created from the base64 string and put it in a Uint8Array.

Then that’s put in the Blob constructor to return the file object.

Once we did that, we put that in the FormData constructor.

Then we upload it with the fetch function.

Conclusion

We can compress and resize images before uploading it in a React app with the React Image File Resizer package.