2

I am using below code for translation in react application. its legacy application. so all of them are class component and old libraries.

import i18next from 'i18next';
import React from 'react';
import TransFile from './TransFile.js';

const LanguageDetector = require('i18next-browser-languagedetector');
const initReactI18next = require('react-i18next');
var output;
//API call
apiDelegate.getTranslations().then((result) => {
  output = JSON.stringify(result);
  alert("output1 =>"+result);

});

alert("output2 is:"+output);

  i18next
    .use(LanguageDetector)
    .use(initReactI18next)
    .init({
      resources: {
        en: output, //Here I need to assign output
      },
      fallbackLng: 'fr',
});
i18next.changeLanguage(navigator.language);
alert("Output3 is:"+output);
export default i18next;

it is printing alert of output2, then output3 then output1 . output2 and output1 are undefined. I need to print them in order because I need to use API data in my application. it is not assigning to actual variable basically I need to assign the output to my en variable. below line in code

 en: output,

I can not use async await because babel is not supporting and its quite old application so when I update webpack gets failed. apiDelegate code.

getTranslations() {
    var token = sessionStorage.getItem('jwt');
    if (token == null) {
      token = '';
    }
    return new Promise((resolve) => {
      request
        .get(baseUrl.api + '/file_download/en')  //API call
        .set({
          'Content-Type': 'application/json',
          Authorization: 'Bearer ' + token,
        })
        .then((value) => {
          var result;
          if (value.status === 200) {
            result = value.body;
            // alert(JSON.stringify(result));
          }
          resolve(result);
          return result;
        })
        .catch((error) => {
          var result;
          if (error.status === 401 || error.status === 403) {
            result = { status: -2, message: error, data: [] };
          }
          resolve(result);
        });
    });
  }

can it be done using callback or setTimeOut? I know its basic but I am a beginner. not able to resolve the same. please help.

Edit1:- Data will be stored in the file or API output will be like below.

translation: {
        app_header:"My contact",
        app_address:"my address",
        app_phone:"+1 93244 3223",
        app_email:"abc@abc.com"
  }

I am using i18 in my file like below.

import i18n from '../../../i18'

in component it will be used like below

i18n.t("app_header")

so value of app_header will be replaced in app.

Shruti sharma
  • 199
  • 6
  • 21
  • 67
  • It is in my component where I defined the code. it internally calls API using Promise. I have attached code of apidelegate method which I am using – Shruti sharma Jan 22 '22 at 16:21
  • 1
    you have to keep the promise chain going: https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call – Daniel A. White Jan 22 '22 at 16:25
  • ok..thank you..i am reading the same. – Shruti sharma Jan 22 '22 at 16:32
  • Hi @DanielA.White I tried my best still could not achieve. could you please help me with the same. I also tried other way but it dint work. https://stackoverflow.com/questions/70589040/how-to-incorporate-api-data-in-i18next-instead-of-static-file/ – Shruti sharma Jan 22 '22 at 18:58
  • Could you show how you're using the exported `i18next` module above? It's easier to help if your can show us the code of the component that imports and uses that module – Cuong Vu Jan 22 '22 at 20:41
  • thank you @CuongVu .I have edited the question. please have a look. – Shruti sharma Jan 22 '22 at 21:22

4 Answers4

2

Since you have a dependency of apiDelegate fn, you need to init the i18next after calling the API. Then only you can able to access the output variable result.

import i18next from 'i18next';
import React from 'react';
import TransFile from './TransFile.js';

const LanguageDetector = require('i18next-browser-languagedetector');
const initReactI18next = require('react-i18next');

//API call
apiDelegate.getTranslations().then((result) => {
  var output;
  output = JSON.stringify(result);
  alert("output1 =>"+result);

  //Moved the assigning logic here
  i18next
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: {
      en: output, //Here I need to assign output
    },
    fallbackLng: 'fr',
  });
   console.log('Output set to en', output)
  i18next.changeLanguage(navigator.language);
});

export default i18next;
  • thank you. actually en is getting undefined because APIdeletegate is asynchronus call...can we do something? this qauestion i put https://stackoverflow.com/questions/70432739/need-to-pass-the-execution-of-code-to-get-output-in-javascript?noredirect=1#comment125189512_70432739 – Shruti sharma Jan 22 '22 at 20:23
  • If you move the logic inside then() it will work, Even though if it is async. Are you not getting the result value in the above code ? check the console I've updated the code – Srimurugan Subramanian Jan 22 '22 at 20:28
  • Application export default is running before everything else so in en it is going undefined. – Shruti sharma Jan 22 '22 at 20:32
  • Try removing export default i18next, try to call the apiDelegate after loading your application – Srimurugan Subramanian Jan 22 '22 at 20:52
1

For detailed answer here attaching an sample react code,

  1. I'm getting a translation response from API/FN will return after 5 sec
  2. After getting response init the i18next using the API result

No need to export i18next , just invoke it in your main app after getting the result.

import React, { useState } from "react";
import i18next from 'i18next';

function App(){
  const [result,setResult] = useState('')

  getTranslationFromAPi().then( response => {
    i18next
    .init({
      resources: {
        en: response, //Here I need to assign output
      },
      fallbackLng: 'fr',
    });
    i18next.changeLanguage(navigator.language);
  })
  
  //Mock funtion gives response after 5sec
  function getTranslationFromAPi(){
    return new Promise((resolve, rej)=>{
      setTimeout(() => {
        resolve({translation:{ln:'sample lang'}});
      }, 5000);
    })
  }

  setTimeout(() => {
    setResult(i18next.t('ln'))
  }, 10000);

  return(
    <div>
      {/* Result will come after 10 sec */}
      {result}  
    </div>
  )
}

export default App;
1

I found several issues with your code. Most importantly as mentioned in the comments you always have to make sure to keep the promise chain going. In apiDelegate you don't have to return a new promise, just return the existing from request. Anyways, request is deprecated. Also all your imports were kind of messed up. In your component you have to make sure to call the init of i18 only once. I used the useEffect to achieve it. I tried to make a sample application for you with a fake api for demonstration purposes for you to debug your code. You can simply comment out the lines in apiDelegate to use the fetch method to call your real api.

App.js

import i18n, { t } from "i18next";
import React, { useEffect, useState } from "react";
import { getTranslations } from "./apiDelegate";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";

export default function App() {
  const [init, setInit] = useState(false);

  //API call
  useEffect(() => {
    (function () {
      getTranslations().then((result) => {
        alert("output1 =>" + result);

        i18n
          .use(initReactI18next)
          .use(LanguageDetector)
          .init({
            resources: {
              en: (alert("output2 =>" + JSON.stringify(result)), result) //Here I need to assign output
            },
            fallbackLng: "fr"
          })
          .then(() => {
            //i18n.changeLanguage(navigator.language);
            i18n.changeLanguage("en");
            setInit(true);
          });
      });
    })();
  }, []);

  return (
    <div i18nready={init.toString()} className="App">
      <div>{t("app_header")}</div>
    </div>
  );
}

apiDelegate.js

//import request from "request"; deprecated

export const getTranslations = () => {
  var token = sessionStorage.getItem("jwt");
  if (token == null) {
    token = "";
  }

  // return fetch(baseUrl.api + '/file_download/en', {  //when using api
  return fetch(
    //remove line when using api
    "./translation.json" //remove line when using api
    /*     , {   //when using api
    method: 'post',
    headers: new Headers({
      'Authorization': "Bearer " + token,
      "Content-Type": "application/json",
      Accept: "application/json"
    }),
    body: 'A=1&B=2'
  } */
  )
    .then((res) => res.json())
    .then((result) => {
      /*       if (result.status === 200) {  //when using api
        return result.body;
      } */
      if (Object.entries(result).length) return result; //remove line when using api

      return { status: -2, message: result.status, data: [] };
    })
    .catch((error) => {
      return { status: -2, message: error.message, data: [] };
    });
};
MWO
  • 2,627
  • 2
  • 10
  • 25
0
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import backend from 'i18next-http-backend';
import api from "../api";

 var lang=navigator.language;

let loadResources= apiDelegate.getTranslations(lang);
const backendOptions = {
  loadPath: 'http://localhost:8080/code/'+lang, 
  request: (options, url, payload, callback) => {
    try {
      loadResources.then((result) => {
        callback(null, {
          data: result,
          status: 200, 
        });
      });
    } catch (e) {
      console.error(e);
      callback(null, {
        status: 500,
      });
    }
  },
};

i18n
  .use(LanguageDetector)
  .use(backend)
  .init({
    backend: backendOptions,
    fallbackLng: "fr",
    debug: false,
    load:"languageOnly",
    ns: ["translations"],
    defaultNS: "translations",
    keySeparator: false, 
    interpolation: {
      escapeValue: false, 
      formatSeparator: ","
    },
    react: {
      wait: true
    }
});
i18n.changeLanguage(navigator.language);
export default i18n;
Shruti sharma
  • 199
  • 6
  • 21
  • 67