diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9779b9399bf12ff112378d3959b4c0243345088
--- /dev/null
+++ b/indra/llcommon/llfindlocale.cpp
@@ -0,0 +1,525 @@
+/** 
+ * @file llfindlocale.cpp
+ * @brief Detect system language setting
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/* Yes, this was originally C code. */
+
+#include "linden_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <winnt.h>
+#endif
+
+#include "llfindlocale.h"
+
+static int
+is_lcchar(const int c) {
+  return isalnum(c);
+}
+
+static void
+lang_country_variant_from_envstring(const char *str,
+                                    char **lang,
+                                    char **country,
+                                    char **variant) {
+  int end = 0;
+  int start;
+
+  /* get lang, if any */
+  start = end;
+  while (is_lcchar(str[end])) {
+    ++end;
+  }
+  if (start != end) {
+    int i;
+    int len = end - start;
+    char *s = (char*)malloc(len + 1);
+    for (i=0; i<len; ++i) {
+      s[i] = tolower(str[start + i]);
+    }
+    s[i] = '\0';
+    *lang = s;
+  } else {
+    *lang = NULL;
+  }
+
+  if (str[end] && str[end]!=':') { /* not at end of str */
+    ++end;
+  }
+
+  /* get country, if any */
+  start = end;
+  while (is_lcchar(str[end])) {
+    ++end;
+  }
+  if (start != end) {
+    int i;
+    int len = end - start;
+    char *s = (char*)malloc(len + 1);
+    for (i=0; i<len; ++i) {
+      s[i] = toupper(str[start + i]);
+    }
+    s[i] = '\0';
+    *country = s;
+  } else {
+    *country = NULL;
+  }
+
+  if (str[end] && str[end]!=':') { /* not at end of str */
+    ++end;
+  }
+
+  /* get variant, if any */
+  start = end;
+  while (str[end] && str[end]!=':') {
+    ++end;
+  }
+  if (start != end) {
+    int i;
+    int len = end - start;
+    char *s = (char*)malloc(len + 1);
+    for (i=0; i<len; ++i) {
+      s[i] = str[start + i];
+    }
+    s[i] = '\0';
+    *variant = s;
+  } else {
+    *variant = NULL;
+  }
+}
+
+
+static int
+accumulate_locstring(const char *str, FL_Locale *l) {
+  char *lang = NULL;
+  char *country = NULL;
+  char *variant = NULL;
+  if (str) {
+    lang_country_variant_from_envstring(str, &lang, &country, &variant);
+    if (lang) {
+      l->lang = lang;
+      l->country = country;
+      l->variant = variant;
+      return 1;
+    }
+  }
+  free(lang); free(country); free(variant);
+  return 0;
+}
+
+
+static int
+accumulate_env(const char *name, FL_Locale *l) {
+  char *env;
+  char *lang = NULL;
+  char *country = NULL;
+  char *variant = NULL;
+  env = getenv(name);
+  if (env) {
+    return accumulate_locstring(env, l);
+  }
+  free(lang); free(country); free(variant);
+  return 0;
+}
+
+
+static void
+canonise_fl(FL_Locale *l) {
+  /* this function fixes some common locale-specifying mistakes */
+  /* en_UK -> en_GB */
+  if (l->lang && 0 == strcmp(l->lang, "en")) {
+    if (l->country && 0 == strcmp(l->country, "UK")) {
+      free((void*)l->country);
+      l->country = strdup("GB");
+    }
+  }
+  /* ja_JA -> ja_JP */
+  if (l->lang && 0 == strcmp(l->lang, "ja")) {
+    if (l->country && 0 == strcmp(l->country, "JA")) {
+      free((void*)l->country);
+      l->country = strdup("JP");
+    }
+  }
+}
+
+
+#ifdef WIN32
+#include <stdio.h>
+#define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
+#define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
+#define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
+typedef struct {
+  LANGID id;
+  char*  code;
+} IDToCode;
+static const IDToCode both_to_code[] = {
+  {ML(ENGLISH,US),           "en_US.ISO_8859-1"},
+  {ML(ENGLISH,CAN),          "en_CA"}, /* english / canadian */
+  {ML(ENGLISH,UK),           "en_GB"},
+  {ML(ENGLISH,EIRE),         "en_IE"},
+  {ML(ENGLISH,AUS),          "en_AU"},
+  {MLN(GERMAN),              "de_DE"},
+  {MLN(SPANISH),             "es_ES"},
+  {ML(SPANISH,MEXICAN),      "es_MX"},
+  {MLN(FRENCH),              "fr_FR"},
+  {ML(FRENCH,CANADIAN),      "fr_CA"},
+  {ML(FRENCH,BELGIAN),       "fr_BE"}, /* ? */
+  {ML(DUTCH,BELGIAN),        "nl_BE"}, /* ? */
+  {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
+  {MLN(PORTUGUESE),          "pt_PT"},
+  {MLN(SWEDISH),             "sv_SE"},
+  {ML(CHINESE,HONGKONG),     "zh_HK"},
+  /* these are machine-generated and not yet verified */
+  {RML(AFRIKAANS,DEFAULT), "af_ZA"},
+  {RML(ALBANIAN,DEFAULT), "sq_AL"},
+  {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
+  {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
+  {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
+  {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
+  {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
+  {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
+  {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
+  {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
+  {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
+  {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
+  {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
+  {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
+  {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
+  {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
+  {RML(ARABIC,ARABIC_UAE), "ar_AE"},
+  {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
+  {RML(ARMENIAN,DEFAULT), "hy_AM"},
+  {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
+  {RML(AZERI,AZERI_LATIN), "az_AZ"},
+  {RML(BASQUE,DEFAULT), "eu_ES"},
+  {RML(BELARUSIAN,DEFAULT), "be_BY"},
+/*{RML(BRETON,DEFAULT), "br_FR"},*/
+  {RML(BULGARIAN,DEFAULT), "bg_BG"},
+  {RML(CATALAN,DEFAULT), "ca_ES"},
+  {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
+  {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
+  {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
+  {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
+  {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
+/*{RML(CORNISH,DEFAULT), "kw_GB"},*/
+  {RML(CZECH,DEFAULT), "cs_CZ"},
+  {RML(DANISH,DEFAULT), "da_DK"},
+  {RML(DUTCH,DUTCH), "nl_NL"},
+  {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
+/*{RML(DUTCH,DUTCH_SURINAM), "nl_SR"},*/
+  {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
+  {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
+  {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
+  {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
+  {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
+  {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
+  {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
+  {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
+  {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
+  {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
+  {RML(ENGLISH,ENGLISH_UK), "en_GB"},
+  {RML(ENGLISH,ENGLISH_US), "en_US"},
+  {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
+/*{RML(ESPERANTO,DEFAULT), "eo_"},*/
+  {RML(ESTONIAN,DEFAULT), "et_EE"},
+  {RML(FAEROESE,DEFAULT), "fo_FO"},
+  {RML(FARSI,DEFAULT), "fa_IR"},
+  {RML(FINNISH,DEFAULT), "fi_FI"},
+  {RML(FRENCH,FRENCH), "fr_FR"},
+  {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
+  {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
+  {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
+  {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
+  {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
+/*{RML(GAELIC,GAELIC), "ga_IE"},*/
+/*{RML(GAELIC,GAELIC_MANX), "gv_GB"},*/
+/*{RML(GAELIC,GAELIC_SCOTTISH), "gd_GB"},*/
+/*{RML(GALICIAN,DEFAULT), "gl_ES"},*/
+  {RML(GEORGIAN,DEFAULT), "ka_GE"},
+  {RML(GERMAN,GERMAN), "de_DE"},
+  {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
+  {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
+  {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
+  {RML(GERMAN,GERMAN_SWISS), "de_CH"},
+  {RML(GREEK,DEFAULT), "el_GR"},
+  {RML(GUJARATI,DEFAULT), "gu_IN"},
+  {RML(HEBREW,DEFAULT), "he_IL"},
+  {RML(HINDI,DEFAULT), "hi_IN"},
+  {RML(HUNGARIAN,DEFAULT), "hu_HU"},
+  {RML(ICELANDIC,DEFAULT), "is_IS"},
+  {RML(INDONESIAN,DEFAULT), "id_ID"},
+  {RML(ITALIAN,ITALIAN), "it_IT"},
+  {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
+  {RML(JAPANESE,DEFAULT), "ja_JP"},
+  {RML(KANNADA,DEFAULT), "kn_IN"},
+  {RML(KAZAK,DEFAULT), "kk_KZ"},
+  {RML(KONKANI,DEFAULT), "kok_IN"},
+  {RML(KOREAN,KOREAN), "ko_KR"},
+/*{RML(KYRGYZ,DEFAULT), "ky_KG"},*/
+  {RML(LATVIAN,DEFAULT), "lv_LV"},
+  {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
+  {RML(MACEDONIAN,DEFAULT), "mk_MK"},
+  {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
+  {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
+  {RML(MARATHI,DEFAULT), "mr_IN"},
+/*{RML(MONGOLIAN,DEFAULT), "mn_MN"},*/
+  {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
+  {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
+  {RML(POLISH,DEFAULT), "pl_PL"},
+  {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
+  {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
+  {RML(PUNJABI,DEFAULT), "pa_IN"},
+  {RML(ROMANIAN,DEFAULT), "ro_RO"},
+  {RML(RUSSIAN,DEFAULT), "ru_RU"},
+  {RML(SANSKRIT,DEFAULT), "sa_IN"},
+  {RML(SERBIAN,DEFAULT), "hr_HR"},
+  {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
+  {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
+  {RML(SLOVAK,DEFAULT), "sk_SK"},
+  {RML(SLOVENIAN,DEFAULT), "sl_SI"},
+  {RML(SPANISH,SPANISH), "es_ES"},
+  {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
+  {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
+  {RML(SPANISH,SPANISH_CHILE), "es_CL"},
+  {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
+  {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
+  {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
+  {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
+  {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
+  {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
+  {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
+  {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
+  {RML(SPANISH,SPANISH_MODERN), "es_ES"},
+  {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
+  {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
+  {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
+  {RML(SPANISH,SPANISH_PERU), "es_PE"},
+  {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
+  {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
+  {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
+  {RML(SWAHILI,DEFAULT), "sw_KE"},
+  {RML(SWEDISH,SWEDISH), "sv_SE"},
+  {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
+/*{RML(SYRIAC,DEFAULT), "syr_SY"},*/
+  {RML(TAMIL,DEFAULT), "ta_IN"},
+  {RML(TATAR,DEFAULT), "tt_TA"},
+  {RML(TELUGU,DEFAULT), "te_IN"},
+  {RML(THAI,DEFAULT), "th_TH"},
+  {RML(TURKISH,DEFAULT), "tr_TR"},
+  {RML(UKRAINIAN,DEFAULT), "uk_UA"},
+  {RML(URDU,URDU_PAKISTAN), "ur_PK"},
+  {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
+  {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
+  {RML(VIETNAMESE,DEFAULT), "vi_VN"},
+/*{RML(WALON,DEFAULT), "wa_BE"},*/
+/*{RML(WELSH,DEFAULT), "cy_GB"},*/
+};
+static const IDToCode primary_to_code[] = {
+  {LANG_AFRIKAANS,  "af"},
+  {LANG_ARABIC,     "ar"},
+  {LANG_AZERI,      "az"},
+  {LANG_BULGARIAN,  "bg"},
+/*{LANG_BRETON,     "br"},*/
+  {LANG_BELARUSIAN, "by"},
+  {LANG_CATALAN,    "ca"},
+  {LANG_CZECH,      "cs"},
+/*{LANG_WELSH,      "cy"},*/
+  {LANG_DANISH,     "da"},
+  {LANG_GERMAN,     "de"},
+  {LANG_GREEK,      "el"},
+  {LANG_ENGLISH,    "en"},
+/*{LANG_ESPERANTO,  "eo"},*/
+  {LANG_SPANISH,    "es"},
+  {LANG_ESTONIAN,   "et"},
+  {LANG_BASQUE,     "eu"},
+  {LANG_FARSI,      "fa"},
+  {LANG_FINNISH,    "fi"},
+  {LANG_FAEROESE,   "fo"},
+  {LANG_FRENCH,     "fr"},
+/*{LANG_GAELIC,     "ga"},*/
+/*{LANG_GALICIAN,   "gl"},*/
+  {LANG_GUJARATI,   "gu"},
+  {LANG_HEBREW,     "he"},
+  {LANG_HINDI,      "hi"},
+  {LANG_SERBIAN,    "hr"},
+  {LANG_HUNGARIAN,  "hu"},
+  {LANG_ARMENIAN,   "hy"},
+  {LANG_INDONESIAN, "id"},
+  {LANG_ITALIAN,    "it"},
+  {LANG_JAPANESE,   "ja"},
+  {LANG_GEORGIAN,   "ka"},
+  {LANG_KAZAK,      "kk"},
+  {LANG_KANNADA,    "kn"},
+  {LANG_KOREAN,     "ko"},
+/*{LANG_KYRGYZ,     "ky"},*/
+  {LANG_LITHUANIAN, "lt"},
+  {LANG_LATVIAN,    "lv"},
+  {LANG_MACEDONIAN, "mk"},
+/*{LANG_MONGOLIAN,  "mn"},*/
+  {LANG_MARATHI,    "mr"},
+  {LANG_MALAY,      "ms"},
+  {LANG_NORWEGIAN,  "nb"},
+  {LANG_DUTCH,      "nl"},
+  {LANG_NORWEGIAN,  "nn"},
+  {LANG_NORWEGIAN,  "no"},/* unofficial? */
+  {LANG_PUNJABI,    "pa"},
+  {LANG_POLISH,     "pl"},
+  {LANG_PORTUGUESE, "pt"},
+  {LANG_ROMANIAN,   "ro"},
+  {LANG_RUSSIAN,    "ru"},
+  {LANG_SLOVAK,     "sk"},
+  {LANG_SLOVENIAN,  "sl"},
+  {LANG_ALBANIAN,   "sq"},
+  {LANG_SERBIAN,    "sr"},
+  {LANG_SWEDISH,    "sv"},
+  {LANG_SWAHILI,    "sw"},
+  {LANG_TAMIL,      "ta"},
+  {LANG_THAI,       "th"},
+  {LANG_TURKISH,    "tr"},
+  {LANG_TATAR,      "tt"},
+  {LANG_UKRAINIAN,  "uk"},
+  {LANG_URDU,       "ur"},
+  {LANG_UZBEK,      "uz"},
+  {LANG_VIETNAMESE, "vi"},
+/*{LANG_WALON,      "wa"},*/
+  {LANG_CHINESE,    "zh"},
+};
+static int num_primary_to_code =
+  sizeof(primary_to_code) / sizeof(*primary_to_code);
+static int num_both_to_code =
+  sizeof(both_to_code) / sizeof(*both_to_code);
+
+static const int
+lcid_to_fl(LCID lcid,
+           FL_Locale *rtn) {
+  LANGID langid       = LANGIDFROMLCID(lcid);
+  LANGID primary_lang = PRIMARYLANGID(langid);
+  /*LANGID sub_lang     = SUBLANGID(langid);*/
+  int i;
+  /* try to find an exact primary/sublanguage combo that we know about */
+  for (i=0; i<num_both_to_code; ++i) {
+    if (both_to_code[i].id == langid) {
+      accumulate_locstring(both_to_code[i].code, rtn);
+      return 1;
+    }
+  }
+  /* fallback to just checking the primary language id */
+  for (i=0; i<num_primary_to_code; ++i) {
+    if (primary_to_code[i].id == primary_lang) {
+      accumulate_locstring(primary_to_code[i].code, rtn);
+      return 1;
+    }
+  }
+  return 0;
+}
+#endif
+
+
+FL_Success
+FL_FindLocale(FL_Locale **locale, FL_Domain domain) {
+  FL_Success success = FL_FAILED;
+  FL_Locale *rtn = (FL_Locale*)malloc(sizeof(FL_Locale));
+  rtn->lang = NULL;
+  rtn->country = NULL;
+  rtn->variant = NULL;
+
+#ifdef WIN32
+  /* win32 >= mswindows95 */
+  {
+    LCID lcid = GetThreadLocale();
+    if (lcid_to_fl(lcid, rtn)) {
+      success = FL_CONFIDENT;
+    }
+    if (success == FL_FAILED) {
+      /* assume US English on mswindows systems unless we know otherwise */
+      if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
+        success = FL_DEFAULT_GUESS;
+      }
+    }
+  }
+#else
+  /* assume unixoid */
+  {
+    /* examples: */
+    /* sv_SE.ISO_8859-1 */
+    /* fr_FR.ISO8859-1 */
+    /* no_NO_NB */
+    /* no_NO_NY */
+    /* no_NO */
+    /* de_DE */
+    /* try the various vars in decreasing order of authority */
+    if (accumulate_env("LC_ALL", rtn) ||
+        accumulate_env("LC_MESSAGES", rtn) ||
+        accumulate_env("LANG", rtn) ||
+        accumulate_env("LANGUAGE", rtn)) {
+      success = FL_CONFIDENT;
+    }
+    if (success == FL_FAILED) {
+      /* assume US English on unixoid systems unless we know otherwise */
+      if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
+        success = FL_DEFAULT_GUESS;
+      }
+    }
+  }
+#endif
+
+  if (success != FL_FAILED) {
+    canonise_fl(rtn);
+  }
+
+  *locale = rtn;
+  return success;
+}
+
+
+void
+FL_FreeLocale(FL_Locale **locale) {
+  if (locale) {
+    FL_Locale *l = *locale;
+    if (l) {
+      if (l->lang) {
+        free((void*)l->lang);
+      }
+      if (l->country) {
+        free((void*)l->country);
+      }
+      if (l->variant) {
+        free((void*)l->variant);
+      }
+      free(l);
+      *locale = NULL;
+    }
+  }
+}
diff --git a/indra/llcommon/llfindlocale.h b/indra/llcommon/llfindlocale.h
new file mode 100644
index 0000000000000000000000000000000000000000..1401609d40377b8ca9eff22f4a10e404dc040883
--- /dev/null
+++ b/indra/llcommon/llfindlocale.h
@@ -0,0 +1,65 @@
+/** 
+ * @file llfindlocale.h
+ * @brief Detect system language setting
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef __findlocale_h_
+#define __findlocale_h_
+
+typedef const char* FL_Lang;
+typedef const char* FL_Country;
+typedef const char* FL_Variant;
+
+typedef struct {
+  FL_Lang    lang;
+  FL_Country country;
+  FL_Variant variant;
+} FL_Locale;
+
+typedef enum {
+  /* for some reason we failed to even guess: this should never happen */
+  FL_FAILED        = 0,
+  /* couldn't query locale -- returning a guess (almost always English) */
+  FL_DEFAULT_GUESS = 1,
+  /* the returned locale type was found by successfully asking the system */
+  FL_CONFIDENT     = 2
+} FL_Success;
+
+typedef enum {
+  FL_MESSAGES = 0
+} FL_Domain;
+
+/* This allocates/fills in a FL_Locale structure with pointers to
+   strings (which should be treated as static), or NULL for inappropriate /
+   undetected fields. */
+FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
+/* This should be used to free the struct written by FL_FindLocale */
+void FL_FreeLocale(FL_Locale **locale);
+
+#endif /*__findlocale_h_*/
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 52df5b8e75d921fe1e786ecf0c0f3cf691421306..c58517d16757afb33d0c7337cee35f041ab091c8 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -279,12 +279,12 @@ bool LLFontGL::loadFace(LLFontGL *fontp, const LLString& fontname, const F32 poi
 
 // static
 BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
-								const LLString& monospace_file, F32 monospace_size,
-								const LLString& sansserif_file,
-								const LLString& sanserif_fallback_file, F32 ss_fallback_scale,
-								F32 small_size, F32 medium_size, F32 big_size, F32 huge_size,
-								const LLString& sansserif_bold_file, F32 bold_size,
-								const LLString& app_dir)
+				const LLString& monospace_file, F32 monospace_size,
+				const LLString& sansserif_file,
+				const LLString& sanserif_fallback_file, F32 ss_fallback_scale,
+				F32 small_size, F32 medium_size, F32 big_size, F32 huge_size,
+				const LLString& sansserif_bold_file, F32 bold_size,
+				const LLString& app_dir)
 {
 	BOOL failed = FALSE;
 	sVertDPI = (F32)llfloor(screen_dpi * y_scale);
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index c640a83328da0194ce24575c52124e0e5b561cf0..fd850fe258d8f98b9fba15e54b6ceb32dd62b4d3 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -287,6 +287,20 @@ void LLWindow::setCallbacks(LLWindowCallbacks *callbacks)
 	}
 }
 
+// static
+std::string LLWindow::getFontListSans()
+{
+#if LL_WINDOWS
+	return LLWindowWin32::getFontListSans();
+#elif LL_DARWIN
+	return LLWindowMacOSX::getFontListSans();
+#elif LL_SDL
+	return LLWindowSDL::getFontListSans();
+#else
+	return "";
+#endif
+}
+
 #define UTF16_IS_HIGH_SURROGATE(U) ((U16)((U) - 0xD800) < 0x0400)
 #define UTF16_IS_LOW_SURROGATE(U)  ((U16)((U) - 0xDC00) < 0x0400)
 #define UTF16_SURROGATE_PAIR_TO_UTF32(H,L) (((H) << 10) + (L) - (0xD800 << 10) - 0xDC00 + 0x00010000)
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 81adf8b13ab07e0631ff8b625e01bc4ebb315cb4..7a7c14fa35d45f68267a754e9ce58817a8600afa 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -234,6 +234,8 @@ class LLWindow
 	virtual void updateLanguageTextInputArea() {}
 	virtual void interruptLanguageTextInput() {}
 
+	static std::string getFontListSans();
+
 protected:
 	LLWindow(BOOL fullscreen, U32 flags);
 	virtual ~LLWindow() {}
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 8483e37cf9a2caef450c2fff6a52391852c3cf1e..ba92e8040250363ac6e897b441e0885cd5a0e01b 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -3394,4 +3394,13 @@ void LLWindowMacOSX::interruptLanguageTextInput()
 	// Well, if Apple's TSM document is correct, we don't.
 }
 
+//static
+std::string LLWindowMacOSX::getFontListSans()
+{
+	// This is a fairly complete Japanese font that ships with Mac OS X.
+	// The first filename is in UTF8, but it shows up in the font menu as "Hiragino Kaku Gothic Pro W3".
+	// The third filename is in UTF8, but it shows up in the font menu as "STHeiti Light"
+	return "\xE3\x83\x92\xE3\x83\xA9\xE3\x82\xAD\xE3\x82\x99\xE3\x83\x8E\xE8\xA7\x92\xE3\x82\xB3\xE3\x82\x99 Pro W3.otf;\xE3\x83\x92\xE3\x83\xA9\xE3\x82\xAD\xE3\x82\x99\xE3\x83\x8E\xE8\xA7\x92\xE3\x82\xB3\xE3\x82\x99 ProN W3.otf;AppleGothic.dfont;AppleGothic.ttf;\xe5\x8d\x8e\xe6\x96\x87\xe7\xbb\x86\xe9\xbb\x91.ttf";
+}
+
 #endif // LL_DARWIN
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index 3fb4eff728ec98add65e0424612acc8b3eaff456..0534893aa7eae7a1feeabb9480d1f2b22105f512 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -116,6 +116,8 @@ class LLWindowMacOSX : public LLWindow
 	/*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b);
 	/*virtual*/ void interruptLanguageTextInput();
 
+	static std::string getFontListSans();
+
 protected:
 	LLWindowMacOSX(
 		char *title, char *name, int x, int y, int width, int height, U32 flags,
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index 519e0e8ec84bf99cf2ae49c3d7c6341445e16d38..5ed6094f4a2b67a105cb1415d16c62a111f39b8a 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -39,6 +39,7 @@
 #include "llgl.h"
 #include "llstring.h"
 #include "lldir.h"
+#include "llfindlocale.h"
 
 #include "llglheaders.h"
 
@@ -51,6 +52,10 @@ extern "C" {
 #include <locale.h>
 #endif // LL_GTK
 
+extern "C" {
+# include "fontconfig/fontconfig.h"
+}
+
 #if LL_LINUX || LL_SOLARIS
 // not necessarily available on random SDL platforms, so #if LL_LINUX
 // for execv(), waitpid(), fork()
@@ -2027,7 +2032,8 @@ void LLWindowSDL::gatherInput()
 	    // the locale to protect it, as exotic/non-C locales
 	    // causes our code lots of general critical weirdness
 	    // and crashness. (SL-35450)
-	    std::string saved_locale = setlocale(LC_ALL, NULL);
+	    static std::string saved_locale;
+	    saved_locale = ll_safe_string(setlocale(LC_ALL, NULL));
 
 	    // Pump until we've nothing left to do or passed 1/15th of a
 	    // second pumping for this frame.
@@ -2748,8 +2754,8 @@ void spawn_web_browser(const char* escaped_url)
 # endif // LL_X11
 
 	std::string cmd;
-	cmd  = gDirUtilp->getAppRODataDir().c_str();
-	cmd += gDirUtilp->getDirDelimiter().c_str();
+	cmd  = gDirUtilp->getAppRODataDir();
+	cmd += gDirUtilp->getDirDelimiter();
 	cmd += "launch_url.sh";
 	char* const argv[] = {(char*)cmd.c_str(), (char*)escaped_url, NULL};
 
@@ -2826,4 +2832,90 @@ void LLWindowSDL::bringToFront()
 #endif // LL_X11
 }
 
+//static
+std::string LLWindowSDL::getFontListSans()
+{
+	// Use libfontconfig to find us a nice ordered list of fallback fonts
+	// specific to this system.
+	std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf");
+	// Our 'ideal' font properties which define the sorting results.
+	// slant=0 means Roman, index=0 means the first face in a font file
+	// (the one we actually use), weight=80 means medium weight,
+	// spacing=0 means proportional spacing.
+	std::string sort_order("slant=0:index=0:weight=80:spacing=0");
+	// elide_unicode_coverage removes fonts from the list whose unicode
+	// range is covered by fonts earlier in the list.  This usually
+	// removes ~90% of the fonts as redundant (which is great because
+	// the font list can be huge), but might unnecessarily reduce the
+	// renderable range if for some reason our FreeType actually fails
+	// to use some of the fonts we want it to.
+	const bool elide_unicode_coverage = true;
+	std::string rtn;
+	FcFontSet *fs = NULL;
+	FcPattern *sortpat = NULL;
+	int font_count = 0;
+
+	llinfos << "Getting system font list from FontConfig..." << llendl;
+
+	// If the user has a system-wide language preference, then favor
+	// fonts from that language group.  This doesn't affect the types
+	// of languages that can be displayed, but ensures that their
+	// preferred language is rendered from a single consistent font where
+	// possible.
+	FL_Locale *locale = NULL;
+	FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
+	if (success != 0)
+	{
+		if (success >= 2 && locale->lang) // confident!
+		{
+			llinfos << "Preferring fonts of language: "
+				<< locale->lang
+				<< llendl;
+			sort_order = "lang=" + std::string(locale->lang) + ":"
+				+ sort_order;
+		}
+		FL_FreeLocale(&locale);
+	}
+
+	if (!FcInit())
+	{
+		llwarns << "FontConfig failed to initialize." << llendl;
+		return final_fallback;
+	}
+
+	sortpat = FcNameParse((FcChar8*) sort_order.c_str());
+	if (sortpat)
+	{
+		// Sort the list of system fonts from most-to-least-desirable.
+		fs = FcFontSort(NULL, sortpat, elide_unicode_coverage,
+				NULL, NULL);
+		FcPatternDestroy(sortpat);
+	}
+
+	if (fs)
+	{
+		// Get the full pathnames to the fonts, where available,
+		// which is what we really want.
+		int i;
+		for (i=0; i<fs->nfont; ++i)
+		{
+			FcChar8 *filename;
+			if (FcResultMatch == FcPatternGetString(fs->fonts[i],
+								FC_FILE, 0,
+								&filename)
+			    && filename)
+			{
+				rtn += std::string((const char*)filename)+";";
+				++font_count;
+			}
+		}
+		FcFontSetDestroy (fs);
+	}
+
+	lldebugs << "Using font list: " << rtn << llendl;
+	llinfos << "Using " << font_count << " system font(s)." << llendl;
+
+	return rtn + final_fallback;
+}
+
 #endif // LL_SDL
diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h
index 51d34eb96f89b62e791dc899615a1ef57060f8ea..58bb93bbc73b5a611e71f74a140513eb1f4e3ec1 100644
--- a/indra/llwindow/llwindowsdl.h
+++ b/indra/llwindow/llwindowsdl.h
@@ -120,6 +120,8 @@ class LLWindowSDL : public LLWindow
 	/*virtual*/ void *getPlatformWindow();
 	/*virtual*/ void bringToFront();
 
+	static std::string getFontListSans();
+
 	// Not great that these are public, but they have to be accessible
 	// by non-class code and it's better than making them global.
 #if LL_X11
@@ -154,7 +156,6 @@ class LLWindowSDL : public LLWindow
 
 	BOOL	shouldPostQuit() { return mPostQuit; }
 
-
 protected:
 	//
 	// Platform specific methods
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index bbc452fe5e93a82c5677d9cc78738fa82695bba4..0a40fb8a956297e45b8f67a2e3f26bb76afe4fe8 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3606,5 +3606,13 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
 	return FALSE;
 }
 
+//static
+std::string LLWindowWin32::getFontListSans()
+{
+	// Lists Japanese, Korean, and Chinese sanserif fonts available in
+	// Windows XP and Vista, as well as "Arial Unicode MS".
+	return "MSGOTHIC.TTC;gulim.ttc;simhei.ttf;ArialUni.ttf";
+}
+
 
 #endif // LL_WINDOWS
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index f6e40a1c7f65f4d7246a4ec47a23d502c6c41e66..38836e0d81a1797f3a2872e06108879338b0495b 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -116,6 +116,8 @@ class LLWindowWin32 : public LLWindow
 	/*virtual*/ void updateLanguageTextInputArea();
 	/*virtual*/ void interruptLanguageTextInput();
 
+	static std::string getFontListSans();
+
 protected:
 	LLWindowWin32(
 		char *title, char *name, int x, int y, int width, int height, U32 flags, 
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 8db336f86f440852dffa96c4c2a3b4f41284cacd..836780d14014e031797980249cda6eeb416608ab 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -87,7 +87,6 @@ SetShellVarContext all			; install for all users (if you change this, change it
 
 ; Start with some default values.
 StrCpy $INSTFLAGS "${INSTFLAGS}"
-StrCpy $INSTFLAGS "$INSTFLAGS $LANGFLAGS"
 StrCpy $INSTPROG "${INSTNAME}"
 StrCpy $INSTEXE "${INSTEXE}"
 StrCpy $INSTSHORTCUT "${SHORTCUT}"
@@ -933,26 +932,6 @@ Function .onInit
 
 	; save language in registry		
 	WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE
-	
-	; generate language ID that will be used as a command line arg	
-	StrCmp $LANGUAGE "1042" 0 +3
-	StrCpy $LANGFLAGS " --set SystemLanguage ko"
-	Goto EndOfFunc
-
-	StrCmp $LANGUAGE "1041" 0 +3
-	StrCpy $LANGFLAGS " --set SystemLanguage ja"
-	Goto EndOfFunc
-
-	StrCmp $LANGUAGE "1031" 0 +3
-	StrCpy $LANGFLAGS " --set SystemLanguage de"
-	Goto EndOfFunc
-
-	StrCmp $LANGUAGE "1033" 0 +3
-	StrCpy $LANGFLAGS " --set SystemLanguage en-us"
-	Goto EndOfFunc
-	
-	EndOfFunc:
-
 FunctionEnd
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt
index 87087be778047add5c823024139a33e736209f98..179cb9e0b718b3d5e7f2312cadd89db60929a9ee 100644
--- a/indra/newview/linux_tools/client-readme.txt
+++ b/indra/newview/linux_tools/client-readme.txt
@@ -12,7 +12,7 @@ Life itself - please see <http://www.secondlife.com/whatis/>.
 5. Troubleshooting
    5.1. 'Error creating window.'
    5.2. System hangs
-   5.3. 'Shiny' and client performance
+   5.3. Blank window after minimizing it
    5.4. Audio
    5.5. 'Alt' key for camera controls doesn't work
    5.6. In-world movie playback
@@ -98,16 +98,6 @@ you wish.
 These are the most commonly-encountered known issues which are specific to
 the Beta release of the Linux client.
 
-* VISUAL EFFECTS AND PERFORMANCE - many Linux graphics drivers are not as
-  robust as their counterparts for other operating systems, so some advanced
-  Second Life graphical features have been DISABLED by default to aid
-  stability.  See PROBLEM 3 in the TROUBLESHOOTING section if you wish to
-  turn these on to possibly enhance your experience.
-
-* MISC - The following features are not currently fully implemented on the
-  Linux client and are therefore known not to work properly:
-  * Full Unicode font rendering
-
 * UPLOAD / SAVE / COLOR-PICKER DIALOGS - These only appear when the client
   is in 'windowed' mode, not 'fullscreen' mode.
 
@@ -156,29 +146,21 @@ SOLUTION:- As a last resort, you can disable most of Second Life's advanced
    graphics features by editing the 'secondlife' script and removing the '#'
    from the line which reads '#export LL_GL_NOEXT=x'
 
-PROBLEM 3:- Performance or graphical quality are not as high as I expect.
-PROBLEM:- 'SHINY' doesn't work.
-PROBLEM:- I can't turn on Anisotropic Filtering, Ripple Water, or AGP.
-SOLUTION:- Some graphics performance features in Second Life are disabled
-   by default for the Linux version due to stability issues with some common
-   Linux graphic drivers.  You can re-enable these features at the slight
-   risk of decreasing system stability.  To do so:
-   * Edit the 'secondlife' script.  Comment-out these lines by putting a '#'
-     in front of them: 'export LL_GL_BASICEXT=x', 'export LL_GL_NOEXT=x',
-     'export LL_GL_BLACKLIST=abcdefghijklmno'.
-   * Now start Second Life.  Some advanced performance features will now be
-     automatically used, and some new options in Preferences will now be
-     available to you; there is no guarantee, however, that they will
-     positively affect performance!
-SOLUTION:- If you are not running an official Second Life client obtained from
-     secondlife.com, you should consider doing so as you may find its
-     performance to be superior to third-party versions.
-
-PROBLEM 4:- Sound effects seem to 'lag' a fraction of a second behind
-   actions.
-SOLUTION:- You may uncomment the 'LL_BAD_ESD' line in the 'secondlife' script
-   to get more responsive audio.  However, if you do this then you may
-   encounter audio issues or a hang during login, so beware.
+PROBLEM 3:- After I minimize the Second Life window, it's just blank when
+   it comes back.
+SOLUTION:- Some Linux desktop 'Visual Effects' features are incompatible
+   with Second Life.  One reported solution is to use your desktop
+   configuration program to disable such effects.  For example, on Ubuntu 7.10,
+   use the desktop toolbar menu to select System -> Preferences -> Appearance,
+   then change 'Visual Effects' to 'None'.
+
+PROBLEM 4:- Music and sound effects are silent or very stuttery.
+SOLUTION:- The most common solution is to ensure that you have the 'esd'
+   program (part of the 'esound' package) installed and running before you
+   start Second Life.  Users of Ubuntu (and some other) Linux systems can
+   simply run the following to install and configure 'esound':
+     sudo apt-get install esound
+  For others, simply running 'esd&' from a command-line should get it running.
 
 PROBLEM 5:- Using the 'Alt' key to control the camera doesn't work or just
    moves the Second Life window.
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1550b6dc2302c65b926fb6174c61998395421721..69c71224a9592c9e9fa13ad8783f6fd9a10395ee 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -159,6 +159,13 @@
 
 #include "llcommandlineparser.h"
 
+// annoying detail to determine whether font prefs are over-ridden
+#if LL_LINUX
+# define LL_DYNAMIC_FONT_DISCOVERY 1
+#else
+# define LL_DYNAMIC_FONT_DISCOVERY 0
+#endif
+
 // *FIX: These extern globals should be cleaned up.
 // The globals either represent state/config/resource-storage of either 
 // this app, or another 'component' of the viewer. App globals should be 
@@ -1483,30 +1490,17 @@ bool LLAppViewer::initConfiguration()
 
 	gSavedSettings.setString("VersionChannelName", LL_CHANNEL);
 
-#ifndef		LL_RELEASE_FOR_DOWNLOAD
+#ifndef	LL_RELEASE_FOR_DOWNLOAD
         gSavedSettings.setBOOL("ShowConsoleWindow", TRUE);
         gSavedSettings.setBOOL("AllowMultipleViewers", TRUE);
 #endif
 
-#if LL_WINDOWS
-	// Lists Japanese, Korean, and Chinese sanserif fonts available in
-	// Windows XP and Vista, as well as "Arial Unicode MS".
+#if !LL_DYNAMIC_FONT_DISCOVERY
+	// static font discovery - user settings can override.
 	gSavedSettings.setString("FontSansSerifFallback",
-							 "MSGOTHIC.TTC;gulim.ttc;simhei.ttf;ArialUni.ttf");
-#elif LL_DARWIN
-	// This is a fairly complete Japanese font that ships with Mac OS X.
-	// The first filename is in UTF8, but it shows up in the font menu as "Hiragino Kaku Gothic Pro W3".
-	// The third filename is in UTF8, but it shows up in the font menu as "STHeiti Light"
-	gSavedSettings.setString("FontSansSerifFallback", 
-							 "\xE3\x83\x92\xE3\x83\xA9\xE3\x82\xAD\xE3\x82\x99\xE3\x83\x8E\xE8\xA7\x92\xE3\x82\xB3\xE3\x82\x99 Pro W3.otf;\xE3\x83\x92\xE3\x83\xA9\xE3\x82\xAD\xE3\x82\x99\xE3\x83\x8E\xE8\xA7\x92\xE3\x82\xB3\xE3\x82\x99 ProN W3.otf;AppleGothic.dfont;AppleGothic.ttf;\xe5\x8d\x8e\xe6\x96\x87\xe7\xbb\x86\xe9\xbb\x91.ttf");
-#else
-	// 'unicode.ttf' doesn't exist, but hopefully an international
-	// user can take the hint and drop in their favourite local font.
-	gSavedSettings.setString("FontSansSerifFallback",	
-							 "unicode.ttf");
+				 LLWindow::getFontListSans());
 #endif
 
-
 	// These are warnings that appear on the first experience of that condition.
 	// They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
 	// for disable/reset ability
@@ -1553,6 +1547,15 @@ bool LLAppViewer::initConfiguration()
 	// Overwrite default user settings with	user settings
 	loadSettingsFromDirectory(LL_PATH_USER_SETTINGS);
 
+#if LL_DYNAMIC_FONT_DISCOVERY
+	// Linux does *dynamic* font discovery which is preferable to
+	// whatever got written-out into the config file last time.  This
+	// does remove the ability of the user to hand-define the fallbacks
+	// though, so from a config-management point of view this is hacky.
+	gSavedSettings.setString("FontSansSerifFallback",
+				 LLWindow::getFontListSans());
+#endif
+
 	// Parse command line settings.
 	LLControlGroupCLP clp;
 	std::string	cmd_line_config	= gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
@@ -1604,11 +1607,11 @@ bool LLAppViewer::initConfiguration()
 		gSavedSettings.setString("ClientSettingsFile", full_settings_path);
 	}
 
-	// Apply the command line params to	the	settings system.
-	// Anyway the following	call to	notify depends upon	the	settings being init'd.
+	// Apply the command line params to the settings system.
+	// Anyway the following	call to	notify depends upon the settings being init'd.
 	clp.notify(); 
 
-	// Start up	the	debugging console before handling other	options.
+	// Start up the debugging console before handling other options.
 	if (gSavedSettings.getBOOL("ShowConsoleWindow"))
 	{
 		initConsole();
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index d7a8e66a4bebe30df70475536889834ee89fdcd2..3ea8c737c987ee3ad25f18013843c6f1f4dda9df 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -37,7 +37,9 @@
 
 #include "llmemtype.h"
 #include "llviewernetwork.h"
+#include "llviewercontrol.h"
 #include "llmd5.h"
+#include "llfindlocale.h"
 
 #include <exception>
 
@@ -432,7 +434,27 @@ bool LLAppViewerLinux::initLogging()
 
 bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
 {
-	clp.parseCommandLine(gArgC, gArgV);
+	if (!clp.parseCommandLine(gArgC, gArgV))
+	{
+		return false;
+	}
+
+	// Find the system language.
+	FL_Locale *locale = NULL;
+	FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
+	if (success != 0)
+	{
+		if (success >= 2 && locale->lang) // confident!
+		{
+			LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
+			if(c)
+			{
+				c->setValue(std::string(locale->lang), false);
+			}
+		}
+		FL_FreeLocale(&locale);
+	}
+
 	return true;
 }
 
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 3770fe2a337c678bb1d033933f76f9cbf59156f7..fed538da37a28ba7f0a0e74cd812fa831f361eff 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -54,6 +54,7 @@
 
 #include "llviewernetwork.h"
 #include "llmd5.h"
+#include "llfindlocale.h"
 
 #include "llcommandlineparser.h"
 
@@ -385,7 +386,28 @@ bool LLAppViewerWin32::initHardwareTest()
 
 bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
 {
-    return clp.parseCommandLineString(mCmdLine);
+	if (!clp.parseCommandLineString(mCmdLine))
+	{
+		return false;
+	}
+
+	// Find the system language.
+	FL_Locale *locale = NULL;
+	FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
+	if (success != 0)
+	{
+		if (success >= 2 && locale->lang) // confident!
+		{
+			LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
+			if(c)
+			{
+				c->setValue(std::string(locale->lang), false);
+			}
+		}
+		FL_FreeLocale(&locale);
+	}
+
+	return true;
 }
 
 void LLAppViewerWin32::handleSyncCrashTrace()
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 21b827cc0fd09f8d0f3bbac81103f366a8408b10..c6c751147c5c2432c0f679d558391b37955a97da 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -4951,21 +4951,21 @@ void LLViewerWindow::initFonts(F32 zoom_factor)
 {
 	LLFontGL::destroyGL();
 	LLFontGL::initDefaultFonts( gSavedSettings.getF32("FontScreenDPI"),
-								mDisplayScale.mV[VX] * zoom_factor,
-								mDisplayScale.mV[VY] * zoom_factor,
-								gSavedSettings.getString("FontMonospace"),
-								gSavedSettings.getF32("FontSizeMonospace"),
-								gSavedSettings.getString("FontSansSerif"), 
-								gSavedSettings.getString("FontSansSerifFallback"),
-								gSavedSettings.getF32("FontSansSerifFallbackScale"),
-								gSavedSettings.getF32("FontSizeSmall"),	
-								gSavedSettings.getF32("FontSizeMedium"), 
-								gSavedSettings.getF32("FontSizeLarge"),			 
-								gSavedSettings.getF32("FontSizeHuge"),			 
-								gSavedSettings.getString("FontSansSerifBold"),
-								gSavedSettings.getF32("FontSizeMedium"),
-								gDirUtilp->getAppRODataDir()
-							);
+				    mDisplayScale.mV[VX] * zoom_factor,
+				    mDisplayScale.mV[VY] * zoom_factor,
+				    gSavedSettings.getString("FontMonospace"),
+				    gSavedSettings.getF32("FontSizeMonospace"),
+				    gSavedSettings.getString("FontSansSerif"), 
+				    gSavedSettings.getString("FontSansSerifFallback"),
+				    gSavedSettings.getF32("FontSansSerifFallbackScale"),
+				    gSavedSettings.getF32("FontSizeSmall"),	
+				    gSavedSettings.getF32("FontSizeMedium"), 
+				    gSavedSettings.getF32("FontSizeLarge"),			 
+				    gSavedSettings.getF32("FontSizeHuge"),			 
+				    gSavedSettings.getString("FontSansSerifBold"),
+				    gSavedSettings.getF32("FontSizeMedium"),
+				    gDirUtilp->getAppRODataDir()
+				    );
 }
 void LLViewerWindow::toggleFullscreen(BOOL show_progress)
 {
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index b147b471faa994cbbeb9a2a1c424ad8c2a5fdfef..0fbd177da4ba92a07a2ba8fec57847aa4e83eb39 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -445,18 +445,20 @@ def construct(self):
                         self.path("wrapper.sh","secondlife")
                         self.path("handle_secondlifeprotocol.sh")
                         self.path("register_secondlifeprotocol.sh")
-                        self.path("unicode.ttf","unicode.ttf")
                         self.end_prefix("linux_tools")
 
                 # Create an appropriate gridargs.dat for this package, denoting required grid.
                 self.put_in_file(self.flags_list(), 'gridargs.dat')
 
+
+        def package_finish(self):
                 # stripping all the libs removes a few megabytes from the end-user package
                 for s,d in self.file_list:
                         if re.search("lib/lib.+\.so.*", d):
                                 self.run_command('strip -S %s' % d)
+                        if re.search("app_settings/mozilla-runtime-.*/lib.+\.so.*", d):
+                                self.run_command('strip %s' % d)
 
-        def package_finish(self):
                 if(self.args.has_key('installer_name')):
                         installer_name = self.args['installer_name']
                 else: