i18next-http-backend is making multiple API calls - reactjs

I am applying internationalisation to my app with i18Next. The translation resources are severed via REST micro service. I am using i18next-http-backend plugin to fetch the translations.
The problem is that the plugin is making multiple API calls instead of one and I am not sure why
This is how my code looks like
i18n
.use(HttpApi)
.use(initReactI18next)
.init({
backend: {
backends: [
HttpApi,
HttpApi,
resourcesToBackend(localResources) // 2nd fallback
],
backendOptions: [
{
loadPath: HOST,
queryStringParams: {file: FILENAME, languageCode: `${langMap[lang]}`}, // primary API call
parse: (data) => parseTranslation(data),
},
{
loadPath: HOST,
queryStringParams: {file: FILENAME, languageCode: `${langMap['en']}`}, // 1st fallback
parse: (data) => parseTranslation(data),
}
],
},
fallbackLng: 'en',
lng: 'en', // TODO: make dynamic
debug: true,
keySeparator: false,
interpolation: {
escapeValue: false,
},
});
P.S HOST and FILENAME are variables here

const loadResources = async (locale: string) => {
return await axios
.get(`${BASE_URL}/lang/strings/${locale}/translation.json`, {
headers: { "Access-Control-Allow-Origin": "*" },
})
.then((res) => {
return JSON.stringify(res.data);
})
.catch((error) => {
console.log(error);
});
};
const backendOptions = {
loadPath: "{{lng}}|{{ns}}",
request: (options: any, url: any, payload: any, callback: any) => {
try {
const [lng] = url.split("|");
loadResources(lng).then((response) => {
callback(null, {
data: response,
status: 200,
});
});
} catch (e) {
console.log(e, "error from language");
callback(null, {
status: 500,
});
}
},
};
i18n
.use(backend)
.use(initReactI18next)
.init({
backend: backendOptions,
fallbackLng: "en",
debug: false,
lng: "en",
ns: ["translations"],
defaultNS: "translations",
interpolation: {
escapeValue: false,
formatSeparator: ",",
},
})
.then(noop)
.catch(noop);
I hope this would be helpful for you

Try to change the load option to currentlyOnly -> https://www.i18next.com/overview/configuration-options#languages-namespaces-resources like: https://github.com/i18next/i18next-http-backend/issues/61#issuecomment-812378629
Setting the fallbackLng to false may also work.

Related

How to make www.mydomain.com work in nextjs

I am working on a project and trying to make www.mydomain.com work. I am working on localhost:3000 and when I put in url: mydomain.com:3000 it works but when I set www.mydomian.com:3000 it redirects me on mydomain.is which is my main page.
this is my code in next.config.js file
const path = require("path");
const redirects = require("./redirects");
/** #type {import('next').NextConfig} */
const nextConfig = async () => {
return {
reactStrictMode: false,
swcMinify: true,
sassOptions: {
includePaths: [path.join(__dirname, "src/styles")],
},
redirects() {
return Promise.resolve(redirects);
},
images: {
domains: ["mydomain.cdn.prismic.io", "images.prismic.io"],
},
i18n: {
// https://nextjs.org/docs/advanced-features/i18n-routing
localeDetection: false,
locales: ["is", "en"],
defaultLocale: "is",
domains: [
{
domain: 'mydomain.is',
defaultLocale: 'is',
},
{
domain: 'mydomain.com',
defaultLocale: 'en',
},
],
},
};
};
module.exports = nextConfig;`

Why doesn't my API work when I use info from an env file in my React app?

I have a React app where I access data from an API.
I works perfectly when I hard code all the info in my API function, but when I try to get it from an .env file, it does not work.
Below is the API code:
const [data, setDatas] = useState()
let myHeaders = new Headers();
const getDatas = async () => {
myHeaders.append("Access-Control-Request-Headers", process.env.REACT_APP_ACCESS_CONTROL);
myHeaders.append("Authorization", process.env.REACT_APP_BEARER);
const requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
try {
let response = await fetch(
process.env.REACT_APP_DATAS_API, requestOptions);
let result = await response.json();
setDatas(result)
} catch (err) { console.error(err); }
};
console.log(datas && Object.values(datas))
Below is what the .env file looks like:
REACT_APP_PROJECTS_API=https://this-is-the-api-uri
REACT_APP_ACCESS_CONTROL=this-is-the-access-control
REACT_APP_BEARER=Bearer this-is-the-bearer-token
And below is the contents of my gatsby-config.js file:
require("dotenv").config({
path: `.env.${process.env.NODE_ENV}`,
})
module.exports = {
siteMetadata: {
title: `Site Name`,
siteUrl: `https://www.yourdomain.tld`
},
plugins: ["gatsby-plugin-image", "gatsby-plugin-react-helmet", "gatsby-plugin-sitemap", {
resolve: 'gatsby-plugin-manifest',
options: {
"icon": "src/images/icon.png"
}
}, "gatsby-plugin-mdx", "gatsby-transformer-remark", "gatsby-plugin-sharp", "gatsby-transformer-sharp", {
resolve: 'gatsby-source-filesystem',
options: {
"name": "images",
"path": "./src/images/"
},
__key: "images"
}, {
resolve: 'gatsby-source-filesystem',
options: {
"name": "pages",
"path": "./src/pages/"
},
__key: "pages"
}]
};
Why doesn't it work with .env?
If you want your .env variables to be accessible on Gatsby's frontend, you need to prefix those variables with GATSBY_ prefix

How to update react-i18next language based on a state?

I know how to change react-i18next language, but this change would only be valid for the current session or device.
So, when changing the locale, I update i18next first to provide an immediate ux feedback and then make an api call to update the user profile in my database.
export async function useLocale(locale: Locale) {
const { i18n } = useTranslation();
const { updateProfile }= userService();
i18n.changeLanguage(locale);
return updateProfile({locale})
}
Now, how to make sure i18next fetches the locale from the user state on the next connection? My user state is stored in zustand:
export const userStore = create(() => ({ name: "Joe", locale: "en" }));
The i18nconfig is:
const languages = {
EN: "en",
FR: "fr",
};
const langDetectorOptions = {
order: ["cookie", "localStorage", "navigator"],
lookupCookie: "locale",
lookupLocalStorage: "locale",
caches: ["localStorage", "cookie"],
excludeCacheFor: ["cimode"],
checkWhitelist: true,
};
const resources = {
en: { translation: en },
fr: { translation: fr },
};
export default i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources,
lng: languages.EN,
detection: langDetectorOptions,
fallbackLng: languages.EN,
keySeparator: ".",
whitelist: [languages.EN, languages.FR],
interpolation: { escapeValue: false },
});
You may need to implement a custom language detector: https://www.i18next.com/misc/creating-own-plugins.html#languagedetector

How to change language locally in react-i18next?

I'm trying to give user an option to specify language of generated receipt while keeping the language of the app the same. How would I change the language only for receipt component? i18n.changeLanguage does it globally.
If it helps, here is my i18n config:
i18n
.use(Backend)
.use(initReactI18next)
.init({
ns: ["translation", "login", "orders", "products", "invoices"],
defaultNS: "translation",
lng: "sl",
fallbackLng: "en",
debug: process.env.NODE_ENV === "development",
interpolation: {
escapeValue: false,
},
react: {
useSuspense: true,
wait: true,
},
});
You can use the getFixedT method to get translations of a particular object in a given language regardless of the global language. Here is an example:
en.json
{
nested: {
object: {
...
}
}
}
App.jsx
import { getFixedT } from "i18next";
const App = () => {
const fixedT = getFixedT("en");
const templateData = fixedT("nested.object", {
returnObjects: true,
});
}
References
i18next official documentation: getFixedT

How can we load translations using api calls instead of having them defined in static jsons? How can this be done in React-i18next?

On using internationalization in React application, Need to load the language translation files on demand using api calls and not have them defined upfront. How can this be achieved by using React-i18next?
Tried out the normal translations being picked from static predefined files using React-i18next. Tried using xhr-backend but unable to find any sample to implement this requirement of on-demand load of translation related data.
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import backend from 'i18next-http-backend';
import axiosInstance from './helpers/Axios';
const loadResources=async(locale:string)=> {
return await axiosInstance().get('/translate-data/get', { params: { lang: locale } })
.then((response) => { return response.data })
.catch((error) => { console.log(error); });
}
const backendOptions = {
loadPath: '{{lng}}|{{ns}}',
request: (options:any, url:any, payload:any, callback:any) => {
try {
const [lng] = url.split('|');
loadResources(lng).then((response) => {
callback(null, {
data: response,
status: 200,
});
});
} catch (e) {
console.error(e);
callback(null, {
status: 500,
});
}
},
};
i18n
.use(LanguageDetector)
.use(backend)
.init({
backend: backendOptions,
fallbackLng: "en",
debug: false,
load:"languageOnly",
ns: ["translations"],
defaultNS: "translations",
keySeparator: false,
interpolation: {
escapeValue: false,
formatSeparator: ","
},
react: {
wait: true
}
});
export default i18n;
Request from backend options is used to call backend API using Axios.
import i18next from 'i18next';
import XHR from 'i18next-xhr-backend';
var language = i18next.language ||'en-US';
const backendOptions = {
type: 'backend',
crossDomain: false,
allowMultiLoading: false,
loadPath: `your-backend-api/?locale_code=${language}`
}
const options = {
interpolation: {
escapeValue: false, // not needed for react!!
},
initImmediate: false ,
debug: true,
lng: language,
fallbackLng: language,
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
react: {
wait: false,
bindI18n: 'languageChanged loaded',
bindStore: 'added removed',
nsMode: 'default',
defaultTransParent: 'div',
},
};
options['backend'] = backendOptions;
i18next
.use(XHR)
.init(options)
export default i18next;

Resources