From 981fe2d7fe7727d66d725c3de57e77dfdf48fa27 Mon Sep 17 00:00:00 2001 From: Matheus Paiva Date: Sun, 2 Dec 2018 02:03:58 +0000 Subject: [PATCH] feat: Add first version of Rosetta engine --- package-lock.json | 3 +- package.json | 3 ++ src/Rosetta.js | 46 +++++++++++++++++++++++ src/index.js | 3 ++ src/rosetta-service.js | 45 ++++++++++++++++++++++ src/utils/format-phrase-with-variables.js | 19 ++++++++++ 6 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/Rosetta.js create mode 100644 src/index.js create mode 100644 src/rosetta-service.js create mode 100644 src/utils/format-phrase-with-variables.js diff --git a/package-lock.json b/package-lock.json index 2b4b6a3..163f07c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2401,8 +2401,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.debounce": { "version": "4.0.8", diff --git a/package.json b/package.json index e1c00cb..9d1d9a6 100644 --- a/package.json +++ b/package.json @@ -32,5 +32,8 @@ "onchange": "^5.1.3", "webpack": "^4.26.1", "webpack-cli": "^3.1.2" + }, + "dependencies": { + "lodash": "^4.17.11" } } diff --git a/src/Rosetta.js b/src/Rosetta.js new file mode 100644 index 0000000..9480544 --- /dev/null +++ b/src/Rosetta.js @@ -0,0 +1,46 @@ +import { merge, get } from 'lodash'; +import formatPhraseWithVariables from './utils/format-phrase-with-variables'; +import rosettaService from './rosetta-service'; + +export default class Rosetta { + constructor({ + cultureCodes = [], + clientId = '', + contentService = rosettaService, + } = {}, names) { + // eslint-disable-next-line + this.cultureCode = cultureCodes[0]; + this.phrasesByCultureCode = {}; + this.contentService = contentService(clientId); + this.fetchNames(cultureCodes, names); + } + + async fetchNames(cultureCodes, names) { + try { + const phrasesByCultureCode = await this.contentService.getNames(cultureCodes, names); + this.phrasesByCultureCode = merge(this.phrasesByCultureCode, phrasesByCultureCode); + } catch (error) { + throw new Error('[GAPLESS] Something went wrong at Rosetta.fetchNames'); + } + } + + getPhrases() { + return this.phrasesByCultureCode[this.cultureCode]; + } + + translate(name, { placeholder, ...variables } = {}) { + const phrase = get(this.getPhrases(), name, placeholder); + + return formatPhraseWithVariables(phrase, variables) || name; + } + + namespace(name) { + const space = get(this.getPhrases(), name); + + if (typeof space !== 'object') { + throw new Error('[GAPLESS] Namespace should be an object.'); + } + + return space; + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..f0bd48a --- /dev/null +++ b/src/index.js @@ -0,0 +1,3 @@ +import Rosetta from './Rosetta'; + +export default Rosetta; diff --git a/src/rosetta-service.js b/src/rosetta-service.js new file mode 100644 index 0000000..1353095 --- /dev/null +++ b/src/rosetta-service.js @@ -0,0 +1,45 @@ +const sleep = time => new Promise(resolve => setTimeout(resolve, time)); + +// eslint-disable-next-line +export default (id) => ({ + // eslint-disable-next-line + getNames: async (cultureCodes, names) => { + await sleep(300); + + return { + 'en-US': { + BREAD: { + ROOT: 'bread', + CORN: 'corn bread', + CROISSANT: 'croissant', + }, + BUTTER: 'butter', + TOASTER: 'toaster', + }, + 'pt-PT': { + BREAD: { + ROOT: 'pão', + CORN: 'broa', + CROISSANT: 'croissant', + }, + BUTTER: 'manteiga', + TOASTER: 'torradeira', + }, + }; + }, + getCultures: async () => { + await sleep(300); + + return [ + 'pt-PT', + 'pt-BR', + 'en-GB', + 'en-US', + 'en-CA', + 'es-ES', + 'es-MX', + 'fr-FR', + 'fr-CA', + ]; + }, +}); diff --git a/src/utils/format-phrase-with-variables.js b/src/utils/format-phrase-with-variables.js new file mode 100644 index 0000000..8a71cc5 --- /dev/null +++ b/src/utils/format-phrase-with-variables.js @@ -0,0 +1,19 @@ +export default (phrase, ...variables) => { + if (!variables.length) return phrase; + + let formattedPhrase = phrase; + + const t = typeof variables[0]; + const args = (t === 'string' || t === 'number') + ? Array.prototype.slice.call(variables) + : variables[0]; + + Object.keys(args) + .forEach((key) => { + const regex = new RegExp(`\\{${key}\\}`, 'gi'); + + formattedPhrase = phrase.replace(regex, args[key]); + }); + + return formattedPhrase; +};