【问题标题】:How to maintain changing state of language in expressJS如何在 expressJS 中保持不断变化的语言状态
【发布时间】:2019-03-16 03:46:22
【问题描述】:

我正在开发一个使用 nodeJs、handlebars 和 expressJs 框架的项目。我使用i18n-express 模块添加更改语言功能。当我们要更改语言时,此模块在 url 末尾添加查询字符串。现在的问题是,当我将一页移动到另一页时,查询字符串被删除并丢失了他的状态。那么我怎样才能保持语言状态?如果用户选择法语,那么所有页面都以法语打开。这就是我要的。

代码:

var i18n =  require("i18n-express");

app.use(i18n({
  translationsPath: path.join(__dirname, 'lang'), // <--- use here. Specify translations files path.
  siteLangs: ["ar","en","cn","fr","ge","he","hu","it","ja","ko","es","ru"],
  cookieLangName : 'ulang',
  textsVarName: 'translation'  
}));

更改语言的链接

<a href="#!" id="{{icon}}" onclick=" return changeLanguage(this)"></a>

Onclick 功能更改语言

function changeLanguage(event){
   $('#languages img').attr('src','/images/flag-icons/'+event.id+'.png');
   var url = window.location.href;
   url = url.split("?")[0];
   url += '?clang='+event.id;
   window.location.href = url;
   localStorage.setItem("clang", '?clang='+event.id); //event.id returns locale name such as en, ar, sp, fr etc.
   //console.log(url);
}

【问题讨论】:

  • 您能否在codesandbox 中创建一个您遇到的“双刷新”问题的最小示例(来自以下解决方案)?

标签: javascript node.js express internationalization


【解决方案1】:

我推荐你Lingua for ExpressJS

基本上,Lingua 是 Express.js 的中间件,它可以帮助您轻松地国际化您的 web 应用程序。它确定用户代理的语言并将 i18n 资源推送到您的视图。

$ npm install -s lingua

var express = require('express'),
    lingua  = require('lingua');

// Express app configuration code and lingua init.
app.configure(function() {

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

// Lingua configuration
app.use(lingua(app, {
    defaultLocale: 'en',
    path: __dirname + '/i18n'
}));

app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(__dirname + '/public'));
app.use(app.router);

语言文件

'./i18n/en.json' and './i18n/de-de.json').

// en.json
    {
        "title": "Hello World",
        "content": {
            "description": "A little description."
        }
    }

// de-de.json
    {
        "title": "Hallo Welt",
        "content": {
            "description": "Eine kleine Beschreibung."
        }
    }

您可以通过以下方式在您的页面上轻松实现它:

<h1><%= lingua.title %></h1> <!-- out: <h1>Hello World</h1> -->
<p><%= lingua.content.description %></h1> <!-- out: <p>A little description.</p> -->

【讨论】:

  • 突然这个页面没有用于 TypeScript 编程的@types
【解决方案2】:

在客户端,如果您能够在本地存储上设置项目,那么您也可以获取相同的项目并使用其值将其推送到查询字符串。因此,您基本上需要在客户端 javascript 上添加一个附加功能,该功能将在每次页面打开时获取该项目。

    function getParameterByName(name, url) {
        if (!url) url = window.location.href;
        name = name.replace(/[\[\]]/g, '\\$&');
        var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }

    function checkLanguageFromLocalStorage(){
        var clang = getParameterByName('clang');
        if (clang == null) {
            if (localStorage.getItem("clang") != null) {
                var clang = localStorage.getItem("clang");
                var url = window.location.href;
                url = url.split("?")[0];
                url += '?clang='+clang;
                window.location.href = url;
            }
        }
    }

    checkLanguageFromLocalStorage();

【讨论】:

  • 我已经尝试过了,但它会加载页面两次。有什么想法吗?
  • 基于这个答案link 你可以在你的控件上添加一个额外的检查来获取是否已经设置了“clang”并且已经推送到查询字符串上,所以如果已经设置了就不要刷新页面.我用这张支票改变了答案。
【解决方案3】:

为什么不使用语言而不是查询参数传递 cookie? i18n-express 有一个名为 cookieLangNameoption,您已经在服务器端配置了它 (cookieLangName: 'ulang')。设置cookieLangName 使i18n-express 使用您传递的名称从cookie 中读取语言。您只需要在客户端脚本中设置此 cookie - 在 changeLanguage 函数内 - 它会成功:

function changeLanguage(event){
   $('#languages img').attr('src','/images/flag-icons/'+event.id+'.png');
   document.cookie = `ulang=${event.id}; path=/`;

   localStorage.setItem("ulang", `ulang=${event.id}; path=/`); // you can still save it to localStorage and synchronize it when cookie is removed
}

【讨论】:

    【解决方案4】:

    要求,我理解归结为:

    如果最终用户选择了一种语言,则该选择在 URL 中应始终透明,以使翻译模块能够正常运行。满足此要求不应导致不必要的页面重新加载。但是,这个问题的范围忽略了这样一个事实,即在不存在 clang=xx 的冷启动时,需要手动重定向才能加载正确的内容,因为只有客户端知道之前的用户选择。

    根据您发布的 sn-p,您快到了。函数changeLanguage 正确加载所选语言的内容。但是,如果我要对其进行代码审查,我会要求对以下结果进行一些更改:

    修补的 HTML

    <a href="#!" id="{{icon}}" onclick="return loadContentInSelectedLanguage(this.id)"></a>
    

    已修补的 JS:

    function processLanguageSelection(selectedLang) {
    
      highlightCurrentlySelectedLang(selectedLang);
      saveSelectedLangAcrossSession("clang", selectedLang);
    
      reloadContentInSelectedLang(selectedLang);
    }
    
    function highlightCurrentlySelectedLanguage(selectedLang) {
      $('#languages img').attr('src', '/images/flag-icons/' + selectedLang + '.png');
    }
    
    function saveSelectedLangAcrossSession(entryKey, selectedLang) {
      window.localStorage.setItem(entryKey, selectedLang);
    }
    
    function reloadContentInSelectedLang(selectedLang) {
      var search = window.location.search || "?";
    
      if (/clang=\w{2}/.test(search)) {
        search = search.replace(/clang=\w{2}/, "clang=" + selectedLang);
      } else {
        search += ("?" === search ? "clang=" : "&clang=") + selectedLang;
      }
    
      window.history.replaceState(null, "", search);
      window.location.reload();
    }
    

    你快到了,就像我说的那样。 那么,最终还剩下什么? -- 缺少的筹码是:应该在页面开始加载时应用之前的用户选择。并且任何必要的重定向都应该在浏览器开始处理文档正文之前尽早完成。 自然地,这意味着你的脚本中承担这个责任的部分应该是首先在里面运行的东西&lt;head&gt;...&lt;/head&gt; 部分。

    <head>
      <script>
        (function() {
          var previouslySelectedLanguage = window.localStorage.getItem("clang");
    
          if (/clang=\w{2}/.test(window.location.search)) {
            // correct content should have been loaded in this case
            // otherwise the server needs fixing, but that's not
            // in the scope of this question.
    
            // determine selectedLang from window.location.search, then..
            highlightCurrentlySelectedLanguage(selectedLang);
    
            if (!previouslySelectedLanguage || "selectedLang" !== previouslySelectedLanguage) {
              saveSelectedLangAcrossSession("clang", selectedLang);
            }
    
            return;
          }
    
          if (previouslySelectedLanguage) {
            // redirect
            reloadContentInSelectedLang(previouslySelectedLanguage);
          }
        })();
    
      </script>
    </head>
    

    请注意,此答案中提供的示例尚未准备好生产。通过确保它们稳健、有弹性并符合组织要求的其他标准来进行尽职调查。例如,这个正则表达式 /clang=\w{2}/ 做出了一个并不总是正确的大胆假设。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-08
      • 1970-01-01
      • 2015-07-02
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      相关资源
      最近更新 更多