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 bool ParseLang (string lang)
181 XPathDocument doc = new XPathDocument (Path.Combine ("langs", lang + ".xml"));
182 XPathNavigator nav = doc.CreateNavigator ();
183 CultureInfoEntry ci = new CultureInfoEntry ();
184 string lang_type, terr_type;
186 // ci.Name = lang; // TODO: might need to be mapped.
188 lang_type = nav.Evaluate ("string (ldml/identity/language/@type)").ToString ();
189 terr_type = nav.Evaluate ("string (ldml/identity/territory/@type)").ToString ();
191 ci.Language = (lang_type == String.Empty ? null : lang_type);
192 ci.Territory = (terr_type == String.Empty ? null : terr_type);
194 if (!LookupLcids (ci))
197 doc = new XPathDocument (Path.Combine ("langs", Lang + ".xml"));
198 nav = doc.CreateNavigator ();
199 ci.DisplayName = LookupFullName (ci, nav);
202 ci.EnglishName = ci.DisplayName;
204 doc = new XPathDocument (Path.Combine ("langs", Lang + ".xml"));
205 nav = doc.CreateNavigator ();
206 ci.EnglishName = LookupFullName (ci, nav);
209 if (ci.Language == Lang) {
210 ci.NativeName = ci.DisplayName;
212 doc = new XPathDocument (Path.Combine ("langs", lang + ".xml"));
213 nav = doc.CreateNavigator ();
214 ci.NativeName = LookupFullName (ci, nav);
217 // Null these out because langs dont have them
218 ci.DateTimeFormatEntry = null;
219 ci.NumberFormatEntry = null;
227 private void ParseLocale (string locale)
231 ci = LookupCulture (locale);
236 if (langs [ci.Language] == null) {
237 if (!ParseLang (ci.Language)) // If we can't parse the lang we cant have the locale
244 private CultureInfoEntry LookupCulture (string locale)
246 XPathDocument doc = new XPathDocument (Path.Combine ("locales", locale + ".xml"));
247 XPathNavigator nav = doc.CreateNavigator ();
248 CultureInfoEntry ci = new CultureInfoEntry ();
251 // ci.Name = locale; // TODO: Some of these need to be mapped.
253 // First thing we do is get the lang-territory combo, lcid, and full names
254 ci.Language = nav.Evaluate ("string (ldml/identity/language/@type)").ToString ();
255 ci.Territory = nav.Evaluate ("string (ldml/identity/territory/@type)").ToString ();
257 if (!LookupLcids (ci))
262 * Locale generation is done in six steps, first we
263 * read the root file which is the base invariant data
264 * then the supplemental root data,
265 * then the language file, the supplemental languages
266 * file then the locale file, then the supplemental
267 * locale file. Values in each descending file can
268 * overwrite previous values.
270 doc = new XPathDocument (Path.Combine ("langs", "root.xml"));
271 nav = doc.CreateNavigator ();
274 doc = new XPathDocument (Path.Combine ("supp", "root.xml"));
275 nav = doc.CreateNavigator ();
278 doc = new XPathDocument (Path.Combine ("langs", ci.Language + ".xml"));
279 nav = doc.CreateNavigator ();
282 supp = Path.Combine ("supp", ci.Language + ".xml");
283 if (File.Exists (supp)) {
284 doc = new XPathDocument (supp);
285 nav = doc.CreateNavigator ();
289 doc = new XPathDocument (Path.Combine ("locales", locale + ".xml"));
290 nav = doc.CreateNavigator ();
293 supp = Path.Combine ("supp", locale + ".xml");
294 if (File.Exists (supp)) {
295 doc = new XPathDocument (supp);
296 nav = doc.CreateNavigator ();
303 private void Lookup (XPathNavigator nav, CultureInfoEntry ci)
305 LookupDateTimeInfo (nav, ci);
306 LookupNumberInfo (nav, ci);
309 private void LookupNames (CultureInfoEntry ci)
311 XPathDocument doc = new XPathDocument (Path.Combine ("langs", Lang + ".xml"));
312 XPathNavigator nav = doc.CreateNavigator ();
314 ci.DisplayName = LookupFullName (ci, nav);
317 ci.EnglishName = ci.DisplayName;
319 doc = new XPathDocument (Path.Combine ("langs", "en.xml"));
320 nav = doc.CreateNavigator ();
321 ci.EnglishName = LookupFullName (ci, nav);
324 if (ci.Language == Lang) {
325 ci.NativeName = ci.DisplayName;
327 doc = new XPathDocument (Path.Combine ("langs", ci.Language + ".xml"));
328 nav = doc.CreateNavigator ();
329 ci.NativeName = LookupFullName (ci, nav);
333 private void LookupDateTimeInfo (XPathNavigator nav, CultureInfoEntry ci)
336 * TODO: Does anyone have multiple calendars?
338 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("ldml/dates/calendars/calendar");
340 while (ni.MoveNext ()) {
341 DateTimeFormatEntry df = ci.DateTimeFormatEntry;
342 string cal_type = ni.Current.GetAttribute ("type", String.Empty);
344 if (cal_type != String.Empty)
345 df.CalendarType = cal_type;
347 XPathNodeIterator ni2 = (XPathNodeIterator) ni.Current.Evaluate ("optionalCalendars/calendar");
348 int opt_cal_count = 0;
349 while (ni2.MoveNext ()) {
351 string greg_type_str;
352 XPathNavigator df_nav = ni2.Current;
353 switch (df_nav.GetAttribute ("type", String.Empty)) {
364 Console.WriteLine ("unknown calendar type: " +
365 df_nav.GetAttribute ("type", String.Empty));
369 greg_type_str = df_nav.GetAttribute ("greg_type", String.Empty);
370 if (greg_type_str != null && greg_type_str != String.Empty) {
371 GregorianCalendarTypes greg_type = (GregorianCalendarTypes)
372 Enum.Parse (typeof (GregorianCalendarTypes), greg_type_str);
373 int greg_type_int = (int) greg_type;
374 type |= greg_type_int;
377 Console.WriteLine ("Setting cal type: {0:X} for {1}", type, ci.Name);
378 ci.CalendarData [opt_cal_count++] = type;
381 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("monthNames/month");
382 while (ni2.MoveNext ()) {
383 if (ni2.CurrentPosition == 1)
384 df.MonthNames.Clear ();
385 df.MonthNames.Add (ni2.Current.Value);
388 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dayNames/day");
389 while (ni2.MoveNext ()) {
390 if (ni2.CurrentPosition == 1)
391 df.DayNames.Clear ();
392 df.DayNames.Add (ni2.Current.Value);
395 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dayAbbr/day");
396 while (ni2.MoveNext ()) {
397 if (ni2.CurrentPosition == 1)
398 df.AbbreviatedDayNames.Clear ();
399 df.AbbreviatedDayNames.Add (ni2.Current.Value);
402 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("monthAbbr/month");
403 while (ni2.MoveNext ()) {
404 if (ni2.CurrentPosition == 1)
405 df.AbbreviatedMonthNames.Clear ();
406 df.AbbreviatedMonthNames.Add (ni2.Current.Value);
409 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dateFormats/dateFormatLength");
410 while (ni2.MoveNext ()) {
411 XPathNavigator df_nav = ni2.Current;
412 switch (df_nav.GetAttribute ("type", String.Empty)) {
414 ParseFullDateFormat (df, df_nav.Value);
417 df.LongDatePattern = df_nav.Value;
420 df.ShortDatePattern = df_nav.Value;
423 df.YearMonthPattern = df_nav.Value;
426 df.MonthDayPattern = df_nav.Value;
431 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("timeFormats/timeFormatLength");
432 while (ni2.MoveNext ()) {
433 XPathNavigator df_nav = ni2.Current;
434 switch (df_nav.GetAttribute ("type", String.Empty)) {
436 df.LongTimePattern = df_nav.Value.Replace ('a', 't');
439 df.ShortTimePattern = df_nav.Value.Replace ('a', 't');
444 ni2 = (XPathNodeIterator) ni.Current.Evaluate ("dateTimeFormats/dateTimeFormatLength/dateTimeFormat/pattern");
446 df.FullDateTimePattern = String.Format (ni2.Current.ToString (),
447 df.LongTimePattern, df.LongDatePattern);
449 XPathNodeIterator am = ni.Current.SelectChildren ("am", "");
451 df.AMDesignator = am.Current.Value;
452 XPathNodeIterator pm = ni.Current.SelectChildren ("pm", "");
454 df.PMDesignator = pm.Current.Value;
456 string am = (string) ni.Current.Evaluate ("string(am)");
457 string pm = (string) ni.Current.Evaluate ("string(pm)");
459 if (am != String.Empty)
460 df.AMDesignator = am;
461 if (pm != String.Empty)
462 df.PMDesignator = pm;
466 string date_sep = (string) nav.Evaluate ("string(ldml/dates/symbols/dateSeparator)");
467 string time_sep = (string) nav.Evaluate ("string(ldml/dates/symbols/timeSeparator)");
469 if (date_sep != String.Empty)
470 ci.DateTimeFormatEntry.DateSeparator = date_sep;
471 if (time_sep != String.Empty)
472 ci.DateTimeFormatEntry.TimeSeparator = time_sep;
475 private void LookupNumberInfo (XPathNavigator nav, CultureInfoEntry ci)
477 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("ldml/numbers");
479 while (ni.MoveNext ()) {
480 LookupNumberSymbols (ni.Current, ci);
481 LookupDecimalFormat (ni.Current, ci);
482 LookupPercentFormat (ni.Current, ci);
483 LookupCurrencyFormat (ni.Current, ci);
484 LookupCurrencySymbol (ni.Current, ci);
488 private void LookupDecimalFormat (XPathNavigator nav, CultureInfoEntry ci)
490 string format = (string) nav.Evaluate ("string(decimalFormats/" +
491 "decimalFormatLength/decimalFormat/pattern)");
493 if (format == String.Empty)
496 string [] part_one, part_two;
497 string [] pos_neg = format.Split (new char [1] {';'}, 2);
499 if (pos_neg.Length == 2) {
501 part_one = pos_neg [0].Split (new char [1] {'.'}, 2);
503 if (part_one.Length == 2) {
504 // assumed same for both positive and negative
505 // decimal digit side
506 ci.NumberFormatEntry.NumberDecimalDigits = 0;
507 for (int i = 0; i < part_one [1].Length; i++) {
508 if (part_one [1][i] == '#') {
509 ci.NumberFormatEntry.NumberDecimalDigits ++;
514 // decimal grouping side
515 part_two = part_one [0].Split (',');
516 if (part_two.Length > 1) {
517 int len = part_two.Length - 1;
518 ci.NumberFormatEntry.NumberGroupSizes = new int [len];
519 for (int i = 0; i < len; i++) {
520 string pat = part_two [i + 1];
521 ci.NumberFormatEntry.NumberGroupSizes [i] = pat.Length;
524 ci.NumberFormatEntry.NumberGroupSizes = new int [1] { 0 };
527 if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith (")")) {
528 ci.NumberFormatEntry.NumberNegativePattern = 0;
529 } else if (pos_neg [1].StartsWith ("- ")) {
530 ci.NumberFormatEntry.NumberNegativePattern = 2;
531 } else if (pos_neg [1].StartsWith ("-")) {
532 ci.NumberFormatEntry.NumberNegativePattern = 1;
533 } else if (pos_neg [1].EndsWith (" -")) {
534 ci.NumberFormatEntry.NumberNegativePattern = 4;
535 } else if (pos_neg [1].EndsWith ("-")) {
536 ci.NumberFormatEntry.NumberNegativePattern = 3;
538 ci.NumberFormatEntry.NumberNegativePattern = 1;
544 private void LookupPercentFormat (XPathNavigator nav, CultureInfoEntry ci)
546 string format = (string) nav.Evaluate ("string(percentFormats/" +
547 "percentFormatLength/percentFormat/pattern)");
549 if (format == String.Empty)
552 string [] part_one, part_two;
554 // we don't have percentNegativePattern in CLDR so
555 // the percentNegativePattern are just guesses
556 if (format.StartsWith ("%")) {
557 ci.NumberFormatEntry.PercentPositivePattern = 2;
558 ci.NumberFormatEntry.PercentNegativePattern = 2;
559 } else if (format.EndsWith (" %")) {
560 ci.NumberFormatEntry.PercentPositivePattern = 0;
561 ci.NumberFormatEntry.PercentNegativePattern = 0;
562 } else if (format.EndsWith ("%")) {
563 ci.NumberFormatEntry.PercentPositivePattern = 1;
564 ci.NumberFormatEntry.PercentNegativePattern = 1;
566 ci.NumberFormatEntry.PercentPositivePattern = 0;
567 ci.NumberFormatEntry.PercentNegativePattern = 0;
570 part_one = format.Split (new char [1] {'.'}, 2);
572 if (part_one.Length == 2) {
573 // assumed same for both positive and negative
574 // decimal digit side
575 ci.NumberFormatEntry.PercentDecimalDigits = 0;
576 for (int i = 0; i < part_one [1].Length; i++) {
577 if (part_one [1][i] == '#')
578 ci.NumberFormatEntry.PercentDecimalDigits++;
583 // percent grouping side
584 part_two = part_one [0].Split (',');
585 if (part_two.Length > 1) {
586 int len = part_two.Length - 1;
587 ci.NumberFormatEntry.PercentGroupSizes = new int [len];
588 for (int i = 0; i < len; i++) {
589 string pat = part_two [i + 1];
590 ci.NumberFormatEntry.PercentGroupSizes [i] = pat.Length;
593 ci.NumberFormatEntry.PercentGroupSizes = new int [1] { 0 };
598 private void LookupCurrencyFormat (XPathNavigator nav, CultureInfoEntry ci)
600 string format = (string) nav.Evaluate ("string(currencyFormats/" +
601 "currencyFormatLength/currencyFormat/pattern)");
603 if (format == String.Empty)
606 string [] part_one, part_two;
607 string [] pos_neg = format.Split (new char [1] {';'}, 2);
609 pos_neg = format.Split (new char [1] {';'}, 2);
610 if (pos_neg.Length == 2) {
611 part_one = pos_neg [0].Split (new char [1] {'.'}, 2);
613 if (part_one.Length == 2) {
614 // assumed same for both positive and negative
615 // decimal digit side
616 ci.NumberFormatEntry.CurrencyDecimalDigits = 0;
617 for (int i = 0; i < part_one [1].Length; i++) {
618 if (part_one [1][i] == '0')
619 ci.NumberFormatEntry.CurrencyDecimalDigits++;
624 // decimal grouping side
625 part_two = part_one [0].Split (',');
626 if (part_two.Length > 1) {
627 int len = part_two.Length - 1;
628 ci.NumberFormatEntry.CurrencyGroupSizes = new int [len];
629 for (int i = 0; i < len; i++) {
630 string pat = part_two [i + 1];
631 ci.NumberFormatEntry.CurrencyGroupSizes [i] = pat.Length;
634 ci.NumberFormatEntry.CurrencyGroupSizes = new int [1] { 0 };
637 if (pos_neg [1].StartsWith ("(\u00a4 ") && pos_neg [1].EndsWith (")")) {
638 ci.NumberFormatEntry.CurrencyNegativePattern = 14;
639 } else if (pos_neg [1].StartsWith ("(\u00a4") && pos_neg [1].EndsWith (")")) {
640 ci.NumberFormatEntry.CurrencyNegativePattern = 0;
641 } else if (pos_neg [1].StartsWith ("\u00a4 ") && pos_neg [1].EndsWith ("-")) {
642 ci.NumberFormatEntry.CurrencyNegativePattern = 11;
643 } else if (pos_neg [1].StartsWith ("\u00a4") && pos_neg [1].EndsWith ("-")) {
644 ci.NumberFormatEntry.CurrencyNegativePattern = 3;
645 } else if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith (" \u00a4")) {
646 ci.NumberFormatEntry.CurrencyNegativePattern = 15;
647 } else if (pos_neg [1].StartsWith ("(") && pos_neg [1].EndsWith ("\u00a4")) {
648 ci.NumberFormatEntry.CurrencyNegativePattern = 4;
649 } else if (pos_neg [1].StartsWith ("-") && pos_neg [1].EndsWith (" \u00a4")) {
650 ci.NumberFormatEntry.CurrencyNegativePattern = 8;
651 } else if (pos_neg [1].StartsWith ("-") && pos_neg [1].EndsWith ("\u00a4")) {
652 ci.NumberFormatEntry.CurrencyNegativePattern = 5;
653 } else if (pos_neg [1].StartsWith ("-\u00a4 ")) {
654 ci.NumberFormatEntry.CurrencyNegativePattern = 9;
655 } else if (pos_neg [1].StartsWith ("-\u00a4")) {
656 ci.NumberFormatEntry.CurrencyNegativePattern = 1;
657 } else if (pos_neg [1].StartsWith ("\u00a4 -")) {
658 ci.NumberFormatEntry.CurrencyNegativePattern = 12;
659 } else if (pos_neg [1].StartsWith ("\u00a4-")) {
660 ci.NumberFormatEntry.CurrencyNegativePattern = 2;
661 } else if (pos_neg [1].EndsWith (" \u00a4-")) {
662 ci.NumberFormatEntry.CurrencyNegativePattern = 10;
663 } else if (pos_neg [1].EndsWith ("\u00a4-")) {
664 ci.NumberFormatEntry.CurrencyNegativePattern = 7;
665 } else if (pos_neg [1].EndsWith ("- \u00a4")) {
666 ci.NumberFormatEntry.CurrencyNegativePattern = 13;
667 } else if (pos_neg [1].EndsWith ("-\u00a4")) {
668 ci.NumberFormatEntry.CurrencyNegativePattern = 6;
670 ci.NumberFormatEntry.CurrencyNegativePattern = 0;
673 if (pos_neg [0].StartsWith ("\u00a4 ")) {
674 ci.NumberFormatEntry.CurrencyPositivePattern = 2;
675 } else if (pos_neg [0].StartsWith ("\u00a4")) {
676 ci.NumberFormatEntry.CurrencyPositivePattern = 0;
677 } else if (pos_neg [0].EndsWith (" \u00a4")) {
678 ci.NumberFormatEntry.CurrencyPositivePattern = 3;
679 } else if (pos_neg [0].EndsWith ("\u00a4")) {
680 ci.NumberFormatEntry.CurrencyPositivePattern = 1;
682 ci.NumberFormatEntry.CurrencyPositivePattern = 0;
688 private void LookupNumberSymbols (XPathNavigator nav, CultureInfoEntry ci)
690 string dec = (string) nav.Evaluate ("string(symbols/decimal)");
691 string group = (string) nav.Evaluate ("string(symbols/group)");
692 string percent = (string) nav.Evaluate ("string(symbols/percentSign)");
693 string positive = (string) nav.Evaluate ("string(symbols/plusSign)");
694 string negative = (string) nav.Evaluate ("string(symbols/minusSign)");
695 string per_mille = (string) nav.Evaluate ("string(symbols/perMille)");
696 string infinity = (string) nav.Evaluate ("string(symbols/infinity)");
697 string nan = (string) nav.Evaluate ("string(symbols/nan)");
699 if (dec != String.Empty) {
700 ci.NumberFormatEntry.NumberDecimalSeparator = dec;
701 ci.NumberFormatEntry.PercentDecimalSeparator = dec;
702 ci.NumberFormatEntry.CurrencyDecimalSeparator = dec;
705 if (group != String.Empty) {
706 ci.NumberFormatEntry.NumberGroupSeparator = group;
707 ci.NumberFormatEntry.PercentGroupSeparator = group;
708 ci.NumberFormatEntry.CurrencyGroupSeparator = group;
711 if (percent != String.Empty)
712 ci.NumberFormatEntry.PercentSymbol = percent;
713 if (positive != String.Empty)
714 ci.NumberFormatEntry.PositiveSign = positive;
715 if (negative != String.Empty)
716 ci.NumberFormatEntry.NegativeSign = negative;
717 if (per_mille != String.Empty)
718 ci.NumberFormatEntry.PerMilleSymbol = per_mille;
719 if (infinity != String.Empty)
720 ci.NumberFormatEntry.PositiveInfinitySymbol = infinity;
721 if (nan != String.Empty)
722 ci.NumberFormatEntry.NaNSymbol = nan;
725 private void LookupCurrencySymbol (XPathNavigator nav, CultureInfoEntry ci)
727 string type = currency_types [ci.Territory] as string;
730 Console.WriteLine ("no currency type for: " + ci.Territory);
734 string cur = (string) nav.Evaluate ("string(currencies/currency [@type='" +
735 type + "']/symbol)");
737 if (cur != String.Empty)
738 ci.NumberFormatEntry.CurrencySymbol = cur;
741 private bool LookupLcids (CultureInfoEntry ci)
743 XPathDocument doc = new XPathDocument ("lcids.xml");
744 XPathNavigator nav = doc.CreateNavigator ();
745 string name = ci.Language;
747 if (ci.Territory != null)
748 name += "-" + ci.Territory;
750 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("lcids/lcid[@name='"
752 if (!ni.MoveNext ()) {
754 if (ci.Territory != null) {
755 file = Path.Combine ("locales", ci.Language + "_" + ci.Territory + ".xml");
757 Console.WriteLine ("deleting file: " + file);
759 Console.WriteLine ("no lcid found for: " + name);
763 string id = ni.Current.GetAttribute ("id", String.Empty);
764 string parent = ni.Current.GetAttribute ("parent", String.Empty);
765 string specific = ni.Current.GetAttribute ("specific", String.Empty);
766 string iso2 = ni.Current.GetAttribute ("iso2", String.Empty);
767 string iso3 = ni.Current.GetAttribute ("iso3", String.Empty);
768 string win = ni.Current.GetAttribute ("win", String.Empty);
769 string icu = ni.Current.GetAttribute ("icu_name", String.Empty);
771 // lcids are in 0x<hex> format
773 ci.ParentLcid = parent;
774 ci.SpecificLcid = specific;
783 private string LookupFullName (CultureInfoEntry ci, XPathNavigator nav)
785 string pre = "ldml/localeDisplayNames/";
788 ret = (string) nav.Evaluate ("string("+
789 pre + "languages/language[@type='" + ci.Language + "'])");
791 if (ci.Territory == null)
793 ret += " (" + (string) nav.Evaluate ("string("+
794 pre + "territories/territory[@type='" + ci.Territory + "'])") + ")";
799 private void LookupCurrencyTypes ()
801 XPathDocument doc = new XPathDocument ("supplementalData.xml");
802 XPathNavigator nav = doc.CreateNavigator ();
804 currency_types = new Hashtable ();
806 XPathNodeIterator ni =(XPathNodeIterator) nav.Evaluate ("supplementalData/currencyData/region");
807 while (ni.MoveNext ()) {
808 string territory = (string) ni.Current.GetAttribute ("iso3166", String.Empty);
809 string currency = (string) ni.Current.Evaluate ("string(currency/@iso4217)");
810 currency_types [territory] = currency;
814 static string control_chars = "ghmsftz";
816 // HACK: We are trying to build year_month and month_day patterns from the full pattern.
817 private void ParseFullDateFormat (DateTimeFormatEntry df, string full)
820 string month_day = String.Empty;
821 string year_month = String.Empty;
822 bool in_month_data = false;
823 bool in_year_data = false;
827 for (int i = 0; i < full.Length; i++) {
833 in_month_data = true;
834 month_end = month_day.Length;
835 year_end = year_month.Length;
836 } else if (Char.ToLower (c) == 'd') {
838 in_month_data = true;
839 in_year_data = false;
840 month_end = month_day.Length;
841 } else if (Char.ToLower (c) == 'y') {
844 in_month_data = false;
845 year_end = year_month.Length;
846 } else if (control_chars.IndexOf (Char.ToLower (c)) >= 0) {
847 in_year_data = false;
848 in_month_data = false;
849 } else if (in_year_data || in_month_data) {
857 if (month_day != String.Empty) {
858 month_day = month_day.Substring (0, month_end);
859 df.MonthDayPattern = month_day;
861 if (year_month != String.Empty) {
862 year_month = year_month.Substring (0, year_end);
863 df.YearMonthPattern = year_month;
867 private class LcidComparer : IComparer {
869 public int Compare (object a, object b)
871 CultureInfoEntry aa = (CultureInfoEntry) a;
872 CultureInfoEntry bb = (CultureInfoEntry) b;
874 return aa.Lcid.CompareTo (bb.Lcid);
878 private class NameComparer : IComparer {
880 public int Compare (object a, object b)
882 CultureInfoEntry aa = (CultureInfoEntry) a;
883 CultureInfoEntry bb = (CultureInfoEntry) b;
885 return aa.Name.ToLower ().CompareTo (bb.Name.ToLower ());