@transifex/react
Version:
i18n React framework using Transifex Native
250 lines (237 loc) • 6.7 kB
JavaScript
'use client';
import React, { createContext, useContext, useState, useEffect, Fragment, useCallback } from 'react';
import { tx, onEvent, LOCALE_CHANGED, offEvent, t, TRANSLATIONS_FETCHED, FETCHING_TRANSLATIONS } from '@transifex/native';
import PropTypes from 'prop-types';
const TXNativeContext = /*#__PURE__*/createContext({
instance: null
});
function useLanguages(txInstance) {
const context = useContext(TXNativeContext);
const instance = txInstance || context.instance || tx;
const [languages, setLanguages] = useState([]);
useEffect(() => {
const fetch = function () {
try {
return Promise.resolve(instance.getLanguages()).then(function (_instance$getLanguage) {
setLanguages(_instance$getLanguage);
});
} catch (e) {
return Promise.reject(e);
}
};
fetch();
}, [instance]);
return languages;
}
function useLocale(txInstance) {
const context = useContext(TXNativeContext);
const instance = txInstance || context.instance || tx;
const [locale, setLocale] = useState(instance.getCurrentLocale());
useEffect(() => {
function cb(_, caller) {
if (caller === instance) {
setLocale(instance.getCurrentLocale());
}
}
onEvent(LOCALE_CHANGED, cb);
return () => {
offEvent(LOCALE_CHANGED, cb);
};
}, [instance]);
return locale;
}
function translateWithElements(_str, props, tx) {
let _t = t;
if (tx) {
if (tx.instance && tx.instance.t) {
_t = tx.instance.t;
} else if (tx.t) {
_t = tx.t;
}
}
const actualProps = {};
const reactElements = [];
if (props) {
Object.entries(props).forEach(([key, value]) => {
if (/*#__PURE__*/React.isValidElement(value)) {
actualProps[key] = `__txnative__${reactElements.length}__txnative__`;
reactElements.push(value);
} else {
actualProps[key] = value;
}
});
}
const translation = _t(_str, actualProps);
const result = [];
let lastEnd = 0;
let lastKey = 0;
const regexp = RegExp('__txnative__(\\d+)__txnative__', 'g');
let match = regexp.exec(translation);
while (match !== null) {
const chunk = translation.slice(lastEnd, match.index);
if (chunk) {
result.push(/*#__PURE__*/React.createElement(Fragment, {
key: lastKey
}, chunk));
lastKey += 1;
}
result.push(/*#__PURE__*/React.cloneElement(reactElements[parseInt(match[1], 10)], {
key: lastKey
}));
lastKey += 1;
lastEnd = match.index + match[0].length;
match = regexp.exec(translation);
}
const chunk = translation.slice(lastEnd);
if (chunk) {
result.push(/*#__PURE__*/React.createElement(Fragment, {
key: lastKey
}, chunk));
}
if (result.length === 0) {
return '';
}
if (result.length === 1) {
return result[0].props.children;
}
return /*#__PURE__*/React.createElement(Fragment, null, result);
}
function useT(txInstance) {
const context = useContext(TXNativeContext);
const instance = txInstance || context.instance || tx;
const [counter, setCounter] = useState(0);
useEffect(() => {
function rerender(_, caller) {
if (instance === caller) {
setCounter(c => c + 1);
}
}
onEvent(LOCALE_CHANGED, rerender);
onEvent(TRANSLATIONS_FETCHED, rerender);
return () => {
offEvent(LOCALE_CHANGED, rerender);
offEvent(TRANSLATIONS_FETCHED, rerender);
};
}, [setCounter, instance]);
return useCallback((_str, props) => translateWithElements(_str, props, instance), [instance, counter]);
}
function useTX() {
const context = useContext(TXNativeContext);
return context.instance || tx;
}
function useTranslations(filterTags, txInstance) {
const context = useContext(TXNativeContext);
const instance = txInstance || context.instance || tx;
const [ready, setReady] = useState((instance.fetchedTags[instance.currentLocale] || []).indexOf(filterTags) !== -1);
useEffect(() => {
function setReadyToFalse({
filterTags: eventFilterTags
}, caller) {
if (caller !== instance) return;
if (eventFilterTags === filterTags) {
setReady(false);
}
}
const fetchTranslations = function () {
try {
function _temp2() {
setReady(true);
}
const _temp = function () {
if (instance.currentLocale) {
return Promise.resolve(instance.fetchTranslations(instance.currentLocale, {
filterTags
})).then(function () {});
}
}();
return Promise.resolve(_temp && _temp.then ? _temp.then(_temp2) : _temp2(_temp));
} catch (e) {
return Promise.reject(e);
}
};
onEvent(FETCHING_TRANSLATIONS, setReadyToFalse);
function setReadyToTrue({
filterTags: eventFilterTags
}, caller) {
if (caller !== instance) return;
if (eventFilterTags === filterTags) {
setReady(true);
}
}
onEvent(TRANSLATIONS_FETCHED, setReadyToTrue);
fetchTranslations();
onEvent(LOCALE_CHANGED, fetchTranslations);
return () => {
offEvent(FETCHING_TRANSLATIONS, setReadyToFalse);
offEvent(TRANSLATIONS_FETCHED, setReadyToTrue);
offEvent(LOCALE_CHANGED, fetchTranslations);
};
}, [filterTags, instance]);
return {
ready
};
}
function LanguagePicker({
className = ''
}) {
const languages = useLanguages();
const locale = useLocale();
const tx = useTX();
return /*#__PURE__*/React.createElement("select", {
className: className,
value: locale,
onChange: e => tx.setCurrentLocale(e.target.value)
}, languages.map(({
name,
code
}) => /*#__PURE__*/React.createElement("option", {
key: code,
value: code
}, name)));
}
LanguagePicker.propTypes = {
className: PropTypes.string
};
function T({
_str,
...props
}) {
return useT()(_str, props);
}
T.propTypes = {
_str: PropTypes.string.isRequired
};
function UT({
_str,
_inline = false,
...props
}) {
const translation = useT()(_str, {
_inline,
_escapeVars: true,
...props
});
const parentProps = {
dangerouslySetInnerHTML: {
__html: translation
}
};
const parent = _inline ? 'span' : 'div';
return /*#__PURE__*/React.createElement(parent, parentProps);
}
UT.propTypes = {
_str: PropTypes.string.isRequired,
_inline: PropTypes.bool
};
function TXProvider({
instance,
children
}) {
return /*#__PURE__*/React.createElement(TXNativeContext.Provider, {
value: {
instance
}
}, children);
}
export { LanguagePicker, T, TXProvider, UT, useLanguages, useLocale, useT, useTX, useTranslations };
//# sourceMappingURL=index.modern.js.map