i18next / i18next-http-backend

i18next-http-backend is a backend layer for i18next using in Node.js, in the browser and for Deno.
MIT License
453 stars 70 forks source link

Only load certain namespaces via http-backend #89

Closed yss14 closed 2 years ago

yss14 commented 2 years ago

🚀 Feature Proposal

As far as I can see it is currently not possible to only specify certain namespaces which should be loaded via the http-backend. All other namespaces should fallback to the default logic which loads the translations from local path.

Motivation

In some webapps most of the translations are fixed and defined as local resources, e.g. placed in /public/locale/{lng}/{ns}.json, but some resource must be loaded dynamically from a http endpoint.

Example

// next-i18next.config.js
module.exports = {
  backend: {
    ns: ['engine'], // here you could specify for which namespaces the translations should be loaded from http endpoint. All other namespaces would fallback to default behaviour -> loaded from local resources
    loadPath: () => {
      return 'https://myhttpendpoint.com/translations';
    },
    parse: (data, language) => JSON.parse(data),
    allowMultiLoading: false,
  },
  debug: true,
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'de'],
  },
  serializeConfig: false,
  use: [HttpBackend],
  ns: ['common', 'engine'] // <common> would be loaded from local resources, <engine> from http backend
};
adrai commented 2 years ago

You could use the i18next-chained-backend plugin: https://www.i18next.com/how-to/backend-fallback you would need to configure it with i18next-http-bakend and i18next-fs-backend...

or alternatively create your own backend that selectively would forward to http or to fs... https://www.i18next.com/misc/creating-own-plugins#backend

adrai commented 2 years ago

btw: there is an example using chained backend also here: https://github.com/i18next/i18next-http-backend/tree/master/example/next

adrai commented 2 years ago

but honestly I don't know if next-i18next would allow a config with a custom injected i18next-fs-backend... this would not work on client side....

so tldr; this is probably not possible without changing (probably a lot) next-i18next

yss14 commented 2 years ago

@adrai Thanks for the quick response! I'm actually sitting a few hours trying to solve this problem and I nearly tried all examples I could find.

The main problem with the chained backend is that I don't know how to tell i18n that as primary backend it should lookup the translations from the local resources (as it is the default behaviour when specifying no backend at all).

I don't want to use resourcesToBackend function, since that would mean I would have to import 20+ local json files first so that I can pass the content of all local json files to the resourcesToBackend function.

I also can't use the i18next-fs-backend since this causes problem when passing the i18n config to appWithTranslation HOC since the browser can't resolve the fs module (which makes sense).

adrai commented 2 years ago

Yes, check my tldr im my last comment:

this is probably not possible without changing (probably a lot) next-i18next

I'm sorry.

yss14 commented 2 years ago

For all people in the same situation: I now solved it with a custom solution as proposed in this issue.

import { merge } from 'lodash'
import { SSRConfig, UserConfig } from 'next-i18next'
import { DeepPartial } from 'ts-essentials'

export const mergeTranslations = (
  serverTranslations: SSRConfig,
  customTranslations: UserConfig['resources']
): SSRConfig => {
  const customSSRLikeConfig: DeepPartial<SSRConfig> = {
    _nextI18Next: {
      userConfig: {
        resources: customTranslations,
      },
      initialI18nStore: customTranslations,
    },
  }

  return merge(serverTranslations, customSSRLikeConfig)
}

// some nextjs page
export const getStaticProps: GetStaticProps = async (...args) => {
  // ...

  return {
    props: {
      // ...
      ...mergeTranslations(
        await serverSideTranslations(locale || 'de', [/* namespaces */]),
        await myCustomEndpointTranslations()
      ),
    },
  }
}

Not as nice as defining a global strategy in the i18n config, but it works for now.