| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 | 
							- import React, { useContext, useState } from 'react';
 
- import PropTypes from 'prop-types';
 
- const DEFAULT_LANGUAGE = 'en';
 
- const LANGUAGES_PATH = 'static/locales';
 
- const LANGUAGES_FILE = 'translations.json';
 
- const VARIABLE_REGEX = /\{([^}]+)\}/g;
 
- export const store = {
 
-     /* dictionaries */
 
- };
 
- /**
 
-  * Set a dictionary for a specific language
 
-  * @param  {String} lang language
 
-  * @param  {Object} data dictionary
 
-  * @return {Object}      dictionary added
 
-  */
 
- export const setDict = (lang, data) => (store[lang] = data);
 
- /**
 
-  * Get a dictionary for specific language
 
-  * @param  {String} lang language
 
-  * @return {Object}      dictionary
 
-  */
 
- export const getDict = lang => store[lang];
 
- /**
 
-  * Fetch a dictionary for specific language defined in JSON format
 
-  * @param  {Strong} lang language
 
-  * @return {Object}      dictionary loaded
 
-  */
 
- export const fetchStore = async lang => {
 
-     if (!store[lang]) {
 
-         const res = await fetch(`/${LANGUAGES_PATH}/${lang}/${LANGUAGES_FILE}`);
 
-         store[lang] = await res.json();
 
-     }
 
-     return store[lang];
 
- };
 
- /**
 
-  * Interpolates values given in 'params'
 
-  * @param  {String} str    text
 
-  * @param  {Object} params object to interpolate
 
-  * @return {String}
 
-  */
 
- const compile = (str = '', params) => {
 
-     const matches = str.match(VARIABLE_REGEX);
 
-     if (matches) {
 
-         matches
 
-             .map(v => v.replace(/\{|\}/g, ''))
 
-             .forEach(v => (str = str.replace('{' + v + '}', params[v])));
 
-     }
 
-     return str;
 
- };
 
- /**
 
-  * Reads an object value using dot notation for nested keys
 
-  * @param  {Object} obj  object to parse
 
-  * @param  {String} skey key to search
 
-  * @return {String|null}
 
-  */
 
- export const accessKey = (obj, skey = '') => skey.split('.').reduce((a, b) => a && a[b], obj);
 
- /**
 
-  * Returns the translated text for given key and interpolates values in 'params'
 
-  * @param  {String} key    the key to search for
 
-  * @param  {String} lang   language
 
-  * @param  {Object} params object with params to interpolate
 
-  * @return {[type]}        [description]
 
-  */
 
- export const translateKey = (key, lang, params = {}) => compile(accessKey(getDict(lang), key));
 
- // =====================
 
- // REACT INTERFACE
 
- // =====================
 
- /**
 
-  * Context used to handle translation in the component tree
 
-  */
 
- const TranslateContext = React.createContext({
 
-     language: DEFAULT_LANGUAGE,
 
-     changeLanguage: () => {}
 
- });
 
- /**
 
-  * Component provider to pass down context to child components
 
-  * Must be used to wrap application
 
-  */
 
- export class Provider extends React.Component {
 
-     changeLanguage = language => {
 
-         fetchStore(language).then(() => {
 
-             this.setState(state => ({
 
-                 language
 
-             }));
 
-         });
 
-     };
 
-     state = {
 
-         language: DEFAULT_LANGUAGE,
 
-         changeLanguage: this.changeLanguage
 
-     };
 
-     constructor(props) {
 
-         super(props);
 
-         if (props.store) {
 
-             Object.keys(props.store).forEach(l => setDict(l, props.store[l]));
 
-         }
 
-     }
 
-     render() {
 
-         return (
 
-             <TranslateContext.Provider value={this.state}>
 
-                 {this.props.children}
 
-             </TranslateContext.Provider>
 
-         );
 
-     }
 
- }
 
- /**
 
-  * HOC to provide 'changeLanguage' and 't' method to WrappedComponent
 
-  */
 
- export function withTranslation(WrappedComponent) {
 
-     return function TranslatedComponent(props) {
 
-         const { language, changeLanguage } = useContext(TranslateContext);
 
-         const t = (k, l, p) => translateKey(k, l || language, p);
 
-         return <WrappedComponent changeLanguage={changeLanguage} t={t} {...props} />;
 
-     };
 
- }
 
- /**
 
-  * Component to translate a given key
 
-  * If key is missing, render children without changes
 
-  */
 
- export const Trans = props => {
 
-     const { language } = useContext(TranslateContext);
 
-     const { i18nKey, lang, params, children } = props;
 
-     return [translateKey(i18nKey, lang || language, params) || children];
 
- };
 
- Trans.proptypes = {
 
-     i18nKey: PropTypes.string.isRequired,
 
-     lang: PropTypes.string,
 
-     params: PropTypes.object
 
- };
 
 
  |