UNPKG

@particular.cloud/i18n-react

Version:

i18n-react builds on top of i18n-js and implements a translation hook and provider

292 lines (276 loc) 13.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var i18n = require('@particular.cloud/i18n-js'); var React = require('react'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var i18n__default = /*#__PURE__*/_interopDefaultLegacy(i18n); var React__default = /*#__PURE__*/_interopDefaultLegacy(React); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } var I18nContext = React.createContext({ langCodeOrLocale: undefined, published: undefined, config: undefined, }); function isServerSide() { return !!(typeof window !== 'undefined' && window.document && window.document.createElement); } function adaptConfig(particularConfig, setPublished, setLangCodeOrLocale, _setConfig) { if (!particularConfig) { return undefined; } var configData = __assign({}, particularConfig); // bind to websocket publish event if (particularConfig.enableWebsocket) { var handlePublish_1 = particularConfig.onPublish; configData.onPublish = function () { setPublished(new Date()); if (handlePublish_1) { // if user has defined a custom onPublish, call it handlePublish_1(); } }; } // bind to changes of langCodeOrLocale configData.onChangeLanguage = function (langCodeOrLocale) { var onChangeLanguage = particularConfig.onChangeLanguage; setLangCodeOrLocale(langCodeOrLocale); if (onChangeLanguage) { onChangeLanguage(langCodeOrLocale); } }; configData.onChangeConfig = function (config) { var onChangeConfig = particularConfig.onChangeConfig; _setConfig(config); if (onChangeConfig) { onChangeConfig(config); } }; return configData; } /** * I18nProvider: set your Particular.Cloud project token and add options to your ParticularConfig (resets all prior configurations) */ function I18nProvider(_a) { var config = _a.config, children = _a.children; var _b = React.useState(), langCodeOrLocale = _b[0], setLangCodeOrLocale = _b[1]; var _c = React.useState(), published = _c[0], setPublished = _c[1]; var initiliazedByProviderRef = React.useRef(false); // a pointer to the config object changed by i18n-js var _d = React.useState(), _config = _d[0], _setConfig = _d[1]; // our context config var _e = React.useState(adaptConfig(config, setPublished, setLangCodeOrLocale, _setConfig)), i18nConfig = _e[0], setI18nConfig = _e[1]; // do not wrap in useEffect as this has to run once on the server if (isServerSide() && !initiliazedByProviderRef.current) { initiliazedByProviderRef.current = true; i18n__default['default'].init(i18nConfig); } React.useEffect(function () { // changes via React have priority, we do a full init i18n__default['default'].init(adaptConfig(config, setPublished, setLangCodeOrLocale, _setConfig)); // we don't have to setI18nConfig() here, this will happen through the onChangeConfig callback }, [config]); React.useEffect(function () { setI18nConfig(_config); }, [_config]); var context = { published: published, config: i18nConfig, langCodeOrLocale: langCodeOrLocale, }; return React__default['default'].createElement(I18nContext.Provider, { value: context }, children); } /** * usually you want to put your useText hook call within your JSX: * <p>{useText({ key: 'hello', values: { name: "Tony Stark" } })}</p> * the issue with that is that we will pass a new values object to the hook * everytime the JSX renders. * To avoid unnecessary queries, * we make sure to compare the params object with the previous one. */ var paramsDiffer = function (oldParams, newParams) { var primitivesDiffer = oldParams.key !== newParams.key || oldParams.language !== newParams.language || oldParams.isolate !== newParams.isolate; if (primitivesDiffer) { return true; } if (!oldParams.values || !newParams.values) { return oldParams.values !== newParams.values; } var newKeys = Object.keys(newParams.values); for (var _i = 0, newKeys_1 = newKeys; _i < newKeys_1.length; _i++) { var key = newKeys_1[_i]; var newValue = newParams.values[key]; var oldValue = oldParams.values[key]; if (Array.isArray(newValue) && Array.isArray(oldValue)) { if (newValue.length !== oldValue.length) { return true; } for (var i = 0; i < newValue.length; i++) { if (newValue[i] !== oldValue[i]) { return true; } } } else if (oldValue !== newValue) { return true; } } }; /** * useText: hook to query and populate your localized application text */ var useText = function (_a) { var key = _a.key, language = _a.language, values = _a.values, isolate = _a.isolate; var _b = React.useContext(I18nContext), config = _b.config, published = _b.published; var _c = React.useState(i18n__default['default'].t({ key: key, language: language, values: values, isolate: isolate })), string = _c[0], setString = _c[1]; var paramsRef = React.useRef({ key: key, language: language, values: values, isolate: isolate }); var mountedRef = React.useRef(true); React.useEffect(function () { return function () { mountedRef.current = false; }; }, []); var queryText = React.useCallback(function (params) { // update string when either parameter changes var value = i18n__default['default'].t(params, function (fetchedValue) { // this callback is fired if config.updateStrategy = "fetchOnExpired" // it will be triggered if the cache has expired and the string is fetched from the server // see @particular.cloud/i18n-js for more details if (mountedRef.current) { setString(fetchedValue); } }); setString(value); // make sure the dependency array stays empty }, []); React.useEffect(function () { if (!paramsDiffer(paramsRef.current, { key: key, language: language, values: values, isolate: isolate })) { return; } // query text again if params changed queryText({ key: key, language: language, values: values, isolate: isolate }); // update reference for other useEffects paramsRef.current = { key: key, language: language, values: values, isolate: isolate }; }, [key, language, values, isolate]); React.useEffect(function () { // query text again on config change as language might have changed queryText({ key: key, language: language, values: values, isolate: isolate }); }, [config]); React.useEffect(function () { var _a = paramsRef.current, key = _a.key, language = _a.language, values = _a.values, isolate = _a.isolate; // don't run this on first render (no published) if (published) { (function () { return __awaiter(void 0, void 0, void 0, function () { var value; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, i18n__default['default'].fetchT({ key: key, language: language, values: values, isolate: isolate })]; case 1: value = _a.sent(); if (mountedRef.current) { setString(value); } return [2 /*return*/]; } }); }); })(); } }, [published]); return string; }; /** * useLanguage: hook to quickly access the current languageCode or locale */ var useLanguage = function () { var langCodeOrLocale = React.useContext(I18nContext).langCodeOrLocale; return { langCodeOrLocale: langCodeOrLocale }; }; /** * Text: A component wrapper around the useT hook * (useful in class components where hooks cannot be used.) */ var Text = function (_a) { var textKey = _a.textKey, language = _a.language, values = _a.values, isolate = _a.isolate; if (!textKey) { throw Error('Particular.Cloud: i18n-react Text component called without property "textKey". Make sure to pass a "textKey" to your Text component. Did you maybe use the React attribute key instead?'); } return React__default['default'].createElement(React__default['default'].Fragment, null, useText({ key: textKey, language: language, values: values, isolate: isolate })); }; Object.defineProperty(exports, 'default', { enumerable: true, get: function () { return i18n__default['default']; } }); exports.I18nContext = I18nContext; exports.I18nProvider = I18nProvider; exports.Text = Text; exports.useLanguage = useLanguage; exports.useText = useText; Object.keys(i18n).forEach(function (k) { if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, { enumerable: true, get: function () { return i18n[k]; } }); }); //# sourceMappingURL=index.js.map