简体   繁体   English

如何使用来自 Node.js/Express/EJS 网站的一些 JS 脚本的 i18n JSON 翻译,这些脚本只能在客户端运行?

[英]How to use i18n JSON translations from some JS scripts that are to be ran only client-side, from a Node.js / Express / EJS website?

Here is my problem,这是我的问题,

I am using i18n to manage the translations of all the content of a website made on Node.js, Express and EJS.我正在使用i18n来管理在 Node.js、Express 和 EJS 上制作的网站的所有内容的翻译。 i18n uses json files server-side. i18n 在服务器端使用 json 文件。 I've updated all pages I needed to, except for one.我已经更新了我需要的所有页面,除了一个。

My client is used to have a js file called from the footer on every pages.我的客户端习惯于在每个页面上从页脚调用一个 js 文件。 This file is pretty dense, and is ran only client-side.该文件非常密集,仅在客户端运行。

Because of time constraints, we would prefer not to refactor this code.由于时间限制,我们不希望重构此代码。

How could I use my json translation files server-side from a script that is to be run only client side ?如何从仅在客户端运行的脚本中使用我的 json 翻译文件服务器端?

I though about making a dedicated api service to call from client side and get all the translations but it seems pretty heavy.我想制作一个专用的 api 服务来从客户端调用并获取所有翻译,但它似乎很重。

Or I though about using Node.js to write manually, at the end of my js file ran client side, the translations JSON files when they'd get updated.或者我想使用 Node.js 手动编写,在我的 js 文件的末尾运行客户端,当它们更新时翻译 JSON 文件。 But that would mean thousands of lines, it's true I have to forget writing perfect clean code for this case, but, well...但这将意味着数千行,确实我必须忘记为这种情况编写完美干净的代码,但是,好吧......

Before going further I'd really appreciate your help on this.在继续之前,我非常感谢您在这方面的帮助。 I would have love just to refactor, but for some tricky reasons, it may not be the greatest for now.我很想重构,但由于一些棘手的原因,它现在可能不是最好的。

Thanks and have a great day you all.谢谢,祝大家有美好的一天。 :) :)

What I did finally:我最后做了什么:

I've created a directory in /assets to store all translation json files.我在 /assets 中创建了一个目录来存储所有翻译 json 文件。

If on test or dev environment, at every request I check if those files have been updated before or after /locales json files.如果在测试或开发环境中,在每次请求时,我都会检查这些文件是否在 /locales json 文件之前或之后更新。

/server.js /server.js

const { watchAssetsTrads } = require("./middleware/clientSideTrads");
const notInProd = env === "test" || env === "dev";
if (notInProd) app.use((req, res, next) => watchAssetsTrads(next));

I need to improve this next file as I've learned here how I managed poorly my promises, though it works great.我需要改进下一个文件,因为我在这里了解到我是如何管理我的承诺的,尽管它很有效。

/middlewares/clientSideTrads.js /middlewares/clientSideTrads.js

const debug = require("debug")("trads");
const fs = require('fs');
const lodash = require('lodash');
const path = require('path');

const locales = path.join(__dirname, '../locales/');
const assetsTrads = path.join(__dirname, '../assets/trads');

const getFilesNamesFrom = path => {
  return new Promise((resolve, reject) => {
    fs.readdir(path, (err, files) => {
      if (err) return reject(err);
      return resolve(files.filter(e => e !== ".DS_Store"));
    });
  });
};

const read = jsonPath => {
  return new Promise((resolve, reject) => {
    fs.readFile(jsonPath, (err, data) => {
      if (err) return reject(err);
      return resolve(JSON.parse(data));
    });
  });
};

const update = (jsonPath, newJson) => {
  return new Promise((resolve, reject) => {
    fs.writeFile(jsonPath, JSON.stringify(newJson), err => {
      if (err) return reject(err);
      return resolve();
    });
  });
};

const getLastUpdateTime = filePath => {
  return new Promise((resolve, reject) => {
    fs.stat(filePath, (err, stats) => {
      if (err) return reject(err);
      return resolve(stats.mtime);
    });
  });
};

const updateAssetsTrads = async (localesTradPath, assetsTradPath) => {
  const localesTrad = await read(localesTradPath);
  const selectedKeys = lodash.pickBy(localesTrad, function(value, key) {
    if ((/^clientside/u).test(key)) return true;
    return false;
  });
  await update(assetsTradPath, selectedKeys);
  return null;
};

const watchAssetsTrads = async next => {
  debug('Checking asset trads');
  const files = await getFilesNamesFrom(locales);
  files.forEach(async file => {
    try {
      const localesTradPath = path.join(locales, file);
      const assetsTradPath = path.join(assetsTrads, file);
      const lastUpdate = await getLastUpdateTime(localesTradPath);
      const lastMerge = await getLastUpdateTime(assetsTradPath);
      if (lastUpdate > lastMerge) {
        updateAssetsTrads(localesTradPath, assetsTradPath);
        debug('File updated');
      }
    }
    catch (err) {
      return debug(err);
    }
    return null;
  });
  return next();
};

module.exports = {
  watchAssetsTrads
};

With i18n I manage translations via a cookie.使用 i18n,我通过 cookie 管理翻译。 As I mentioned, I needed to use a script file included in all pages on footer.正如我所提到的,我需要使用包含在页脚所有页面中的脚本文件。 There, I've imported this:在那里,我已经导入了这个:

getCurrentLanguage.js获取当前语言.js

const getCookie = () => {
  const cookies = document.cookie.split('; ');
  const myCookie = cookies.filter(c => (/^my-cookie/u).test(c));
  if (typeof myCookie[0] == 'undefined') return 'fr';
  const cookieSplitted = myCookie[0].split('=');
  const currentLanguage = cookieSplitted[1];
  return currentLanguage;
};

const getCurrentLanguage = () => {
  const currentLanguage = getCookie();
  return currentLanguage;
};

export { getCurrentLanguage };

And then, I get all translations and return the one available for current language client side (I realize I only need to get one translation file, improve in coming).然后,我获得所有翻译并返回当前语言客户端可用的翻译(我意识到我只需要获得一个翻译文件,即将改进)。

getTrads.js getTrads.js

const createTradsObjFrom = async (languages, tradsPaths) => {
  try {
    const obj = {};
    for (const [index, lang] of languages.entries()) {
      const path = tradsPaths[index];
      obj[lang] = {
        json: await $.getJSON(path)
      };
    }
    return obj;
  }
  catch (err) {
    throw new Error("some error");
  }
};

const getTrads = currentLanguage => {
  return new Promise((resolve, reject) => {
    const tradsDir = "/assets/trads/";
    const languages = [
      "de",
      "en",
      "es",
      "fr",
      "it",
      "nl",
      "ru"
    ];
    const tradsPaths = languages.map(e => tradsDir + e + '.json');
    createTradsObjFrom(languages, tradsPaths)
    .then(trads => resolve(trads[currentLanguage].json))
    .catch(err => reject(err));
  });
};

export { getTrads };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM