diff --git a/.gitignore b/.gitignore index 95db24e4d7..9aa4658204 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ website/transpiled-babel/ website/common/transpiled-babel/ node_modules content_cache +i18n_cache apidoc_build *.swp .idea* diff --git a/gulp/gulp-build.js b/gulp/gulp-build.js index 4d4cbcef7c..bed1bbf3e5 100644 --- a/gulp/gulp-build.js +++ b/gulp/gulp-build.js @@ -11,10 +11,16 @@ gulp.task('build:babel:common', () => gulp.src('website/common/script/**/*.js') gulp.task('build:babel', gulp.parallel('build:babel:server', 'build:babel:common', done => done())); +gulp.task('build:cache', gulp.parallel( + 'cache:content', + 'cache:i18n', + done => done(), +)); + gulp.task('build:prod', gulp.series( 'build:babel', 'apidoc', - 'content:cache', + 'build:cache', done => done(), )); diff --git a/gulp/gulp-content.js b/gulp/gulp-cache.js similarity index 50% rename from gulp/gulp-content.js rename to gulp/gulp-cache.js index c36bfeb125..ebe85ff984 100644 --- a/gulp/gulp-content.js +++ b/gulp/gulp-cache.js @@ -2,7 +2,7 @@ import gulp from 'gulp'; import fs from 'fs'; // TODO parallelize, use gulp file helpers -gulp.task('content:cache', done => { +gulp.task('cache:content', done => { // Requiring at runtime because these files access `common` // code which in production works only if transpiled so after // gulp build:babel:common has run @@ -32,3 +32,32 @@ gulp.task('content:cache', done => { done(err); } }); + +gulp.task('cache:i18n', done => { + // Requiring at runtime because these files access `common` + // code which in production works only if transpiled so after + // gulp build:babel:common has run + const { BROWSER_SCRIPT_CACHE_PATH, geti18nBrowserScript } = require('../website/server/libs/i18n'); // eslint-disable-line global-require + const { langCodes } = require('../website/server/libs/i18n'); // eslint-disable-line global-require + + try { + // create the cache folder (if it doesn't exist) + try { + fs.mkdirSync(BROWSER_SCRIPT_CACHE_PATH); + } catch (err) { + if (err.code !== 'EEXIST') throw err; + } + + // create and save the i18n browser script for each language + langCodes.forEach(languageCode => { + fs.writeFileSync( + `${BROWSER_SCRIPT_CACHE_PATH}${languageCode}.js`, + geti18nBrowserScript(languageCode), + 'utf8', + ); + }); + done(); + } catch (err) { + done(err); + } +}); diff --git a/gulpfile.js b/gulpfile.js index 354011b2fe..86c9f32a38 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -13,11 +13,11 @@ const gulp = require('gulp'); if (process.env.NODE_ENV === 'production') { // eslint-disable-line no-process-env require('./gulp/gulp-apidoc'); // eslint-disable-line global-require - require('./gulp/gulp-content'); // eslint-disable-line global-require + require('./gulp/gulp-cache'); // eslint-disable-line global-require require('./gulp/gulp-build'); // eslint-disable-line global-require } else { require('./gulp/gulp-apidoc'); // eslint-disable-line global-require - require('./gulp/gulp-content'); // eslint-disable-line global-require + require('./gulp/gulp-cache'); // eslint-disable-line global-require require('./gulp/gulp-build'); // eslint-disable-line global-require require('./gulp/gulp-console'); // eslint-disable-line global-require require('./gulp/gulp-sprites'); // eslint-disable-line global-require diff --git a/website/server/controllers/api-v3/i18n.js b/website/server/controllers/api-v3/i18n.js index 092521f216..4c86cb986a 100644 --- a/website/server/controllers/api-v3/i18n.js +++ b/website/server/controllers/api-v3/i18n.js @@ -1,26 +1,13 @@ -import _ from 'lodash'; +import nconf from 'nconf'; import { - translations, - momentLangs, - availableLanguages, + BROWSER_SCRIPT_CACHE_PATH, + geti18nBrowserScript, } from '../../libs/i18n'; +const IS_PROD = nconf.get('IS_PROD'); + const api = {}; -function geti18nBrowserScript (language) { - const langCode = language.code; - - return `(function () { - if (!window) return; - window['habitica-i18n'] = ${JSON.stringify({ - availableLanguages, - language, - strings: translations[langCode], - momentLang: momentLangs[langCode], - })}; - })()`; -} - /** * @api {get} /api/v3/i18n/browser-script Returns the i18n JS script. * @apiDescription Returns the i18n JS script to make @@ -33,14 +20,16 @@ api.geti18nBrowserScript = { method: 'GET', url: '/i18n/browser-script', async handler (req, res) { - const language = _.find(availableLanguages, { code: req.language }); + if (IS_PROD) { + res.sendFile(`${BROWSER_SCRIPT_CACHE_PATH}${req.language}.js`); + } else { + res.set({ + 'Content-Type': 'application/javascript', + }); - res.set({ - 'Content-Type': 'application/javascript', - }); - - const jsonResString = geti18nBrowserScript(language); - res.status(200).send(jsonResString); + const jsonResString = geti18nBrowserScript(req.language); + res.status(200).send(jsonResString); + } }, }; diff --git a/website/server/libs/i18n.js b/website/server/libs/i18n.js index 7fd6069014..bec852768c 100644 --- a/website/server/libs/i18n.js +++ b/website/server/libs/i18n.js @@ -4,6 +4,7 @@ import _ from 'lodash'; import shared from '../../common'; export const localePath = path.join(__dirname, '../../common/locales/'); +export const BROWSER_SCRIPT_CACHE_PATH = path.join(__dirname, '/../../../i18n_cache/'); // Store translations export const translations = {}; @@ -115,3 +116,17 @@ export const multipleVersionsLanguages = { 'pt-br': 'pt_BR', }, }; + +export function geti18nBrowserScript (languageCode) { + const language = _.find(availableLanguages, { code: languageCode }); + + return `(function () { + if (!window) return; + window['habitica-i18n'] = ${JSON.stringify({ + availableLanguages, + language, + strings: translations[languageCode], + momentLang: momentLangs[languageCode], + })}; + })()`; +}