react-i18next
Version:
Internationalization for react done right. Using the i18next i18n ecosystem.
159 lines (158 loc) • 6.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useTranslation = void 0;
var _react = require("react");
var _shim = require("use-sync-external-store/shim");
var _context = require("./context.js");
var _utils = require("./utils.js");
const notReadyT = (k, optsOrDefaultValue) => {
if ((0, _utils.isString)(optsOrDefaultValue)) return optsOrDefaultValue;
if ((0, _utils.isObject)(optsOrDefaultValue) && (0, _utils.isString)(optsOrDefaultValue.defaultValue)) return optsOrDefaultValue.defaultValue;
return Array.isArray(k) ? k[k.length - 1] : k;
};
const notReadySnapshot = {
t: notReadyT,
ready: false
};
const dummySubscribe = () => () => {};
const useTranslation = (ns, props = {}) => {
const {
i18n: i18nFromProps
} = props;
const {
i18n: i18nFromContext,
defaultNS: defaultNSFromContext
} = (0, _react.useContext)(_context.I18nContext) || {};
const i18n = i18nFromProps || i18nFromContext || (0, _context.getI18n)();
if (i18n && !i18n.reportNamespaces) i18n.reportNamespaces = new _context.ReportNamespaces();
if (!i18n) {
(0, _utils.warnOnce)(i18n, 'NO_I18NEXT_INSTANCE', 'useTranslation: You will need to pass in an i18next instance by using initReactI18next');
}
const i18nOptions = (0, _react.useMemo)(() => ({
...(0, _context.getDefaults)(),
...i18n?.options?.react,
...props
}), [i18n, props]);
const {
useSuspense,
keyPrefix
} = i18nOptions;
const nsOrContext = ns || defaultNSFromContext || i18n?.options?.defaultNS;
const unstableNamespaces = (0, _utils.isString)(nsOrContext) ? [nsOrContext] : nsOrContext || ['translation'];
const namespaces = (0, _react.useMemo)(() => unstableNamespaces, unstableNamespaces);
i18n?.reportNamespaces?.addUsedNamespaces?.(namespaces);
const revisionRef = (0, _react.useRef)(0);
const subscribe = (0, _react.useCallback)(callback => {
if (!i18n) return dummySubscribe;
const {
bindI18n,
bindI18nStore
} = i18nOptions;
const wrappedCallback = () => {
revisionRef.current += 1;
callback();
};
if (bindI18n) i18n.on(bindI18n, wrappedCallback);
if (bindI18nStore) i18n.store.on(bindI18nStore, wrappedCallback);
return () => {
if (bindI18n) bindI18n.split(' ').forEach(e => i18n.off(e, wrappedCallback));
if (bindI18nStore) bindI18nStore.split(' ').forEach(e => i18n.store.off(e, wrappedCallback));
};
}, [i18n, i18nOptions]);
const snapshotRef = (0, _react.useRef)();
const getSnapshot = (0, _react.useCallback)(() => {
if (!i18n) {
return notReadySnapshot;
}
const calculatedReady = !!(i18n.isInitialized || i18n.initializedStoreOnce) && namespaces.every(n => (0, _utils.hasLoadedNamespace)(n, i18n, i18nOptions));
const currentLng = props.lng || i18n.language;
const currentRevision = revisionRef.current;
const lastSnapshot = snapshotRef.current;
if (lastSnapshot && lastSnapshot.ready === calculatedReady && lastSnapshot.lng === currentLng && lastSnapshot.keyPrefix === keyPrefix && lastSnapshot.revision === currentRevision) {
return lastSnapshot;
}
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix);
const newSnapshot = {
t: calculatedT,
ready: calculatedReady,
lng: currentLng,
keyPrefix,
revision: currentRevision
};
snapshotRef.current = newSnapshot;
return newSnapshot;
}, [i18n, namespaces, keyPrefix, i18nOptions, props.lng]);
const [loadCount, setLoadCount] = (0, _react.useState)(0);
const {
t,
ready
} = (0, _shim.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
(0, _react.useEffect)(() => {
if (i18n && !ready && !useSuspense) {
const onLoaded = () => setLoadCount(c => c + 1);
if (props.lng) {
(0, _utils.loadLanguages)(i18n, props.lng, namespaces, onLoaded);
} else {
(0, _utils.loadNamespaces)(i18n, namespaces, onLoaded);
}
}
}, [i18n, props.lng, namespaces, ready, useSuspense, loadCount]);
const finalI18n = i18n || {};
const wrapperRef = (0, _react.useRef)(null);
const wrapperLangRef = (0, _react.useRef)();
const createI18nWrapper = original => {
const descriptors = Object.getOwnPropertyDescriptors(original);
if (descriptors.__original) delete descriptors.__original;
const wrapper = Object.create(Object.getPrototypeOf(original), descriptors);
if (!Object.prototype.hasOwnProperty.call(wrapper, '__original')) {
try {
Object.defineProperty(wrapper, '__original', {
value: original,
writable: false,
enumerable: false,
configurable: false
});
} catch (_) {}
}
return wrapper;
};
const ret = (0, _react.useMemo)(() => {
const original = finalI18n;
const lang = original?.language;
let i18nWrapper = original;
if (original) {
if (wrapperRef.current && wrapperRef.current.__original === original) {
if (wrapperLangRef.current !== lang) {
i18nWrapper = createI18nWrapper(original);
wrapperRef.current = i18nWrapper;
wrapperLangRef.current = lang;
} else {
i18nWrapper = wrapperRef.current;
}
} else {
i18nWrapper = createI18nWrapper(original);
wrapperRef.current = i18nWrapper;
wrapperLangRef.current = lang;
}
}
const arr = [t, i18nWrapper, ready];
arr.t = t;
arr.i18n = i18nWrapper;
arr.ready = ready;
return arr;
}, [t, finalI18n, ready, finalI18n.resolvedLanguage, finalI18n.language, finalI18n.languages]);
if (i18n && useSuspense && !ready) {
throw new Promise(resolve => {
const onLoaded = () => resolve();
if (props.lng) {
(0, _utils.loadLanguages)(i18n, props.lng, namespaces, onLoaded);
} else {
(0, _utils.loadNamespaces)(i18n, namespaces, onLoaded);
}
});
}
return ret;
};
exports.useTranslation = useTranslation;