使用Javascript更改网站语言

23

我正在开发一个可以使用多种语言的GUI网站。我得到的原始HTML文件完全是静态的,所以如果需要翻译,我必须遍历所有文件,找出其中的一些单词或术语,收集它们并将其交给翻译部门,并在新的语言文件中输入这些翻译。

由于这些文件完全是静态的,这意味着需要多次翻译整个部分,效率不高。

因此,现在我正在用Javascript开发某种字典,只需在这些网站中交换术语即可。它主要是这样工作的:

var dicEnglish = {
term 1: "This is the English text"
Ref: "Another English text"
}
var dicFrench = {
term 1: "This is the French text"
Ref: "Another French text"   
}

其中包含所有需要更改的可能内容。HTML代码中每个候选项都以class="dicRef" id="l_dicTag_#"作为标识符,我将其切割为词典标记并替换为以下代码:

var imgSrc = "en";
var ActiveDic;
var langSel;
if(window.name){
    langSel=window.name;
    }
else{langSel="English";
}

function LangChange(){
langClass = document.getElementsByClassName("dicRef");
var i = langClass.length;
var Start, Stop, idSrc, idDic;
var navText;

switch(langSel){
    case "French":
        langSel="French";
        imgSrc = "en";
        navText="Anglais";
        break;
    case "English":
    case "Anglais":
    default:
        langSel="English";
        imgSrc = "fr";
        navText="French";
        break;
    }
ActiveDic="dic"+langSel;
window.name=langSel;

while(i--){
    idSrc = langClass[i].id;
    Start=idSrc.indexOf("_")+1;
    Stop=idSrc.lastIndexOf("_");
    idDic=idSrc.slice(Start,Stop);
    if(window[ActiveDic][idDic]){
        document.getElementById(idSrc).innerHTML=window[ActiveDic][idDic];}
    else{
        document.getElementById(idSrc).innerHTML="N/A";
    }
}
if(document.getElementById("imgSel")){
    document.getElementById("imgSel").src="../../img/"+imgSrc+".gif";
}
if (document.getElementById("l_SelLang1_1")){
    document.getElementById("l_SelLang1_1").innerHTML=navText;
}
}

问题在于id标签的唯一性。因为有些术语可能会出现多次,而有些术语是由计数器生成的,所以需要计数器。我更喜欢省略计数器,但找不到其他标识符来区分所有目标术语并更改其内容。

由于我希望未来能够安全处理可能出现的第三种语言,所以我更喜欢一种解决方案。使用内部HTML将需要为每种语言多次标记相同的术语。

那么有没有更有效、更容易地针对所有术语进行交换的方法,或者更好的方法呢?我只能使用客户端解决方案,所以没有PHP等等。


我必须承认,由于我对深层HTML和完全陌生的Javascript还很新,所以我不知道这一点,因为W3C学校从HTML 4开始。 ;)那么向后兼容呢?规格说明它必须与IE 7或Firefox 3.5(当然是更高版本)配合使用。我在HTML 5和旧浏览器方面发现了矛盾的信息。 - Blind Seer
4个回答

60

不针对其他答案者,但在JavaScript或数据属性中存储文本对于搜索引擎或残障站点访问者不利,并且增加了不必要的复杂代码而没有任何好处。在我看来,最好、最简单的解决方案是利用HTML lang属性并使用JavaScript来显示和隐藏所需的语言。这个解决方案还能优雅地退化,所以如果网站访问者禁用了JavaScript,它仍然会显示内容。以下是我的解决方案:

HTML

<button id="switch-lang">Switch Language</button>

<h1><span lang="en">Hello</span> <span lang="es">Hola</span></h1>

<p lang="en">I really enjoy coding.</p>

<p lang="es">Me gusta mucho la codificación.</p>

jQuery

$('[lang="es"]').hide();

$('#switch-lang').click(function() {
  $('[lang="es"]').toggle();
  $('[lang="en"]').toggle();
});

那么我建议添加HTML5 Geolocation来确定最初显示哪种语言,基于用户在世界上的位置。我还将使用Fontawesome语言图标,向用户显示他们可以以任何人都能理解的方式切换语言:http://fontawesome.io/icon/language/

以下是在CodePen上的工作代码示例:https://codepen.io/codepajamas/pen/ZejaQz?editors=1010

以下是在JSFiddle上的附加示例,使用下拉菜单在3种(或更多)语言之间切换:https://jsfiddle.net/726kgom1/1/

带有地理位置和Cookies的更新完整示例

我一直在努力,创建了一个更新的示例,可以在两种语言中切换:中文和英文(如果您需要超过两种语言,则必须隐藏所有语言,并仅显示所选语言,而不是使用切换方式)。此代码还使用jQuery Cookie检测是否已为语言设置现有cookie。它还会检查他们的地理位置(如果他们的浏览器支持),如果他们在台湾或中国,则自动将语言设置为中文,并在其他所有国家默认为英语。下面的代码进行了注释,因此您可以看到每个步骤正在执行什么操作,并希望能够修改它以满足您的需求。这是它: HTML
<button id="switch-lang">Switch Language Icon Here</button>

<h1><span lang="en">Hello</span> <span lang="zh">你好</span></h1>

<p lang="en">I really enjoy coding.</p>

<p lang="zh">我真的很喜歡編碼。</p>

jQuery 注意:这需要链接到不仅是jQuery,还包括jQuery Cookie

$(function () {
  ///// Language Switching (2 languages: English and Chinese). /////

  // Initially disable language switching button.
  $('#switch-lang').css({'pointer-events':'none',
   'cursor':'default'}).attr('disabled','disabled');

  function langButtonListen() {
    $('#switch-lang').click(function (event) {
      event.preventDefault();
      $('[lang="zh"]').toggle();
      $('[lang="en"]').toggle();
      // Switch cookie stored language.
      if ($.cookie('lang') === 'en') {
        $.cookie('lang', 'zh', { expires: 7 });
      } else {
        $.cookie('lang', 'en', { expires: 7 });
      }
    });
    // Enable lang switching button.
    $('#switch-lang').css({'pointer-events':'auto',
     'cursor':'pointer'}).removeAttr('disabled');
  }

  // Check if language cookie already exists.
  if ($.cookie('lang')) {
    var lang = $.cookie('lang');
    if (lang === 'en') {
      $('[lang="zh"]').hide();
      langButtonListen();
    } else {
      $('[lang="en"]').hide();
      langButtonListen();
    }
  } else {
    // no cookie set, so detect language based on location.
    if ("geolocation" in navigator) {
      // geolocation is available
      navigator.geolocation.getCurrentPosition(function (position) {
        // accepted geolocation so figure out which country
        var lat = position.coords.latitude,
            lng = position.coords.longitude;
        $.getJSON('http://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+lng+'&sensor=true', null, function (response) {
          var country = response.results[response.results.length-1].formatted_address;
          if (country ===  'Taiwan' || country === 'China') {
            $('[lang="en"]').hide();
            $.cookie('lang', 'zh', { expires: 7 });
            langButtonListen();
          } else {
            $('[lang="zh"]').hide();
            $.cookie('lang', 'en', { expires: 7 });
            langButtonListen();
          }
        }).fail(function (err) {
          console.log('error: '+err);
          $('[lang="zh"]').hide();
          $.cookie('lang', 'en', { expires: 7 });
          langButtonListen();
        });
      },
      function (error) {
        if (error.code == error.PERMISSION_DENIED) {
          // denied geolocation
          $('[lang="zh"]').hide();
          $.cookie('lang', 'en', { expires: 7 });
          langButtonListen();
        } else {
          console.log('Unknown error. Defaulting to English!');
          $('[lang="zh"]').hide();
          $.cookie('lang', 'en', { expires: 7 });
          langButtonListen();
        }
      });
    } else {
      // geolocation IS NOT available
      $('[lang="zh"]').hide();
      $.cookie('lang', 'en', { expires: 7 });
      langButtonListen());
    }
  }
});

5
这是一个非常好的解决方案! - James McCormac
我见过的最优雅的解决方案 :) - Yan King Yin
非常好。在我的情况下,残障访客和搜索引擎不会成为问题,因为这是一个面向客户的嵌入式网站,所需的语言组合将会改变。 - Blind Seer
是的,这是一个不错的解决方案,但如果您的网站需要支持超过3种语言怎么办?那么您将被困在几乎相同的HTML标签堆中。 因此,对于小型网站来说,这种方法更有效,因为构建语言翻译系统的工作量不值得。 而且您可以在标签中保留文本,以便让禁用Javascript的访问者仍然能够阅读网站,而且甚至不会像有三个相同标签那样混乱。 - Jon_Kle
好的解决方案,只有一个建议:永远不要使用IP地理位置来选择显示语言。想象一下,有人在旅行中,页面以泰语显示 - 这可能不是您的用户想要的。有一种语言偏好设置,几乎每个浏览器都支持,作为HTTP请求的一部分发送,并且作为Javascript常量navigator.language可用。默认情况下,这是浏览器的UI语言,但用户可以更改它。 - user149408
在JSFiddle上添加了一个带有下拉菜单的三种或更多语言示例,链接在这里:https://jsfiddle.net/726kgom1/1/ - J Grover

10

您可以使用数据属性:由于“HTML5属性不受IE6和IE7支持”的事实,这意味着您无法获得getAttribute()方法或dataset属性来检索/访问它们。但是,您仍然可以按照此帖子中所述进行检索。

<div id="geoff" data-geoff="geoff">
var geoff = document.getElementById("geoff");
alert(geoff.getAttribute("data-geoff"));

更好的是,您可以使用jQuery .data() 来支持先前版本的IE。

按照以下方式操作应该可以:

<div data-translate="translation_key"></div>
$("[data-translate]").each(function(){
    var key = $(this).data('translate');
    $(this).html(dictionary[key][current_lang] || "N/A");
});

实例演示:https://jsfiddle.net/x93oLad8/4/


请注意,jQuery的data仅适用于json编码的值,因此在这种情况下,您需要引用和转义数据属性的内容(当仅使用标量值时,这并不太方便)。 - Gerard van Helden
谢谢您指出这一点,但我认为在这种情况下这不会是一个限制,因为翻译键应该是纯字母数字字符串,可能带有下划线作为分隔符,并且不需要任何特殊的转义。 - Andrea Casaccia
抱歉,我查阅了文档,发现我犯了一个错误。字符串值按原样加载,不需要在JSON中进行编码。 - Gerard van Helden
这是一个不错的解决方案,但请注意在iPad和其他情况下它可能无法正常工作。您需要调用dataSet()并从中提取值,例如:var key = $(this).dataSet(); console.log(key.translate);。使用此方法可以在所有浏览器和设备上正常工作。 - Marcos Pérez Gude
1
为什么这个在iPad上不能工作?你能提供一个具体的原因吗? - Andrea Casaccia
显示剩余4条评论

4

解决这个问题的一种方法可能是使用某种客户端模板系统来处理您的界面。 这样,您不需要不必要地将HTML加载了一堆数据属性来详细说明语言要求,而只需在JavaScript中描述一次并使用几个函数来协助翻译即可。 我编写了一个快速示例以向您展示我的意思。

这是字典对象。 它包含按国家/地区代码划分的所有翻译。 这意味着您不需要为每个国家/地区创建单独的字典。 这很重要,因为它意味着我们可以非常轻松地在翻译函数中使用此单一对象结构,您马上就会看到。 这也意味着您可以添加任意多种语言和翻译。

var dict = {
    en: {
        'Hallo': 'Hallo',
        'Goodbye': 'Goodbye',
        'castle': 'castle'
    },
    fr: {
        'Hallo': 'Bonjour',
        'Goodbye': 'Au revoir',
        'castle': 'chateau'
    },
    de: {
        'Hallo': 'Hallo',
        'Goodbye': 'Auf Wiedersehen',
        'castle': 'schloss'
    }
}

这是我们的国家代码,它直接关联到我们字典对象中的国家代码键:

var lang = 'fr';

我们的两个函数中的第一个。它接受一个模板和一种语言,并执行翻译,返回剩余的内容(通常是一些HTML,就像我们的示例一样)。
function applyTemplate(tmpl, lang) {

    // find all words within {{word}} a double set of curly braces
    // (this format is similar to the handlebars templating engine)
    var regex = /\{\{([a-zA-Z])\w+\}\}/g

    // for each found word perform the translation and
    // remove the curly braces
    return tmpl.replace(regex, function (word) {
        return translate(dict, lang, word.replace(/[\{\}]/g, ''));
    });
}

translate函数接受字典、语言和一个单词作为参数,并返回翻译后的单词。请注意,如果有一个包含所有国家翻译的对象,这将更加简单。

function translate(dict, lang, word) {
    return dict[lang][word];
}

一些HTML。这是我们的模板(display: none)和输出元素。请注意花括号中的单词需要翻译。

<div class="template"><div>{{Goodbye}}, {{castle}}</div></div>
<div id="translation"></div>

最后,将所有内容放在一起:
//  grab the template
var tmpl = document.querySelector('.template').textContent;
var translation = document.querySelector('#translation');

// grab our translated html and add it to the output element
var html = applyTemplate(tmpl, lang);
translation.insertAdjacentHTML('afterbegin', html);

演示

显然,您不必使用此方法(有数十种JS模板引擎可供选择),但是模板对于需要使用多种语言的网站尤其有用。许多人在后端执行此操作,但是如您所见,也可以轻松地在客户端执行。

希望这对您有所帮助,并为您提供了几种不同的解决方案思路。


以上解决方案运行得非常好。不过我建议进行一些微小的修改。 首先,关闭 id="translation" 的 <div> 标签。 其次,使用 innerHtml 属性而不是 replaceAdjacentHTML() 方法。这样您就可以运行多个翻译而无需复制实际文本。 - Norbert Hüthmayr
一定要使用它,服务器端资源可扩展和可定制,不依赖于JavaScript。 - Nathaniel Flick

1
 <script type="text/javascript">

// 加载 Google Transliteration API google.load("elements", "1", { packages: "transliteration" });

  var transliterationControl;
  function onLoad() {
    var options = {
        sourceLanguage: 'en',
        destinationLanguage: ['hi','or','bn','ta','te'],
        transliterationEnabled: true,
        shortcutKey: 'ctrl+g'
    };
    // Create an instance on TransliterationControl with the required
    // options.
    transliterationControl =
      new google.elements.transliteration.TransliterationControl(options);

    // Enable transliteration in the textfields with the given ids.
    var ids = [ "transl1", "transl2" ];
    transliterationControl.makeTransliteratable(ids);

    // Add the STATE_CHANGED event handler to correcly maintain the state
    // of the checkbox.
    transliterationControl.addEventListener(
        google.elements.transliteration.TransliterationControl.EventType.STATE_CHANGED,
        transliterateStateChangeHandler);

    // Add the SERVER_UNREACHABLE event handler to display an error message
    // if unable to reach the server.
    transliterationControl.addEventListener(
        google.elements.transliteration.TransliterationControl.EventType.SERVER_UNREACHABLE,
        serverUnreachableHandler);

    // Add the SERVER_REACHABLE event handler to remove the error message
    // once the server becomes reachable.
    transliterationControl.addEventListener(
        google.elements.transliteration.TransliterationControl.EventType.SERVER_REACHABLE,
        serverReachableHandler);

    // Set the checkbox to the correct state.
    document.getElementById('checkboxId').checked =
      transliterationControl.isTransliterationEnabled();

    // Populate the language dropdown
    var destinationLanguage =
      transliterationControl.getLanguagePair().destinationLanguage;
    var languageSelect = document.getElementById('languageDropDown');
    var supportedDestinationLanguages =
      google.elements.transliteration.getDestinationLanguages(
        google.elements.transliteration.LanguageCode.ENGLISH);
    for (var lang in supportedDestinationLanguages) {
      var opt = document.createElement('option');
      opt.text = lang;
if (lang=="TAMIL" || lang=="TELUGU" || lang=="HINDI" || lang=="ORIYA" || lang=="BENGALI"){
      opt.value = supportedDestinationLanguages[lang];
      if (destinationLanguage == opt.value) {
        opt.selected = true;
      }
      try {
        languageSelect.add(opt, null);
      } catch (ex) {
        languageSelect.add(opt);
      }
}//End of if
    }
  }

  // Handler for STATE_CHANGED event which makes sure checkbox status
  // reflects the transliteration enabled or disabled status.
  function transliterateStateChangeHandler(e) {
    document.getElementById('checkboxId').checked = e.transliterationEnabled;
  }

  // Handler for checkbox's click event.  Calls toggleTransliteration to toggle
  // the transliteration state.
  function checkboxClickHandler() {
    transliterationControl.toggleTransliteration();
  }

  // Handler for dropdown option change event.  Calls setLanguagePair to
  // set the new language.
  function languageChangeHandler() {
    var dropdown = document.getElementById('languageDropDown');
    transliterationControl.setLanguagePair(
        google.elements.transliteration.LanguageCode.ENGLISH,
        dropdown.options[dropdown.selectedIndex].value);
  }

  // SERVER_UNREACHABLE event handler which displays the error message.
  function serverUnreachableHandler(e) {
    document.getElementById("errorDiv").innerHTML =
        "Transliteration Server unreachable";
  }

  // SERVER_UNREACHABLE event handler which clears the error message.
  function serverReachableHandler(e) {
    document.getElementById("errorDiv").innerHTML = "";
  }
  google.setOnLoadCallback(onLoad);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接