UNPKG

create-dan

Version:

Dan frameworks

192 lines (162 loc) 4.55 kB
import React from 'react' import fetch from 'isomorphic-unfetch' import getConfig from 'config' const DEFAULT_FILES = ['main'] // Cache const i18nFilesCache = {} /** * Cache i18n files * @param {Object} i18n */ function cacheI18n(i18n) { const config = getConfig() const files = i18n.files if( (config.isServer && config.cacheI18nServer) || (!config.isServer && config.cacheI18nClient) ) { for(let locale in files) { i18nFilesCache[locale] = i18nFilesCache[locale] || {} for(let file in files[locale]) { if(!i18nFilesCache[locale][file]) { i18nFilesCache[locale][file] = files[locale][file] } } } } } // Context export const I18nContext = React.createContext() /** * Use i18n context */ export function useI18n() { return React.useContext(I18nContext) } /** * With i18n as a props */ export function withI18n(ComposedComponent) { const Component = (props) => <ComposedComponent is={useI18n()} {...props} /> if(ComposedComponent.getInitialProps) { Component.getInitialProps = ComposedComponent.getInitialProps } return Component } /** * Page with i18n as a props */ export function pageWithI18n(ComposedComponent, files = DEFAULT_FILES) { const Component = (props) => { cacheI18n(props.i18n) return ( <I18nContext.Provider value={props.i18n}> <ComposedComponent {...props} /> </I18nContext.Provider> ) } Component.getInitialProps = async (ctx) => { ctx.i18n = await getI18n(ctx.query.locale || getConfig().locale, files) // Data let data = {} // Get component data if(ComposedComponent.getInitialProps) { Object.assign(data, await ComposedComponent.getInitialProps(ctx)) } // Complete return Object.assign( data, { i18n: ctx.i18n, } ) } return Component } /** * Get i18n * @param {String} locale * @param {Array} files */ export async function getI18n(locale, files = DEFAULT_FILES) { const i18n = { locale: locale, files: {} } await Promise.all(files.map((file) => addI18nFile({ file, i18n }))) return i18n } /** * Add a new file to localize */ export async function addI18nFile({ file, i18n, locale, path }) { const config = getConfig() // Setup locale = locale || i18n.locale i18n.files[locale] = i18n.files[locale] || {} i18nFilesCache[locale] = i18nFilesCache[locale] || {} // Allready in i18n if(i18n.files[locale][file]) { return i18n.files[locale][file] } // Allready in cache if(i18nFilesCache[locale][file]) { i18n.files[locale][file] = i18nFilesCache[locale][file] return i18n.files[locale][file] } // Load path = (path || `${config.basePath}${config.assets}locales/{locale}/{file}.json`) .replace('{locale}', locale) .replace('{file}', file) i18n.files[locale][file] = await (await fetch(path)).json() return i18n.files[locale][file] } /** * Localize * @param {String} key * @param {Object} params * @param {Object} options */ export function localize(key, params = null, { file = 'main', locale, defaultValue = null, i18n } = {}) { i18n = i18n || useI18n() // i18n not found if(!i18n) { return defaultValue } locale = locale || i18n.locale // Seek let output = ( i18n.files[locale] && i18n.files[locale][file] ) ? get(i18n.files[locale][file], key, defaultValue) : defaultValue // Params if(output) { for (var id in params) { output = output.replace(new RegExp(`\\\{${id}\\\}`, 'g'), params[id]); } } return output } /** * Localize component * @param {Object} props */ export function Localize(props) { return localize(props.children, props, props) } /** * Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place. * @param {Object} obj - Targeted object * @param {String} path - Object path * @param {*} def - Default value */ function get(obj, path, def) { const fullPath = path .replace(/\[/g, '.') .replace(/]/g, '') .split('.') .filter(Boolean) return fullPath.every(everyFunc) ? obj : def function everyFunc(step) { return !(step && (obj = obj[step]) === undefined) } }