Skip to content

Commit

Permalink
adapt to i18next v18.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jamuhl committed Oct 24, 2019
1 parent 8f22267 commit 90f0e44
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 20 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### 11.0.0

- **Breaking** based on i18next changes made in [v18.0.0](https://github.com/i18next/i18next/blob/master/CHANGELOG.md#1800) changing the language should not trigger a Suspense anylonger. The state will be ready and `t` bound to the previous language until `languageChanged` get triggered -> this results in a nicer experience for users (no flickering Suspense while changing the language). Based on issue "Suspence is fired during lang change when useTranslation called in between" [975](https://github.com/i18next/react-i18next/issues/975)
- the default bindI18n is now `languageChanged` and `languageChanging` was removed from that default
- Adding `languageChanging` to bindI18n will bring back old behaviour where a language change will trigger a Suspense / ready: false while loading those new translations
- You can now override the defaults in i18next.options.react for `bindI18n`, `bindI18nStore` and `useSuspense` in the hook by `useTranslation(ns, { bindI18n, bindI18nStore, useSuspense})` or in the HOC by passing those as props.

### 10.13.2

- typescript: Add t function to TransProps types [969](https://github.com/i18next/react-i18next/pull/969)
Expand Down
14 changes: 7 additions & 7 deletions example/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"i18next": "15.0.4",
"i18next-browser-languagedetector": "3.0.0",
"i18next-xhr-backend": "2.0.0",
"react": "16.8.2",
"react-dom": "16.8.2",
"react-i18next": "10.1.2",
"react-scripts": "2.1.3"
"i18next": "17.3.1",
"i18next-browser-languagedetector": "4.0.0",
"i18next-xhr-backend": "3.2.0",
"react": "16.11.0",
"react-dom": "16.11.0",
"react-i18next": "10.13.2",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "react-scripts start",
Expand Down
18 changes: 12 additions & 6 deletions react-i18next.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@
};

var defaultOptions = {
bindI18n: 'languageChanging languageChanged',
bindI18n: 'languageChanged',
bindI18nStore: '',
// nsMode: 'fallback' // loop through all namespaces given to hook, HOC, render prop for key lookup
transEmptyNodeValue: '',
Expand Down Expand Up @@ -468,6 +468,8 @@
});
}
function hasLoadedNamespace(ns, i18n) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

if (!i18n.languages || !i18n.languages.length) {
warnOnce('i18n.languages were undefined or empty', i18n.languages);
return true;
Expand All @@ -482,8 +484,12 @@
var loadNotPending = (l, n) => {
var loadState = i18n.services.backendConnector.state["".concat(l, "|").concat(n)];
return loadState === -1 || loadState === 2;
}; // loaded -> SUCCESS
}; // bound to trigger on event languageChanging
// so set ready to false while we are changing the language
// and namespace pending (depends on having a backend)


if (options.bindI18n && options.bindI18n.indexOf('languageChanging') > -1 && i18n.services.backendConnector.backend && i18n.isLanguageChangingTo && !loadNotPending(i18n.isLanguageChangingTo, ns)) return false; // loaded -> SUCCESS

if (i18n.hasResourceBundle(lng, ns)) return true; // were not loading at all -> SEMI SUCCESS

Expand Down Expand Up @@ -765,18 +771,18 @@
return retNotReady;
}

var i18nOptions = _objectSpread2({}, getDefaults(), {}, i18n.options.react);
var i18nOptions = _objectSpread2({}, getDefaults(), {}, i18n.options.react, {}, props);

var {
useSuspense = i18nOptions.useSuspense
} = props; // prepare having a namespace
useSuspense
} = i18nOptions; // prepare having a namespace

var namespaces = ns || defaultNSFromContext || i18n.options && i18n.options.defaultNS;
namespaces = typeof namespaces === 'string' ? [namespaces] : namespaces || ['translation']; // report namespaces as used

if (i18n.reportNamespaces.addUsedNamespaces) i18n.reportNamespaces.addUsedNamespaces(namespaces); // are we ready? yes if all namespaces in first language are loaded already (either with data or empty object on failed load)

var ready = (i18n.isInitialized || i18n.initializedStoreOnce) && namespaces.every(n => hasLoadedNamespace(n, i18n)); // binding t function to namespace (acts also as rerender trigger)
var ready = (i18n.isInitialized || i18n.initializedStoreOnce) && namespaces.every(n => hasLoadedNamespace(n, i18n, i18nOptions)); // binding t function to namespace (acts also as rerender trigger)

function getT() {
return {
Expand Down
2 changes: 1 addition & 1 deletion react-i18next.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/context.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

let defaultOptions = {
bindI18n: 'languageChanging languageChanged',
bindI18n: 'languageChanged',
bindI18nStore: '',
// nsMode: 'fallback' // loop through all namespaces given to hook, HOC, render prop for key lookup
transEmptyNodeValue: '',
Expand Down
7 changes: 4 additions & 3 deletions src/useTranslation.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ export function useTranslation(ns, props = {}) {
retNotReady.ready = false;
return retNotReady;
}
const i18nOptions = { ...getDefaults(), ...i18n.options.react };
const { useSuspense = i18nOptions.useSuspense } = props;

const i18nOptions = { ...getDefaults(), ...i18n.options.react, ...props };
const { useSuspense } = i18nOptions;

// prepare having a namespace
let namespaces = ns || defaultNSFromContext || (i18n.options && i18n.options.defaultNS);
Expand All @@ -38,7 +39,7 @@ export function useTranslation(ns, props = {}) {
// are we ready? yes if all namespaces in first language are loaded already (either with data or empty object on failed load)
const ready =
(i18n.isInitialized || i18n.initializedStoreOnce) &&
namespaces.every(n => hasLoadedNamespace(n, i18n));
namespaces.every(n => hasLoadedNamespace(n, i18n, i18nOptions));

// binding t function to namespace (acts also as rerender trigger)
function getT() {
Expand Down
14 changes: 13 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function loadNamespaces(i18n, ns, cb) {
});
}

export function hasLoadedNamespace(ns, i18n) {
export function hasLoadedNamespace(ns, i18n, options = {}) {
if (!i18n.languages || !i18n.languages.length) {
warnOnce('i18n.languages were undefined or empty', i18n.languages);
return true;
Expand All @@ -58,6 +58,18 @@ export function hasLoadedNamespace(ns, i18n) {
return loadState === -1 || loadState === 2;
};

// bound to trigger on event languageChanging
// so set ready to false while we are changing the language
// and namespace pending (depends on having a backend)
if (
options.bindI18n &&
options.bindI18n.indexOf('languageChanging') > -1 &&
i18n.services.backendConnector.backend &&
i18n.isLanguageChangingTo &&
!loadNotPending(i18n.isLanguageChangingTo, ns)
)
return false;

// loaded -> SUCCESS
if (i18n.hasResourceBundle(lng, ns)) return true;

Expand Down
2 changes: 1 addition & 1 deletion test/useTranslation.loading.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('useTranslation loading ns', () => {
});
});

const TestElement = ({ useSuspense = undefined }) => {
const TestElement = ({ useSuspense = true }) => {
const [t] = useTranslation('common', { i18n: newI18n, useSuspense });
return <div>{t('key1')}</div>;
};
Expand Down

0 comments on commit 90f0e44

Please sign in to comment.