X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=tools%2Flocale-builder%2FDriver.cs;h=52586043f241713ffeb53948ee225b67cc290485;hb=c0ba6dca416db15e7919fe775d29b9cf0124a611;hp=9e1ad27bcb5a9d9fcd5a96101700d5ac2e3e30be;hpb=2bbfe589c83b52c15fc5b12cf13dea7f9e400747;p=mono.git diff --git a/tools/locale-builder/Driver.cs b/tools/locale-builder/Driver.cs index 9e1ad27bcb5..52586043f24 100644 --- a/tools/locale-builder/Driver.cs +++ b/tools/locale-builder/Driver.cs @@ -3,8 +3,9 @@ // // 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) // @@ -46,7 +47,10 @@ namespace Mono.Tools.LocaleBuilder { 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 { @@ -73,35 +77,96 @@ namespace Mono.Tools.LocaleBuilder { 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 @@ -161,7 +226,7 @@ namespace Mono.Tools.LocaleBuilder { 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 (','); @@ -172,13 +237,61 @@ namespace Mono.Tools.LocaleBuilder { 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 = 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 = new XPathDocument (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; @@ -191,17 +304,17 @@ namespace Mono.Tools.LocaleBuilder { 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 = new XPathDocument (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 = new XPathDocument (Path.Combine ("langs", Lang + ".xml")); + doc = GetXPathDocument (Path.Combine ("langs", GetShortName (lang) + ".xml")); nav = doc.CreateNavigator (); ci.EnglishName = LookupFullName (ci, nav); } @@ -209,7 +322,7 @@ namespace Mono.Tools.LocaleBuilder { if (ci.Language == Lang) { ci.NativeName = ci.DisplayName; } else { - doc = new XPathDocument (Path.Combine ("langs", lang + ".xml")); + doc = GetXPathDocument (Path.Combine ("langs", GetShortName (lang) + ".xml")); nav = doc.CreateNavigator (); ci.NativeName = LookupFullName (ci, nav); } @@ -233,8 +346,8 @@ namespace Mono.Tools.LocaleBuilder { 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; } @@ -243,7 +356,10 @@ namespace Mono.Tools.LocaleBuilder { private CultureInfoEntry LookupCulture (string locale) { - XPathDocument doc = new XPathDocument (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; @@ -254,7 +370,7 @@ namespace Mono.Tools.LocaleBuilder { 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); @@ -267,32 +383,32 @@ namespace Mono.Tools.LocaleBuilder { * locale file. Values in each descending file can * overwrite previous values. */ - doc = new XPathDocument (Path.Combine ("langs", "root.xml")); + doc = GetXPathDocument (Path.Combine ("langs", "root.xml")); nav = doc.CreateNavigator (); Lookup (nav, ci); - doc = new XPathDocument (Path.Combine ("supp", "root.xml")); + doc = GetXPathDocument (Path.Combine ("supp", "root.xml")); nav = doc.CreateNavigator (); Lookup (nav, ci); - doc = new XPathDocument (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 = new XPathDocument (supp); + doc = GetXPathDocument (supp); nav = doc.CreateNavigator (); Lookup (nav, ci); } - doc = new XPathDocument (Path.Combine ("locales", locale + ".xml")); + doc = GetXPathDocument (Path.Combine ("locales", locale + ".xml")); nav = doc.CreateNavigator (); Lookup (nav, ci); supp = Path.Combine ("supp", locale + ".xml"); if (File.Exists (supp)) { - doc = new XPathDocument (supp); + doc = GetXPathDocument (supp); nav = doc.CreateNavigator (); Lookup (nav, ci); } @@ -306,9 +422,22 @@ namespace Mono.Tools.LocaleBuilder { 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 = new XPathDocument (Path.Combine ("langs", Lang + ".xml")); + XPathDocument doc = GetXPathDocument (Path.Combine ("langs", GetShortName (Lang) + ".xml")); XPathNavigator nav = doc.CreateNavigator (); ci.DisplayName = LookupFullName (ci, nav); @@ -316,7 +445,7 @@ namespace Mono.Tools.LocaleBuilder { if (Lang == "en") { ci.EnglishName = ci.DisplayName; } else { - doc = new XPathDocument (Path.Combine ("langs", "en.xml")); + doc = GetXPathDocument (Path.Combine ("langs", "en.xml")); nav = doc.CreateNavigator (); ci.EnglishName = LookupFullName (ci, nav); } @@ -324,12 +453,22 @@ namespace Mono.Tools.LocaleBuilder { if (ci.Language == Lang) { ci.NativeName = ci.DisplayName; } else { - doc = new XPathDocument (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) { /** @@ -384,6 +523,8 @@ namespace Mono.Tools.LocaleBuilder { df.MonthNames.Clear (); df.MonthNames.Add (ni2.Current.Value); } + if (df.MonthNames.Count == 12) + df.MonthNames.Add (String.Empty); ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dayNames/day"); while (ni2.MoveNext ()) { @@ -405,46 +546,105 @@ namespace Mono.Tools.LocaleBuilder { df.AbbreviatedMonthNames.Clear (); df.AbbreviatedMonthNames.Add (ni2.Current.Value); } + if (df.AbbreviatedMonthNames.Count == 12) + df.AbbreviatedMonthNames.Add (String.Empty); ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dateFormats/dateFormatLength"); while (ni2.MoveNext ()) { XPathNavigator df_nav = ni2.Current; + XPathNodeIterator p = df_nav.Select ("dateFormat/pattern"); + string value = null; + if (p.MoveNext ()) + value = p.Current.Value; + XPathNodeIterator ext = null; switch (df_nav.GetAttribute ("type", String.Empty)) { - case "full": - ParseFullDateFormat (df, df_nav.Value); - break; + case "full": + if (value != null) + ParseFullDateFormat (df, value); + break; case "long": - df.LongDatePattern = df_nav.Value; + if (value != null) + df.LongDatePattern = value; + 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": - df.ShortDatePattern = df_nav.Value; + if (value != null) + df.ShortDatePattern = value; + 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) + df.YearMonthPattern = value; + break; + case "month_day": + if (value != null) + df.MonthDayPattern = value; break; - case "year_month": - df.YearMonthPattern = df_nav.Value; - break; - case "month_day": - df.MonthDayPattern = df_nav.Value; - break; } } ni2 = (XPathNodeIterator) ni.Current.Evaluate ("timeFormats/timeFormatLength"); while (ni2.MoveNext ()) { XPathNavigator df_nav = ni2.Current; + XPathNodeIterator p = df_nav.Select ("timeFormat/pattern"); + string value = null; + if (p.MoveNext ()) + value = p.Current.Value; + XPathNodeIterator ext = null; switch (df_nav.GetAttribute ("type", String.Empty)) { case "long": - df.LongTimePattern = df_nav.Value.Replace ('a', 't'); + if (value != null) + df.LongTimePattern = value.Replace ('a', 't'); + 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": - df.ShortTimePattern = df_nav.Value.Replace ('a', 't'); + if (value != null) + df.ShortTimePattern = value.Replace ('a', 't'); + 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; } } ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dateTimeFormats/dateTimeFormatLength/dateTimeFormat/pattern"); if (ni2.MoveNext ()) - df.FullDateTimePattern = String.Format (ni2.Current.ToString (), - df.LongTimePattern, df.LongDatePattern); + df.RawFullDateTimePattern = ni2.Current.ToString ();/*String.Format (ni2.Current.ToString (), + df.LongTimePattern, df.LongDatePattern);*/ XPathNodeIterator am = ni.Current.SelectChildren ("am", ""); if (am.MoveNext ()) @@ -495,11 +695,17 @@ namespace Mono.Tools.LocaleBuilder { string [] part_one, part_two; string [] pos_neg = format.Split (new char [1] {';'}, 2); - + + // Most of the patterns are common in positive and negative + if (pos_neg.Length == 1) + pos_neg = new string [] {pos_neg [0], pos_neg [0]}; + if (pos_neg.Length == 2) { part_one = pos_neg [0].Split (new char [1] {'.'}, 2); - + if (part_one.Length == 1) + part_one = new string [] {part_one [0], String.Empty}; + if (part_one.Length == 2) { // assumed same for both positive and negative // decimal digit side @@ -508,8 +714,10 @@ namespace Mono.Tools.LocaleBuilder { if (part_one [1][i] == '#') { ci.NumberFormatEntry.NumberDecimalDigits ++; } else - break; - } + break; } + // FIXME: This should be actually done by modifying culture xml files, but too many files to be modified. + if (ci.NumberFormatEntry.NumberDecimalDigits > 0) + ci.NumberFormatEntry.NumberDecimalDigits --; // decimal grouping side part_two = part_one [0].Split (','); @@ -521,7 +729,7 @@ namespace Mono.Tools.LocaleBuilder { ci.NumberFormatEntry.NumberGroupSizes [i] = pat.Length; } } else { - ci.NumberFormatEntry.NumberGroupSizes = new int [1] { 0 }; + ci.NumberFormatEntry.NumberGroupSizes = new int [1] { 3 }; } if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith (")")) { @@ -556,19 +764,21 @@ namespace Mono.Tools.LocaleBuilder { if (format.StartsWith ("%")) { ci.NumberFormatEntry.PercentPositivePattern = 2; ci.NumberFormatEntry.PercentNegativePattern = 2; + format = format.Substring (1); } else if (format.EndsWith (" %")) { ci.NumberFormatEntry.PercentPositivePattern = 0; ci.NumberFormatEntry.PercentNegativePattern = 0; + format = format.Substring (0, format.Length - 2); } else if (format.EndsWith ("%")) { ci.NumberFormatEntry.PercentPositivePattern = 1; ci.NumberFormatEntry.PercentNegativePattern = 1; + format = format.Substring (0, format.Length - 1); } else { ci.NumberFormatEntry.PercentPositivePattern = 0; ci.NumberFormatEntry.PercentNegativePattern = 0; } part_one = format.Split (new char [1] {'.'}, 2); - if (part_one.Length == 2) { // assumed same for both positive and negative // decimal digit side @@ -579,7 +789,9 @@ namespace Mono.Tools.LocaleBuilder { else break; } + } + if (part_one.Length > 0) { // percent grouping side part_two = part_one [0].Split (','); if (part_two.Length > 1) { @@ -587,10 +799,13 @@ namespace Mono.Tools.LocaleBuilder { ci.NumberFormatEntry.PercentGroupSizes = new int [len]; for (int i = 0; i < len; i++) { string pat = part_two [i + 1]; + if (pat [pat.Length -1] == '0') + ci.NumberFormatEntry.PercentDecimalDigits = pat.Length - 1; ci.NumberFormatEntry.PercentGroupSizes [i] = pat.Length; } } else { - ci.NumberFormatEntry.PercentGroupSizes = new int [1] { 0 }; + ci.NumberFormatEntry.PercentGroupSizes = new int [1] { 3 }; + ci.NumberFormatEntry.PercentDecimalDigits = 2; } } } @@ -605,11 +820,15 @@ namespace Mono.Tools.LocaleBuilder { string [] part_one, part_two; string [] pos_neg = format.Split (new char [1] {';'}, 2); - - pos_neg = format.Split (new char [1] {';'}, 2); + + // Most of the patterns are common in positive and negative + if (pos_neg.Length == 1) + pos_neg = new string [] {pos_neg [0], pos_neg [0]}; + if (pos_neg.Length == 2) { part_one = pos_neg [0].Split (new char [1] {'.'}, 2); - + if (part_one.Length == 1) + part_one = new string [] {part_one [0], String.Empty}; if (part_one.Length == 2) { // assumed same for both positive and negative // decimal digit side @@ -631,7 +850,7 @@ namespace Mono.Tools.LocaleBuilder { ci.NumberFormatEntry.CurrencyGroupSizes [i] = pat.Length; } } else { - ci.NumberFormatEntry.CurrencyGroupSizes = new int [1] { 0 }; + ci.NumberFormatEntry.CurrencyGroupSizes = new int [1] { 3 }; } if (pos_neg [1].StartsWith ("(\u00a4 ") && pos_neg [1].EndsWith (")")) { @@ -738,25 +957,29 @@ namespace Mono.Tools.LocaleBuilder { ci.NumberFormatEntry.CurrencySymbol = cur; } - private bool LookupLcids (CultureInfoEntry ci) + private bool LookupLcids (CultureInfoEntry ci, bool lang) { - XPathDocument doc = new XPathDocument ("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; } @@ -776,6 +999,8 @@ namespace Mono.Tools.LocaleBuilder { 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; } @@ -785,8 +1010,11 @@ namespace Mono.Tools.LocaleBuilder { 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; @@ -796,9 +1024,45 @@ namespace Mono.Tools.LocaleBuilder { 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 = new XPathDocument ("supplementalData.xml"); + XPathDocument doc = GetXPathDocument ("supplementalData.xml"); XPathNavigator nav = doc.CreateNavigator (); currency_types = new Hashtable (); @@ -811,7 +1075,7 @@ namespace Mono.Tools.LocaleBuilder { } } - static string control_chars = "ghmsftz"; + static string control_chars = "eghmsftz"; // HACK: We are trying to build year_month and month_day patterns from the full pattern. private void ParseFullDateFormat (DateTimeFormatEntry df, string full) @@ -821,29 +1085,37 @@ namespace Mono.Tools.LocaleBuilder { string year_month = String.Empty; bool in_month_data = false; bool in_year_data = false; - int month_end = 0; - int year_end = 0; + int day_start = 0, day_end = 0; + int month_start = 0, month_end = 0; + int year_start = 0, year_end = 0; + bool inquote = false; for (int i = 0; i < full.Length; i++) { char c = full [i]; - if (c == 'M') { + if (!inquote && c == 'M') { month_day += c; year_month += c; in_year_data = true; in_month_data = true; - month_end = month_day.Length; + if (month_start == 0) + month_start = i; + month_end = i; year_end = year_month.Length; - } else if (Char.ToLower (c) == 'd') { + } else if (!inquote && Char.ToLower (c) == 'd') { month_day += c; in_month_data = true; in_year_data = false; - month_end = month_day.Length; - } else if (Char.ToLower (c) == 'y') { + if (day_start == 0) + day_start = i; + day_end = i; + } else if (!inquote && Char.ToLower (c) == 'y') { year_month += c; in_year_data = true; in_month_data = false; - year_end = year_month.Length; - } else if (control_chars.IndexOf (Char.ToLower (c)) >= 0) { + if (year_start == 0) + year_start = i; + year_end = i; + } else if (!inquote && control_chars.IndexOf (Char.ToLower (c)) >= 0) { in_year_data = false; in_month_data = false; } else if (in_year_data || in_month_data) { @@ -852,18 +1124,42 @@ namespace Mono.Tools.LocaleBuilder { if (in_year_data) year_month += c; } + + if (c == '\'') { + inquote = !inquote; + } } if (month_day != String.Empty) { - month_day = month_day.Substring (0, month_end); - df.MonthDayPattern = month_day; + //month_day = month_day.Substring (0, month_end); + df.MonthDayPattern = TrimPattern (month_day); } if (year_month != String.Empty) { - year_month = year_month.Substring (0, year_end); - df.YearMonthPattern = year_month; + //year_month = year_month.Substring (0, year_end); + df.YearMonthPattern = TrimPattern (year_month); } } + string TrimPattern (string p) + { + int idx = 0; + p = p.Trim ().TrimEnd (','); + idx = p.LastIndexOf ("' de '"); // spanish dates + if (idx > 0) + p = p.Substring (0, idx); + idx = p.LastIndexOf ("' ta '"); // finnish + if (idx > 0) + p = p.Substring (0, idx); + idx = p.LastIndexOf ("'ren'"); // euskara + if (idx > 0) + p = p.Replace ("'ren'", "").Trim (); + idx = p.LastIndexOf ("'a'"); // estonian + if (idx > 0) + p = p.Substring (0, idx); + + return p.Replace ("'ta '", "'ta'"); // finnish + } + private class LcidComparer : IComparer { public int Compare (object a, object b) @@ -882,9 +1178,34 @@ namespace Mono.Tools.LocaleBuilder { CultureInfoEntry aa = (CultureInfoEntry) a; CultureInfoEntry bb = (CultureInfoEntry) b; - return aa.Name.ToLower ().CompareTo (bb.Name.ToLower ()); + return String.CompareOrdinal(aa.Name.ToLower (), 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; + } } }