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
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.

Categories
React

Add a Date Picker with Airbnb’s React Dates Package

We can add a date picker easily with Airbnb’s React Dates packages.

In this article, we’ll look at how to use it to add a date picker.

Installation

We install the required packages by running:

npm install --save react-dates moment

Basic Datepicker

We add the date picker to our React component by writing:

import React from "react";
import "react-dates/initialize";
import { DateRangePicker } from "react-dates";
import "react-dates/lib/css/_datepicker.css";

export default function App() {
  const [startDate, setStartDate] = React.useState();
  const [endDate, setEndDate] = React.useState();
  const [focusedInput, setFocusedInput] = React.useState();
  return (
    <div className="App">
      <DateRangePicker
        startDate={startDate}
        startDateId="start-date"
        endDate={endDate}
        endDateId="end-date"
        onDatesChange={({ startDate, endDate }) => {
          setStartDate(startDate);
          setEndDate(endDate);
        }}
        focusedInput={focusedInput}
        onFocusChange={(focusedInput) => setFocusedInput(focusedInput)}
      />
    </div>
  );
}

We import the react-dates/initialize package to run the initialization code.

And we import the CSS.

We add the date picker with the DateRangePicker component.

The listed props are all required.

startDate has the start date.

startDateId is the ID of the start date field.

endDate has the end date.

endDateId is the ID of the end date field.

onDatesChanges lets us update the start and end date states.

focusedInput sets whether the input is focused.

onFocusChange has the function to set the focusedInput state to set which field is focused.

Overriding Styles

We can override the styles by setting styles for a few classes.

For example, we can write:

styles.css

.CalendarDay__selected_span {
  background: #82e0aa;
  color: white;
  border: 1px solid lightred;
}

.CalendarDay__selected {
  background: red;
  color: white;
}

.CalendarDay__selected:hover {
  background: orange;
  color: white;
}

.CalendarDay__hovered_span:hover,
.CalendarDay__hovered_span {
  background: brown;
}

CalendarDay__selected_span is the class for the calendar boxes in between the dates.

CalendarDay__selected is the class for the selected start date.

CalendarDay__selected:hover is the pseudoclass for the selected start date when we hover over it.

CalendarDay__hovered_span sets the color for the end date box.

SingleDatePicker

We can also add the SingleDatePicker if we only want to pick a single date.

For example, we can write:

import React from "react";
import "react-dates/initialize";
import { SingleDatePicker } from "react-dates";
import "react-dates/lib/css/_datepicker.css";

export default function App() {
  const [date, setDate] = React.useState();
  const [focused, setFocused] = React.useState();
  return (
    <div className="App">
      <SingleDatePicker
        date={date}
        onDateChange={(date) => setDate(date)}
        focused={focused}
        onFocusChange={({ focused }) => setFocused(focused)}
        id="date"
      />
    </div>
  );
}

We add the SingleDatePicker component to add the date picker.

date has the date.

onDateChange lets us set the date.

focused has the focus date.

onFocusChanged lets us change the focus state.

id has the ID of the date field.

Conclusion

We can add a simple date range and date picker with the react-dates library.

Categories
React

Add a Masonry Grid to a React App with the react-masonry-css Library

We can add the masonry grid to a React app with the react-masonry-css library.

In this article, we’ll look at how to use the library to add the masonry grid.

Installation

We can install the package by running:

npm install react-masonry-css

Adding the Grid

After installing the package, we add the styles by writing:

styles.css

.my-masonry-grid {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  margin-left: -30px;
  width: auto;
}
.my-masonry-grid_column {
  padding-left: 30px;
  background-clip: padding-box;
}

.my-masonry-grid_column > div {
  background: yellow;
  margin-bottom: 30px;
}

to add the background color and make the items display with a flexbox layout.

Then we can use it by writing:

App.js

import React from "react";
import Masonry from "react-masonry-css";
import "./styles.css";

let items = [
  { id: 1, name: "one" },
  { id: 2, name: "two" },
  { id: 3, name: "three" },
  { id: 4, name: "four" },
  { id: 5, name: "five" }
];

items = items.map(function (item) {
  return <div key={item.id}>{item.name}</div>;
});

const breakpointColumnsObj = {
  default: 4,
  1100: 3,
  700: 2,
  500: 1
};

export default function App() {
  return (
    <div className="App">
      <Masonry
        breakpointCols={breakpointColumnsObj}
        className="my-masonry-grid"
        columnClassName="my-masonry-grid_column"
      >
        {items}
      </Masonry>
    </div>
  );
}

We add the breakpointColumnsObj to set the number of items to display when our screen meets the given width.

The keys are the screen sizes and the values are the number of items to display in a row.

className has the class name for the items.

columnClassName has the class name for the grid columns.

We render the items inside the Masonry component.

The class names must match what we have in the CSS file.

The grid is responsive, so the masonry grid will always fit on the screen.

Conclusion

We can add a masonry grid to a React app easily with the react-masonry-css library.