Failed to load path from API to get translation content
TommyLeong opened this issue Β· comments
π Bug Report
I'm trying to get my translation content from a API, the payload response structure is designed as below. (It's not necessarily to follow such structure, as I'm currently concept proofing the reading from API is possible)
en -> language
ns1 -> namespace
anything inside namespace is just key:value translation
{
"en": {
"ns1": {
"welcome": "hello world"
}
}
}
I'm however getting the following error message while visiting the page itself (loading the page itself has no issue, everything render fine)
i18next::backendConnector: loading namespace ns1 for language en failed TypeError: Failed to parse URL from maskedDirectoryPath/public/locales/en/ns1.json
at Object.fetch (maskedDirectoryPath/node_modules/next/dist/compiled/undici/index.js:1:26669)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
[cause]: TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:387:5)
at URL.onParseError (node:internal/url:565:9)
at new URL (node:internal/url:641:5)
at new Request (maskedDirectoryPath/node_modules/next/dist/compiled/undici/index.js:2:42745)
at fetch (maskedDirectoryPath/node_modules/next/dist/compiled/undici/index.js:2:25959)
at Object.fetch (maskedDirectoryPath/node_modules/next/dist/compiled/undici/index.js:1:26638)
at globalThis.fetch (maskedDirectoryPath/node_modules/next/dist/server/node-polyfill-fetch.js:30:26)
at fetchIt (maskedDirectoryPath/node_modules/i18next-http-backend/cjs/request.js:52:3)
at requestWithFetch (maskedDirectoryPath/node_modules/i18next-http-backend/cjs/request.js:78:5)
at Object.request (maskedDirectoryPath/node_modules/i18next-http-backend/cjs/request.js:144:12)
at Backend.loadUrl (maskedDirectoryPath/node_modules/i18next-http-backend/cjs/index.js:107:20)
at maskedDirectoryPath/node_modules/i18next-http-backend/cjs/index.js:97:16
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
input: 'maskedDirectoryPath/public/locales/en/ns1.json',
code: 'ERR_INVALID_URL'
}
}
At the same time, I have created 2 .json file within FE project, at path of projectRootDir/public/locales/en/
- common.json
- ns1.json
Inside both this file, I have also placed the key:value for welcome
common.json
{
"welcome": "COMMON EN"
}
ns1.json
{
"welcome":"ns1 EN welcome"
}
To Reproduce
next-i18next.config.js
const I18NextHttpBackend = require('i18next-http-backend')
const HttpBackend = require('i18next-http-backend/cjs')
/** @type {import('next-i18next').UserConfig} */
module.exports = {
i18n: {
// Testing backend calling
defaultLocale: 'en',
locales: ['en'],
defaultNS: 'ns1',
serializeConfig: false,
use: [HttpBackend],
backend: {
loadPath: 'http://localhost:8080/locales?lng=en&ns=ns1',
},
debug: true,
}
}
_app.js
import '../styles/globals.css'
import { appWithTranslation } from 'next-i18next'
import nextI18NextConfig from '../next-i18next.config'
const App = ({ Component, pageProps }) => {
return <Component {...pageProps} />
}
// export default appWithTranslation(App);
export default appWithTranslation(App, nextI18NextConfig);
FE code
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
export default function Home(props) {
const { t:translate } = useTranslation(['ns1']);
return(
<div>
<h1>
Translation the key "welcome"
<br/> ---::: {translate("welcome")}
</h1>
</div>
)
}
export async function getServerSideProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['ns1'])),
// ...(await serverSideTranslations(locale, ['ns1','common'], nextI18NextConfig)),
},
}
}
Expected behavior
I'm expecting that the translation content read from API will be returned as the namespace ns1
.
Your Environment
- runtime version: node v16.20.0
- i18next version: ^23.3.0
- os: Mac
- extra package.json info
"i18next": "^23.3.0",
"i18next-chained-backend": "^4.4.0",
"i18next-http-backend": "^2.2.1",
"i18next-localstorage-backend": "^4.1.1",
"i18next-multiload-backend-adapter": "^2.2.2",
"next": "^13.4.12",
"next-i18next": "^14.0.0",
More information on the debug
- wait compiling...
- event compiled client and server successfully in 344 ms (314 modules)
i18next: languageChanged en
i18next: initialized {
debug: true,
initImmediate: undefined,
ns: [],
defaultNS: 'ns1',
fallbackLng: [ 'en' ],
fallbackNS: false,
supportedLngs: false,
nonExplicitSupportedLngs: false,
load: 'currentOnly',
preload: [ 'en' ],
simplifyPluralSuffix: true,
keySeparator: '.',
nsSeparator: ':',
pluralSeparator: '_',
contextSeparator: '_',
partialBundledLanguages: false,
saveMissing: false,
updateMissing: false,
saveMissingTo: 'fallback',
saveMissingPlurals: true,
missingKeyHandler: false,
missingInterpolationHandler: false,
postProcess: false,
postProcessPassResolved: false,
returnNull: false,
returnEmptyString: true,
returnObjects: false,
joinArrays: false,
returnedObjectHandler: false,
parseMissingKeyHandler: false,
appendNamespaceToMissingKey: false,
appendNamespaceToCIMode: false,
overloadTranslationOptionHandler: [Function: handle],
interpolation: {
escapeValue: false,
format: [Function: bound format],
prefix: '{{',
suffix: '}}',
formatSeparator: ',',
unescapePrefix: '-',
nestingPrefix: '$t(',
nestingSuffix: ')',
nestingOptionsSeparator: ',',
maxReplaces: 1000,
skipOnVariables: true
},
errorStackTraceLimit: 0,
localeExtension: 'json',
localePath: './public/locales',
localeStructure: '{{lng}}/{{ns}}',
react: { useSuspense: false },
reloadOnPrerender: false,
serializeConfig: false,
use: [ [Function: Backend] { type: 'backend' } ],
lng: 'en',
defaultLocale: 'en',
locales: [ 'en' ],
backend: {
addPath: 'maskedDirectoryPath/public/locales/{{lng}}/{{ns}}.missing.json',
loadPath: 'maskedDirectoryPath/public/locales/{{lng}}/{{ns}}.json',
allowMultiLoading: false,
parse: [Function: parse],
stringify: [Function: stringify],
parsePayload: [Function: parsePayload],
parseLoadPayload: [Function: parseLoadPayload],
request: [Function: request],
reloadInterval: 3600000,
customHeaders: {},
queryStringParams: {},
crossDomain: false,
withCredentials: false,
overrideMimeType: false,
requestOptions: { mode: 'cors', credentials: 'same-origin', cache: 'default' }
},
resources: undefined,
ignoreJSONStructure: true
}
Make sure maskedDirectoryPath starts with http...
@adrai actually no, it's pointing to my local project path. Any chance u spotted something configured wrongly?
If it does not start with http, pn server side that will fail...
Beside that, a reproducible example would help to investigate.
@adrai I have created a repo here for reproduce purpose. Hope to hear from you soon!
So can this issue be closed?
Yes. Thank you for your prompt response!
May I understand why must the url leave it with http://localhost:8080/locales?lng={{lng}}&ns={{ns}}
? From where the value of lng
and ns
is coming?
it gets automatically interpolated with the requested language and namespace by the used backend plugin