Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to load path from API to get translation content #117

Closed
TommyLeong opened this issue Jul 27, 2023 · 8 comments
Closed

Failed to load path from API to get translation content #117

TommyLeong opened this issue Jul 27, 2023 · 8 comments

Comments

@TommyLeong
Copy link

🐛 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
}
@adrai
Copy link
Member

adrai commented Jul 27, 2023

Make sure maskedDirectoryPath starts with http...

@TommyLeong
Copy link
Author

@adrai actually no, it's pointing to my local project path. Any chance u spotted something configured wrongly?

@adrai
Copy link
Member

adrai commented Jul 27, 2023

If it does not start with http, pn server side that will fail...
Beside that, a reproducible example would help to investigate.

@TommyLeong
Copy link
Author

@adrai I have created a repo here for reproduce purpose. Hope to hear from you soon!

@adrai
Copy link
Member

adrai commented Jul 28, 2023

@adrai
Copy link
Member

adrai commented Jul 28, 2023

So can this issue be closed?

@TommyLeong
Copy link
Author

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?

@adrai
Copy link
Member

adrai commented Jul 28, 2023

it gets automatically interpolated with the requested language and namespace by the used backend plugin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants