react-localize-redux
Advanced tools
Comparing version 1.1.2 to 2.0.0
@@ -10,3 +10,3 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
root["ReactLocalizeRedux"] = factory(root["React"], root["ReactRedux"], root["Redux"], root["Reselect"]); | ||
})(this, function(__WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__, __WEBPACK_EXTERNAL_MODULE_6__) { | ||
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_6__, __WEBPACK_EXTERNAL_MODULE_7__, __WEBPACK_EXTERNAL_MODULE_8__) { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
@@ -77,3 +77,3 @@ /******/ // The module cache | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(__webpack_require__.s = 7); | ||
/******/ return __webpack_require__(__webpack_require__.s = 9); | ||
/******/ }) | ||
@@ -89,36 +89,66 @@ /************************************************************************/ | ||
exports.__esModule = true; | ||
exports.getTranslationsForKey = exports.setGlobalTranslations = exports.setLocalTranslations = exports.updateLanguage = exports.UPDATE_LANGUAGE = exports.SET_LOCAL_TRANSLATIONS = exports.SET_GLOBAL_TRANSLATIONS = exports.GLOBAL_TRANSLATIONS_KEY = exports.DEFUALT_LOCALE = undefined; | ||
exports.getTranslate = exports.getTranslationsForActiveLanguage = exports.customeEqualSelector = exports.getActiveLanguage = exports.getLanguages = exports.getTranslations = exports.setActiveLanguage = exports.setLanguages = exports.addTranslation = exports.localeReducer = exports.TRANSLATE = exports.SET_ACTIVE_LANGUAGE = exports.SET_LANGUAGES = exports.ADD_TRANSLATION = undefined; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
// import { LANG, DEFUALT_LANG } from 'store/constants'; | ||
exports.languages = languages; | ||
exports.translations = translations; | ||
var _redux = __webpack_require__(5); | ||
var _redux = __webpack_require__(7); | ||
var _reselect = __webpack_require__(6); | ||
var _flat = __webpack_require__(4); | ||
var _utils = __webpack_require__(1); | ||
var _reselect = __webpack_require__(8); | ||
var DEFUALT_LOCALE = exports.DEFUALT_LOCALE = 'en'; | ||
var GLOBAL_TRANSLATIONS_KEY = exports.GLOBAL_TRANSLATIONS_KEY = 'global'; | ||
var _utils = __webpack_require__(3); | ||
// export const FETCH_LOCALE_REQUEST = '@@localize/FETCH_LOCALE_REQUEST'; | ||
// export const FETCH_LOCALE_SUCCESS = '@@localize/FETCH_LOCALE_SUCCESS'; | ||
// export const FETCH_LOCALE_ERROR = '@@localize/FETCH_LOCALE_ERROR'; | ||
var ADD_TRANSLATION = exports.ADD_TRANSLATION = '@@localize/ADD_TRANSLATION'; | ||
var SET_LANGUAGES = exports.SET_LANGUAGES = '@@localize/SET_LANGUAGES'; | ||
var SET_ACTIVE_LANGUAGE = exports.SET_ACTIVE_LANGUAGE = '@@localize/SET_ACTIVE_LANGUAGE'; | ||
var TRANSLATE = exports.TRANSLATE = '@@localize/TRANSLATE'; | ||
var SET_GLOBAL_TRANSLATIONS = exports.SET_GLOBAL_TRANSLATIONS = '@@localize/SET_GLOBAL_TRANSLATIONS'; | ||
var SET_LOCAL_TRANSLATIONS = exports.SET_LOCAL_TRANSLATIONS = '@@localize/SET_LOCAL_TRANSLATIONS'; | ||
var UPDATE_LANGUAGE = exports.UPDATE_LANGUAGE = '@@localize/UPDATE_LANGUAGE'; | ||
/** | ||
* REDUCERS | ||
*/ | ||
function languages() { | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; | ||
var action = arguments[1]; | ||
var _ret = function () { | ||
switch (action.type) { | ||
case SET_LANGUAGES: | ||
var languageCodes = action.payload.languageCodes; | ||
var activeLanguage = action.payload.activeLanguage || languageCodes[0]; | ||
var activeIndex = languageCodes.indexOf(activeLanguage); | ||
return { | ||
v: languageCodes.map(function (code, index) { | ||
var isActive = index === activeIndex; | ||
return { code: code, active: isActive }; | ||
}) | ||
}; | ||
case SET_ACTIVE_LANGUAGE: | ||
return { | ||
v: state.map(function (language) { | ||
return language.code === action.payload.languageCode ? _extends({}, language, { active: true }) : _extends({}, language, { active: false }); | ||
}) | ||
}; | ||
default: | ||
return { | ||
v: state | ||
}; | ||
} | ||
}(); | ||
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; | ||
} | ||
function translations() { | ||
var _extends2, _extends3; | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var action = arguments[1]; | ||
switch (action.type) { | ||
case SET_LOCAL_TRANSLATIONS: | ||
return _extends({}, state, (_extends2 = {}, _extends2[action.payload.key] = action.payload.json, _extends2)); | ||
case SET_GLOBAL_TRANSLATIONS: | ||
return _extends({}, state, (_extends3 = {}, _extends3[GLOBAL_TRANSLATIONS_KEY] = action.payload, _extends3)); | ||
case ADD_TRANSLATION: | ||
return _extends({}, state, (0, _flat.flatten)(action.payload.translation, { safe: true })); | ||
default: | ||
@@ -129,67 +159,73 @@ return state; | ||
function currentLanguage() { | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'en'; | ||
var action = arguments[1]; | ||
var localeReducer = exports.localeReducer = (0, _redux.combineReducers)({ languages: languages, translations: translations }); | ||
return action.type === UPDATE_LANGUAGE ? action.payload : state; | ||
} | ||
exports.default = (0, _redux.combineReducers)({ | ||
currentLanguage: currentLanguage, | ||
translations: translations | ||
}); | ||
var updateLanguage = exports.updateLanguage = function updateLanguage(language) { | ||
var selectedLanguage = language; | ||
selectedLanguage = selectedLanguage ? selectedLanguage : 'en'; | ||
/** | ||
* ACTION CREATORS | ||
*/ | ||
var addTranslation = exports.addTranslation = function addTranslation(translation) { | ||
return { | ||
type: UPDATE_LANGUAGE, | ||
payload: selectedLanguage | ||
type: ADD_TRANSLATION, | ||
payload: { translation: translation } | ||
}; | ||
}; | ||
var setLocalTranslations = exports.setLocalTranslations = function setLocalTranslations(key, json) { | ||
var setLanguages = exports.setLanguages = function setLanguages(languageCodes) { | ||
var activeLanguage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
return { | ||
type: SET_LOCAL_TRANSLATIONS, | ||
payload: { key: key, json: json } | ||
type: SET_LANGUAGES, | ||
payload: { languageCodes: languageCodes, activeLanguage: activeLanguage } | ||
}; | ||
}; | ||
var setGlobalTranslations = exports.setGlobalTranslations = function setGlobalTranslations(json) { | ||
var setActiveLanguage = exports.setActiveLanguage = function setActiveLanguage(languageCode) { | ||
return { | ||
type: SET_GLOBAL_TRANSLATIONS, | ||
payload: json | ||
type: SET_ACTIVE_LANGUAGE, | ||
payload: { languageCode: languageCode } | ||
}; | ||
}; | ||
// export const fetchLocaleJson = (json, key): IApiActionType => { | ||
// return { | ||
// type: [FETCH_LOCALE_REQUEST, FETCH_LOCALE_SUCCESS, FETCH_LOCALE_ERROR], | ||
// shouldCallApi: (state) => true, | ||
// callApi: () => Promise.resolve(json), | ||
// payload: { key } | ||
// }; | ||
// }; | ||
var getCurrentLanguage = function getCurrentLanguage(state) { | ||
return state.locale.currentLanguage; | ||
/** | ||
* SELECTORS | ||
*/ | ||
var getTranslations = exports.getTranslations = function getTranslations(state) { | ||
return state.translations; | ||
}; | ||
var getTranslations = function getTranslations(state) { | ||
return state.locale.translations; | ||
var getLanguages = exports.getLanguages = function getLanguages(state) { | ||
return state.languages; | ||
}; | ||
var getActiveLanguage = exports.getActiveLanguage = function getActiveLanguage(state) { | ||
return getLanguages(state).find(function (language) { | ||
return language.active === true; | ||
}); | ||
}; | ||
var getTranslationsForKey = exports.getTranslationsForKey = function getTranslationsForKey(key) { | ||
return (0, _reselect.createSelector)(getCurrentLanguage, getTranslations, function (currentLanguage, translations) { | ||
var globalTranslations = {}; | ||
var localTranslations = {}; | ||
var customeEqualSelector = exports.customeEqualSelector = (0, _reselect.createSelectorCreator)(_reselect.defaultMemoize, function (cur, prev) { | ||
var isTranslationsData = !(Array.isArray(cur) || Object.keys(cur).toString() === 'code,active'); | ||
if (translations && (0, _utils.isDefinedNested)(translations, GLOBAL_TRANSLATIONS_KEY)) { | ||
globalTranslations = translations.global[currentLanguage] || {}; | ||
} | ||
// for translations data use keys for comparison | ||
if (isTranslationsData) { | ||
prev = Object.keys(prev).toString(); | ||
cur = Object.keys(cur).toString(); | ||
} | ||
if (translations && (0, _utils.isDefinedNested)(translations, key, currentLanguage)) { | ||
localTranslations = translations[key][currentLanguage]; | ||
} | ||
return prev === cur; | ||
}); | ||
return _extends({}, globalTranslations, localTranslations); | ||
}); | ||
var getTranslationsForActiveLanguage = exports.getTranslationsForActiveLanguage = customeEqualSelector(getActiveLanguage, getLanguages, getTranslations, function (activeLanguage, languages, translations) { | ||
var activeLanguageCode = activeLanguage.code; | ||
var activeLanguageIndex = (0, _utils.getIndexForLanguageCode)(activeLanguageCode, languages); | ||
return Object.keys(translations).reduce(function (prev, key) { | ||
var _extends2; | ||
return _extends({}, prev, (_extends2 = {}, _extends2[key] = translations[key][activeLanguageIndex], _extends2)); | ||
}, {}); | ||
}); | ||
var getTranslate = exports.getTranslate = function getTranslate(state) { | ||
var translations = getTranslationsForActiveLanguage(state); | ||
return function (key, data) { | ||
return (0, _utils.getLocalizedElement)(key, translations, data); | ||
}; | ||
}; | ||
@@ -199,2 +235,8 @@ | ||
/* 1 */ | ||
/***/ function(module, exports) { | ||
module.exports = __WEBPACK_EXTERNAL_MODULE_1__; | ||
/***/ }, | ||
/* 2 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
@@ -206,10 +248,42 @@ | ||
exports.__esModule = true; | ||
exports.templater = exports.isDefinedNested = exports.hasHtmlTags = exports.getLocalizedElement = undefined; | ||
exports.localize = undefined; | ||
var _react = __webpack_require__(2); | ||
var _react = __webpack_require__(1); | ||
var _react2 = _interopRequireDefault(_react); | ||
var _reactRedux = __webpack_require__(6); | ||
var _locale = __webpack_require__(0); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var localize = exports.localize = function localize(Component) { | ||
var mapStateToProps = function mapStateToProps(state) { | ||
return { | ||
currentLanguage: (0, _locale.getActiveLanguage)(state).code, | ||
translate: (0, _locale.getTranslate)(state) | ||
}; | ||
}; | ||
return (0, _reactRedux.connect)(mapStateToProps, null)(Component); | ||
}; | ||
/***/ }, | ||
/* 3 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports.getIndexForLanguageCode = exports.templater = exports.hasHtmlTags = exports.getLocalizedElement = undefined; | ||
var _react = __webpack_require__(1); | ||
var _react2 = _interopRequireDefault(_react); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var getLocalizedElement = exports.getLocalizedElement = function getLocalizedElement(key, translations, data) { | ||
@@ -231,31 +305,2 @@ var localizedString = translations[key] || 'Missing locaized: ' + key; | ||
/** | ||
* @func isDefinedNested | ||
* @desc Check if a nested property exists on an object. | ||
* @param {Object} target The object that you want to test against | ||
* @param {string} props The nested props you want verify are defined on target | ||
* @example | ||
* // checks if theObject.prop1.prop2.prop3 is defined | ||
* isDefinedNested(theObject, 'prop1', 'prop2', 'prop3') | ||
*/ | ||
var isDefinedNested = exports.isDefinedNested = function isDefinedNested(target) { | ||
for (var _len = arguments.length, props = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
props[_key - 1] = arguments[_key]; | ||
} | ||
var firstProp = props.shift(); | ||
if (target[firstProp] === undefined) { | ||
return false; | ||
} | ||
return props.reduce(function (prev, cur, index) { | ||
if (index === props.length - 1) { | ||
return prev[cur] !== undefined; | ||
} else { | ||
return prev === undefined ? {} : prev[cur]; | ||
} | ||
}, target[firstProp]); | ||
}; | ||
/** | ||
* @func templater | ||
@@ -278,60 +323,119 @@ * @desc A poor mans template parser | ||
/***/ }, | ||
/* 2 */ | ||
/***/ function(module, exports) { | ||
var getIndexForLanguageCode = exports.getIndexForLanguageCode = function getIndexForLanguageCode(code, languages) { | ||
return languages.map(function (language) { | ||
return language.code; | ||
}).indexOf(code); | ||
}; | ||
module.exports = __WEBPACK_EXTERNAL_MODULE_2__; | ||
/***/ }, | ||
/* 3 */ | ||
/* 4 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
"use strict"; | ||
var isBuffer = __webpack_require__(5) | ||
var flat = module.exports = flatten | ||
flatten.flatten = flatten | ||
flatten.unflatten = unflatten | ||
exports.__esModule = true; | ||
exports.localize = undefined; | ||
function flatten(target, opts) { | ||
opts = opts || {} | ||
var _react = __webpack_require__(2); | ||
var delimiter = opts.delimiter || '.' | ||
var maxDepth = opts.maxDepth | ||
var output = {} | ||
var _react2 = _interopRequireDefault(_react); | ||
function step(object, prev, currentDepth) { | ||
currentDepth = currentDepth ? currentDepth : 1 | ||
Object.keys(object).forEach(function(key) { | ||
var value = object[key] | ||
var isarray = opts.safe && Array.isArray(value) | ||
var type = Object.prototype.toString.call(value) | ||
var isbuffer = isBuffer(value) | ||
var isobject = ( | ||
type === "[object Object]" || | ||
type === "[object Array]" | ||
) | ||
var _reactRedux = __webpack_require__(4); | ||
var newKey = prev | ||
? prev + delimiter + key | ||
: key | ||
var _locale = __webpack_require__(0); | ||
if (!isarray && !isbuffer && isobject && Object.keys(value).length && | ||
(!opts.maxDepth || currentDepth < maxDepth)) { | ||
return step(value, newKey, currentDepth + 1) | ||
} | ||
var _utils = __webpack_require__(1); | ||
output[newKey] = value | ||
}) | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
step(target) | ||
var localize = exports.localize = function localize(localeKey) { | ||
return function (Component) { | ||
return output | ||
} | ||
var Localize = function Localize(props) { | ||
return _react2.default.createElement(Component, props); | ||
}; | ||
function unflatten(target, opts) { | ||
opts = opts || {} | ||
var mapStateToProps = function mapStateToProps(state) { | ||
var translations = (0, _locale.getTranslationsForKey)(localeKey)(state); | ||
return { | ||
currentLanguage: state.locale.currentLanguage, | ||
translate: function translate(key, data) { | ||
return (0, _utils.getLocalizedElement)(key, translations, data); | ||
} | ||
}; | ||
}; | ||
var delimiter = opts.delimiter || '.' | ||
var overwrite = opts.overwrite || false | ||
var result = {} | ||
// use cases | ||
// I have ${ variable } and another ${ variable } | ||
var isbuffer = isBuffer(target) | ||
if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') { | ||
return target | ||
} | ||
return (0, _reactRedux.connect)(mapStateToProps, null)(Localize); | ||
}; | ||
}; | ||
// safely ensure that the key is | ||
// an integer. | ||
function getkey(key) { | ||
var parsedKey = Number(key) | ||
/***/ }, | ||
/* 4 */ | ||
/***/ function(module, exports) { | ||
return ( | ||
isNaN(parsedKey) || | ||
key.indexOf('.') !== -1 | ||
) ? key | ||
: parsedKey | ||
} | ||
module.exports = __WEBPACK_EXTERNAL_MODULE_4__; | ||
Object.keys(target).forEach(function(key) { | ||
var split = key.split(delimiter) | ||
var key1 = getkey(split.shift()) | ||
var key2 = getkey(split[0]) | ||
var recipient = result | ||
while (key2 !== undefined) { | ||
var type = Object.prototype.toString.call(recipient[key1]) | ||
var isobject = ( | ||
type === "[object Object]" || | ||
type === "[object Array]" | ||
) | ||
// do not write over falsey, non-undefined values if overwrite is false | ||
if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') { | ||
return | ||
} | ||
if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) { | ||
recipient[key1] = ( | ||
typeof key2 === 'number' && | ||
!opts.object ? [] : {} | ||
) | ||
} | ||
recipient = recipient[key1] | ||
if (split.length > 0) { | ||
key1 = getkey(split.shift()) | ||
key2 = getkey(split[0]) | ||
} | ||
} | ||
// unflatten again for 'messy objects' | ||
recipient[key1] = unflatten(target[key], opts) | ||
}) | ||
return result | ||
} | ||
/***/ }, | ||
@@ -341,4 +445,25 @@ /* 5 */ | ||
module.exports = __WEBPACK_EXTERNAL_MODULE_5__; | ||
/*! | ||
* Determine if an object is a Buffer | ||
* | ||
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> | ||
* @license MIT | ||
*/ | ||
// The _isBuffer check is for Safari 5-7 support, because it's missing | ||
// Object.prototype.constructor. Remove this eventually | ||
module.exports = function (obj) { | ||
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) | ||
} | ||
function isBuffer (obj) { | ||
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) | ||
} | ||
// For Node v0.10 support. Remove this eventually. | ||
function isSlowBuffer (obj) { | ||
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) | ||
} | ||
/***/ }, | ||
@@ -352,2 +477,14 @@ /* 6 */ | ||
/* 7 */ | ||
/***/ function(module, exports) { | ||
module.exports = __WEBPACK_EXTERNAL_MODULE_7__; | ||
/***/ }, | ||
/* 8 */ | ||
/***/ function(module, exports) { | ||
module.exports = __WEBPACK_EXTERNAL_MODULE_8__; | ||
/***/ }, | ||
/* 9 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
@@ -359,5 +496,4 @@ | ||
exports.__esModule = true; | ||
exports.getTranslationsForKey = exports.setGlobalTranslations = exports.setLocalTranslations = exports.updateLanguage = exports.localeReducer = exports.localize = undefined; | ||
var _Localize = __webpack_require__(3); | ||
var _Localize = __webpack_require__(2); | ||
@@ -373,35 +509,35 @@ Object.defineProperty(exports, 'localize', { | ||
Object.defineProperty(exports, 'updateLanguage', { | ||
Object.defineProperty(exports, 'localeReducer', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.updateLanguage; | ||
return _locale.localeReducer; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'setLocalTranslations', { | ||
Object.defineProperty(exports, 'addTranslation', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.setLocalTranslations; | ||
return _locale.addTranslation; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'setGlobalTranslations', { | ||
Object.defineProperty(exports, 'setLanguages', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.setGlobalTranslations; | ||
return _locale.setLanguages; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'getTranslationsForKey', { | ||
Object.defineProperty(exports, 'setActiveLanguage', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.getTranslationsForKey; | ||
return _locale.setActiveLanguage; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'getTranslate', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.getTranslate; | ||
} | ||
}); | ||
var _locale2 = _interopRequireDefault(_locale); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
exports.localeReducer = _locale2.default; | ||
/***/ } | ||
/******/ ]); | ||
}); |
@@ -1,1 +0,7 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("react-redux"),require("redux"),require("reselect")):"function"==typeof define&&define.amd?define(["react","react-redux","redux","reselect"],t):"object"==typeof exports?exports.ReactLocalizeRedux=t(require("react"),require("react-redux"),require("redux"),require("reselect")):e.ReactLocalizeRedux=t(e.React,e.ReactRedux,e.Redux,e.Reselect)}(this,function(e,t,n,r){return function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,t),a.l=!0,a.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=7)}([function(e,t,n){"use strict";function r(){var e,t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,r=arguments[1];switch(r.type){case d:return o({},n,(e={},e[r.payload.key]=r.payload.json,e));case s:return o({},n,(t={},t[c]=r.payload,t));default:return n}}function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"en",t=arguments[1];return t.type===f?t.payload:e}t.__esModule=!0,t.getTranslationsForKey=t.setGlobalTranslations=t.setLocalTranslations=t.updateLanguage=t.UPDATE_LANGUAGE=t.SET_LOCAL_TRANSLATIONS=t.SET_GLOBAL_TRANSLATIONS=t.GLOBAL_TRANSLATIONS_KEY=t.DEFUALT_LOCALE=void 0;var o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},u=n(5),l=n(6),i=n(1),c=(t.DEFUALT_LOCALE="en",t.GLOBAL_TRANSLATIONS_KEY="global"),s=t.SET_GLOBAL_TRANSLATIONS="@@localize/SET_GLOBAL_TRANSLATIONS",d=t.SET_LOCAL_TRANSLATIONS="@@localize/SET_LOCAL_TRANSLATIONS",f=t.UPDATE_LANGUAGE="@@localize/UPDATE_LANGUAGE";t.default=(0,u.combineReducers)({currentLanguage:a,translations:r});var p=(t.updateLanguage=function(e){var t=e;return t=t?t:"en",{type:f,payload:t}},t.setLocalTranslations=function(e,t){return{type:d,payload:{key:e,json:t}}},t.setGlobalTranslations=function(e){return{type:s,payload:e}},function(e){return e.locale.currentLanguage}),L=function(e){return e.locale.translations};t.getTranslationsForKey=function(e){return(0,l.createSelector)(p,L,function(t,n){var r={},a={};return n&&(0,i.isDefinedNested)(n,c)&&(r=n.global[t]||{}),n&&(0,i.isDefinedNested)(n,e,t)&&(a=n[e][t]),o({},r,a)})}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.templater=t.isDefinedNested=t.hasHtmlTags=t.getLocalizedElement=void 0;var a=n(2),o=r(a),u=(t.getLocalizedElement=function(e,t,n){var r=t[e]||"Missing locaized: "+e,a=l(r,n);return u(a)?o.default.createElement("span",{dangerouslySetInnerHTML:{__html:a}}):o.default.createElement("span",null,a)},t.hasHtmlTags=function(e){var t=/<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/;return e.search(t)>=0}),l=(t.isDefinedNested=function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];var a=n.shift();return void 0!==e[a]&&n.reduce(function(e,t,r){return r===n.length-1?void 0!==e[t]:void 0===e?{}:e[t]},e[a])},t.templater=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};for(var n in t){var r="\\${\\s*"+n+"\\s*}",a=new RegExp(r,"gmi");e=e.replace(a,t[n])}return e})},function(t,n){t.exports=e},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.localize=void 0;var a=n(2),o=r(a),u=n(4),l=n(0),i=n(1);t.localize=function(e){return function(t){var n=function(e){return o.default.createElement(t,e)},r=function(t){var n=(0,l.getTranslationsForKey)(e)(t);return{currentLanguage:t.locale.currentLanguage,translate:function(e,t){return(0,i.getLocalizedElement)(e,n,t)}}};return(0,u.connect)(r,null)(n)}}},function(e,n){e.exports=t},function(e,t){e.exports=n},function(e,t){e.exports=r},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.getTranslationsForKey=t.setGlobalTranslations=t.setLocalTranslations=t.updateLanguage=t.localeReducer=t.localize=void 0;var a=n(3);Object.defineProperty(t,"localize",{enumerable:!0,get:function(){return a.localize}});var o=n(0);Object.defineProperty(t,"updateLanguage",{enumerable:!0,get:function(){return o.updateLanguage}}),Object.defineProperty(t,"setLocalTranslations",{enumerable:!0,get:function(){return o.setLocalTranslations}}),Object.defineProperty(t,"setGlobalTranslations",{enumerable:!0,get:function(){return o.setGlobalTranslations}}),Object.defineProperty(t,"getTranslationsForKey",{enumerable:!0,get:function(){return o.getTranslationsForKey}});var u=r(o);t.localeReducer=u.default}])}); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("react-redux"),require("redux"),require("reselect")):"function"==typeof define&&define.amd?define(["react","react-redux","redux","reselect"],t):"object"==typeof exports?exports.ReactLocalizeRedux=t(require("react"),require("react-redux"),require("redux"),require("reselect")):e.ReactLocalizeRedux=t(e.React,e.ReactRedux,e.Redux,e.Reselect)}(this,function(e,t,n,r){return function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,t),a.l=!0,a.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=9)}([function(e,t,n){"use strict";function r(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=function(){switch(t.type){case d:var n=t.payload.languageCodes,r=t.payload.activeLanguage||n[0],a=n.indexOf(r);return{v:n.map(function(e,t){var n=t===a;return{code:e,active:n}})};case g:return{v:e.map(function(e){return e.code===t.payload.languageCode?u({},e,{active:!0}):u({},e,{active:!1})})};default:return{v:e}}}();if("object"===("undefined"==typeof n?"undefined":o(n)))return n.v}function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];switch(t.type){case f:return u({},e,(0,i.flatten)(t.payload.translation,{safe:!0}));default:return e}}t.__esModule=!0,t.getTranslate=t.getTranslationsForActiveLanguage=t.customeEqualSelector=t.getActiveLanguage=t.getLanguages=t.getTranslations=t.setActiveLanguage=t.setLanguages=t.addTranslation=t.localeReducer=t.TRANSLATE=t.SET_ACTIVE_LANGUAGE=t.SET_LANGUAGES=t.ADD_TRANSLATION=void 0;var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},u=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e};t.languages=r,t.translations=a;var c=n(7),i=n(4),l=n(8),s=n(3),f=t.ADD_TRANSLATION="@@localize/ADD_TRANSLATION",d=t.SET_LANGUAGES="@@localize/SET_LANGUAGES",g=t.SET_ACTIVE_LANGUAGE="@@localize/SET_ACTIVE_LANGUAGE",p=(t.TRANSLATE="@@localize/TRANSLATE",t.localeReducer=(0,c.combineReducers)({languages:r,translations:a}),t.addTranslation=function(e){return{type:f,payload:{translation:e}}},t.setLanguages=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return{type:d,payload:{languageCodes:e,activeLanguage:t}}},t.setActiveLanguage=function(e){return{type:g,payload:{languageCode:e}}},t.getTranslations=function(e){return e.translations}),v=t.getLanguages=function(e){return e.languages},y=t.getActiveLanguage=function(e){return v(e).find(function(e){return e.active===!0})},b=t.customeEqualSelector=(0,l.createSelectorCreator)(l.defaultMemoize,function(e,t){var n=!(Array.isArray(e)||"code,active"===Object.keys(e).toString());return n&&(t=Object.keys(t).toString(),e=Object.keys(e).toString()),t===e}),A=t.getTranslationsForActiveLanguage=b(y,v,p,function(e,t,n){var r=e.code,a=(0,s.getIndexForLanguageCode)(r,t);return Object.keys(n).reduce(function(e,t){var r;return u({},e,(r={},r[t]=n[t][a],r))},{})});t.getTranslate=function(e){var t=A(e);return function(e,n){return(0,s.getLocalizedElement)(e,t,n)}}},function(t,n){t.exports=e},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.localize=void 0;var a=n(1),o=(r(a),n(6)),u=n(0);t.localize=function(e){var t=function(e){return{currentLanguage:(0,u.getActiveLanguage)(e).code,translate:(0,u.getTranslate)(e)}};return(0,o.connect)(t,null)(e)}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.getIndexForLanguageCode=t.templater=t.hasHtmlTags=t.getLocalizedElement=void 0;var a=n(1),o=r(a),u=(t.getLocalizedElement=function(e,t,n){var r=t[e]||"Missing locaized: "+e,a=c(r,n);return u(a)?o.default.createElement("span",{dangerouslySetInnerHTML:{__html:a}}):o.default.createElement("span",null,a)},t.hasHtmlTags=function(e){var t=/<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/;return e.search(t)>=0}),c=t.templater=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};for(var n in t){var r="\\${\\s*"+n+"\\s*}",a=new RegExp(r,"gmi");e=e.replace(a,t[n])}return e};t.getIndexForLanguageCode=function(e,t){return t.map(function(e){return e.code}).indexOf(e)}},function(e,t,n){function r(e,t){function n(e,c,i){i=i?i:1,Object.keys(e).forEach(function(l){var s=e[l],f=t.safe&&Array.isArray(s),d=Object.prototype.toString.call(s),g=o(s),p="[object Object]"===d||"[object Array]"===d,v=c?c+r+l:l;return!f&&!g&&p&&Object.keys(s).length&&(!t.maxDepth||i<a)?n(s,v,i+1):void(u[v]=s)})}t=t||{};var r=t.delimiter||".",a=t.maxDepth,u={};return n(e),u}function a(e,t){function n(e){var t=Number(e);return isNaN(t)||e.indexOf(".")!==-1?e:t}t=t||{};var r=t.delimiter||".",u=t.overwrite||!1,c={},i=o(e);return i||"[object Object]"!==Object.prototype.toString.call(e)?e:(Object.keys(e).forEach(function(o){for(var i=o.split(r),l=n(i.shift()),s=n(i[0]),f=c;void 0!==s;){var d=Object.prototype.toString.call(f[l]),g="[object Object]"===d||"[object Array]"===d;if(!u&&!g&&"undefined"!=typeof f[l])return;(u&&!g||!u&&null==f[l])&&(f[l]="number"!=typeof s||t.object?{}:[]),f=f[l],i.length>0&&(l=n(i.shift()),s=n(i[0]))}f[l]=a(e[o],t)}),c)}var o=n(5);e.exports=r;r.flatten=r,r.unflatten=a},function(e,t){function n(e){return!!e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function r(e){return"function"==typeof e.readFloatLE&&"function"==typeof e.slice&&n(e.slice(0,0))}/*! | ||
* Determine if an object is a Buffer | ||
* | ||
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> | ||
* @license MIT | ||
*/ | ||
e.exports=function(e){return null!=e&&(n(e)||r(e)||!!e._isBuffer)}},function(e,n){e.exports=t},function(e,t){e.exports=n},function(e,t){e.exports=r},function(e,t,n){"use strict";t.__esModule=!0;var r=n(2);Object.defineProperty(t,"localize",{enumerable:!0,get:function(){return r.localize}});var a=n(0);Object.defineProperty(t,"localeReducer",{enumerable:!0,get:function(){return a.localeReducer}}),Object.defineProperty(t,"addTranslation",{enumerable:!0,get:function(){return a.addTranslation}}),Object.defineProperty(t,"setLanguages",{enumerable:!0,get:function(){return a.setLanguages}}),Object.defineProperty(t,"setActiveLanguage",{enumerable:!0,get:function(){return a.setActiveLanguage}}),Object.defineProperty(t,"getTranslate",{enumerable:!0,get:function(){return a.getTranslate}})}])}); |
@@ -14,28 +14,14 @@ 'use strict'; | ||
var _utils = require('../utils'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var localize = exports.localize = function localize(localeKey) { | ||
return function (Component) { | ||
var localize = exports.localize = function localize(Component) { | ||
var Localize = function Localize(props) { | ||
return _react2.default.createElement(Component, props); | ||
var mapStateToProps = function mapStateToProps(state) { | ||
return { | ||
currentLanguage: (0, _locale.getActiveLanguage)(state).code, | ||
translate: (0, _locale.getTranslate)(state) | ||
}; | ||
}; | ||
var mapStateToProps = function mapStateToProps(state) { | ||
var translations = (0, _locale.getTranslationsForKey)(localeKey)(state); | ||
return { | ||
currentLanguage: state.locale.currentLanguage, | ||
translate: function translate(key, data) { | ||
return (0, _utils.getLocalizedElement)(key, translations, data); | ||
} | ||
}; | ||
}; | ||
// use cases | ||
// I have ${ variable } and another ${ variable } | ||
return (0, _reactRedux.connect)(mapStateToProps, null)(Localize); | ||
}; | ||
return (0, _reactRedux.connect)(mapStateToProps, null)(Component); | ||
}; |
'use strict'; | ||
exports.__esModule = true; | ||
exports.getTranslationsForKey = exports.setGlobalTranslations = exports.setLocalTranslations = exports.updateLanguage = exports.localeReducer = exports.localize = undefined; | ||
@@ -17,31 +16,31 @@ var _Localize = require('./containers/Localize'); | ||
Object.defineProperty(exports, 'updateLanguage', { | ||
Object.defineProperty(exports, 'localeReducer', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.updateLanguage; | ||
return _locale.localeReducer; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'setLocalTranslations', { | ||
Object.defineProperty(exports, 'addTranslation', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.setLocalTranslations; | ||
return _locale.addTranslation; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'setGlobalTranslations', { | ||
Object.defineProperty(exports, 'setLanguages', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.setGlobalTranslations; | ||
return _locale.setLanguages; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'getTranslationsForKey', { | ||
Object.defineProperty(exports, 'setActiveLanguage', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.getTranslationsForKey; | ||
return _locale.setActiveLanguage; | ||
} | ||
}); | ||
var _locale2 = _interopRequireDefault(_locale); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
exports.localeReducer = _locale2.default; | ||
Object.defineProperty(exports, 'getTranslate', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.getTranslate; | ||
} | ||
}); |
'use strict'; | ||
exports.__esModule = true; | ||
exports.getTranslationsForKey = exports.setGlobalTranslations = exports.setLocalTranslations = exports.updateLanguage = exports.UPDATE_LANGUAGE = exports.SET_LOCAL_TRANSLATIONS = exports.SET_GLOBAL_TRANSLATIONS = exports.GLOBAL_TRANSLATIONS_KEY = exports.DEFUALT_LOCALE = undefined; | ||
exports.getTranslate = exports.getTranslationsForActiveLanguage = exports.customeEqualSelector = exports.getActiveLanguage = exports.getLanguages = exports.getTranslations = exports.setActiveLanguage = exports.setLanguages = exports.addTranslation = exports.localeReducer = exports.TRANSLATE = exports.SET_ACTIVE_LANGUAGE = exports.SET_LANGUAGES = exports.ADD_TRANSLATION = undefined; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
// import { LANG, DEFUALT_LANG } from 'store/constants'; | ||
exports.languages = languages; | ||
exports.translations = translations; | ||
var _redux = require('redux'); | ||
var _flat = require('flat'); | ||
var _reselect = require('reselect'); | ||
@@ -16,24 +21,49 @@ | ||
var DEFUALT_LOCALE = exports.DEFUALT_LOCALE = 'en'; | ||
var GLOBAL_TRANSLATIONS_KEY = exports.GLOBAL_TRANSLATIONS_KEY = 'global'; | ||
var ADD_TRANSLATION = exports.ADD_TRANSLATION = '@@localize/ADD_TRANSLATION'; | ||
var SET_LANGUAGES = exports.SET_LANGUAGES = '@@localize/SET_LANGUAGES'; | ||
var SET_ACTIVE_LANGUAGE = exports.SET_ACTIVE_LANGUAGE = '@@localize/SET_ACTIVE_LANGUAGE'; | ||
var TRANSLATE = exports.TRANSLATE = '@@localize/TRANSLATE'; | ||
// export const FETCH_LOCALE_REQUEST = '@@localize/FETCH_LOCALE_REQUEST'; | ||
// export const FETCH_LOCALE_SUCCESS = '@@localize/FETCH_LOCALE_SUCCESS'; | ||
// export const FETCH_LOCALE_ERROR = '@@localize/FETCH_LOCALE_ERROR'; | ||
/** | ||
* REDUCERS | ||
*/ | ||
function languages() { | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; | ||
var action = arguments[1]; | ||
var SET_GLOBAL_TRANSLATIONS = exports.SET_GLOBAL_TRANSLATIONS = '@@localize/SET_GLOBAL_TRANSLATIONS'; | ||
var SET_LOCAL_TRANSLATIONS = exports.SET_LOCAL_TRANSLATIONS = '@@localize/SET_LOCAL_TRANSLATIONS'; | ||
var UPDATE_LANGUAGE = exports.UPDATE_LANGUAGE = '@@localize/UPDATE_LANGUAGE'; | ||
var _ret = function () { | ||
switch (action.type) { | ||
case SET_LANGUAGES: | ||
var languageCodes = action.payload.languageCodes; | ||
var activeLanguage = action.payload.activeLanguage || languageCodes[0]; | ||
var activeIndex = languageCodes.indexOf(activeLanguage); | ||
return { | ||
v: languageCodes.map(function (code, index) { | ||
var isActive = index === activeIndex; | ||
return { code: code, active: isActive }; | ||
}) | ||
}; | ||
case SET_ACTIVE_LANGUAGE: | ||
return { | ||
v: state.map(function (language) { | ||
return language.code === action.payload.languageCode ? _extends({}, language, { active: true }) : _extends({}, language, { active: false }); | ||
}) | ||
}; | ||
default: | ||
return { | ||
v: state | ||
}; | ||
} | ||
}(); | ||
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; | ||
} | ||
function translations() { | ||
var _extends2, _extends3; | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var action = arguments[1]; | ||
switch (action.type) { | ||
case SET_LOCAL_TRANSLATIONS: | ||
return _extends({}, state, (_extends2 = {}, _extends2[action.payload.key] = action.payload.json, _extends2)); | ||
case SET_GLOBAL_TRANSLATIONS: | ||
return _extends({}, state, (_extends3 = {}, _extends3[GLOBAL_TRANSLATIONS_KEY] = action.payload, _extends3)); | ||
case ADD_TRANSLATION: | ||
return _extends({}, state, (0, _flat.flatten)(action.payload.translation, { safe: true })); | ||
default: | ||
@@ -44,67 +74,73 @@ return state; | ||
function currentLanguage() { | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'en'; | ||
var action = arguments[1]; | ||
var localeReducer = exports.localeReducer = (0, _redux.combineReducers)({ languages: languages, translations: translations }); | ||
return action.type === UPDATE_LANGUAGE ? action.payload : state; | ||
} | ||
exports.default = (0, _redux.combineReducers)({ | ||
currentLanguage: currentLanguage, | ||
translations: translations | ||
}); | ||
var updateLanguage = exports.updateLanguage = function updateLanguage(language) { | ||
var selectedLanguage = language; | ||
selectedLanguage = selectedLanguage ? selectedLanguage : 'en'; | ||
/** | ||
* ACTION CREATORS | ||
*/ | ||
var addTranslation = exports.addTranslation = function addTranslation(translation) { | ||
return { | ||
type: UPDATE_LANGUAGE, | ||
payload: selectedLanguage | ||
type: ADD_TRANSLATION, | ||
payload: { translation: translation } | ||
}; | ||
}; | ||
var setLocalTranslations = exports.setLocalTranslations = function setLocalTranslations(key, json) { | ||
var setLanguages = exports.setLanguages = function setLanguages(languageCodes) { | ||
var activeLanguage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
return { | ||
type: SET_LOCAL_TRANSLATIONS, | ||
payload: { key: key, json: json } | ||
type: SET_LANGUAGES, | ||
payload: { languageCodes: languageCodes, activeLanguage: activeLanguage } | ||
}; | ||
}; | ||
var setGlobalTranslations = exports.setGlobalTranslations = function setGlobalTranslations(json) { | ||
var setActiveLanguage = exports.setActiveLanguage = function setActiveLanguage(languageCode) { | ||
return { | ||
type: SET_GLOBAL_TRANSLATIONS, | ||
payload: json | ||
type: SET_ACTIVE_LANGUAGE, | ||
payload: { languageCode: languageCode } | ||
}; | ||
}; | ||
// export const fetchLocaleJson = (json, key): IApiActionType => { | ||
// return { | ||
// type: [FETCH_LOCALE_REQUEST, FETCH_LOCALE_SUCCESS, FETCH_LOCALE_ERROR], | ||
// shouldCallApi: (state) => true, | ||
// callApi: () => Promise.resolve(json), | ||
// payload: { key } | ||
// }; | ||
// }; | ||
var getCurrentLanguage = function getCurrentLanguage(state) { | ||
return state.locale.currentLanguage; | ||
/** | ||
* SELECTORS | ||
*/ | ||
var getTranslations = exports.getTranslations = function getTranslations(state) { | ||
return state.translations; | ||
}; | ||
var getTranslations = function getTranslations(state) { | ||
return state.locale.translations; | ||
var getLanguages = exports.getLanguages = function getLanguages(state) { | ||
return state.languages; | ||
}; | ||
var getActiveLanguage = exports.getActiveLanguage = function getActiveLanguage(state) { | ||
return getLanguages(state).find(function (language) { | ||
return language.active === true; | ||
}); | ||
}; | ||
var getTranslationsForKey = exports.getTranslationsForKey = function getTranslationsForKey(key) { | ||
return (0, _reselect.createSelector)(getCurrentLanguage, getTranslations, function (currentLanguage, translations) { | ||
var globalTranslations = {}; | ||
var localTranslations = {}; | ||
var customeEqualSelector = exports.customeEqualSelector = (0, _reselect.createSelectorCreator)(_reselect.defaultMemoize, function (cur, prev) { | ||
var isTranslationsData = !(Array.isArray(cur) || Object.keys(cur).toString() === 'code,active'); | ||
if (translations && (0, _utils.isDefinedNested)(translations, GLOBAL_TRANSLATIONS_KEY)) { | ||
globalTranslations = translations.global[currentLanguage] || {}; | ||
} | ||
// for translations data use keys for comparison | ||
if (isTranslationsData) { | ||
prev = Object.keys(prev).toString(); | ||
cur = Object.keys(cur).toString(); | ||
} | ||
if (translations && (0, _utils.isDefinedNested)(translations, key, currentLanguage)) { | ||
localTranslations = translations[key][currentLanguage]; | ||
} | ||
return prev === cur; | ||
}); | ||
return _extends({}, globalTranslations, localTranslations); | ||
}); | ||
var getTranslationsForActiveLanguage = exports.getTranslationsForActiveLanguage = customeEqualSelector(getActiveLanguage, getLanguages, getTranslations, function (activeLanguage, languages, translations) { | ||
var activeLanguageCode = activeLanguage.code; | ||
var activeLanguageIndex = (0, _utils.getIndexForLanguageCode)(activeLanguageCode, languages); | ||
return Object.keys(translations).reduce(function (prev, key) { | ||
var _extends2; | ||
return _extends({}, prev, (_extends2 = {}, _extends2[key] = translations[key][activeLanguageIndex], _extends2)); | ||
}, {}); | ||
}); | ||
var getTranslate = exports.getTranslate = function getTranslate(state) { | ||
var translations = getTranslationsForActiveLanguage(state); | ||
return function (key, data) { | ||
return (0, _utils.getLocalizedElement)(key, translations, data); | ||
}; | ||
}; |
'use strict'; | ||
exports.__esModule = true; | ||
exports.templater = exports.isDefinedNested = exports.hasHtmlTags = exports.getLocalizedElement = undefined; | ||
exports.getIndexForLanguageCode = exports.templater = exports.hasHtmlTags = exports.getLocalizedElement = undefined; | ||
@@ -28,31 +28,2 @@ var _react = require('react'); | ||
/** | ||
* @func isDefinedNested | ||
* @desc Check if a nested property exists on an object. | ||
* @param {Object} target The object that you want to test against | ||
* @param {string} props The nested props you want verify are defined on target | ||
* @example | ||
* // checks if theObject.prop1.prop2.prop3 is defined | ||
* isDefinedNested(theObject, 'prop1', 'prop2', 'prop3') | ||
*/ | ||
var isDefinedNested = exports.isDefinedNested = function isDefinedNested(target) { | ||
for (var _len = arguments.length, props = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
props[_key - 1] = arguments[_key]; | ||
} | ||
var firstProp = props.shift(); | ||
if (target[firstProp] === undefined) { | ||
return false; | ||
} | ||
return props.reduce(function (prev, cur, index) { | ||
if (index === props.length - 1) { | ||
return prev[cur] !== undefined; | ||
} else { | ||
return prev === undefined ? {} : prev[cur]; | ||
} | ||
}, target[firstProp]); | ||
}; | ||
/** | ||
* @func templater | ||
@@ -73,2 +44,8 @@ * @desc A poor mans template parser | ||
return strings; | ||
}; | ||
var getIndexForLanguageCode = exports.getIndexForLanguageCode = function getIndexForLanguageCode(code, languages) { | ||
return languages.map(function (language) { | ||
return language.code; | ||
}).indexOf(code); | ||
}; |
@@ -14,28 +14,14 @@ 'use strict'; | ||
var _utils = require('../utils'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var localize = exports.localize = function localize(localeKey) { | ||
return function (Component) { | ||
var localize = exports.localize = function localize(Component) { | ||
var Localize = function Localize(props) { | ||
return _react2.default.createElement(Component, props); | ||
var mapStateToProps = function mapStateToProps(state) { | ||
return { | ||
currentLanguage: (0, _locale.getActiveLanguage)(state).code, | ||
translate: (0, _locale.getTranslate)(state) | ||
}; | ||
}; | ||
var mapStateToProps = function mapStateToProps(state) { | ||
var translations = (0, _locale.getTranslationsForKey)(localeKey)(state); | ||
return { | ||
currentLanguage: state.locale.currentLanguage, | ||
translate: function translate(key, data) { | ||
return (0, _utils.getLocalizedElement)(key, translations, data); | ||
} | ||
}; | ||
}; | ||
// use cases | ||
// I have ${ variable } and another ${ variable } | ||
return (0, _reactRedux.connect)(mapStateToProps, null)(Localize); | ||
}; | ||
return (0, _reactRedux.connect)(mapStateToProps, null)(Component); | ||
}; |
'use strict'; | ||
exports.__esModule = true; | ||
exports.getTranslationsForKey = exports.setGlobalTranslations = exports.setLocalTranslations = exports.updateLanguage = exports.localeReducer = exports.localize = undefined; | ||
@@ -17,31 +16,31 @@ var _Localize = require('./containers/Localize'); | ||
Object.defineProperty(exports, 'updateLanguage', { | ||
Object.defineProperty(exports, 'localeReducer', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.updateLanguage; | ||
return _locale.localeReducer; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'setLocalTranslations', { | ||
Object.defineProperty(exports, 'addTranslation', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.setLocalTranslations; | ||
return _locale.addTranslation; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'setGlobalTranslations', { | ||
Object.defineProperty(exports, 'setLanguages', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.setGlobalTranslations; | ||
return _locale.setLanguages; | ||
} | ||
}); | ||
Object.defineProperty(exports, 'getTranslationsForKey', { | ||
Object.defineProperty(exports, 'setActiveLanguage', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.getTranslationsForKey; | ||
return _locale.setActiveLanguage; | ||
} | ||
}); | ||
var _locale2 = _interopRequireDefault(_locale); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
exports.localeReducer = _locale2.default; | ||
Object.defineProperty(exports, 'getTranslate', { | ||
enumerable: true, | ||
get: function get() { | ||
return _locale.getTranslate; | ||
} | ||
}); |
'use strict'; | ||
exports.__esModule = true; | ||
exports.getTranslationsForKey = exports.setGlobalTranslations = exports.setLocalTranslations = exports.updateLanguage = exports.UPDATE_LANGUAGE = exports.SET_LOCAL_TRANSLATIONS = exports.SET_GLOBAL_TRANSLATIONS = exports.GLOBAL_TRANSLATIONS_KEY = exports.DEFUALT_LOCALE = undefined; | ||
exports.getTranslate = exports.getTranslationsForActiveLanguage = exports.customeEqualSelector = exports.getActiveLanguage = exports.getLanguages = exports.getTranslations = exports.setActiveLanguage = exports.setLanguages = exports.addTranslation = exports.localeReducer = exports.TRANSLATE = exports.SET_ACTIVE_LANGUAGE = exports.SET_LANGUAGES = exports.ADD_TRANSLATION = undefined; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
// import { LANG, DEFUALT_LANG } from 'store/constants'; | ||
exports.languages = languages; | ||
exports.translations = translations; | ||
var _redux = require('redux'); | ||
var _flat = require('flat'); | ||
var _reselect = require('reselect'); | ||
@@ -16,24 +21,49 @@ | ||
var DEFUALT_LOCALE = exports.DEFUALT_LOCALE = 'en'; | ||
var GLOBAL_TRANSLATIONS_KEY = exports.GLOBAL_TRANSLATIONS_KEY = 'global'; | ||
var ADD_TRANSLATION = exports.ADD_TRANSLATION = '@@localize/ADD_TRANSLATION'; | ||
var SET_LANGUAGES = exports.SET_LANGUAGES = '@@localize/SET_LANGUAGES'; | ||
var SET_ACTIVE_LANGUAGE = exports.SET_ACTIVE_LANGUAGE = '@@localize/SET_ACTIVE_LANGUAGE'; | ||
var TRANSLATE = exports.TRANSLATE = '@@localize/TRANSLATE'; | ||
// export const FETCH_LOCALE_REQUEST = '@@localize/FETCH_LOCALE_REQUEST'; | ||
// export const FETCH_LOCALE_SUCCESS = '@@localize/FETCH_LOCALE_SUCCESS'; | ||
// export const FETCH_LOCALE_ERROR = '@@localize/FETCH_LOCALE_ERROR'; | ||
/** | ||
* REDUCERS | ||
*/ | ||
function languages() { | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; | ||
var action = arguments[1]; | ||
var SET_GLOBAL_TRANSLATIONS = exports.SET_GLOBAL_TRANSLATIONS = '@@localize/SET_GLOBAL_TRANSLATIONS'; | ||
var SET_LOCAL_TRANSLATIONS = exports.SET_LOCAL_TRANSLATIONS = '@@localize/SET_LOCAL_TRANSLATIONS'; | ||
var UPDATE_LANGUAGE = exports.UPDATE_LANGUAGE = '@@localize/UPDATE_LANGUAGE'; | ||
var _ret = function () { | ||
switch (action.type) { | ||
case SET_LANGUAGES: | ||
var languageCodes = action.payload.languageCodes; | ||
var activeLanguage = action.payload.activeLanguage || languageCodes[0]; | ||
var activeIndex = languageCodes.indexOf(activeLanguage); | ||
return { | ||
v: languageCodes.map(function (code, index) { | ||
var isActive = index === activeIndex; | ||
return { code: code, active: isActive }; | ||
}) | ||
}; | ||
case SET_ACTIVE_LANGUAGE: | ||
return { | ||
v: state.map(function (language) { | ||
return language.code === action.payload.languageCode ? _extends({}, language, { active: true }) : _extends({}, language, { active: false }); | ||
}) | ||
}; | ||
default: | ||
return { | ||
v: state | ||
}; | ||
} | ||
}(); | ||
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; | ||
} | ||
function translations() { | ||
var _extends2, _extends3; | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var action = arguments[1]; | ||
switch (action.type) { | ||
case SET_LOCAL_TRANSLATIONS: | ||
return _extends({}, state, (_extends2 = {}, _extends2[action.payload.key] = action.payload.json, _extends2)); | ||
case SET_GLOBAL_TRANSLATIONS: | ||
return _extends({}, state, (_extends3 = {}, _extends3[GLOBAL_TRANSLATIONS_KEY] = action.payload, _extends3)); | ||
case ADD_TRANSLATION: | ||
return _extends({}, state, (0, _flat.flatten)(action.payload.translation, { safe: true })); | ||
default: | ||
@@ -44,67 +74,73 @@ return state; | ||
function currentLanguage() { | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'en'; | ||
var action = arguments[1]; | ||
var localeReducer = exports.localeReducer = (0, _redux.combineReducers)({ languages: languages, translations: translations }); | ||
return action.type === UPDATE_LANGUAGE ? action.payload : state; | ||
} | ||
exports.default = (0, _redux.combineReducers)({ | ||
currentLanguage: currentLanguage, | ||
translations: translations | ||
}); | ||
var updateLanguage = exports.updateLanguage = function updateLanguage(language) { | ||
var selectedLanguage = language; | ||
selectedLanguage = selectedLanguage ? selectedLanguage : 'en'; | ||
/** | ||
* ACTION CREATORS | ||
*/ | ||
var addTranslation = exports.addTranslation = function addTranslation(translation) { | ||
return { | ||
type: UPDATE_LANGUAGE, | ||
payload: selectedLanguage | ||
type: ADD_TRANSLATION, | ||
payload: { translation: translation } | ||
}; | ||
}; | ||
var setLocalTranslations = exports.setLocalTranslations = function setLocalTranslations(key, json) { | ||
var setLanguages = exports.setLanguages = function setLanguages(languageCodes) { | ||
var activeLanguage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
return { | ||
type: SET_LOCAL_TRANSLATIONS, | ||
payload: { key: key, json: json } | ||
type: SET_LANGUAGES, | ||
payload: { languageCodes: languageCodes, activeLanguage: activeLanguage } | ||
}; | ||
}; | ||
var setGlobalTranslations = exports.setGlobalTranslations = function setGlobalTranslations(json) { | ||
var setActiveLanguage = exports.setActiveLanguage = function setActiveLanguage(languageCode) { | ||
return { | ||
type: SET_GLOBAL_TRANSLATIONS, | ||
payload: json | ||
type: SET_ACTIVE_LANGUAGE, | ||
payload: { languageCode: languageCode } | ||
}; | ||
}; | ||
// export const fetchLocaleJson = (json, key): IApiActionType => { | ||
// return { | ||
// type: [FETCH_LOCALE_REQUEST, FETCH_LOCALE_SUCCESS, FETCH_LOCALE_ERROR], | ||
// shouldCallApi: (state) => true, | ||
// callApi: () => Promise.resolve(json), | ||
// payload: { key } | ||
// }; | ||
// }; | ||
var getCurrentLanguage = function getCurrentLanguage(state) { | ||
return state.locale.currentLanguage; | ||
/** | ||
* SELECTORS | ||
*/ | ||
var getTranslations = exports.getTranslations = function getTranslations(state) { | ||
return state.translations; | ||
}; | ||
var getTranslations = function getTranslations(state) { | ||
return state.locale.translations; | ||
var getLanguages = exports.getLanguages = function getLanguages(state) { | ||
return state.languages; | ||
}; | ||
var getActiveLanguage = exports.getActiveLanguage = function getActiveLanguage(state) { | ||
return getLanguages(state).find(function (language) { | ||
return language.active === true; | ||
}); | ||
}; | ||
var getTranslationsForKey = exports.getTranslationsForKey = function getTranslationsForKey(key) { | ||
return (0, _reselect.createSelector)(getCurrentLanguage, getTranslations, function (currentLanguage, translations) { | ||
var globalTranslations = {}; | ||
var localTranslations = {}; | ||
var customeEqualSelector = exports.customeEqualSelector = (0, _reselect.createSelectorCreator)(_reselect.defaultMemoize, function (cur, prev) { | ||
var isTranslationsData = !(Array.isArray(cur) || Object.keys(cur).toString() === 'code,active'); | ||
if (translations && (0, _utils.isDefinedNested)(translations, GLOBAL_TRANSLATIONS_KEY)) { | ||
globalTranslations = translations.global[currentLanguage] || {}; | ||
} | ||
// for translations data use keys for comparison | ||
if (isTranslationsData) { | ||
prev = Object.keys(prev).toString(); | ||
cur = Object.keys(cur).toString(); | ||
} | ||
if (translations && (0, _utils.isDefinedNested)(translations, key, currentLanguage)) { | ||
localTranslations = translations[key][currentLanguage]; | ||
} | ||
return prev === cur; | ||
}); | ||
return _extends({}, globalTranslations, localTranslations); | ||
}); | ||
var getTranslationsForActiveLanguage = exports.getTranslationsForActiveLanguage = customeEqualSelector(getActiveLanguage, getLanguages, getTranslations, function (activeLanguage, languages, translations) { | ||
var activeLanguageCode = activeLanguage.code; | ||
var activeLanguageIndex = (0, _utils.getIndexForLanguageCode)(activeLanguageCode, languages); | ||
return Object.keys(translations).reduce(function (prev, key) { | ||
var _extends2; | ||
return _extends({}, prev, (_extends2 = {}, _extends2[key] = translations[key][activeLanguageIndex], _extends2)); | ||
}, {}); | ||
}); | ||
var getTranslate = exports.getTranslate = function getTranslate(state) { | ||
var translations = getTranslationsForActiveLanguage(state); | ||
return function (key, data) { | ||
return (0, _utils.getLocalizedElement)(key, translations, data); | ||
}; | ||
}; |
'use strict'; | ||
exports.__esModule = true; | ||
exports.templater = exports.isDefinedNested = exports.hasHtmlTags = exports.getLocalizedElement = undefined; | ||
exports.getIndexForLanguageCode = exports.templater = exports.hasHtmlTags = exports.getLocalizedElement = undefined; | ||
@@ -28,31 +28,2 @@ var _react = require('react'); | ||
/** | ||
* @func isDefinedNested | ||
* @desc Check if a nested property exists on an object. | ||
* @param {Object} target The object that you want to test against | ||
* @param {string} props The nested props you want verify are defined on target | ||
* @example | ||
* // checks if theObject.prop1.prop2.prop3 is defined | ||
* isDefinedNested(theObject, 'prop1', 'prop2', 'prop3') | ||
*/ | ||
var isDefinedNested = exports.isDefinedNested = function isDefinedNested(target) { | ||
for (var _len = arguments.length, props = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
props[_key - 1] = arguments[_key]; | ||
} | ||
var firstProp = props.shift(); | ||
if (target[firstProp] === undefined) { | ||
return false; | ||
} | ||
return props.reduce(function (prev, cur, index) { | ||
if (index === props.length - 1) { | ||
return prev[cur] !== undefined; | ||
} else { | ||
return prev === undefined ? {} : prev[cur]; | ||
} | ||
}, target[firstProp]); | ||
}; | ||
/** | ||
* @func templater | ||
@@ -73,2 +44,8 @@ * @desc A poor mans template parser | ||
return strings; | ||
}; | ||
var getIndexForLanguageCode = exports.getIndexForLanguageCode = function getIndexForLanguageCode(code, languages) { | ||
return languages.map(function (language) { | ||
return language.code; | ||
}).indexOf(code); | ||
}; |
{ | ||
"name": "react-localize-redux", | ||
"version": "1.1.2", | ||
"version": "2.0.0", | ||
"description": "Dead simple localization for your React/Redux components", | ||
@@ -71,3 +71,3 @@ "main": "lib/index", | ||
"html-webpack-plugin": "^2.24.1", | ||
"jest": "^18.0.0", | ||
"jest": "^20.0.4", | ||
"json-loader": "^0.5.4", | ||
@@ -82,2 +82,3 @@ "progress-bar-webpack-plugin": "^1.9.1", | ||
"redux-devtools": "^3.3.1", | ||
"redux-devtools-extension": "^2.13.2", | ||
"redux-mock-store": "^1.2.1", | ||
@@ -93,3 +94,3 @@ "reselect": "^2.5.4", | ||
"verbose": true, | ||
"testPathDirs": [ | ||
"roots": [ | ||
"tests/" | ||
@@ -101,3 +102,6 @@ ], | ||
] | ||
}, | ||
"dependencies": { | ||
"flat": "^2.0.1" | ||
} | ||
} |
337
README.md
@@ -1,29 +0,26 @@ | ||
# react-localize-redux | ||
<h3 align="center"> | ||
React Localize Redux | ||
</h3> | ||
[![Build Status](https://travis-ci.org/ryandrewjohnson/react-localize-redux.svg?branch=master)](https://travis-ci.org/ryandrewjohnson/react-localize-redux) | ||
<p align="center"> | ||
A collection of helpers for managing localized content in your React/Redux application. | ||
</p> | ||
A HoC (higher-order component) to add multi-language support to your React/Redux components. | ||
* Supports multiple languages | ||
* Provides components with global and component specific translations | ||
* Will render HTML tags included in translation copy | ||
* With webpack code splitting translation json can be bundled with their component | ||
<p align="center"> | ||
<a href="https://www.npmjs.com/package/react-localize-redux"><img src="https://img.shields.io/npm/dm/react-localize-redux.svg?style=flat-square"></a> | ||
<a href="https://travis-ci.org/ryandrewjohnson/react-localize-redux"><img src="https://img.shields.io/travis/ryandrewjohnson/react-localize-redux/master.svg?style=flat-square"></a> | ||
</p> | ||
## Table of Contents | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Bundle translations with Webpack and react-router](#localize-translationid--wrappedcomponent-) | ||
- [Getting Started](#getting-started) | ||
- [Features](#features) | ||
- [API](#api) | ||
- [Introduction to react-localize-redux](https://medium.com/@ryandrewjohnson/adding-multi-language-support-to-your-react-redux-app-cf6e64250050#.jmxxptvpu) | ||
- [Migrating from v1 to v2?](MIGRATING.md) | ||
## Installation | ||
The following dependencies are required: | ||
* [react](https://facebook.github.io/react/) | ||
* [redux](https://github.com/reactjs/redux) | ||
* [react-redux](https://github.com/reactjs/react-redux) | ||
* [reselect](https://github.com/reactjs/reselect) | ||
``` | ||
@@ -33,22 +30,12 @@ npm install react-localize-redux --save | ||
## Usage | ||
## Getting Started | ||
Add the `localeReducer` to your app's redux store. This will contain all translations data as well as the setting for current language. | ||
### 1. Add `localeReducer` to redux store. | ||
```javascript | ||
import React from 'react'; | ||
import { createStore, combineReducers } from 'redux'; | ||
import ReactDOM from 'react-dom'; | ||
import { Store } from 'redux'; | ||
import { Provider } from 'react-redux'; | ||
... | ||
import { localeReducer } from 'react-localize-redux'; | ||
const ROOT_NODE = document.getElementById('root'); | ||
const store = createStore(localeReducer); | ||
const store = createStore( | ||
combineReducers({ | ||
locale: localeReducer | ||
}), | ||
); | ||
const App = props => { | ||
@@ -61,59 +48,92 @@ return ( | ||
}; | ||
ReactDOM.render(<App />, ROOT_NODE); | ||
``` | ||
### Setting the language | ||
### 2. Set the supported languages | ||
Set the current language for your app by dispatching the `updateLanguage` action creator. | ||
Dispatch [setLanguages](#setlanguageslanguages-defaultactivelanguage) action creator and pass in the languages for your app. By default the first language in the array will be set as the active language. | ||
```javascript | ||
import { updateLanguage } from 'react-localize-redux'; | ||
import { setLanguages } from 'react-localize-redux'; | ||
store.dispatch(updateLanguage('en')); | ||
const languages = ['en', 'fr', 'es']; | ||
store.dispatch(setLanguages(languages)); | ||
``` | ||
### Set global translations | ||
To set a different default active language pass in the `language`. | ||
Translations that are shared between components are called `global` translations. | ||
Assuming you have global transaltions stored in a file called `global.locale.json` you can add them | ||
to your store by dispatching the `setGlobalTranslations` action creator. | ||
```javascript | ||
const languages = ['en', 'fr', 'es']; | ||
store.dispatch(setLanguages(languages, 'fr')); | ||
``` | ||
> NOTE: The following assumes you are using [webpack](https://webpack.github.io/) with [json-loader](https://github.com/webpack/json-loader) | ||
### 3. Add localized translation data | ||
Typically you will store your translation data in json files, but the data can also be a vanilla JS object. Once your translation data is in the correct format use the [addTranslation](#addtranslationdata) action creator. | ||
> NOTE: The following assumes you are using [webpack](https://webpack.github.io/) to bundle json | ||
```javascript | ||
import { setGlobalTranslations } from 'react-localize-redux'; | ||
import { addTranslation } from 'react-localize-redux'; | ||
const json = require("global.locale.json"); | ||
store.dispatch(setGlobalTranslations(json)); | ||
const json = require('global.locale.json'); | ||
store.dispatch(addTranslation(json)); | ||
``` | ||
As mentioned above translation content is stored in json files. Each json file requires that there be | ||
a property for each supported language, where the property name would match the language key passed to [updateLanguage](#updatelanguagelanguagecode). | ||
The json data should enforce the following format, where each translation string is a represented by a `{ key: value }` pair. | ||
The `value` is an array that should enforce the following... | ||
* Include a translation for each language your app supports. | ||
* The translation order matches the order of the languages in `setLanguages`. | ||
```json | ||
{ | ||
"en": { | ||
"greeting": "Hello ${ name }", | ||
"farwell": "Goodbye" | ||
}, | ||
"fr": { | ||
"greeting": "Bonjour ${ name }", | ||
"farwell": "Au revoir" | ||
}, | ||
"es": { | ||
"greeting": "Hola ${ name }", | ||
"farwell": "Adiós" | ||
} | ||
"greeting": [ | ||
"Hello", (en) | ||
"Bonjour", (fr) | ||
"Hola", (es) | ||
], | ||
"farwell": [ | ||
"Goodbye", (en) | ||
"Au revoir", (fr) | ||
"Adiós" (es) | ||
] | ||
} | ||
``` | ||
To add translations to a component you will need to decorate it with the [localize](#localize-translationid--wrappedcomponent-) function. By default | ||
all components decorated with `localize` have access to `global` translations. It will not modify your | ||
component class, but return a new localized component with additional props `translate` and `currentLanguage`. | ||
The `translate` prop is a function that takes the unique id from the transaltion file as a param, | ||
and an optional `data` param for variable substitutions. The function will return the localized string based on `currentLanguage`. | ||
### 4. Change the current language | ||
Dispatch [setActiveLanguage](#setactivelanguagelanguage) action creator and pass the language. | ||
```javascript | ||
import React from 'react'; | ||
import { setActiveLanguage } from 'react-localize-redux'; | ||
store.dispatch(setActiveLanguage('fr')); | ||
``` | ||
### 5. Translate components | ||
If you have a component that is already using `connect` you can use the [getTranslate](#gettranslatestate) selector that returns the `translate` function. This function will return the localized string based on active language. | ||
```javascript | ||
import { getTranslate } from 'react-localize-redux'; | ||
const Greeting = ({ translate, currentLanguage }) => ( | ||
<div> | ||
<h1>{ translate('greeting') }</h1> | ||
<button>{ translate('farwell') }</button> | ||
</div> | ||
); | ||
const mapStateToProps = state => ({ | ||
translate: getTranslate(state), | ||
currentLanguage: getActiveLanguage(state).code | ||
}); | ||
export default connect(mapStateToProps)(Greeting); | ||
``` | ||
For components not already using `connect` instead use [localize](#localizecomponent). This will automatically connect your component with the `translate` function and `currentLanguage` prop. | ||
```javascript | ||
import { localize } from 'react-localize-redux'; | ||
@@ -123,4 +143,3 @@ | ||
<div> | ||
<h1>{ translate('greeting', { name: 'Ryan' }) }</h1> | ||
<p>The current language is { `${ currentLanguage }` }</p> | ||
<h1>{ translate('greeting') }</h1> | ||
<button>{ translate('farwell') }</button> | ||
@@ -130,145 +149,147 @@ </div> | ||
// decorate your component with localize | ||
export default localize()(Greeting); | ||
export default localize(Greeting); | ||
``` | ||
### Set local translations | ||
## Features | ||
In addtion to `global` translations you can also include translations specific to your component called `local` translations. | ||
Similar to global translations `local` transaltions are added using an action creator `setLocalTranslations`. | ||
### Include HTML in translations | ||
Assuming we have a component called `WelcomeView` with translations specific to it stored in a file named `welcome.locale.json`. | ||
Include HTML in your translation strings and it will be rendered in your component. | ||
```json | ||
{ | ||
"en": { | ||
"welcome-body": "Here is some <strong>bold</strong> text." | ||
}, | ||
"fr": { | ||
"welcome-body": "Voici un texte en <strong>gras</strong>" | ||
}, | ||
"es": { | ||
"welcome-body": "Aquí le damos algunos texto en <strong>negrita</strong>" | ||
} | ||
"google-link": [ | ||
"<a href='https://www.google.en/'>Google</a>", | ||
"<a href='https://www.google.fr/'>Google</a>" | ||
] | ||
} | ||
``` | ||
First you will load the local json data passing in a `translationId`, in this case `welcome`, followed by the json data. | ||
### Add dynamic content to translations | ||
```javascript | ||
import { setLocalTranslations } from 'react-localize-redux'; | ||
You can insert dynamic content into your translation strings by inserting placeholders with the following format `${ placeholder }`. | ||
const json = require("welcome.locale.json"); | ||
store.dispatch(setLocalTranslations('welcome', json)); | ||
```json | ||
{ | ||
"greeting": [ | ||
"Hello ${ name }", | ||
"Bonjour ${ name }" | ||
] | ||
} | ||
``` | ||
To access `local` translations in your component you still use the `localize` function, | ||
but this time passing in the unique id that was used in `setLocalTranslations`. | ||
Then pass in the data you want to swap in for placeholders to the `translate` function. | ||
> NOTE: In addition to the `local` translations you will still have access `global` translations as well. | ||
```javascript | ||
import React from 'react'; | ||
import { localize } from 'react-localize-redux'; | ||
<h1>{ translate('greeting', { name: 'Testy McTest' }) }</h1> | ||
``` | ||
const WelcomeView = ({ translate }) => ( | ||
<div> | ||
<h1>{ translate('greeting') }</h1> | ||
<p>{ translate('welcome-body') }</p> | ||
<button>{ translate('farwell') }</button> | ||
</div> | ||
); | ||
### Supports nested translation data to avoid naming collisions | ||
// pass in the unique id for the local content you would like to add | ||
export default localize('welcome')(Greeting); | ||
```json | ||
{ | ||
"welcome": { | ||
"greeting": [ | ||
"Hello ${ name }!", | ||
"Bonjour ${ name }!" | ||
] | ||
}, | ||
"info": { | ||
"greeting": [ | ||
"Hello", | ||
"Bonjour" | ||
] | ||
} | ||
} | ||
``` | ||
## Bundle translations with Webpack and react-router | ||
```javascript | ||
<h1>{ translate('welcome.greeting', { name: 'Testy McTest' }) }</h1> | ||
<h1>{ translate('info.greeting') }</h1> | ||
``` | ||
When used with Webpack's [json-loader](https://github.com/webpack/json-loader), and react-router [Dynamic Routing](https://github.com/ReactTraining/react-router/blob/master/docs/guides/DynamicRouting.md) you can leverage code splitting to bundle components with their transaltion data. | ||
### Load translation data on demand | ||
See the `dynamic-routes` folder in the examples forward on a working example of how to implement this setup. | ||
If you have a larger app you may want to break your translation data up into multiple files, or maybe your translation data is being loaded from a service. Either way you can call [addTranslation](#addtranslationdata) for each new translation file/service, and the new translation data will be merged with any existing data. | ||
Also If you are using a tool like [webpack](https://webpack.js.org) for bundling, then you can use [async code-splitting](https://webpack.js.org/guides/code-splitting-async/) to split translations across bundles, and async load them when you need them. | ||
## API | ||
### localize( [translationId] )( WrappedComponent ) | ||
### `getTranslate(state)` | ||
A HoC factory method that returns an enhanced version of the WrappedComponent with the additional props for | ||
adding localized content to your component. | ||
A selector that takes your redux `state` and returns the translate function. This function will have access to any and all translations that were added with [addTranslation](). | ||
By calling `localize` with no params your WrappedComponent will only have access to `global` translations. | ||
returns `(key, data) => LocalizedElement` | ||
```javascript | ||
const MyComponent = ({ translate }) => <div>{ translate('greeting') }</div>; | ||
export default localize()(MyComponent); | ||
``` | ||
* `key: string` = The key for the transaltion string e.g. 'greeting' | ||
* `data: object` = Pass data to your [dynamic translation](#add-dynamic-content-to-translations) string. | ||
By default all components decorated with `localize` will have access to `global` transaltions. To add additional transaltion | ||
data that was added by [setLocalTranslations(translationId, json)](#setlocaltranslationsid-json) you will need pass the `translationId` as a param to `localize`. | ||
#### Usage: | ||
```javascript | ||
const MyComponent = ({ translate }) => <div>{ translate('title') }</div>; | ||
export default localize('translationId')(MyComponent); | ||
const Greeting = ({ translate }) => <h1>{ translate('greeting', { name: 'Testy McTest' }) }</h1> | ||
const mapStateToProps = state => ({ translate: getTranslate(state) }); | ||
export default connect(mapStateToProps)(Greeting); | ||
``` | ||
The following additional props are provided to localized components: | ||
### `localize(Component)` | ||
#### currentLanguage | ||
If you have a Component that is not using `connect` you can wrap it with `localize` to automatically add the `translate` function and `currentLanguage` prop. | ||
The current language set in your application. See [updateLanguage]() on how to update current language. | ||
#### Usage: | ||
#### translate( id, data ) | ||
```javascript | ||
const Greeting = ({ translate, currentLanguage }) => ( | ||
<span> | ||
<h1>languageCode: { currentLanguage }</h1> | ||
<h2>{ translate('greeting', { name: 'Testy McTest' }) }</h2> | ||
</span> | ||
); | ||
export default localize(Greeting); | ||
``` | ||
The translate will be used to insert translated copy in your component. The `id` param will need to match the property of the string you wish | ||
to retrieve from your json translaion data. | ||
### `setLanguages(languages, defaultActiveLanguage)` | ||
The `data` param is optional and can be used to insert dynamic data into your translations. The syntax follows the Javascript template | ||
literal format. | ||
**Redux action creator** to set which languages you are supporting in your translations. If `defaultActiveLanguage` is not passed then the first language in the `languages` array will be used. | ||
#### Usage: | ||
```javascript | ||
// Here is a string where I want to dynamically insert the user's name, and country | ||
{ "greet": "Hi here is my ${ name } and ${ country }" } | ||
const languages = ['en', 'fr', 'es']; | ||
// With translate you'd do the following | ||
translate('greet', { name: 'Ryan', country: 'Canada' }) | ||
``` | ||
store.dispatch(setLanguages(languages)); | ||
For example if the below json file was added using either [setGlobalTranslations](#setglobaltranslationsjson) or [setLocalTranslations](#setlocaltranslationsid-json). | ||
```json | ||
{ | ||
"en": { | ||
"title": "My Title", | ||
"desc": "My Description" | ||
}, | ||
"fr": { | ||
"title": "My Title French", | ||
"desc": "My Description French" | ||
} | ||
} | ||
// if you wanted 'fr' to be default language instead of 'en' | ||
store.dispatch(setLanguages(languages, 'fr')); | ||
``` | ||
and this component had been decorated with [localize](#localize-translationid--wrappedcomponent-) you would access the json content like so... | ||
### `addTranslation(data)` | ||
```html | ||
<h1>{ translate('title') }</h1> | ||
<p>{ translate('desc') }</p> | ||
``` | ||
**Redux action creator** to add new translation data to your redux store. Typically this data will be loaded from a json file, but can also be a plain JS object as long as it's structured properly. | ||
>NOTE: The json content that `translate` has access to will depend on the `translationId` passed to the `localize` method. | ||
>**IMPORTANT:** The order of the translation strings in the array matters! The order **MUST** follow the order of the languages array passed to [setLanguages](#setlanguageslanguages-defaultactivelanguage). | ||
### Redux Action Creators | ||
#### Usage: | ||
#### updateLanguage(languageCode) | ||
```javascript | ||
// assuming your app has set languages ['en', 'fr'] | ||
const welcomePageTranslations = { | ||
greeting: ['Hi!', 'Bonjour!'], | ||
farwell: ['Bye!', 'Au revoir!'] | ||
}; | ||
This will set the current language for your application, where `languageCode` should match the `languageCode` prop used in your translation json data. | ||
store.dispatch(addTranslation(welcomePageTranslations)); | ||
``` | ||
#### setGlobalTranslations(json) | ||
#### `setActiveLanguage(language)` | ||
The global json should contain any localized content that will be shared by multiple components. | ||
By default all components created by [localize](#localize-translationid--wrappedcomponent-) will have access to transaltion from this global json. | ||
**Redux action creator** to change the current language being used. | ||
#### setLocalTranslations(translationId, json) | ||
#### Usage: | ||
The local json should contain localized content specific to a component. This is especially useful when used | ||
in combination with react-router dynamic routing, and webpack code splitting features. | ||
```javascript | ||
// assuming your app has set languages ['en', 'fr'] | ||
store.dispatch(setActiveLanguage('fr')); | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
54822
15
867
292
5
30
1
+ Addedflat@^2.0.1
+ Addedflat@2.0.2(transitive)
+ Addedis-buffer@1.1.6(transitive)