Bug 444411 - Migrate SeaMonkey's "Browser > Languages" preferences to new pref window (part 1 - stefanh's changes)
authorStefan Hermes <stefanh@inbox.com>
Tue, 16 Sep 2008 22:51:16 +0100
changeset 344 83c3bdc8df86280e1bc12f5b6296501579d806be
parent 343 4c8b7768fc76e5669ad68442011c3a73eeef77be
child 345 5048efa447abd879e388deb7a36dc6859bc21822
push idunknown
push userunknown
push dateunknown
bugs444411
Bug 444411 - Migrate SeaMonkey's "Browser > Languages" preferences to new pref window (part 1 - stefanh's changes) r=iann/mnyromyr sr=neil a=blocking-seamonkey2.0a1+
suite/common/jar.mn
suite/common/pref/pref-languages-add.js
suite/common/pref/pref-languages-add.xul
suite/common/pref/pref-languages.js
suite/common/pref/pref-languages.xul
suite/common/pref/preferences.xul
suite/common/pref/preftree.xul
--- a/suite/common/jar.mn
+++ b/suite/common/jar.mn
@@ -176,16 +176,17 @@ comm.jar:
    content/communicator/pref/pref-http.js                           (pref/pref-http.js)
    content/communicator/pref/pref-http.xul                          (pref/pref-http.xul)
    content/communicator/pref/pref-images.xul                        (pref/pref-images.xul)
    content/communicator/pref/pref-keynav.js                         (pref/pref-keynav.js)
    content/communicator/pref/pref-keynav.xul                        (pref/pref-keynav.xul)
    content/communicator/pref/pref-languages.js                      (pref/pref-languages.js)
    content/communicator/pref/pref-languages.xul                     (pref/pref-languages.xul)
    content/communicator/pref/pref-languages-add.xul                 (pref/pref-languages-add.xul)
+   content/communicator/pref/pref-languages-add.js                  (pref/pref-languages-add.js)
    content/communicator/pref/pref-locationbar.js                    (pref/pref-locationbar.js)
    content/communicator/pref/pref-locationbar.xul                   (pref/pref-locationbar.xul)
    content/communicator/pref/pref-mousewheel.js                     (pref/pref-mousewheel.js)
    content/communicator/pref/pref-mousewheel.xul                    (pref/pref-mousewheel.xul)
    content/communicator/pref/pref-navigator.js                      (pref/pref-navigator.js)
    content/communicator/pref/pref-navigator.xul                     (pref/pref-navigator.xul)
    content/communicator/pref/pref-offline.xul                       (pref/pref-offline.xul)
    content/communicator/pref/pref-policies.xul                      (pref/pref-policies.xul)
new file mode 100644
--- /dev/null
+++ b/suite/common/pref/pref-languages-add.js
@@ -0,0 +1,273 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Adrian Havill <havill@redhat.com>
+ *   Stefan Hermes <stefanh@inbox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gLangObj;                             
+var availableLanguages;
+var otherField;
+
+function Startup()
+{ 
+  gLangObj = window.arguments[0];
+  availableLanguages = document.getElementById("availableLanguages");
+  otherField = document.getElementById("otherLanguages");
+  LoadAvailableLanguages();
+}
+
+function LoadAvailableLanguages()
+{
+  if (gLangObj.availLanguageDict)
+  {
+    for (var i = 0; i < gLangObj.availLanguageDict.length; i++)
+    {
+      if (gLangObj.availLanguageDict[i][2] == "true")
+        AddListItem(document, availableLanguages, gLangObj.availLanguageDict[i][1], gLangObj.availLanguageDict[i][0]);
+    }
+  }
+}
+
+function IsAlpha(aMixedCase)
+{
+  var allCaps = aMixedCase.toUpperCase();
+  for (var i = allCaps.length - 1; i >= 0; i--)
+  {
+    let c = allCaps.charAt(i);
+    if (c < 'A' || c > 'Z') return false;
+  }
+  return true;
+}
+
+function IsAlphaNum(aMixedCase)
+{
+  var allCaps = aMixedCase.toUpperCase();
+  for (var i = allCaps.length - 1; i >= 0; i--)
+  {
+    let c = allCaps.charAt(i);
+    if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) return false;
+  }
+  return true;
+}
+
+function IsRFC1766LangTag(aCandidate)
+{
+
+  /* reject bogus lang strings, INCLUDING those with HTTP "q"
+     values kludged on the end of them
+
+     Valid language codes examples:
+     i.e. ja-JP-kansai (Kansai dialect of Japanese)
+          en-US-texas (Texas dialect)
+          i-klingon-tng (did TOS Klingons speak in non-English?)
+          sgn-US-MA (Martha Vineyard's Sign Language)
+  */
+  var tags = aCandidate.split('-');
+
+  /* if not IANA "i" or a private "x" extension, the primary
+     tag should be a ISO 639 country code, two or three letters long.
+     we don't check if the country code is bogus or not.
+  */
+  var checkedTags = 0;
+  if (tags[0].toLowerCase() != "x" && tags[0].toLowerCase() != "i")
+  {
+    if (tags[0].length != 2 && tags[0].length != 3) return false;
+    if (!IsAlpha(tags[0])) return false;
+    checkedTags++;
+
+    /* the first subtag can be either a 2 letter ISO 3166 country code,
+       or an IANA registered tag from 3 to 8 characters.
+    */
+    if (tags.length > 1)
+    {
+      if (tags[1].length < 2 || tags[1].length > 8) return false;
+      if (!IsAlphaNum(tags[1])) return false;
+
+      /* do not allow user-assigned ISO 3166 country codes */
+      if (tags[1].length == 2 && IsAlpha(tags[1]))
+      {
+        var countryCode = tags[1].toUpperCase();
+        if (countryCode == "AA" || countryCode == "ZZ") return false;
+        if (countryCode[0] == 'X') return false;
+        if (countryCode[0] == 'Q' && countryCode[1] > 'L') return false;
+      }
+      checkedTags++;
+    }
+  }
+  else if (tags.length < 2) return false;
+  else
+  {
+    if ((tags[1].length < 1) || (tags[1].length > 8)) return false;
+    if (!IsAlphaNum(tags[1])) return false;
+    checkedTags++;
+  }
+
+  /* any remaining subtags must be one to eight alphabetic characters */
+
+  for (var i = checkedTags; i < tags.length; i++)
+  {
+    if ((tags[1].length < 1) || (tags[i].length > 8)) return false;
+    if (!IsAlphaNum(tags[i])) return false;
+    checkedTags++;
+  }
+  return true;
+}
+
+function WriteAddedLanguages(aListbox)
+{
+  var addedLang = [];
+  var prefString = document.getElementById("intl.accept_languages").value;
+
+  //selected languages
+  for (var i = 0; i < aListbox.selectedItems.length; i++)
+  {
+    let selItem = aListbox.selectedItems[i];
+    let languageId = selItem.id;
+    if (!LangAlreadyActive(languageId))
+      addedLang.push(languageId);
+  }
+
+  //user-defined languages
+  if (otherField.value)
+  {
+    let languageIdsString = otherField.value.replace(/\s/g,"").toLowerCase();
+    let languageIds = languageIdsString.split(/\s*,\s*/);
+    for (var i = 0; i < languageIds.length; i++)
+    {
+      let languageId = languageIds[i];
+      
+      if (IsRFC1766LangTag(languageId))
+      {
+        if (!LangAlreadySelected(languageId) && !LangAlreadyActive(languageId))
+          addedLang.push(languageId);
+      }
+    }
+  }
+
+  if (addedLang.length > 0)
+  {
+    if (!prefString)
+      prefString = addedLang[0];
+    else
+      prefString += ", " + addedLang[0];
+
+    for (var i = 1; i < addedLang.length; i++)
+      prefString += ", " + addedLang[i];
+  }
+
+  return prefString;
+}
+
+function CheckOtherField()
+{
+  if (!otherField.value)
+    return true;
+
+  var invalidLangs = [];
+  var languageIdsString = otherField.value.replace(/\s/g,"").toLowerCase();
+  var languageIds = languageIdsString.split(/\s*,\s*/);
+
+  languageIds.forEach(function(aElement) {
+    if (!IsRFC1766LangTag(aElement))
+      invalidLangs.push(aElement);
+  });
+
+  if (invalidLangs.length > 0)
+  {
+    let prefLangBundle = document.getElementById("prefLangBundle");
+    const errorMsg = prefLangBundle.getString("illegalOtherLanguage") + " " +
+                     invalidLangs.join(", ");
+    const errorTitle = prefLangBundle.getString("illegalOtherLanguageTitle");
+    let prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+                             .getService(Components.interfaces.nsIPromptService);
+    prompter.alert(this.window, errorTitle, errorMsg);
+    otherField.focus();
+    return false;
+  }
+
+  return true;
+}
+
+
+function LangAlreadySelected(aLangID)
+{
+  return availableLanguages.selectedItems.some(AlreadyExists, aLangID);
+}
+
+function LangAlreadyActive(aLangID)
+{
+  var prefString = document.getElementById("intl.accept_languages").value;
+  var arrayOfPrefs = prefString.split(/\s*,\s*/);
+
+  if (arrayOfPrefs)
+    return arrayOfPrefs.some(AlreadyExists, aLangID);
+
+  return false;
+}
+
+function AlreadyExists(aElement, aIndex, aArray, aLangID)
+{
+  return (aElement == this)
+}
+
+function HandleDoubleClick()
+{
+  document.documentElement.acceptDialog();
+}
+
+function DoBeforeAccept()
+{
+  availableLanguages.doCommand();
+}
+
+function AddListItem(doc, listbox, langID, langTitle)
+{
+  try {  //let's beef up our error handling for languages without label / title
+
+      // Create a listitem for the new Language
+      var item = doc.createElement('listitem');
+
+      // Copy over the attributes
+      item.setAttribute('label', langTitle);
+      item.id = langID;
+
+      listbox.appendChild(item);
+
+  } //try
+
+  catch (ex) {
+  } //catch
+}
--- a/suite/common/pref/pref-languages-add.xul
+++ b/suite/common/pref/pref-languages-add.xul
@@ -18,16 +18,17 @@
 
  The Initial Developer of the Original Code is
  Netscape Communications Corporation.
  Portions created by the Initial Developer are Copyright (C) 1999
  the Initial Developer. All Rights Reserved.
 
  Contributor(s):
    Adrian Havill <havill@redhat.com>
+   Stefan Hermes <stefanh@inbox.com>
 
  Alternatively, the contents of this file may be used under the terms of
  either of the GNU General Public License Version 2 or later (the "GPL"),
  or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
@@ -35,35 +36,49 @@
  and other provisions required by the GPL or the LGPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.
 
  ***** END LICENSE BLOCK ***** -->
 
 <?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?>
 
-<!DOCTYPE dialog SYSTEM "chrome://communicator/locale/pref/pref-languages.dtd" >
+<!DOCTYPE prefwindow SYSTEM "chrome://communicator/locale/pref/pref-languages.dtd" >
+
 
-<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-      title="&languages.customize.add.title.label;"
-      onload="Init();"
-      ondialogaccept="return AddAvailableLanguage();"
-      style="width: 25em;height: 28em;">
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+            title="&languages.customize.add.title.label;"
+            type="child"
+            onload="Startup();"
+            onbeforeaccept="DoBeforeAccept();"
+            ondialogaccept="return CheckOtherField();"
+            style="width: 25em;height: 28em;">
 
-  <script type="application/x-javascript" src="pref-languages.js"/>
- 
-  <description>&languages.customize.prefAddLangDescript;</description>
-  <separator class="thin"/>
-  <description>&languages.customize.available.label;</description>
+  <script type="application/javascript" src="chrome://communicator/content/pref/pref-languages-add.js"/>
+
+  <prefpane id="addLanguagesPane">
+    <preferences id="addLanguages">
+      <preference id="intl.accept_languages"
+                  name="intl.accept_languages"
+                  type="wstring"/>
+    </preferences>
 
-  <listbox id="available_languages" flex="1" seltype="multiple"
-           ondblclick="HandleDoubleClick(event.target)"/>
+    <stringbundle id="prefLangBundle"
+                  src="chrome://communicator/locale/pref/pref-languages.properties"/>
+ 
+    <description>&languages.customize.prefAddLangDescript;</description>
+    <separator class="thin"/>
+    <description>&languages.customize.available.label;</description>
+ 
+    <listbox id="availableLanguages" flex="1" seltype="multiple"
+             preference="intl.accept_languages"
+             ondblclick="HandleDoubleClick();"
+             onsynctopreference="return WriteAddedLanguages(this);"/>
 
-  <hbox align="center">
-    <label value="&languages.customize.others.label;" 
-           accesskey="&languages.customize.others.accesskey;" 
-           control="languages.other"/>
-    <textbox id="languages.other" size="6" flex="1"/>
-    <label value="&languages.customize.others.examples;" control="languages.other"/>
-  </hbox>
-
-</dialog>
-
+    <hbox align="center">
+      <label value="&languages.customize.others.label;" 
+             accesskey="&languages.customize.others.accesskey;" 
+             control="otherLanguages"/>
+      <textbox id="otherLanguages" size="6" flex="1"/>
+      <label value="&languages.customize.others.examples;" control="otherLanguages"/>
+    </hbox>
+  </prefpane>
+</prefwindow>
--- a/suite/common/pref/pref-languages.js
+++ b/suite/common/pref/pref-languages.js
@@ -15,583 +15,325 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *         Adrian Havill <havill@redhat.com>
+ *   Adrian Havill <havill@redhat.com>
+ *   Stefan Hermes <stefanh@inbox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-//GLOBALS
-
-
-//locale bundles
-var regionsBundle;
-var languagesBundle;
-var acceptedBundle;
-var prefLangBundle;
+//Dictionary of all available languages
+var langObj = { availLanguageDict: [] };
 
-//dictionary of all supported locales
-var availLanguageDict;
-
-//XUL listbox handles
-var available_languages;
-var active_languages;
-
-//XUL window pref window interface object
-var pref_string = new String();
-
-//Reg expression for splitting multiple pref values
-var separatorRe = /\s*,\s*/;
-
+var activeLanguages;
 
 function Startup()
 {
-  // Load base window.
+  var observerService = Components.classes["@mozilla.org/observer-service;1"]
+                                  .getService(Components.interfaces.nsIObserverService);
+  observerService.notifyObservers(null, "charsetmenu-selected", "other");
 
-  acceptedBundle = document.getElementById("acceptedBundle");
-  languagesBundle = document.getElementById("languagesBundle");
-  prefLangBundle = document.getElementById("prefLangBundle");
-  regionsBundle = document.getElementById("regionsBundle");
+  var defaultCharsetList = document.getElementById("DefaultCharsetList");
+  defaultCharsetList.setAttribute("ref", "NC:DecodersRoot");
 
-  active_languages = document.getElementById("active_languages");
-  pref_string = active_languages.getAttribute("prefvalue");
+  activeLanguages = document.getElementById("activeLanguages");
 
   ReadAvailableLanguages();
-  LoadActiveLanguages();
-  SelectLanguage();
 }
 
-
-function Init()
-{
-  // Load available languages popup.
-
-  // Reuse the language panel's bundle and globals
-  prefLangBundle = opener.prefLangBundle;
-  availLanguageDict = opener.availLanguageDict;
-  pref_string = opener.pref_string;
-  active_languages = opener.active_languages;
-
-  available_languages = document.getElementById("available_languages");
-
-  LoadAvailableLanguages();
-}
-
-
 function AddLanguage()
 {
-    window.openDialog("chrome://communicator/content/pref/pref-languages-add.xul","_blank","modal,chrome,centerscreen,titlebar", "addlangwindow");
-    UpdateSavePrefString();
-    SelectLanguage();
+  document.documentElement.openSubDialog("chrome://communicator/content/pref/pref-languages-add.xul","addlangwindow", langObj);
 }
 
-
 function ReadAvailableLanguages()
 {
-  availLanguageDict   = new Array();
-  var visible = new String();
-  var str = new String();
   var i =0;
-
-  const acceptedBundleEnum = acceptedBundle.stringBundle.getSimpleEnumeration();
+  var languagesBundle = document.getElementById("languagesBundle");
+  var prefLangBundle = document.getElementById("prefLangBundle");
+  var regionsBundle = document.getElementById("regionsBundle");
+  var langStrings = document.getElementById("acceptedBundle").strings;
 
-  var curItem;
-  var stringName;
-  var stringNameProperty;
-
-  while (acceptedBundleEnum.hasMoreElements()) {
-
+  while (langStrings.hasMoreElements())
+  {
     //progress through the bundle
-    curItem = acceptedBundleEnum.getNext();
+    var curItem = langStrings.getNext();
 
-    //"unpack" the item, nsIPropertyElement is now partially scriptable
-    curItem = curItem.QueryInterface(Components.interfaces.nsIPropertyElement);
+    if (!(curItem instanceof Components.interfaces.nsIPropertyElement))
+      break;
 
-    //dump string name (key)
-    stringName = curItem.key;
-    stringNameProperty = stringName.split('.');
-
-    if (stringNameProperty[1] == 'accept') {
+    var stringNameProperty = curItem.key.split('.');
 
-      //dump the UI string (value)
-      visible   = curItem.value;
-
-      //if (visible == 'true') {
+    if (stringNameProperty[1] == 'accept')
+    {
+        var str = stringNameProperty[0];
+        var stringLangRegion = stringNameProperty[0].split('-');
+        var tit;
 
-        str = stringNameProperty[0];
-        var stringLangRegion = stringNameProperty[0].split('-');
-
-        if (stringLangRegion[0]) {
-          var tit;
+        if (stringLangRegion[0])
+        {
           var language;
           var region;
-          var use_region_format = false;
+          var useRegionFormat = false;
 
           try {
             language = languagesBundle.getString(stringLangRegion[0]);
           }
           catch (ex) {
             language = "";
           }
 
-          if (stringLangRegion.length > 1) {
+          if (stringLangRegion.length > 1)
+          {
 
             try {
               region = regionsBundle.getString(stringLangRegion[1]);
-              use_region_format = true;
+              useRegionFormat = true;
             }
             catch (ex) {
             }
           }
           
-          if (use_region_format) {
+          if (useRegionFormat)
             tit = prefLangBundle.getFormattedString("languageRegionCodeFormat",
                                                     [language, region, str]);
-          } else {
+          else
             tit = prefLangBundle.getFormattedString("languageCodeFormat",
                                                     [language, str]);
-          }
-
-        } //if language
-
-        if (str && tit) {
+        }
 
-          availLanguageDict[i] = new Array(3);
-          availLanguageDict[i][0] = tit;
-          availLanguageDict[i][1] = str;
-          availLanguageDict[i][2] = visible;
+        if (str && tit)
+        {
+          langObj.availLanguageDict[i] = [];
+          langObj.availLanguageDict[i].push(tit, str, curItem.value);
           i++;
+        }
+    }
+  }
 
-        } // if str&tit
-      //} //if visible
-    } //if accepted
-  } //while
-  availLanguageDict.sort( // sort on first element
+  langObj.availLanguageDict.sort( // sort on first element
     function compareFn(a, b) {
       return a[0].localeCompare(b[0]);
     });
 }
 
-
-function LoadAvailableLanguages()
-{
-  if (availLanguageDict)
-    for (var i = 0; i < availLanguageDict.length; i++) {
-
-    if (availLanguageDict[i][2] == 'true') {
-
-        AddListItem(document, available_languages, availLanguageDict[i][1], availLanguageDict[i][0]);
-
-      } //if
-
-    } //for
-}
-
-
-function LoadActiveLanguages()
+function ReadActiveLanguages(aListbox)
 {
-  if (pref_string) {
-    var arrayOfPrefs = pref_string.split(separatorRe);
-
-    for (var i = 0; i < arrayOfPrefs.length; i++) {
-      var str = arrayOfPrefs[i];
-      var tit = GetLanguageTitle(str);
+  var prefString = document.getElementById("intl.accept_languages").value;
+  var arrayOfPrefs = prefString.split(/\s*,\s*/);
+  
+  var listboxChildren = aListbox.childNodes;
 
-      if (str) {
-        if (!tit)
-           tit = '[' + str + ']';
-        AddListItem(document, active_languages, str, tit);
+  // No need to rebuild listitems if languages in prefs and listitems match.
+  if (InSync(arrayOfPrefs, listboxChildren))
+   return undefined;
 
-      } //if
-    } //for
-  }
-}
-
+  while (aListbox.hasChildNodes())
+    aListbox.removeChild(aListbox.firstChild);
 
-function LangAlreadyActive(langId)
-{
-  var found = false;
-  try {
-    var arrayOfPrefs = pref_string.split(separatorRe);
+  arrayOfPrefs.forEach(function(aElement) {
+    if (aElement)
+    {
+      let langTitle = GetLanguageTitle(aElement);
 
-    if (arrayOfPrefs)
-      for (var i = 0; i < arrayOfPrefs.length; i++) {
-      if (arrayOfPrefs[i] == langId) {
-         found = true;
-         break;
-      }
-    }
-
-    return found;
-  }
+      if (!langTitle)
+       langTitle = '[' + aElement + ']';
 
-  catch(ex){
-     return false;
-  }
-}
+      let listitem = document.createElement('listitem');
+      listitem.setAttribute('label', langTitle);
+      listitem.id = aElement;
+      aListbox.appendChild(listitem);
+    }
+  });
 
-function isAlpha(mixedCase) {
-  var allCaps = mixedCase.toUpperCase();
-  for (var i = allCaps.length - 1; i >= 0; i--) {
-    var c = allCaps.charAt(i);
-    if (c < 'A' || c > 'Z') return false;
-  }
-  return true;
-}
+  SelectLanguage();
 
-function isAlphaNum(mixedCase) {
-  var allCaps = mixedCase.toUpperCase();
-  for (var i = allCaps.length - 1; i >= 0; i--) {
-    var c = allCaps.charAt(i);
-    if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) return false;
-  }
-  return true;
+  return undefined;
 }
 
-function IsRFC1766LangTag(candidate) {
-
-  /* reject bogus lang strings, INCLUDING those with HTTP "q"
-     values kludged on the end of them
-
-     Valid language codes examples:
-     i.e. ja-JP-kansai (Kansai dialect of Japanese)
-          en-US-texas (Texas dialect)
-          i-klingon-tng (did TOS Klingons speak in non-English?)
-          sgn-US-MA (Martha Vineyard's Sign Language)
-  */
-  var tags = candidate.split('-');
-
-  /* if not IANA "i" or a private "x" extension, the primary
-     tag should be a ISO 639 country code, two or three letters long.
-     we don't check if the country code is bogus or not.
-  */
-  var checkedTags = 0;
-  if (tags[0].toLowerCase() != "x" && tags[0].toLowerCase() != "i") {
-    if (tags[0].length != 2 && tags[0].length != 3) return false;
-    if (!isAlpha(tags[0])) return false;
-    checkedTags++;
+// Checks whether listitems and pref values matches, returns false if not
+function InSync(aPrefArray, aListItemArray)
+{
+  // Can't match if they don't have the same length
+  if (aPrefArray.length != aListItemArray.length)
+    return false;
 
-    /* the first subtag can be either a 2 letter ISO 3166 country code,
-       or an IANA registered tag from 3 to 8 characters.
-    */
-    if (tags.length > 1) {
-      if (tags[1].length < 2 || tags[1].length > 8) return false;
-      if (!isAlphaNum(tags[1])) return false;
+  return aPrefArray.every(IsTheSame, aListItemArray);
+}
 
-      /* do not allow user-assigned ISO 3166 country codes */
-      if (tags[1].length == 2 && isAlpha(tags[1])) {
-        var countryCode = tags[1].toUpperCase();
-        if (countryCode == "AA" || countryCode == "ZZ") return false;
-        if (countryCode[0] == 'X') return false;
-        if (countryCode[0] == 'Q' && countryCode[1] > 'L') return false;
-      }
-      checkedTags++;
-    }
-  }
-  else if (tags.length < 2) return false;
-  else {
-    if ((tags[1].length < 1) || (tags[1].length > 8)) return false;
-    if (!isAlphaNum(tags[1])) return false;
-    checkedTags++;
-  }
-
-  /* any remaining subtags must be one to eight alphabetic characters */
-
-  for (var i = checkedTags; i < tags.length; i++) {
-    if ((tags[1].length < 1) || (tags[i].length > 8)) return false;
-    if (!isAlphaNum(tags[i])) return false;
-    checkedTags++;
-  }
-  return true;
+function IsTheSame(aElement, aIndex, aArray, aListItemArray)
+{
+  return (aElement == this[aIndex].id);
 }
 
-function AddAvailableLanguage()
+// Called on onsynctopreference
+function WriteActiveLanguages(aListbox)
 {
-  var Languagename = new String();
-  var Languageid = new String();
-  
-  var addThese = new Array();
-  var addTheseNames = new Array();
-  var invalidLangs = new Array();
+  var languages = 0;
+  var prefString = "";
 
-  //selected languages
-  for (var nodeIndex=0; nodeIndex < available_languages.selectedItems.length; nodeIndex++) {
-
-    var selItem =  available_languages.selectedItems[nodeIndex];
+  for (var item = aListbox.firstChild; item != null; item = item.nextSibling)
+  {
+    var languageid = item.id;
 
-    Languagename    = selItem.getAttribute('label');
-    Languageid      = selItem.getAttribute('id');
-
-    if (!LangAlreadyActive(Languageid)) {
-      addThese.push(Languageid);
-      addTheseNames.push(Languagename);
+    if (languageid.length > 1)
+    {
+      languages++;
+      //separate > 1 languages by commas
+      if (languages > 1)
+        prefString += ", " + languageid;
+      else
+        prefString = languageid;
     }
   }
-
-  //user-defined languages
-  var otherField = document.getElementById( "languages.other" );
-
-  if (otherField.value) {
-
-    var LanguageidsString = otherField.value.replace(/\s/g,"").toLowerCase();
-    var Languageids = LanguageidsString.split(separatorRe);
-    for (var i = 0; i < Languageids.length; i++) {
-      Languageid = Languageids[i];
       
-      if (IsRFC1766LangTag(Languageid)) {
-        if (!LangAlreadySelected(Languageid)) {
-          if (!LangAlreadyActive(Languageid)) {
-            Languagename = GetLanguageTitle(Languageid);
-            if (!Languagename)
-              Languagename = '[' + Languageid + ']';
-            addThese.push(Languageid);
-            addTheseNames.push(Languagename);
-          }
-        }
-      }
-      else {
-        invalidLangs[invalidLangs.length] = Languageid;
-      }
-    }
-    if (invalidLangs.length > 0) {
-      const errorMsg = prefLangBundle.getString("illegalOtherLanguage") + " " +
-                       invalidLangs.join(", ");
-      const errorTitle = prefLangBundle.getString("illegalOtherLanguageTitle");
-      var prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
-                                 .getService(Components.interfaces.nsIPromptService);
-      prompter.alert(this.window, errorTitle, errorMsg);
-      otherField.focus();
-      return false;
+  return prefString;
+}
+   
+function MoveUp()
+{
+  var selectedItems = activeLanguages.selectedIndex;
+  var selections = activeLanguages.selectedItems;
+  if (activeLanguages.selectedItems.length == 1)
+  {
+    var selected = activeLanguages.selectedItems[0];
+    var before = selected.previousSibling
+    if (before)
+    {
+      before.parentNode.insertBefore(selected, before);
+      activeLanguages.selectItem(selected);
+      activeLanguages.ensureElementIsVisible(selected);
     }
   }
   
-  for (i = 0; i < addThese.length; i++) {
-    AddListItem(window.opener.document, active_languages, addThese[i], addTheseNames[i]);
-  }
-
-  available_languages.clearSelection();
-  return true;
-}
-
-function LangAlreadySelected(langid) {
-  var found = false;
-
-  for (var i = 0; i < available_languages.selectedItems.length; i++) {
-    var currentLang = available_languages.selectedItems[i]; 
-    var Languageid  = currentLang.getAttribute('id');
-    if (Languageid == langid)
-      return true;
-  }
-  return false;
-}
-
-function HandleDoubleClick(node)
-{
-  var languageId    = node.id;
-  var languageName  = node.getAttribute('label');
-
-  if (languageName && languageName.length > 0)
-  {
-    if (!LangAlreadyActive(languageId)) {
-      AddListItem(window.opener.document, active_languages, languageId, languageName);
-    }
-    window.close();
-  }//if
-} //HandleDoubleClick
-
-function RemoveActiveLanguage()
-{
-
-  var nextNode = null;
-  var numSelected = active_languages.selectedItems.length;
-  var deleted_all = false;
-
-  while (active_languages.selectedItems.length > 0) {
-
-  var selectedNode = active_languages.selectedItems[0];
-    nextNode = selectedNode.nextSibling;
-
-  if (!nextNode)
-
-    if (selectedNode.previousSibling)
-    nextNode = selectedNode.previousSibling;
-
-    active_languages.removeChild(selectedNode);
-   } //while
-
-  if (nextNode) {
-    active_languages.selectItem(nextNode)
-  } else {
-    //active_languages.clearSelection();
-  }
-
-  UpdateSavePrefString();
-
-} //RemoveActiveLanguage
-
-
-function GetLanguageTitle(id)
-{
-
-  if (availLanguageDict)
-    for (var j = 0; j < availLanguageDict.length; j++) {
-
-      if ( availLanguageDict[j][1] == id) {
-      //title =
-  return availLanguageDict[j][0];
-      }
-    }
-  return '';
-}
-
-
-function AddListItem(doc, listbox, langID, langTitle)
-{
-  try {  //let's beef up our error handling for languages without label / title
-
-      // Create a listitem for the new Language
-      var item = doc.createElement('listitem');
-
-      // Copy over the attributes
-      item.setAttribute('label', langTitle);
-      item.setAttribute('id', langID);
-
-      listbox.appendChild(item);
-
-  } //try
-
-  catch (ex) {
-  } //catch
-
-}
-
-
-function UpdateSavePrefString()
-{
-  var num_languages = 0;
-  pref_string = "";
-
-  for (var item = active_languages.firstChild; item != null; item = item.nextSibling) {
-
-    var languageid = item.getAttribute('id');
-
-    if (languageid.length > 1) {
-
-          num_languages++;
-
-      //separate >1 languages by commas
-      if (num_languages > 1) {
-        pref_string = pref_string + "," + " " + languageid;
-      } else {
-        pref_string = languageid;
-      } //if
-    } //if
-  }//for
-
-  active_languages.setAttribute("prefvalue", pref_string);
-}
-
-
-function MoveUp() {
-
-  if (active_languages.selectedItems.length == 1) {
-    var selected = active_languages.selectedItems[0];
-    var before = selected.previousSibling
-    if (before) {
-      before.parentNode.insertBefore(selected, before);
-      active_languages.selectItem(selected);
-      active_languages.ensureElementIsVisible(selected);
-    }
-  }
-  
-  if (active_languages.selectedIndex == 0)
+  if (activeLanguages.selectedIndex == 0)
   {
     // selected item is first
     var moveUp = document.getElementById("up");
     moveUp.disabled = true;
   }
 
-  if (active_languages.childNodes.length > 1)
+  if (activeLanguages.childNodes.length > 1)
   {
     // more than one item so we can move selected item back down
     var moveDown = document.getElementById("down");
     moveDown.disabled = false;
   }
 
-  UpdateSavePrefString();
-
-} //MoveUp
-
-
-function MoveDown() {
+  SelectLanguage();
+  activeLanguages.doCommand();
+}
 
-  if (active_languages.selectedItems.length == 1) {
-    var selected = active_languages.selectedItems[0];
-    if (selected.nextSibling) {
-      if (selected.nextSibling.nextSibling) {
-        active_languages.insertBefore(selected, selected.nextSibling.nextSibling);
+function MoveDown()
+{
+  if (activeLanguages.selectedItems.length == 1)
+  {
+    var selected = activeLanguages.selectedItems[0];
+    if (selected.nextSibling)
+    {
+      if (selected.nextSibling.nextSibling)
+      {
+        activeLanguages.insertBefore(selected, selected.nextSibling.nextSibling);
       }
-      else {
-        active_languages.appendChild(selected);
+      else
+      {
+        activeLanguages.appendChild(selected);
       }
-      active_languages.selectItem(selected);
+
+      activeLanguages.selectItem(selected);
     }
   }
 
-  if (active_languages.selectedIndex == active_languages.childNodes.length - 1)
+  if (activeLanguages.selectedIndex == activeLanguages.childNodes.length - 1)
   {
     // selected item is last
     var moveDown = document.getElementById("down");
     moveDown.disabled = true;
   }
 
-  if (active_languages.childNodes.length > 1)
+  if (activeLanguages.childNodes.length > 1)
   {
     // more than one item so we can move selected item back up 
     var moveUp = document.getElementById("up");
     moveUp.disabled = false;
   }
 
-  UpdateSavePrefString();
+  SelectLanguage();
+  activeLanguages.doCommand();
+}
+
+function RemoveActiveLanguage()
+{
+  var nextNode = null;
+  var numSelected = activeLanguages.selectedItems.length;
 
-} //MoveDown
+  for (var i = 0; i < numSelected; i++)
+  {
+    var selectedNode = activeLanguages.selectedItems[0];
+    nextNode = selectedNode.nextSibling;
 
+    if (!nextNode)
+      if (selectedNode.previousSibling)
+        nextNode = selectedNode.previousSibling;
+
+    activeLanguages.removeChild(selectedNode);
+  }
+
+  if (nextNode)
+    activeLanguages.selectItem(nextNode)
 
-function SelectLanguage() {
-  if (active_languages.selectedItems.length) {
+  SelectLanguage();
+  activeLanguages.doCommand();
+}
+
+function GetLanguageTitle(id)
+{
+
+  if (langObj.availLanguageDict)
+    for (var j = 0; j < langObj.availLanguageDict.length; j++)
+    {
+      if ( langObj.availLanguageDict[j][1] == id)
+        return langObj.availLanguageDict[j][0];
+    }
+
+  return "";
+}
+
+function SelectLanguage()
+{
+  if (activeLanguages.selectedItems.length)
+  {
     document.getElementById("remove").disabled = false;
-    var selected = active_languages.selectedItems[0];
+    var selected = activeLanguages.selectedItems[0];
     document.getElementById("down").disabled = !selected.nextSibling;
 
     document.getElementById("up").disabled = !selected.previousSibling;
   }
-  else {
+  else
+  {
     document.getElementById("remove").disabled = true;
     document.getElementById("down").disabled = true;
     document.getElementById("up").disabled = true;
   }
+}
 
-  if (parent.hPrefWindow.getPrefIsLocked(document.getElementById("up").getAttribute("prefstring")))
-    document.getElementById("up").disabled = true;
-  if (parent.hPrefWindow.getPrefIsLocked(document.getElementById("down").getAttribute("prefstring")))
-    document.getElementById("down").disabled = true;
-  if (parent.hPrefWindow.getPrefIsLocked(document.getElementById("add").getAttribute("prefstring")))
-    document.getElementById("add").disabled = true;
-  if (parent.hPrefWindow.getPrefIsLocked(document.getElementById("remove").getAttribute("prefstring")))
-    document.getElementById("remove").disabled = true;
-} // SelectLanguage
+function LanguagesPaneKeyPress(aEvent)
+{
+  if (aEvent.keyCode == aEvent.DOM_VK_DELETE || aEvent.keyCode == aEvent.DOM_VK_BACK_SPACE)
+    RemoveActiveLanguage();
+}
--- a/suite/common/pref/pref-languages.xul
+++ b/suite/common/pref/pref-languages.xul
@@ -17,16 +17,17 @@
  The Original Code is mozilla.org Code.
 
  The Initial Developer of the Original Code is
  Netscape Communications Corporation.
  Portions created by the Initial Developer are Copyright (C) 1999
  the Initial Developer. All Rights Reserved.
 
  Contributor(s):
+   Stefan Hermes <stefanh@inbox.com>
 
  Alternatively, the contents of this file may be used under the terms of
  either of the GNU General Public License Version 2 or later (the "GPL"),
  or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
@@ -34,91 +35,131 @@
  and other provisions required by the GPL or the LGPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.
 
  ***** END LICENSE BLOCK ***** -->
 
 <?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?>
 
-<!DOCTYPE page SYSTEM "chrome://communicator/locale/pref/pref-languages.dtd" >
+<!DOCTYPE overlay SYSTEM "chrome://communicator/locale/pref/pref-languages.dtd">
 
-<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-      onload="parent.initPanel(document.documentURI);"
-      headertitle="&languages.customize.lHeader;">
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <prefpane id="languages_pane"
+            label="&languages.customize.lHeader;"
+            script="chrome://communicator/content/pref/pref-languages.js">
 
-  <script type="application/x-javascript" src="chrome://communicator/content/pref/pref-languages.js"/>
-  <script type="application/x-javascript">
-  <![CDATA[
-    var _elementIDs = ["active_languages", "DefaultCharsetList", "spellcheckDefault"];
-    var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
-    observerService.notifyObservers(null, "charsetmenu-selected", "other");
-  ]]>
-  </script>
+    <preferences id="languages_preferences">
+      <preference id="intl.accept_languages"
+                  name="intl.accept_languages"
+                  type="wstring"/>
+      <preference id="pref.browser.language.disable_button.up"
+                  name="pref.browser.language.disable_button.up"
+                  type="bool"/>
+      <preference id="pref.browser.language.disable_button.down"
+                  name="pref.browser.language.disable_button.down"
+                  type="bool"/>
+      <preference id="pref.browser.language.disable_button.add"
+                  name="pref.browser.language.disable_button.add"
+                  type="bool"/>
+      <preference id="pref.browser.language.disable_button.remove"
+                  name="pref.browser.language.disable_button.remove"
+                  type="bool"/>
+      <preference id="intl.charset.default"
+                  name="intl.charset.default"
+                  type="wstring"/>
+      <preference id="layout.spellcheckDefault"
+                  name="layout.spellcheckDefault"
+                  type="int"/>
+    </preferences>
 
-  <stringbundle id="acceptedBundle" src="resource://gre/res/language.properties"/>
-  <stringbundle id="languagesBundle" src="chrome://global/locale/languageNames.properties"/>
-  <stringbundle id="regionsBundle" src="chrome://global/locale/regionNames.properties"/>
-  <stringbundle id="prefLangBundle" src="chrome://communicator/locale/pref/pref-languages.properties"/>
-
-  <groupbox flex="1">
-    <caption label="&langtitle.label;"/>
-
-    <description>&languages.customize.prefLangDescript;</description>
+    <stringbundle id="acceptedBundle"
+                  src="resource://gre/res/language.properties"/>
+    <stringbundle id="languagesBundle"
+                  src="chrome://global/locale/languageNames.properties"/>
+    <stringbundle id="regionsBundle"
+                  src="chrome://global/locale/regionNames.properties"/>
+    <stringbundle id="prefLangBundle"
+                  src="chrome://communicator/locale/pref/pref-languages.properties"/>
 
-    <label control="active_languages">&languages.customize.active.label;</label>
-    <hbox flex="1">
-      <listbox id="active_languages" flex="1" style="width: 0px; height: 0px;"
-            preftype="localizedstring" prefstring="intl.accept_languages" prefvalue="" prefattribute="prefvalue" wsm_attributes="prefvalue"
-            seltype="multiple" onselect="SelectLanguage();"/>
-      <vbox>
-        <button oncommand="MoveUp();" id="up" class="up" disabled="true"
-                label="&languages.customize.moveUp.label;"
-                accesskey="&languages.customize.moveUp.accesskey;"
-                prefstring="pref.browser.language.disable_button.up"/>
-        <button oncommand="MoveDown();" id="down" class="down" disabled="true"
-                label="&languages.customize.moveDown.label;"
-                accesskey="&languages.customize.moveDown.accesskey;"
-                prefstring="pref.browser.language.disable_button.down"/>
-        <spacer flex="1"/>
-        <button id="add"
-                label="&languages.customize.addButton.label;"
-                accesskey="&languages.customize.addButton.accesskey;"
-                oncommand="AddLanguage();"
-                prefstring="pref.browser.language.disable_button.add"/>
-        <button id="remove" disabled="true"
-                label="&languages.customize.deleteButton.label;"
-                accesskey="&languages.customize.deleteButton.accesskey;"
-                oncommand="RemoveActiveLanguage();"
-                prefstring="pref.browser.language.disable_button.remove"/>
-      </vbox>
-    </hbox>
-  </groupbox>
-  <groupbox align="start">
-    <caption label="&languages.customize.Charset.grouplabel;"/>
-    <hbox align="center">
-      <label value="&languages.customize.DefaultCharset.label;" accesskey="&languages.customize.DefaultCharset.accesskey;" control="DefaultCharsetList"/>
-      <menulist id="DefaultCharsetList" ref="NC:DecodersRoot" datasources="rdf:charset-menu"
-          prefstring="intl.charset.default" preftype="localizedstring"
-          wsm_attributes="value">
+    <groupbox flex="1">
+      <caption label="&langtitle.label;"/>
+      <description>&languages.customize.prefLangDescript;</description>
+      <label control="activeLanguages">&languages.customize.active.label;</label>
+      <hbox flex="1">
+        <listbox id="activeLanguages"
+                 flex="1" style="width: 0px; height: 0px;"
+                 seltype="multiple"
+                 preference="intl.accept_languages"
+                 onkeypress="LanguagesPaneKeyPress(event);"
+                 onselect="SelectLanguage();"
+                 onsynctopreference="return document.getElementById('languages_pane').WriteActiveLanguages(this);"
+                 onsyncfrompreference="return document.getElementById('languages_pane').ReadActiveLanguages(this);"/>
+        <vbox>
+          <button id="up"
+                  class="up"
+                  disabled="true"
+                  label="&languages.customize.moveUp.label;"
+                  accesskey="&languages.customize.moveUp.accesskey;"
+                  prefstring="pref.browser.language.disable_button.up"
+                  oncommand="MoveUp();"/>
+          <button id="down"
+                  class="down"
+                  disabled="true"
+                  label="&languages.customize.moveDown.label;"
+                  accesskey="&languages.customize.moveDown.accesskey;"
+                  preference="pref.browser.language.disable_button.down"
+                  oncommand="MoveDown();"/>
+          <spacer flex="1"/>
+          <button id="add"
+                  label="&languages.customize.addButton.label;"
+                  accesskey="&languages.customize.addButton.accesskey;"
+                  preference="pref.browser.language.disable_button.add"
+                  oncommand="AddLanguage();"/>
+          <button id="remove"
+                  disabled="true"
+                  label="&languages.customize.deleteButton.label;"
+                  accesskey="&languages.customize.deleteButton.accesskey;"
+                  prefstring="pref.browser.language.disable_button.remove"
+                  oncommand="RemoveActiveLanguage();"/>
+        </vbox>
+      </hbox>
+    </groupbox>
+
+    <groupbox align="start">
+      <caption label="&languages.customize.Charset.grouplabel;"/>
+      <hbox align="center">
+        <label value="&languages.customize.DefaultCharset.label;"
+               accesskey="&languages.customize.DefaultCharset.accesskey;"
+               control="DefaultCharsetList"/>
+        <menulist id="DefaultCharsetList"
+                  ref=""
+                  datasources="rdf:charset-menu"
+                  preference="intl.charset.default">
           <template>
             <menupopup>
-              <menuitem label="rdf:http://home.netscape.com/NC-rdf#Name" value="..." uri="..."/>
+              <menuitem label="rdf:http://home.netscape.com/NC-rdf#Name"
+                        value="..."
+                        uri="..."/>
             </menupopup>
           </template>
-      </menulist> 
-    </hbox>
-  </groupbox>
-  <groupbox align="start">
-    <caption label="&spelling.label;"/>
-    <hbox align="center">
-      <label value="&checkSpelling.label;" accesskey="&checkSpelling.accesskey;"
-             control="spellcheckDefault"/>
-      <menulist id="spellcheckDefault" prefstring="layout.spellcheckDefault">
-        <menupopup>
-          <menuitem value="0" label="&dontCheckSpelling.label;"/>
-          <menuitem value="1" label="&multilineCheckSpelling.label;"/>
-          <menuitem value="2" label="&alwaysCheckSpelling.label;"/>
-        </menupopup>
-      </menulist>
-    </hbox>
-  </groupbox>
-</page>
+        </menulist> 
+      </hbox>
+    </groupbox>
+
+    <groupbox align="start">
+      <caption label="&spelling.label;"/>
+      <hbox align="center">
+        <label value="&checkSpelling.label;"
+               accesskey="&checkSpelling.accesskey;"
+               control="spellcheckDefault"/>
+        <menulist id="spellcheckDefault"
+                  preference="layout.spellcheckDefault">
+          <menupopup>
+            <menuitem value="0" label="&dontCheckSpelling.label;"/>
+            <menuitem value="1" label="&multilineCheckSpelling.label;"/>
+            <menuitem value="2" label="&alwaysCheckSpelling.label;"/>
+          </menupopup>
+        </menulist>
+      </hbox>
+    </groupbox>
+  </prefpane>
+</overlay>
--- a/suite/common/pref/preferences.xul
+++ b/suite/common/pref/preferences.xul
@@ -112,20 +112,21 @@
                 prefpane="navigator_pane"
                 helpTopic="navigator_pref_navigator"
                 url="chrome://communicator/content/pref/pref-navigator.xul">
 
         <treechildren id="navigatorChildren">
           <treeitem id="historyItem" label="&history.label;"
                     prefpane="history_pane" helpTopic="navigator_pref_history"
                     url="chrome://communicator/content/pref/pref-history.xul"/>
-<!-- commenting out yet unmigrated panels
-          <treeitem label="&languages.label;"
+          <treeitem id="languagesItem"
+                    label="&languages.label;"
+                    prefpane="languages_pane"
+                    helpTopic="navigator_pref_languages"
                     url="chrome://communicator/content/pref/pref-languages.xul"/>
--->
           <treeitem id="applicationsItem"
                     label="&applications.label;"
                     prefpane="applications_pane"
                     helpTopic="navigator_pref_helper_applications"
                     url="chrome://communicator/content/pref/pref-applications.xul"/>
           <treeitem id="locationBarItem"
                     label="&locationBar.label;"
                     prefpane="locationBar_pane"
--- a/suite/common/pref/preftree.xul
+++ b/suite/common/pref/preftree.xul
@@ -79,17 +79,17 @@
       <treechildren id="navigatorChildren">
         <treeitem>
           <treerow>
             <treecell label="(Migrated: &history.label;)"/> 
           </treerow>
         </treeitem>
         <treeitem>
           <treerow>
-            <treecell url="chrome://communicator/content/pref/pref-languages.xul" label="&languages.label;"/> 
+            <treecell label="(Migrated: &languages.label;)"/> 
           </treerow>
         </treeitem>
         <treeitem>
           <treerow>
             <treecell label="(Migrated: &applications.label;)"/> 
           </treerow>  
         </treeitem> 
         <treeitem>