diff --git a/install/package.json b/install/package.json index bf22db9a0f..90f2b098c7 100644 --- a/install/package.json +++ b/install/package.json @@ -118,6 +118,7 @@ "request-promise-native": "1.0.9", "rimraf": "3.0.2", "rss": "1.2.2", + "rtlcss": "4.0.0", "sanitize-html": "2.7.1", "sass": "1.54.3", "semver": "7.3.7", diff --git a/public/src/client/account/settings.js b/public/src/client/account/settings.js index 57b82151ee..758bf88c0a 100644 --- a/public/src/client/account/settings.js +++ b/public/src/client/account/settings.js @@ -83,16 +83,7 @@ define('forum/account/settings', [ } if (languageChanged && parseInt(app.user.uid, 10) === parseInt(ajaxify.data.theirid, 10)) { - translator.translate('[[language:dir]]', config.userLang, function (translated) { - const htmlEl = $('html'); - htmlEl.attr('data-dir', translated); - htmlEl.css('direction', translated); - }); - - translator.switchTimeagoLanguage(utils.userLangToTimeagoCode(config.userLang), function () { - overrides.overrideTimeago(); - ajaxify.refresh(); - }); + window.location.reload(); } }); } @@ -127,11 +118,14 @@ define('forum/account/settings', [ if (skinName === currentSkin) { return; } - + const langDir = $('html').attr('data-dir'); const linkEl = document.createElement('link'); linkEl.rel = 'stylesheet'; linkEl.type = 'text/css'; - linkEl.href = config.relative_path + '/assets/client' + (skinName ? '-' + skinName : '') + '.css'; + linkEl.href = config.relative_path + + '/assets/client' + (skinName ? '-' + skinName : '') + + (langDir === 'rtl' ? '-rtl' : '') + + '.css'; linkEl.onload = function () { clientEl.parentNode.removeChild(clientEl); diff --git a/src/meta/css.js b/src/meta/css.js index af1014bc14..35f197c3ad 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -218,9 +218,14 @@ CSS.buildBundle = async function (target, fork) { const data = await getBundleMetadata(target); const minify = process.env.NODE_ENV !== 'development'; - const bundle = await minifier.css.bundle(data.imports, data.paths, minify, fork); + const [ltr, rtl] = await Promise.all([ + minifier.css.bundle(data.imports, data.paths, minify, fork, 'ltr'), + minifier.css.bundle(data.imports, data.paths, minify, fork, 'rtl'), + ]); - const filename = `${target}.css`; - await fs.promises.writeFile(path.join(__dirname, '../../build/public', filename), bundle.code); - return bundle.code; + await Promise.all([ + fs.promises.writeFile(path.join(__dirname, '../../build/public', `${target}.css`), ltr.code), + fs.promises.writeFile(path.join(__dirname, '../../build/public', `${target}-rtl.css`), rtl.code), + ]); + return [ltr.code, rtl.code]; }; diff --git a/src/meta/minifier.js b/src/meta/minifier.js index c0dbf6ece4..4ad9a97377 100644 --- a/src/meta/minifier.js +++ b/src/meta/minifier.js @@ -9,6 +9,7 @@ const sass = require('sass'); const postcss = require('postcss'); const autoprefixer = require('autoprefixer'); const clean = require('postcss-clean'); +const rtlcss = require('rtlcss'); const fork = require('./debugFork'); require('../file'); // for graceful-fs @@ -231,6 +232,9 @@ actions.buildCSS = async function buildCSS(data) { }); const postcssArgs = [autoprefixer]; + if (data.direction === 'rtl') { + postcssArgs.push(rtlcss()); + } if (data.minify) { postcssArgs.push(clean({ processImportFrom: ['local'], @@ -243,12 +247,13 @@ actions.buildCSS = async function buildCSS(data) { }; Minifier.css = {}; -Minifier.css.bundle = async function (source, paths, minify, fork) { +Minifier.css.bundle = async function (source, paths, minify, fork, direction) { return await executeAction({ act: 'buildCSS', source: source, paths: paths, minify: minify, + direction: direction, }, fork); }; diff --git a/src/middleware/index.js b/src/middleware/index.js index 96bd3da398..1ae61c4687 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -209,9 +209,9 @@ middleware.buildSkinAsset = helpers.try(async (req, res, next) => { } await plugins.prepareForBuild(['client side styles']); - const css = await meta.css.buildBundle(target[0], true); + const [ltr, rtl] = await meta.css.buildBundle(target[0], true); require('../meta/minifier').killAll(); - res.status(200).type('text/css').send(css); + res.status(200).type('text/css').send(req.originalUrl.includes('-rtl') ? rtl : ltr); }); middleware.addUploadHeaders = function addUploadHeaders(req, res, next) { diff --git a/src/routes/index.js b/src/routes/index.js index 03b5c7fdfb..f3861aa1bf 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -195,6 +195,7 @@ function addCoreRoutes(app, router, middleware, mounts) { // Skins meta.css.supportedSkins.forEach((skin) => { app.use(`${relativePath}/assets/client-${skin}.css`, middleware.buildSkinAsset); + app.use(`${relativePath}/assets/client-${skin}-rtl.css`, middleware.buildSkinAsset); }); app.use(controllers['404'].handle404);