i18next / i18next-xhr-backend

[deprecated] can be replaced with i18next-http-backend
https://github.com/i18next/i18next-http-backend
MIT License
253 stars 75 forks source link

[React] Documentation about url is confused. #340

Closed MP-OT closed 4 years ago

MP-OT commented 4 years ago

I am trying to load language from my .Net core Backend, At the client-side, I have the following code:


import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-xhr-backend';

i18n.use(Backend)
i18n.use(LanguageDetector)
  .init({
    lng: "es",
    backend: {
      // path where resources get loaded from, or a function
      // returning a path:
      // function(lngs, namespaces) { return customPath; }
      // the returned path will interpolate lng, ns if provided like giving a static path
      loadPath: 'https://serverUrl/api/user/lang?locale={lng}',

      // path to post missing resources
      addPath: 'https://serverUrl/api/user/lang?locale={lng}',

      crossDomain: true,
      withCredentials: false,

      // overrideMimeType sets request.overrideMimeType("application/json")
      overrideMimeType: false,

      // custom request headers sets request.setRequestHeader(key, value)
      customHeaders: {
        authorization: 'Bearer xxxxxx',
        // ...
      },

      ajax: function (url, options, callback, data) {

        console.log(url, options, data)
      },

    }
  });

export default i18n;

When I run my application for example with npm start it no send the request to load the file. from backend.

jamuhl commented 4 years ago

but does it log your custom ajax?

jamuhl commented 4 years ago

set debug: true on init options...might show what's going wrong

MP-OT commented 4 years ago

@jamuhl it only show me about not found keys like:

i18next::translator: missingKey undefined translations email email
index.js:4226 i18next::translator: missingKey undefined translations email_placeholder_example email_placeholder_example
index.js:4226 i18next::translator: missingKey undefined translations email_default_error email_default_error
index.js:4226 i18next::translator: missingKey undefined translations password password
index.js:4226 i18next::translator: missingKey undefined translations password_placeholder password_placeholder
jamuhl commented 4 years ago

missings are expected...as your ajax function override is not working...you don't see the console.log from your ajax function? also should show some backendConnector logs -> at least if the init you showed above does not exclude some details...

MP-OT commented 4 years ago

@jahed actually I am trying with this code

import i18n from 'i18next';
import XHR from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { axiosDefaultConfig } from '../config/axiosConfig';

// Test Propouses
const getLangsUrl = 'https://localhost:44322/api/language/getall';

const backendOptions = {
  type: 'backend',
  // path where resources get loaded from, or a function
  // returning a path:
  // function(lngs, namespaces) { return customPath; }
  // the returned path will interpolate lng, ns if provided like giving a static path
  loadPath: '/locales/{{lng}}/{{ns}}.json',

  // path to post missing resources
  addPath: 'locales/add/{{lng}}/{{ns}}',

  // your backend server supports multiloading
  // /locales/resources.json?lng=de+en&ns=ns1+ns2
  // Adapter is needed to enable MultiLoading https://github.com/i18next/i18next-multiload-backend-adapter
  // Returned JSON structure in this case is
  // {
  //  lang : {
  //   namespaceA: {},
  //   namespaceB: {},
  //   ...etc
  //  }
  // }
  allowMultiLoading: false, // set loadPath: '/locales/resources.json?lng={{lng}}&ns={{ns}}' to adapt to multiLoading

  // parse data after it has been fetched
  // in example use https://www.npmjs.com/package/json5
  parse: function(data) {
    console.log(data, 'data parse');
    return data;
  },

  //parse data before it has been sent by addPath
  parsePayload: function(namespace, key, fallbackValue) {
    console.log(key, 'key parseLoad');
    return { key };
  },

  // allow cross domain requests
  crossDomain: false,

  // allow credentials on cross domain requests
  withCredentials: false,

  // overrideMimeType sets request.overrideMimeType("application/json")
  overrideMimeType: false,

  // define a custom xhr function
  // can be used to support XDomainRequest in IE 8 and 9
  //
  // 'url' will be passed the value of 'loadPath'
  // 'options' will be this entire options object
  // 'callback' is a function that takes two parameters, 'data' and 'xhr'.
  //            'data' should be the key:value translation pairs for the
  //            requested language and namespace, or null in case of an error.
  //            'xhr' should be a status object, e.g. { status: 200 }
  // 'data' will be a key:value object used when saving missing translations
  ajax: function(url, options, callback, data) {
    axiosDefaultConfig.get(getLangsUrl).then(response => {
      console.log(response);
      callback(response.data, { status: response.status });
      console.log('URL', url, 'options', options, 'callback', callback, 'data', data);
    });
  },
};

i18n
  // load translation using xhr -> see /public/locales
  // learn more: https://github.com/i18next/i18next-xhr-backend
  .use(XHR)
  // detect user language
  // learn more: https://github.com/i18next/i18next-browser-languageDetector
  // init i18next
  // for all options read: https://www.i18next.com/overview/configuration-options
  .init({
    debug: false,
    initImmediate: false,
    backend: backendOptions,
  });

console.log(i18n.t('password'), 'translated');

export default i18n;

It is my directory: [https://prnt.sc/qv4uec](Print Screen)

The console log show me it: [https://prnt.sc/qv4vfp](Console screenshot)

The response data that I pass to the callback in ajax is this and it is working: {password: 'contradsas'}

But if I try to show the key value with this:

console.log(i18n.t('password'), 'translated'); it only returns me the key.

jamuhl commented 4 years ago

init is async...you access t too early

i18n
  // load translation using xhr -> see /public/locales
  // learn more: https://github.com/i18next/i18next-xhr-backend
  .use(XHR)
  // detect user language
  // learn more: https://github.com/i18next/i18next-browser-languageDetector
  // init i18next
  // for all options read: https://www.i18next.com/overview/configuration-options
  .init({
    debug: false,
    initImmediate: false,
    backend: backendOptions,
  }, () => { console.log(i18n.t('password'), 'translated'); });
jahed commented 4 years ago

@MP-OT wrong mention

grandpa

MP-OT commented 4 years ago

@jamuhl Thank you, I know how it works now. I will share my solution bellow as an example for other developers.

I solve it using React.Suspense and enabling it in i18n.Init like this:

At app index I render it :

      <React.Suspense>
        <I18nextProvider i18n={i18n}>
          <App />
        </I18nextProvider>
      </React.Suspense>

And init options should look like:

i18n
  .use(XHR)
  .init(
    {
      react: {
        wait: true,
        bindI18n: 'languageChanged',
        bindI18nStore: '',
        transEmptyNodeValue: '',
        transSupportBasicHtmlNodes: true,
        transKeepBasicHtmlNodesFor: ['es', 'strong', 'i'],
        useSuspense: true,
      },
      interpolation: {
        escapeValue: false, 
      },
      debug: false,
      initImmediate: false,
      backend: backendOptions,
    }
    },
  );
jamuhl commented 4 years ago

@MP-OT good you got it working - just a sidenote if this is a recent version of react-i18next there is no wait option - the wait functionality was replaced with useSuspense (which already defaults to true)!