//
// Author(s):
// Jackson Harper (jackson@ximian.com)
+// Atsushi Enomoto (atsushi@ximian.com)
//
-// (C) 2004 Novell, Inc (http://www.novell.com)
+// (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
private ArrayList cultures;
private Hashtable langs;
private Hashtable currency_types;
-
+ private Hashtable regions;
+
+ private XPathDocument lcids_doc;
+
// The lang is the language that display names will be displayed in
public string Lang {
get {
public void Run ()
{
+ lcids_doc = GetXPathDocument ("lcids.xml");
+
Regex locales_regex = null;
if (Locales != null)
locales_regex = new Regex (Locales);
langs = new Hashtable ();
cultures = new ArrayList ();
+ regions = new Hashtable ();
+
+ LookupRegions ();
LookupCurrencyTypes ();
foreach (string file in Directory.GetFiles ("locales", "*.xml")) {
string fn = Path.GetFileNameWithoutExtension (file);
+ if (fn == "hy_AM")
+ continue; // see bug #75499
if (locales_regex == null || locales_regex.IsMatch (fn)) {
ParseLocale (fn);
}
}
+ /* FIXME: This is hacky.
+ * Since there is only langs/zh.xml while there are
+ * two "zh" languages (CHS and CHT), there should be
+ * different language profiles and we are not likely
+ * to add lang/* files. So here I just clone zh-CHS
+ * as zh-CHT
+ */
+ foreach (CultureInfoEntry e in cultures) {
+ if (e.Name == "zh-CHS") {
+ CultureInfoEntry t =
+ CultureInfoEntry.ShallowCopy (e);
+ t.Language = "zh-CHT";
+ LookupLcids (t, true);
+ cultures.Add (t);
+ break;
+ }
+ }
+
+ ArrayList regionList = new ArrayList (regions.Values);
+ regionList.Sort (RegionComparer.Instance);
+ int number = 0;
+ foreach (RegionInfoEntry r in regionList)
+ r.RegionId = number++;
+
+ foreach (CultureInfoEntry e in cultures) {
+ int lcid = int.Parse (e.Lcid.Substring (2),
+ NumberStyles.HexNumber);
+ int idx;
+ int start = e.Name.IndexOf ('-') + 1;
+ if (start == 0)
+ continue;
+ for (idx = start; idx < e.Name.Length; idx++)
+ if (!Char.IsLetter (e.Name [idx]))
+ break;
+ if (start == idx) {
+ Console.Error.WriteLine ("Culture {0} {1} is not mappable to Region.", e.Lcid, e.Name);
+ continue;
+ }
+ string name = e.Name.Substring (start, idx - start);
+ RegionInfoEntry rm = null;
+ foreach (RegionInfoEntry r in regions.Values)
+ if (r.ISO2Name == name) {
+ rm = r;
+ break;
+ }
+ if (rm == null) {
+ Console.Error.WriteLine ("No definition for region {0}", name);
+ continue;
+ }
+ e.RegionId = rm.RegionId;
+ }
+
/**
* Dump each table individually. Using StringBuilders
* because it is easier to debug, should switch to just
* writing to streams eventually.
*/
using (StreamWriter writer = new StreamWriter (HeaderFileName, false, new UTF8Encoding (false, true))) {
-
+ writer.NewLine = "\n";
writer.WriteLine ();
+ writer.WriteLine ("/* This is a generated file. Do not edit. See tools/locale-builder. */");
writer.WriteLine ("#ifndef MONO_METADATA_CULTURE_INFO_TABLES");
writer.WriteLine ("#define MONO_METADATA_CULTURE_INFO_TABLES 1");
writer.WriteLine ("\n");
writer.WriteLine ("#define NUM_CULTURE_ENTRIES " + cultures.Count);
+ writer.WriteLine ("#define NUM_REGION_ENTRIES " + regionList.Count);
writer.WriteLine ("\n");
// Sort the cultures by lcid
builder = new StringBuilder ();
for (int i = 0; i < count; i++) {
CultureInfoEntry ci = (CultureInfoEntry) cultures [i];
- builder.Append ("\t{\"" + ci.Name.ToLower () + "\", ");
+ builder.Append ("\t{" + Entry.EncodeStringIdx (ci.Name.ToLower ()) + ", ");
builder.Append (ci.Row + "}");
if (i + 1 < count)
builder.Append (',');
writer.Write (builder);
writer.WriteLine ("};\n\n");
+ builder = new StringBuilder ();
+ int rcount = 0;
+ foreach (RegionInfoEntry r in regionList) {
+ r.AppendTableRow (builder);
+ if (++rcount != regionList.Count)
+ builder.Append (',');
+ builder.Append ('\n');
+ }
+ writer.WriteLine ("static const RegionInfoEntry region_entries [] = {");
+ writer.Write (builder);
+ writer.WriteLine ("};\n\n");
+
+ builder = new StringBuilder ();
+ rcount = 0;
+ foreach (RegionInfoEntry ri in regionList) {
+ builder.Append ("\t{" + Entry.EncodeStringIdx (ri.ISO2Name) + ", ");
+ builder.Append (ri.RegionId + "}");
+ if (++rcount < regionList.Count)
+ builder.Append (',');
+ builder.Append ('\n');
+ }
+
+ writer.WriteLine ("static const RegionInfoNameEntry region_name_entries [] = {");
+ writer.Write (builder);
+ writer.WriteLine ("};\n\n");
+
+ writer.WriteLine ("static const char locale_strings [] = {");
+ writer.Write (Entry.GetStrings ());
+ writer.WriteLine ("};\n\n");
+
writer.WriteLine ("#endif\n");
}
}
private XPathDocument GetXPathDocument (string path)
{
- XmlTextReader xtr = new XmlTextReader (path);
- xtr.XmlResolver = null;
- return new XPathDocument (xtr);
+ XmlTextReader xtr = null;
+ try {
+ xtr = new XmlTextReader (path);
+ xtr.XmlResolver = null;
+ return new XPathDocument (xtr);
+ } finally {
+ if (xtr != null)
+ xtr.Close ();
+ }
+ }
+
+ private string GetShortName (string lang)
+ {
+ return lang == "zh-CHS" ? "zh" : lang;
}
private bool ParseLang (string lang)
{
- XPathDocument doc = GetXPathDocument (Path.Combine ("langs", lang + ".xml"));
+ XPathDocument doc = GetXPathDocument (Path.Combine ("langs", GetShortName (lang) + ".xml"));
XPathNavigator nav = doc.CreateNavigator ();
CultureInfoEntry ci = new CultureInfoEntry ();
string lang_type, terr_type;
ci.Language = (lang_type == String.Empty ? null : lang_type);
ci.Territory = (terr_type == String.Empty ? null : terr_type);
- if (!LookupLcids (ci))
+ if (!LookupLcids (ci, true))
return false;
- doc = GetXPathDocument (Path.Combine ("langs", Lang + ".xml"));
+ doc = GetXPathDocument (Path.Combine ("langs", GetShortName (Lang) + ".xml"));
nav = doc.CreateNavigator ();
ci.DisplayName = LookupFullName (ci, nav);
if (Lang == "en") {
ci.EnglishName = ci.DisplayName;
} else {
- doc = GetXPathDocument (Path.Combine ("langs", Lang + ".xml"));
+ doc = GetXPathDocument (Path.Combine ("langs", GetShortName (lang) + ".xml"));
nav = doc.CreateNavigator ();
ci.EnglishName = LookupFullName (ci, nav);
}
if (ci.Language == Lang) {
ci.NativeName = ci.DisplayName;
} else {
- doc = GetXPathDocument (Path.Combine ("langs", lang + ".xml"));
+ doc = GetXPathDocument (Path.Combine ("langs", GetShortName (lang) + ".xml"));
nav = doc.CreateNavigator ();
ci.NativeName = LookupFullName (ci, nav);
}
if (ci == null)
return;
- if (langs [ci.Language] == null) {
- if (!ParseLang (ci.Language)) // If we can't parse the lang we cant have the locale
+ if (langs [GetLanguageFixed (ci)] == null) {
+ if (!ParseLang (GetLanguageFixed (ci))) // If we can't parse the lang we cant have the locale
return;
}
private CultureInfoEntry LookupCulture (string locale)
{
- XPathDocument doc = GetXPathDocument (Path.Combine ("locales", locale + ".xml"));
+ string path = Path.Combine ("locales", locale + ".xml");
+ if (!File.Exists (path))
+ return null;
+ XPathDocument doc = GetXPathDocument (path);
XPathNavigator nav = doc.CreateNavigator ();
CultureInfoEntry ci = new CultureInfoEntry ();
string supp;
ci.Language = nav.Evaluate ("string (ldml/identity/language/@type)").ToString ();
ci.Territory = nav.Evaluate ("string (ldml/identity/territory/@type)").ToString ();
- if (!LookupLcids (ci))
+ if (!LookupLcids (ci, false))
return null;
LookupNames (ci);
nav = doc.CreateNavigator ();
Lookup (nav, ci);
- doc = GetXPathDocument (Path.Combine ("langs", ci.Language + ".xml"));
+ doc = GetXPathDocument (Path.Combine ("langs", GetShortName (GetLanguageFixed (ci)) + ".xml"));
nav = doc.CreateNavigator ();
Lookup (nav, ci);
- supp = Path.Combine ("supp", ci.Language + ".xml");
+ supp = Path.Combine ("supp", GetLanguageFixed (ci) + ".xml");
if (File.Exists (supp)) {
doc = GetXPathDocument (supp);
nav = doc.CreateNavigator ();
LookupNumberInfo (nav, ci);
}
+ private string GetLanguageFixed (CultureInfoEntry ci)
+ {
+ // This is a hack, but without it nb-NO and nn-NO won't work.
+ if (ci.Territory == "NO") {
+ switch (ci.Language) {
+ case "nb":
+ case "nn":
+ return "no";
+ }
+ }
+ return ci.Language;
+ }
+
private void LookupNames (CultureInfoEntry ci)
{
- XPathDocument doc = GetXPathDocument (Path.Combine ("langs", Lang + ".xml"));
+ XPathDocument doc = GetXPathDocument (Path.Combine ("langs", GetShortName (Lang) + ".xml"));
XPathNavigator nav = doc.CreateNavigator ();
ci.DisplayName = LookupFullName (ci, nav);
if (ci.Language == Lang) {
ci.NativeName = ci.DisplayName;
} else {
- doc = GetXPathDocument (Path.Combine ("langs", ci.Language + ".xml"));
+ // FIXME: We use ci.Language here.
+ // This is nothing more than hack for nb-NO and nn-NO
+ // where Parent of them is nn (not nb or nn).
+ string lang = ci.Language;
+ doc = GetXPathDocument (Path.Combine ("langs", GetShortName (lang) + ".xml"));
nav = doc.CreateNavigator ();
ci.NativeName = LookupFullName (ci, nav);
}
}
+ private void AddPattern (ArrayList al, string pattern)
+ {
+ if (!al.Contains (pattern))
+ al.Add (pattern);
+ }
+
private void LookupDateTimeInfo (XPathNavigator nav, CultureInfoEntry ci)
{
/**
ext = df_nav.Select ("extraPatterns/pattern");
if (ext.MoveNext ()) {
df.LongDatePatterns.Clear ();
+ AddPattern (df.LongDatePatterns, df.LongDatePattern);
do {
df.LongDatePatterns.Add (ext.Current.Value);
} while (ext.MoveNext ());
}
+ else
+ AddPattern (df.LongDatePatterns, df.LongDatePattern);
break;
case "short":
if (value != null)
ext = df_nav.Select ("extraPatterns/pattern");
if (ext.MoveNext ()) {
df.ShortDatePatterns.Clear ();
+ AddPattern (df.ShortDatePatterns, df.ShortDatePattern);
do {
df.ShortDatePatterns.Add (ext.Current.Value);
} while (ext.MoveNext ());
}
+ else
+ AddPattern (df.ShortDatePatterns, df.ShortDatePattern);
break;
case "year_month":
if (value != null)
ext = df_nav.Select ("extraPatterns/pattern");
if (ext.MoveNext ()) {
df.LongTimePatterns.Clear ();
+ AddPattern (df.LongTimePatterns, df.LongTimePattern);
do {
df.LongTimePatterns.Add (ext.Current.Value);
} while (ext.MoveNext ());
}
+ else
+ AddPattern (df.LongTimePatterns, df.LongTimePattern);
break;
case "short":
if (value != null)
ext = df_nav.Select ("extraPatterns/pattern");
if (ext.MoveNext ()) {
df.ShortTimePatterns.Clear ();
+ AddPattern (df.ShortTimePatterns, df.ShortTimePattern);
do {
df.ShortTimePatterns.Add (ext.Current.Value);
} while (ext.MoveNext ());
}
+ else
+ AddPattern (df.ShortTimePatterns, df.ShortTimePattern);
break;
}
}
ci.NumberFormatEntry.CurrencySymbol = cur;
}
- private bool LookupLcids (CultureInfoEntry ci)
+ private bool LookupLcids (CultureInfoEntry ci, bool lang)
{
- XPathDocument doc = GetXPathDocument ("lcids.xml");
- XPathNavigator nav = doc.CreateNavigator ();
- string name = ci.Language;
+ XPathNavigator nav = lcids_doc.CreateNavigator ();
+ string name = ci.Name;
+ // Language name does not always consist of locale name.
+ // (for zh-* it must be either zh-CHS or zh-CHT)
+ string langName = GetLanguageFixed (ci);
- if (ci.Territory != null)
- name += "-" + ci.Territory;
+// if (ci.Territory != null)
+// name += "-" + ci.Territory;
XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("lcids/lcid[@name='"
- + name + "']");
+ + (lang ? langName : name) + "']");
if (!ni.MoveNext ()) {
+ Console.WriteLine ("no lcid found for: {0} ({1}/{2})", name, ci.Language, ci.Territory);
string file;
+
if (ci.Territory != null) {
file = Path.Combine ("locales", ci.Language + "_" + ci.Territory + ".xml");
- File.Delete (file);
Console.WriteLine ("deleting file: " + file);
+ File.Delete (file);
}
- Console.WriteLine ("no lcid found for: " + name);
+
return false;
}
ci.ISO3Lang = iso3;
ci.Win3Lang = win;
ci.IcuName = icu;
+
+ ci.TextInfoEntry = new TextInfoEntry (int.Parse (id.Substring (2), NumberStyles.HexNumber), GetXPathDocument ("textinfo.xml"));
return true;
}
string pre = "ldml/localeDisplayNames/";
string ret;
+ // FIXME: We use ci.Language here.
+ // This is nothing more than hack for nb-NO or nn-NO
+ // where Parent of them is nn (not nb or nn).
ret = (string) nav.Evaluate ("string("+
- pre + "languages/language[@type='" + ci.Language + "'])");
+ pre + "languages/language[@type='" + GetShortName (ci.Language) + "'])");
if (ci.Territory == null)
return ret;
return ret;
}
+ private void LookupRegions ()
+ {
+ XPathDocument doc = GetXPathDocument ("supplementalData.xml");
+ XPathNavigator nav = doc.CreateNavigator ();
+ XPathNodeIterator ni = nav.Select ("supplementalData/currencyData/region");
+ while (ni.MoveNext ()) {
+ string territory = (string) ni.Current.GetAttribute ("iso3166", String.Empty);
+ string currency = (string) ni.Current.Evaluate ("string(currency/@iso4217)");
+ RegionInfoEntry region = new RegionInfoEntry ();
+ region.ISO2Name = territory.ToUpper ();
+ region.ISOCurrencySymbol = currency;
+ regions [territory] = region;
+ }
+
+ doc = GetXPathDocument ("langs/en.xml");
+ nav = doc.CreateNavigator ();
+ ni = nav.Select ("/ldml/localeDisplayNames/territories/territory");
+ while (ni.MoveNext ()) {
+ RegionInfoEntry r = (RegionInfoEntry)
+ regions [ni.Current.GetAttribute ("type", "")];
+ if (r == null)
+ continue;
+ r.EnglishName = ni.Current.Value;
+ }
+
+ Hashtable curNames = new Hashtable ();
+ ni = nav.Select ("/ldml/numbers/currencies/currency");
+ while (ni.MoveNext ())
+ curNames [ni.Current.GetAttribute ("type", "")] =
+ ni.Current.Evaluate ("string (displayName)");
+
+ foreach (RegionInfoEntry r in regions.Values)
+ r.CurrencyEnglishName =
+ (string) curNames [r.ISOCurrencySymbol];
+ }
+
private void LookupCurrencyTypes ()
{
XPathDocument doc = GetXPathDocument ("supplementalData.xml");
return aa.Name.ToLower ().CompareTo (bb.Name.ToLower ());
}
}
+
+ class RegionComparer : IComparer
+ {
+ public static RegionComparer Instance = new RegionComparer ();
+
+ public int Compare (object o1, object o2)
+ {
+ RegionInfoEntry r1 = (RegionInfoEntry) o1;
+ RegionInfoEntry r2 = (RegionInfoEntry) o2;
+ return String.CompareOrdinal (
+ r1.ISO2Name, r2.ISO2Name);
+ }
+ }
+
+ class RegionLCIDMap
+ {
+ public RegionLCIDMap (int lcid, int regionId)
+ {
+ LCID = lcid;
+ RegionId = regionId;
+ }
+
+ public int LCID;
+ public int RegionId;
+ }
}
}