6

I use i18n package in my React application to translate some texts. But I can't iterate through an array of objects which is my translation data.

I want to do iterating through socials array and show it in my template. but when I do that, it says: socials.map is not a function

this is my translation json file:

{
  "socials": [
  {
    "name": "Github",
    "url": "#"
  },
  {
    "name": "Twitter",
    "url": "#"
  },
  {
    "name": "Linkedin",
    "url": "#"
  },
  {
    "name": "Instagram",
    "url": "#"
  }
 ]
}

this is my jsx code:

import { useTranslation } from 'react-i18next';

const Content = () => {
  const { t, i18n } = useTranslation();

  const socials = t('socials', { returnObjects: true });

  rerurn (
    <div className="flex">
      {socials.map((social) => (
        <a href={social.url}>{social.name}</a>
      ))}
    </div>
  );
}

export default Content;

How can I solve this problem?

4
  • What does your t function return? Are you sure it's an array? Commented Mar 12, 2022 at 12:31
  • 1
    it may be the translations are not yet loaded, so check the ready flag before accessing t function Commented Mar 12, 2022 at 14:09
  • Hey Andy. I've updated my jsx code. t function comes from useTranslation() hook. Commented Mar 13, 2022 at 9:25
  • Hey adrai. Thanks for your comment. Yes this is what exactly happens. But I didn't get your mean of ready flag. Can you explain more please? Commented Mar 13, 2022 at 9:33

2 Answers 2

21

Your translations are probably lazy loaded, and you're probably also not using Suspense. This means the translations are not ready for the first render, and you need to check the ready flag: https://react.i18next.com/latest/usetranslation-hook#not-using-suspense

import { useTranslation } from "react-i18next";

const Content = () => {
    const { t, i18n, ready } = useTranslation();

    if (!ready) return "loading translations...";

    const socials = t("socials", { returnObjects: true });

    return (
        <div className="flex">
            {socials.map((social) => (
                <a href={social.url}>{social.name}</a>
            ))}
        </div>
    );
};

export default Content;
Sign up to request clarification or add additional context in comments.

1 Comment

Forgot to comment... Thanks a lot, Adray! It worked for me and solved my issue 👍🏻
0

In my case iterating through translation array worked well until changeLanguage method was triggered. Thing was that for some reason i18n converted array items into properties of an object. Following Mehdi's data from above:

This:

    {
  "socials": [
  {
    "name": "Github",
    "url": "#"
  },
  {
    "name": "Twitter",
    "url": "#"
  },
  {
    "name": "Linkedin",
    "url": "#"
  },
  {
    "name": "Instagram",
    "url": "#"
  }
 ]
}

was turned into this:

    {
  "socials": {
  social1: {
    "name": "Github",
    "url": "#"
  },
  social2: {
    "name": "Twitter",
    "url": "#"
  },
  social3: {
    "name": "Linkedin",
    "url": "#"
  },
  social4: {
    "name": "Instagram",
    "url": "#"
  }
 }
}

To make it work I've written a helper function that checks if passed object is an array or an object (because when 18n is init()ialized, it's an array) and if it's an object it converts its props back into array items. After this conversion mapping / looping works, no more ".map() is not a function" errors.

const objToArr = (obj) => {
    if (obj.length > 0) {
      return obj;
    }
    let arr = [];
    for (let i = 0; i < Object.keys(obj).length; i++) {
      const n = `social${i + 1}`;
      arr.push(obj[n]);
    }
    return arr;
  };

with return object being:

 return (
    <div className="flex">
      {objToArr(socials).map((social) => (
        <a href={social.url}>{social.name}</a>
      ))}
    </div>
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.