2 // Mono.Tools.LocalBuilder.Driver
5 // Jackson Harper (jackson@ximian.com)
7 // (C) 2004 Novell, Inc (http://www.novell.com)
15 using System.Xml.XPath;
16 using System.Collections;
17 using System.Globalization;
18 using System.Text.RegularExpressions;
20 namespace Mono.Tools.LocaleBuilder {
24 public static void Main (string [] args)
26 Driver d = new Driver ();
31 private static void ParseArgs (string [] args, Driver d)
33 for (int i = 0; i < args.Length; i++) {
34 if (args [i] == "--lang" && i+1 < args.Length)
36 else if (args [i] == "--locales" && i+1 < args.Length)
37 d.Locales = args [++i];
38 else if (args [i] == "--header" && i + 1 < args.Length)
39 d.HeaderFileName = args [++i];
44 private string locales;
45 private string header_name;
46 private ArrayList cultures;
47 private Hashtable langs;
48 private Hashtable currency_types;
50 // The lang is the language that display names will be displayed in
60 public string Locales {
61 get { return locales; }
62 set { locales = value; }
65 public string HeaderFileName {
67 if (header_name == null)
68 return "culture-info-tables.h";
71 set { header_name = value; }
76 Regex locales_regex = null;
78 locales_regex = new Regex (Locales);
80 langs = new Hashtable ();
81 cultures = new ArrayList ();
83 LookupCurrencyTypes ();
85 foreach (string file in Directory.GetFiles ("locales", "*.xml")) {
86 string fn = Path.GetFileNameWithoutExtension (file);
87 if (locales_regex == null || locales_regex.IsMatch (fn)) {
93 * Dump each table individually. Using StringBuilders
94 * because it is easier to debug, should switch to just
95 * writing to streams eventually.
97 using (StreamWriter writer = new StreamWriter (HeaderFileName, false, new UTF8Encoding (false, true))) {
100 writer.WriteLine ("#ifndef MONO_METADATA_CULTURE_INFO_TABLES");
101 writer.WriteLine ("#define MONO_METADATA_CULTURE_INFO_TABLES 1");
102 writer.WriteLine ("\n");
104 writer.WriteLine ("#define NUM_CULTURE_ENTRIES " + cultures.Count);
105 writer.WriteLine ("\n");
107 // Sort the cultures by lcid
108 cultures.Sort (new LcidComparer ());
110 StringBuilder builder = new StringBuilder ();
112 int count = cultures.Count;
113 for (int i = 0; i < count; i++) {
114 CultureInfoEntry ci = (CultureInfoEntry) cultures [i];
115 if (ci.DateTimeFormatEntry == null)
117 ci.DateTimeFormatEntry.AppendTableRow (builder);
118 ci.DateTimeFormatEntry.Row = row++;
120 builder.Append (',');
121 builder.Append ('\n');
124 writer.WriteLine ("static const DateTimeFormatEntry datetime_format_entries [] = {");
125 writer.Write (builder);
126 writer.WriteLine ("};\n\n");
128 builder = new StringBuilder ();
130 for (int i=0; i < count; i++) {
131 CultureInfoEntry ci = (CultureInfoEntry) cultures [i];
132 if (ci.NumberFormatEntry == null)
134 ci.NumberFormatEntry.AppendTableRow (builder);
135 ci.NumberFormatEntry.Row = row++;
137 builder.Append (',');
138 builder.Append ('\n');
141 writer.WriteLine ("static const NumberFormatEntry number_format_entries [] = {");
142 writer.Write (builder);
143 writer.WriteLine ("};\n\n");
145 builder = new StringBuilder ();
147 for (int i = 0; i < count; i++) {
148 CultureInfoEntry ci = (CultureInfoEntry) cultures [i];
149 ci.AppendTableRow (builder);
152 builder.Append (',');
153 builder.Append ('\n');
156 writer.WriteLine ("static const CultureInfoEntry culture_entries [] = {");
157 writer.Write (builder);
158 writer.WriteLine ("};\n\n");
160 cultures.Sort (new NameComparer ()); // Sort based on name
161 builder = new StringBuilder ();
162 for (int i = 0; i < count; i++) {
163 CultureInfoEntry ci = (CultureInfoEntry) cultures [i];
164 builder.Append ("\t{\"" + ci.Name.ToLower () + "\", ");
165 builder.Append (ci.Row + "}");
167 builder.Append (',');
168 builder.Append ('\n');
171 writer.WriteLine ("static const CultureInfoNameEntry culture_name_entries [] = {");
172 writer.Write (builder);
173 writer.WriteLine ("};\n\n");
175 writer.WriteLine ("#endif\n");
179 private XPathDocument GetXPathDocument (string path)
181 XmlTextReader xtr = new XmlTextReader (path);
182 xtr.XmlResolver = null;
183 return new XPathDocument (xtr);
186 private bool ParseLang (string lang)
188 XPathDocument doc = GetXPathDocument (Path.Combine ("langs", lang + ".xml"));
189 XPathNavigator nav = doc.CreateNavigator ();
190 CultureInfoEntry ci = new CultureInfoEntry ();
191 string lang_type, terr_type;
193 // ci.Name = lang; // TODO: might need to be mapped.
195 lang_type = nav.Evaluate ("string (ldml/identity/language/@type)").ToString ();
196 terr_type = nav.Evaluate ("string (ldml/identity/territory/@type)").ToString ();
198 ci.Language = (lang_type == String.Empty ? null : lang_type);
199 ci.Territory = (terr_type == String.Empty ? null : terr_type);
201 if (!LookupLcids (ci))
204 doc = GetXPathDocument (Path.Combine ("langs", Lang + ".xml"));
205 nav = doc.CreateNavigator ();
206 ci.DisplayName = LookupFullName (ci, nav);
209 ci.EnglishName = ci.DisplayName;
211 doc = GetXPathDocument (Path.Combine ("langs", Lang + ".xml"));
212 nav = doc.CreateNavigator ();
213 ci.EnglishName = LookupFullName (ci, nav);
216 if (ci.Language == Lang) {
217 ci.NativeName = ci.DisplayName;
219 doc = GetXPathDocument (Path.Combine ("langs", lang + ".xml"));
220 nav = doc.CreateNavigator ();
221 ci.NativeName = LookupFullName (ci, nav);
224 // Null these out because langs dont have them
225 ci.DateTimeFormatEntry = null;
226 ci.NumberFormatEntry = null;
234 private void ParseLocale (string locale)
238 ci = LookupCulture (locale);
243 if (langs [ci.Language] == null) {
244 if (!ParseLang (ci.Language)) // If we can't parse the lang we cant have the locale
251 private CultureInfoEntry LookupCulture (string locale)
253 XPathDocument doc = GetXPathDocument (Path.Combine ("locales", locale + ".xml"));
254 XPathNavigator nav = doc.CreateNavigator ();
255 CultureInfoEntry ci = new CultureInfoEntry ();
258 // ci.Name = locale; // TODO: Some of these need to be mapped.
260 // First thing we do is get the lang-territory combo, lcid, and full names
261 ci.Language = nav.Evaluate ("string (ldml/identity/language/@type)").ToString ();
262 ci.Territory = nav.Evaluate ("string (ldml/identity/territory/@type)").ToString ();
264 if (!LookupLcids (ci))
269 * Locale generation is done in six steps, first we
270 * read the root file which is the base invariant data
271 * then the supplemental root data,
272 * then the language file, the supplemental languages
273 * file then the locale file, then the supplemental
274 * locale file. Values in each descending file can
275 * overwrite previous values.
277 doc = GetXPathDocument (Path.Combine ("langs", "root.xml"));
278 nav = doc.CreateNavigator ();
281 doc = GetXPathDocument (Path.Combine ("supp", "root.xml"));
282 nav = doc.CreateNavigator ();
285 doc = GetXPathDocument (Path.Combine ("langs", ci.Language + ".xml"));
286 nav = doc.CreateNavigator ();
289 supp = Path.Combine ("supp", ci.Language + ".xml");
290 if (File.Exists (supp)) {
291 doc = GetXPathDocument (supp);
292 nav = doc.CreateNavigator ();
296 doc = GetXPathDocument (Path.Combine ("locales", locale + ".xml"));
297 nav = doc.CreateNavigator ();
300 supp = Path.Combine ("supp", locale + ".xml");
301 if (File.Exists (supp)) {
302 doc = GetXPathDocument (supp);
303 nav = doc.CreateNavigator ();
310 private void Lookup (XPathNavigator nav, CultureInfoEntry ci)
312 LookupDateTimeInfo (nav, ci);
313 LookupNumberInfo (nav, ci);
316 private void LookupNames (CultureInfoEntry ci)
318 XPathDocument doc = GetXPathDocument (Path.Combine ("langs", Lang + ".xml"));
319 XPathNavigator nav = doc.CreateNavigator ();
321 ci.DisplayName = LookupFullName (ci, nav);
324 ci.EnglishName = ci.DisplayName;
326 doc = GetXPathDocument (Path.Combine ("langs", "en.xml"));
327 nav = doc.CreateNavigator ();
328 ci.EnglishName = LookupFullName (ci, nav);
331 if (ci.Language == Lang) {
332 ci.NativeName = ci.DisplayName;
334 doc = GetXPathDocument (Path.Combine ("langs", ci.Language + ".xml"));
335 nav = doc.CreateNavigator ();
336 ci.NativeName = LookupFullName (ci, nav);
340 private void LookupDateTimeInfo (XPathNavigator nav, CultureInfoEntry ci)
343 * TODO: Does anyone have multiple calendars?
345 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("ldml/dates/calendars/calendar");
347 while (ni.MoveNext ()) {
348 DateTimeFormatEntry df = ci.DateTimeFormatEntry;
349 string cal_type = ni.Current.GetAttribute ("type", String.Empty);
351 if (cal_type != String.Empty)
352 df.CalendarType = cal_type;
354 XPathNodeIterator ni2 = (XPathNodeIterator) ni.Current.Evaluate ("optionalCalendars/calendar");
355 int opt_cal_count = 0;
356 while (ni2.MoveNext ()) {
358 string greg_type_str;
359 XPathNavigator df_nav = ni2.Current;
360 switch (df_nav.GetAttribute ("type", String.Empty)) {
371 Console.WriteLine ("unknown calendar type: " +
372 df_nav.GetAttribute ("type", String.Empty));
376 greg_type_str = df_nav.GetAttribute ("greg_type", String.Empty);
377 if (greg_type_str != null && greg_type_str != String.Empty) {
378 GregorianCalendarTypes greg_type = (GregorianCalendarTypes)
379 Enum.Parse (typeof (GregorianCalendarTypes), greg_type_str);
380 int greg_type_int = (int) greg_type;
381 type |= greg_type_int;
384 Console.WriteLine ("Setting cal type: {0:X} for {1}", type, ci.Name);
385 ci.CalendarData [opt_cal_count++] = type;
388 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("monthNames/month");
389 while (ni2.MoveNext ()) {
390 if (ni2.CurrentPosition == 1)
391 df.MonthNames.Clear ();
392 df.MonthNames.Add (ni2.Current.Value);
395 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dayNames/day");
396 while (ni2.MoveNext ()) {
397 if (ni2.CurrentPosition == 1)
398 df.DayNames.Clear ();
399 df.DayNames.Add (ni2.Current.Value);
402 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dayAbbr/day");
403 while (ni2.MoveNext ()) {
404 if (ni2.CurrentPosition == 1)
405 df.AbbreviatedDayNames.Clear ();
406 df.AbbreviatedDayNames.Add (ni2.Current.Value);
409 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("monthAbbr/month");
410 while (ni2.MoveNext ()) {
411 if (ni2.CurrentPosition == 1)
412 df.AbbreviatedMonthNames.Clear ();
413 df.AbbreviatedMonthNames.Add (ni2.Current.Value);
416 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dateFormats/dateFormatLength");
417 while (ni2.MoveNext ()) {
418 XPathNavigator df_nav = ni2.Current;
419 switch (df_nav.GetAttribute ("type", String.Empty)) {
421 ParseFullDateFormat (df, df_nav.Value);
424 df.LongDatePattern = df_nav.Value;
427 df.ShortDatePattern = df_nav.Value;
430 df.YearMonthPattern = df_nav.Value;
433 df.MonthDayPattern = df_nav.Value;
438 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("timeFormats/timeFormatLength");
439 while (ni2.MoveNext ()) {
440 XPathNavigator df_nav = ni2.Current;
441 switch (df_nav.GetAttribute ("type", String.Empty)) {
443 df.LongTimePattern = df_nav.Value.Replace ('a', 't');
446 df.ShortTimePattern = df_nav.Value.Replace ('a', 't');
451 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dateTimeFormats/dateTimeFormatLength/dateTimeFormat/pattern");
453 df.FullDateTimePattern = String.Format (ni2.Current.ToString (),
454 df.LongTimePattern, df.LongDatePattern);
456 XPathNodeIterator am = ni.Current.SelectChildren ("am", "");
458 df.AMDesignator = am.Current.Value;
459 XPathNodeIterator pm = ni.Current.SelectChildren ("pm", "");
461 df.PMDesignator = pm.Current.Value;
463 string am = (string) ni.Current.Evaluate ("string(am)");
464 string pm = (string) ni.Current.Evaluate ("string(pm)");
466 if (am != String.Empty)
467 df.AMDesignator = am;
468 if (pm != String.Empty)
469 df.PMDesignator = pm;
473 string date_sep = (string) nav.Evaluate ("string(ldml/dates/symbols/dateSeparator)");
474 string time_sep = (string) nav.Evaluate ("string(ldml/dates/symbols/timeSeparator)");
476 if (date_sep != String.Empty)
477 ci.DateTimeFormatEntry.DateSeparator = date_sep;
478 if (time_sep != String.Empty)
479 ci.DateTimeFormatEntry.TimeSeparator = time_sep;
482 private void LookupNumberInfo (XPathNavigator nav, CultureInfoEntry ci)
484 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("ldml/numbers");
486 while (ni.MoveNext ()) {
487 LookupNumberSymbols (ni.Current, ci);
488 LookupDecimalFormat (ni.Current, ci);
489 LookupPercentFormat (ni.Current, ci);
490 LookupCurrencyFormat (ni.Current, ci);
491 LookupCurrencySymbol (ni.Current, ci);
495 private void LookupDecimalFormat (XPathNavigator nav, CultureInfoEntry ci)
497 string format = (string) nav.Evaluate ("string(decimalFormats/" +
498 "decimalFormatLength/decimalFormat/pattern)");
500 if (format == String.Empty)
503 string [] part_one, part_two;
504 string [] pos_neg = format.Split (new char [1] {';'}, 2);
506 if (pos_neg.Length == 2) {
508 part_one = pos_neg [0].Split (new char [1] {'.'}, 2);
510 if (part_one.Length == 2) {
511 // assumed same for both positive and negative
512 // decimal digit side
513 ci.NumberFormatEntry.NumberDecimalDigits = 0;
514 for (int i = 0; i < part_one [1].Length; i++) {
515 if (part_one [1][i] == '#') {
516 ci.NumberFormatEntry.NumberDecimalDigits ++;
521 // decimal grouping side
522 part_two = part_one [0].Split (',');
523 if (part_two.Length > 1) {
524 int len = part_two.Length - 1;
525 ci.NumberFormatEntry.NumberGroupSizes = new int [len];
526 for (int i = 0; i < len; i++) {
527 string pat = part_two [i + 1];
528 ci.NumberFormatEntry.NumberGroupSizes [i] = pat.Length;
531 ci.NumberFormatEntry.NumberGroupSizes = new int [1] { 3 };
534 if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith (")")) {
535 ci.NumberFormatEntry.NumberNegativePattern = 0;
536 } else if (pos_neg [1].StartsWith ("- ")) {
537 ci.NumberFormatEntry.NumberNegativePattern = 2;
538 } else if (pos_neg [1].StartsWith ("-")) {
539 ci.NumberFormatEntry.NumberNegativePattern = 1;
540 } else if (pos_neg [1].EndsWith (" -")) {
541 ci.NumberFormatEntry.NumberNegativePattern = 4;
542 } else if (pos_neg [1].EndsWith ("-")) {
543 ci.NumberFormatEntry.NumberNegativePattern = 3;
545 ci.NumberFormatEntry.NumberNegativePattern = 1;
551 private void LookupPercentFormat (XPathNavigator nav, CultureInfoEntry ci)
553 string format = (string) nav.Evaluate ("string(percentFormats/" +
554 "percentFormatLength/percentFormat/pattern)");
556 if (format == String.Empty)
559 string [] part_one, part_two;
561 // we don't have percentNegativePattern in CLDR so
562 // the percentNegativePattern are just guesses
563 if (format.StartsWith ("%")) {
564 ci.NumberFormatEntry.PercentPositivePattern = 2;
565 ci.NumberFormatEntry.PercentNegativePattern = 2;
566 } else if (format.EndsWith (" %")) {
567 ci.NumberFormatEntry.PercentPositivePattern = 0;
568 ci.NumberFormatEntry.PercentNegativePattern = 0;
569 } else if (format.EndsWith ("%")) {
570 ci.NumberFormatEntry.PercentPositivePattern = 1;
571 ci.NumberFormatEntry.PercentNegativePattern = 1;
573 ci.NumberFormatEntry.PercentPositivePattern = 0;
574 ci.NumberFormatEntry.PercentNegativePattern = 0;
577 part_one = format.Split (new char [1] {'.'}, 2);
579 if (part_one.Length == 2) {
580 // assumed same for both positive and negative
581 // decimal digit side
582 ci.NumberFormatEntry.PercentDecimalDigits = 0;
583 for (int i = 0; i < part_one [1].Length; i++) {
584 if (part_one [1][i] == '#')
585 ci.NumberFormatEntry.PercentDecimalDigits++;
590 // percent grouping side
591 part_two = part_one [0].Split (',');
592 if (part_two.Length > 1) {
593 int len = part_two.Length - 1;
594 ci.NumberFormatEntry.PercentGroupSizes = new int [len];
595 for (int i = 0; i < len; i++) {
596 string pat = part_two [i + 1];
597 ci.NumberFormatEntry.PercentGroupSizes [i] = pat.Length;
600 ci.NumberFormatEntry.PercentGroupSizes = new int [1] { 3 };
605 private void LookupCurrencyFormat (XPathNavigator nav, CultureInfoEntry ci)
607 string format = (string) nav.Evaluate ("string(currencyFormats/" +
608 "currencyFormatLength/currencyFormat/pattern)");
610 if (format == String.Empty)
613 string [] part_one, part_two;
614 string [] pos_neg = format.Split (new char [1] {';'}, 2);
616 pos_neg = format.Split (new char [1] {';'}, 2);
617 if (pos_neg.Length == 2) {
618 part_one = pos_neg [0].Split (new char [1] {'.'}, 2);
620 if (part_one.Length == 2) {
621 // assumed same for both positive and negative
622 // decimal digit side
623 ci.NumberFormatEntry.CurrencyDecimalDigits = 0;
624 for (int i = 0; i < part_one [1].Length; i++) {
625 if (part_one [1][i] == '0')
626 ci.NumberFormatEntry.CurrencyDecimalDigits++;
631 // decimal grouping side
632 part_two = part_one [0].Split (',');
633 if (part_two.Length > 1) {
634 int len = part_two.Length - 1;
635 ci.NumberFormatEntry.CurrencyGroupSizes = new int [len];
636 for (int i = 0; i < len; i++) {
637 string pat = part_two [i + 1];
638 ci.NumberFormatEntry.CurrencyGroupSizes [i] = pat.Length;
641 ci.NumberFormatEntry.CurrencyGroupSizes = new int [1] { 3 };
644 if (pos_neg [1].StartsWith ("(\u00a4 ") && pos_neg [1].EndsWith (")")) {
645 ci.NumberFormatEntry.CurrencyNegativePattern = 14;
646 } else if (pos_neg [1].StartsWith ("(\u00a4") && pos_neg [1].EndsWith (")")) {
647 ci.NumberFormatEntry.CurrencyNegativePattern = 0;
648 } else if (pos_neg [1].StartsWith ("\u00a4 ") && pos_neg [1].EndsWith ("-")) {
649 ci.NumberFormatEntry.CurrencyNegativePattern = 11;
650 } else if (pos_neg [1].StartsWith ("\u00a4") && pos_neg [1].EndsWith ("-")) {
651 ci.NumberFormatEntry.CurrencyNegativePattern = 3;
652 } else if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith (" \u00a4")) {
653 ci.NumberFormatEntry.CurrencyNegativePattern = 15;
654 } else if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith ("\u00a4")) {
655 ci.NumberFormatEntry.CurrencyNegativePattern = 4;
656 } else if (pos_neg [1].StartsWith ("-") && pos_neg [1].EndsWith (" \u00a4")) {
657 ci.NumberFormatEntry.CurrencyNegativePattern = 8;
658 } else if (pos_neg [1].StartsWith ("-") && pos_neg [1].EndsWith ("\u00a4")) {
659 ci.NumberFormatEntry.CurrencyNegativePattern = 5;
660 } else if (pos_neg [1].StartsWith ("-\u00a4 ")) {
661 ci.NumberFormatEntry.CurrencyNegativePattern = 9;
662 } else if (pos_neg [1].StartsWith ("-\u00a4")) {
663 ci.NumberFormatEntry.CurrencyNegativePattern = 1;
664 } else if (pos_neg [1].StartsWith ("\u00a4 -")) {
665 ci.NumberFormatEntry.CurrencyNegativePattern = 12;
666 } else if (pos_neg [1].StartsWith ("\u00a4-")) {
667 ci.NumberFormatEntry.CurrencyNegativePattern = 2;
668 } else if (pos_neg [1].EndsWith (" \u00a4-")) {
669 ci.NumberFormatEntry.CurrencyNegativePattern = 10;
670 } else if (pos_neg [1].EndsWith ("\u00a4-")) {
671 ci.NumberFormatEntry.CurrencyNegativePattern = 7;
672 } else if (pos_neg [1].EndsWith ("- \u00a4")) {
673 ci.NumberFormatEntry.CurrencyNegativePattern = 13;
674 } else if (pos_neg [1].EndsWith ("-\u00a4")) {
675 ci.NumberFormatEntry.CurrencyNegativePattern = 6;
677 ci.NumberFormatEntry.CurrencyNegativePattern = 0;
680 if (pos_neg [0].StartsWith ("\u00a4 ")) {
681 ci.NumberFormatEntry.CurrencyPositivePattern = 2;
682 } else if (pos_neg [0].StartsWith ("\u00a4")) {
683 ci.NumberFormatEntry.CurrencyPositivePattern = 0;
684 } else if (pos_neg [0].EndsWith (" \u00a4")) {
685 ci.NumberFormatEntry.CurrencyPositivePattern = 3;
686 } else if (pos_neg [0].EndsWith ("\u00a4")) {
687 ci.NumberFormatEntry.CurrencyPositivePattern = 1;
689 ci.NumberFormatEntry.CurrencyPositivePattern = 0;
695 private void LookupNumberSymbols (XPathNavigator nav, CultureInfoEntry ci)
697 string dec = (string) nav.Evaluate ("string(symbols/decimal)");
698 string group = (string) nav.Evaluate ("string(symbols/group)");
699 string percent = (string) nav.Evaluate ("string(symbols/percentSign)");
700 string positive = (string) nav.Evaluate ("string(symbols/plusSign)");
701 string negative = (string) nav.Evaluate ("string(symbols/minusSign)");
702 string per_mille = (string) nav.Evaluate ("string(symbols/perMille)");
703 string infinity = (string) nav.Evaluate ("string(symbols/infinity)");
704 string nan = (string) nav.Evaluate ("string(symbols/nan)");
706 if (dec != String.Empty) {
707 ci.NumberFormatEntry.NumberDecimalSeparator = dec;
708 ci.NumberFormatEntry.PercentDecimalSeparator = dec;
709 ci.NumberFormatEntry.CurrencyDecimalSeparator = dec;
712 if (group != String.Empty) {
713 ci.NumberFormatEntry.NumberGroupSeparator = group;
714 ci.NumberFormatEntry.PercentGroupSeparator = group;
715 ci.NumberFormatEntry.CurrencyGroupSeparator = group;
718 if (percent != String.Empty)
719 ci.NumberFormatEntry.PercentSymbol = percent;
720 if (positive != String.Empty)
721 ci.NumberFormatEntry.PositiveSign = positive;
722 if (negative != String.Empty)
723 ci.NumberFormatEntry.NegativeSign = negative;
724 if (per_mille != String.Empty)
725 ci.NumberFormatEntry.PerMilleSymbol = per_mille;
726 if (infinity != String.Empty)
727 ci.NumberFormatEntry.PositiveInfinitySymbol = infinity;
728 if (nan != String.Empty)
729 ci.NumberFormatEntry.NaNSymbol = nan;
732 private void LookupCurrencySymbol (XPathNavigator nav, CultureInfoEntry ci)
734 string type = currency_types [ci.Territory] as string;
737 Console.WriteLine ("no currency type for: " + ci.Territory);
741 string cur = (string) nav.Evaluate ("string(currencies/currency [@type='" +
742 type + "']/symbol)");
744 if (cur != String.Empty)
745 ci.NumberFormatEntry.CurrencySymbol = cur;
748 private bool LookupLcids (CultureInfoEntry ci)
750 XPathDocument doc = GetXPathDocument ("lcids.xml");
751 XPathNavigator nav = doc.CreateNavigator ();
752 string name = ci.Language;
754 if (ci.Territory != null)
755 name += "-" + ci.Territory;
757 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("lcids/lcid[@name='"
759 if (!ni.MoveNext ()) {
761 if (ci.Territory != null) {
762 file = Path.Combine ("locales", ci.Language + "_" + ci.Territory + ".xml");
764 Console.WriteLine ("deleting file: " + file);
766 Console.WriteLine ("no lcid found for: " + name);
770 string id = ni.Current.GetAttribute ("id", String.Empty);
771 string parent = ni.Current.GetAttribute ("parent", String.Empty);
772 string specific = ni.Current.GetAttribute ("specific", String.Empty);
773 string iso2 = ni.Current.GetAttribute ("iso2", String.Empty);
774 string iso3 = ni.Current.GetAttribute ("iso3", String.Empty);
775 string win = ni.Current.GetAttribute ("win", String.Empty);
776 string icu = ni.Current.GetAttribute ("icu_name", String.Empty);
778 // lcids are in 0x<hex> format
780 ci.ParentLcid = parent;
781 ci.SpecificLcid = specific;
790 private string LookupFullName (CultureInfoEntry ci, XPathNavigator nav)
792 string pre = "ldml/localeDisplayNames/";
795 ret = (string) nav.Evaluate ("string("+
796 pre + "languages/language[@type='" + ci.Language + "'])");
798 if (ci.Territory == null)
800 ret += " (" + (string) nav.Evaluate ("string("+
801 pre + "territories/territory[@type='" + ci.Territory + "'])") + ")";
806 private void LookupCurrencyTypes ()
808 XPathDocument doc = GetXPathDocument ("supplementalData.xml");
809 XPathNavigator nav = doc.CreateNavigator ();
811 currency_types = new Hashtable ();
813 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("supplementalData/currencyData/region");
814 while (ni.MoveNext ()) {
815 string territory = (string) ni.Current.GetAttribute ("iso3166", String.Empty);
816 string currency = (string) ni.Current.Evaluate ("string(currency/@iso4217)");
817 currency_types [territory] = currency;
821 static string control_chars = "ghmsftz";
823 // HACK: We are trying to build year_month and month_day patterns from the full pattern.
824 private void ParseFullDateFormat (DateTimeFormatEntry df, string full)
827 string month_day = String.Empty;
828 string year_month = String.Empty;
829 bool in_month_data = false;
830 bool in_year_data = false;
834 for (int i = 0; i < full.Length; i++) {
840 in_month_data = true;
841 month_end = month_day.Length;
842 year_end = year_month.Length;
843 } else if (Char.ToLower (c) == 'd') {
845 in_month_data = true;
846 in_year_data = false;
847 month_end = month_day.Length;
848 } else if (Char.ToLower (c) == 'y') {
851 in_month_data = false;
852 year_end = year_month.Length;
853 } else if (control_chars.IndexOf (Char.ToLower (c)) >= 0) {
854 in_year_data = false;
855 in_month_data = false;
856 } else if (in_year_data || in_month_data) {
864 if (month_day != String.Empty) {
865 month_day = month_day.Substring (0, month_end);
866 df.MonthDayPattern = month_day;
868 if (year_month != String.Empty) {
869 year_month = year_month.Substring (0, year_end);
870 df.YearMonthPattern = year_month;
874 private class LcidComparer : IComparer {
876 public int Compare (object a, object b)
878 CultureInfoEntry aa = (CultureInfoEntry) a;
879 CultureInfoEntry bb = (CultureInfoEntry) b;
881 return aa.Lcid.CompareTo (bb.Lcid);
885 private class NameComparer : IComparer {
887 public int Compare (object a, object b)
889 CultureInfoEntry aa = (CultureInfoEntry) a;
890 CultureInfoEntry bb = (CultureInfoEntry) b;
892 return aa.Name.ToLower ().CompareTo (bb.Name.ToLower ());