I have an application where I want to use 2 configurations of i18next, one for the app and another for my tests, the problem is that when I run my tests, if the instance is used for testing and my tests pass but I have the warning in the terminal:
init: i18next is already initialized. You should call init just once!
this is what it looks like at the terminal
i18n for app:
// i18n.ts
import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
i18n.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
load: 'languageOnly',
fallbackLng: localStorage.getItem('lang') ?? 'es',
debug: import.meta.env.DEV,
});
export default i18n;
usage in main app:
// main.tsx
...
import './i18n';
...
and the config for my test:
// i18nForTests.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
lng: 'es',
fallbackLng: 'es',
ns: ['translationsNS'],
defaultNS: 'translationsNS',
debug: false,
interpolation: {
escapeValue: false, // not needed for react!!
},
resources: { es: { translationsNS: {} } },
});
export default i18n;
usage:
// setupTests.ts
...
import './i18nForTests';
...
Is there another way to do it? I don’t want the "Backend" and "LanguageDetector" middleware to be used in my tests.
I have already tried the methods described in the documentation here
Even with passing my instance for testing, but this way for some reason, it uses the main instance instead of the test instance.
import i18nForTest from "./i18nForTests"
const WithProviders = ({ children }: { children: React.ReactNode }) => (
<MemoryRouter>
<I18nextProvider i18n={i18nForTest}>
<ChakraProvider>{children}</ChakraProvider>
</I18nextProvider>
</MemoryRouter>
);
I’m using vitest with react-testing-library, here is the config:
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.ts',
coverage: {
provider: 'v8'
},
}
})
2
Answers
Solved
The problem is that in the test environment I was taking into account both instances because both were initialized automatically in each file through the chaining of the init method:
The solution was as obvious as @Mike 'Pomax' Kamermans pointed out, control the initialization, in my case I did it by putting the code inside a function and executing it where it was needed, the same for the test configuration:
and in the implementation:
Seems like you need to use the "createInstance" method of i18next – here is the documentation – https://www.i18next.com/overview/api#createinstance
And the same goes for tests