import config from '../infinitymint.client.config'; import { Project } from './project'; import { log } from '../utils/helpers'; /** * Recursive function to replace special keys inside strings in an object * @param {object} obj * @returns */ const replaceInObject = (obj: object, resources: Resources) => { Object.keys(obj).forEach((index) => { if (typeof obj[index] === 'string') { if ( index.indexOf('Plural') === -1 && obj[index + '_Plural'] === undefined ) obj[index + '_Plural'] = resources.replaceInString( obj[index] .replace(/%token%/g, '%tokens%') .replace(/%tokenCapitalized%/g, '%tokensCapitalized%'), true ); if ( index.indexOf('Plural') === -1 && obj[index + '_Plural'] !== undefined && obj[index + 's'] === undefined ) obj[index + 's'] = obj[index + '_Plural']; if ( index.indexOf('Plural') === -1 && obj[index + '_Plural'] !== undefined && obj[index + 'es'] === undefined ) obj[index + 'es'] = obj[index + '_Plural']; obj[index] = resources.replaceInString( obj[index], index.indexOf('Plural') !== -1 ); } else obj[index] = replaceInObject(obj[index], resources); }); return obj; }; /** * Controller class to work with the strings */ export class Resources { public $; private map; //set in load public currentProject: Project; public resourceStrings: any; constructor(project: Project) { this.$ = { UI: { Responses: { Success: '', Failure: '', Error: '', }, Symbols: {}, Action: { Accept: '', Reject: '', Success: '', Cancel: '', Delete: '', Continue: '', Find: '', Refresh: '', }, Navbar: {}, Footer: {}, }, Pages: {}, }; this.map = {}; this.currentProject = project; } projectName() { return this.currentProject.name; } /** * * @param {string} val * @param {boolean} isPlural * @returns */ replaceInString(val: string, isPlural: boolean = false) { if (typeof val !== 'string') return val; for (let [index, value] of Object.entries(this.map)) { val = val.replace( //Note: Only replaces one! index, typeof value === 'function' ? value(isPlural) : value ); } return val; } /** * Returns the * @returns */ projectToken() { return this.currentProject.collectionToken(); } projectTokenPlural() { return this.currentProject.collectionToken(true); } tokenPlural() { return this.projectTokenPlural(); } token() { return this.projectToken(); } get(term) { let terms = term.split('.'); let scope = this[terms[0]]; terms = terms.slice(1); terms.forEach((term) => { scope = scope[term]; }); return scope; } registerPageString(pageId, key, defaultValue, replaceInValue = true) { if (this.$.Pages[pageId] === undefined) this.$.Pages[pageId] = {}; if (this.$.Pages[pageId][key] === undefined) this.$.Pages[pageId][key] = defaultValue; if (replaceInValue) return this.replaceInString( this.$.Pages[pageId][key], key.indexOf('_Plural') !== -1 ); return this.$.Pages[pageId][key]; } tryGetPageSting(page, key, plural = false) { try { if (this.$.Pages[page][key] === undefined) return false; return this.replaceInString(this.$.Pages[page][key], plural); } catch (error) { return false; } } getPageString(page, key, plural = false) { try { return this.replaceInString(this.$.Pages[page][key], plural); } catch (error) { return page + '.' + key; } } capitalize(str) { return str.substring(0, 1).toUpperCase() + str.substring(1); } async initialize() { let path = config.resources.default || 'default.yaml'; if (path.split('.').pop() !== 'yaml') path = path + '.yaml'; log('fetching resources', { path: path, project: this.currentProject.name, }); this.resourceStrings = await fetch('/resources/' + path); //this.#map has to be defined here due to getDescription needing to be loaded this.map = { '%token%': (isPlural) => (isPlural ? this.projectTokenPlural() : this.projectToken() ).toLowerCase(), '%tokens%': (isPlural) => this.projectTokenPlural().toLowerCase(), '%tokenCapitalized%': (isPlural) => this.capitalize( isPlural ? this.projectTokenPlural() : this.projectToken() ), '%tokensCapitalized%': (isPlural) => this.capitalize(this.projectTokenPlural()), '%name%': this.currentProject.name, '\\!': (isPlural) => (isPlural ? 's' : ''), '\\?': (isPlural) => (isPlural ? "'s" : ''), '\\e': (isPlural) => (isPlural ? 'es' : ''), '\\g': (isPlural) => (isPlural ? 'es' : ''), }; } async load() { //populate map, get description etc await this.initialize(); for (let [key, group] of Object.entries( this.resourceStrings.default || this.resourceStrings )) { let indexes = []; let _ = Object.keys(group).map((index) => { log('registering resource group: ' + index, 'resources'); //push current index to stack to unpack later since map does not retain index indexes.push(index); if (typeof group[index] === 'string') { if ( index.indexOf('Plural') === -1 && group[index + '_Plural'] === undefined ) group[index + '_Plural'] = this.replaceInString( group[index] .replace(/%token%/g, '%tokens%') .replace( /%tokenCapitalized%/g, '%tokensCapitalized%' ), true ); if ( index.indexOf('Plural') !== -1 && group[index + 's'] === undefined ) group[index + 's'] = group[index + '_Plural']; if ( index.indexOf('Plural') !== -1 && group[index + 'es'] === undefined ) group[index + 'es'] = group[index + '_Plural']; return this.replaceInString( group[index], group[index].indexOf('Plural') !== -1 ); } else { //recursive function to step through an array creating plural variants of //members where possible return replaceInObject(group[index], this); } }); //unpack stack replacing numerical keys with actual keys while (indexes.length > 0) { let index = indexes.length - 1; _[indexes.pop()] = { ...(_[index] as any) }; delete _[index]; //delete numerical } this.$[key] = _; } } } const resources = new Resources(null); export default resources;