From 3aad00dca778ff59a1f149a57fbf405f7db5b0bd Mon Sep 17 00:00:00 2001 From: HF Date: Tue, 12 Dec 2023 20:30:39 +0100 Subject: [PATCH] allow building of only specfic languages, english is not a required locale anymore --- README.md | 7 +++++++ package.json | 2 +- scripts/build.js | 33 +++++++++++++++++++++++++++++---- src/core/assets.js | 8 ++++++++ src/core/ttag.js | 37 ++++++++++++++++++++++++++----------- src/routes/index.js | 6 +++--- src/ssr/Main.jsx | 1 - src/ssr/PopUp.jsx | 1 - 8 files changed, 74 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 5f69dff0..9c762635 100644 --- a/README.md +++ b/README.md @@ -258,9 +258,16 @@ Run `npm run lint:src` to check for code errors and warnings or `npm run lint -- [ttag](https://github.com/ttag-org/ttag/) is used for handling translations. For server-side rendering the `Accept-Language` header gets checked and the first locale used and on-the-fly translated (`src/core/ttag.js` provides the functions for it). On the client-side a seperate bundle for every language gets provided. The language definitions in `i18n/template.pot` and `i18n/template-ssr.pot` get updated when doing a dev build with + ``` npm run build:dev ``` which also only builds the default local in a development environment for debugging. +To build only specific languages, you can define them with the `--langs` flag: + +``` +npm run build -- --langs de,tr +``` + You can use `npm run babel-node ./utils/script.js` to execute a script with local babel (path always relative to the root directory). diff --git a/package.json b/package.json index 9eb8aeda..c2cf6437 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "description": "Unlimited planet canvas for placing pixels", "main": "server.js", "scripts": { - "build": "node scripts/build.js && npm run minify-css", + "build": "node scripts/build.js", "build:dev": "webpack --env extract --config ./webpack.config.server.js && webpack --env extract --env development --config ./webpack.config.client.js && npm run minify-css", "deploy": "ssh pixelplanet /home/pixelpla/rebuild.sh", "minify-css": "node scripts/minifyCss.js", diff --git a/scripts/build.js b/scripts/build.js index 800fdd11..dadad8e9 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -6,10 +6,21 @@ const path = require('path'); const fs = require('fs'); const webpack = require('webpack'); + +const minifyCss = require('./minifyCss'); const serverConfig = require('../webpack.config.server.js'); const clientConfig = require('../webpack.config.client.js'); const { getAllAvailableLocals } = clientConfig; +let langs = 'all'; +for (let i = 0; i < process.argv.length; i += 1) { + if (process.argv[i] == '--langs') { + const newLangs = process.argv[++i]; + if (newLangs) langs = newLangs; + break; + } +} + function compile(webpackConfig) { return new Promise((resolve, reject) => { webpack(webpackConfig).run((err, stats) => { @@ -27,6 +38,20 @@ async function buildProduction() { // cleanup old files fs.rmSync(path.resolve(__dirname, '..', 'node_modules', '.cache', 'webpack'), { recursive: true, force: true }); // fs.rmSync(path.resolve(__dirname, '..', 'dist', 'public', 'assets'), { recursive: true, force: true }); + + // decide which languages to build + let avlangs = getAllAvailableLocals(); + if (langs !== 'all') { + avlangs = langs.split(',').map((l) => l.trim()) + .filter((l) => avlangs.includes(l)); + if (!avlangs.length) { + console.error(`ERROR: language ${langs} not available`); + process.exit(1); + return; + } + } + console.log('Building locales:', avlangs); + // server files console.log('-----------------------------'); console.log(`Build server...`); @@ -35,12 +60,11 @@ async function buildProduction() { development: false, extract: false, })); + // client files - const langs = getAllAvailableLocals(); - console.log('Available locales:', langs); const st = Date.now(); - for(let i = 0; i < langs.length; i += 1) { - const lang = langs[i]; + for(let i = 0; i < avlangs.length; i += 1) { + const lang = avlangs[i]; console.log(`Build client for locale ${lang}...`); console.log('-----------------------------'); await compile(clientConfig({ @@ -52,6 +76,7 @@ async function buildProduction() { })); } console.log(`Finished building in ${(Date.now() - st) / 1000}s`); + await minifyCss(); } buildProduction(); diff --git a/src/core/assets.js b/src/core/assets.js index a7f10d07..73270cbb 100644 --- a/src/core/assets.js +++ b/src/core/assets.js @@ -81,6 +81,14 @@ function checkAssets() { // eslint-disable-next-line prefer-const assets = checkAssets(); +export function getLangsOfJsAsset(name) { + const nameAssets = assets.js[name]; + if (!nameAssets) { + return []; + } + return Object.keys(nameAssets); +} + export function getJsAssets(name, lang) { const jsAssets = []; diff --git a/src/core/ttag.js b/src/core/ttag.js index aeddacd4..34fa8589 100644 --- a/src/core/ttag.js +++ b/src/core/ttag.js @@ -5,29 +5,36 @@ import { TTag } from 'ttag'; import cookie from 'cookie'; import { languageFromLocalisation } from '../utils/location'; +import { getLangsOfJsAsset } from './assets'; // eslint-disable-next-line max-len const localeImports = require.context('../../i18n', false, /^\.[/\\]ssr-.+\.po$/); -const ttags = { - en: new TTag(), -}; +const ttags = {}; (() => { const langs = localeImports.keys(); + const jsLangs = getLangsOfJsAsset('client'); + + if (jsLangs.includes('en')) { + ttags.en = new TTag(); + } + for (let i = 0; i < langs.length; i += 1) { const file = langs[i]; - const ttag = new TTag(); // ./ssr-de.po - const lang = file.replace('./ssr-', '').replace('.po', ''); - ttag.addLocale(lang, localeImports(file).default); - ttag.useLocale(lang); - ttags[lang] = ttag; + const lang = file.replace('./ssr-', '').replace('.po', '').toLowerCase(); + if (jsLangs.includes(lang)) { + const ttag = new TTag(); + ttag.addLocale(lang, localeImports(file).default); + ttag.useLocale(lang); + ttags[lang] = ttag; + } } })(); export function getTTag(lang) { - return ttags[lang] || ttags.en; + return ttags[lang] || ttags.en || Object.values(ttags)[0]; } /* @@ -38,8 +45,16 @@ export function getTTag(lang) { export function expressTTag(req, res, next) { const cookies = cookie.parse(req.headers.cookie || ''); const language = cookies.plang || req.headers['accept-language']; - req.lang = languageFromLocalisation(language); - req.ttag = getTTag(req.lang); + let lang = languageFromLocalisation(language); + if (!ttags[lang]) { + if (ttags.en) { + lang = 'en'; + } else { + [lang] = Object.keys(ttags); + } + } + req.lang = lang; + req.ttag = ttags[lang]; next(); } diff --git a/src/routes/index.js b/src/routes/index.js index d6dfa22d..4d2a5121 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -74,7 +74,7 @@ router.get('/globe', (req, res) => { const { html, etag: globeEtag } = generateGlobePage(req); res.set({ - 'Cache-Control': `private, no-cache`, // seconds + 'Cache-Control': 'private, no-cache', // seconds ETag: globeEtag, }); @@ -101,7 +101,7 @@ router.use( const { html, etag: winEtag } = generatePopUpPage(req); res.set({ - 'Cache-Control': `private, no-cache`, // seconds + 'Cache-Control': 'private, no-cache', // seconds ETag: winEtag, }); @@ -122,7 +122,7 @@ router.get('/', (req, res) => { const { html, csp, etag: mainEtag } = generateMainPage(req); res.set({ - 'Cache-Control': `private, no-cache`, // seconds + 'Cache-Control': 'private, no-cache', // seconds 'Content-Security-Policy': csp, ETag: mainEtag, }); diff --git a/src/ssr/Main.jsx b/src/ssr/Main.jsx index 889ebf37..141e8b68 100644 --- a/src/ssr/Main.jsx +++ b/src/ssr/Main.jsx @@ -17,7 +17,6 @@ import { getHostFromRequest } from '../utils/ip'; * generate language list */ const langs = Object.keys(ttags) - .map((l) => (l === 'default' ? 'en' : l)) .map((l) => [l, langCodeToCC(l)]); /* diff --git a/src/ssr/PopUp.jsx b/src/ssr/PopUp.jsx index 683e6460..b27bf55d 100644 --- a/src/ssr/PopUp.jsx +++ b/src/ssr/PopUp.jsx @@ -17,7 +17,6 @@ import { getHostFromRequest } from '../utils/ip'; * generate language list */ const langs = Object.keys(ttags) - .map((l) => (l === 'default' ? 'en' : l)) .map((l) => [l, langCodeToCC(l)]); /*