Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

root/trunk/tango/text/locale/Core.d

Revision 3538, 73.1 kB (checked in by larsivi, 3 months ago)

There is no point in throwing if it is to be caught in the next step, so removing throw in this instance (win32), closes #1109, thanks cybershadow, reopen if needed

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 /*******************************************************************************
2
3         copyright:      Copyright (c) 2005 John Chapman. All rights reserved
4
5         license:        BSD style: $(LICENSE)
6
7         version:        Initial release: 2005
8
9         author:         John Chapman
10
11         Contains classes that provide information about locales, such as
12         the language and calendars, as well as cultural conventions used
13         for formatting dates, currency and numbers. Use these classes when
14         writing applications for an international audience.
15
16 ******************************************************************************/
17
18 /**
19  * $(MEMBERTABLE
20  * $(TR
21  * $(TH Interface)
22  * $(TH Description)
23  * )
24  * $(TR
25  * $(TD $(LINK2 #IFormatService, IFormatService))
26  * $(TD Retrieves an object to control formatting.)
27  * )
28  * )
29  *
30  * $(MEMBERTABLE
31  * $(TR
32  * $(TH Class)
33  * $(TH Description)
34  * )
35  * $(TR
36  * $(TD $(LINK2 #Calendar, Calendar))
37  * $(TD Represents time in week, month and year divisions.)
38  * )
39  * $(TR
40  * $(TD $(LINK2 #Culture, Culture))
41  * $(TD Provides information about a culture, such as its name, calendar and date and number format patterns.)
42  * )
43  * $(TR
44  * $(TD $(LINK2 #DateTimeFormat, DateTimeFormat))
45  * $(TD Determines how $(LINK2 #Time, Time) values are formatted, depending on the culture.)
46  * )
47  * $(TR
48  * $(TD $(LINK2 #DaylightSavingTime, DaylightSavingTime))
49  * $(TD Represents a period of daylight-saving time.)
50  * )
51  * $(TR
52  * $(TD $(LINK2 #Gregorian, Gregorian))
53  * $(TD Represents the Gregorian calendar.)
54  * )
55  * $(TR
56  * $(TD $(LINK2 #Hebrew, Hebrew))
57  * $(TD Represents the Hebrew calendar.)
58  * )
59  * $(TR
60  * $(TD $(LINK2 #Hijri, Hijri))
61  * $(TD Represents the Hijri calendar.)
62  * )
63  * $(TR
64  * $(TD $(LINK2 #Japanese, Japanese))
65  * $(TD Represents the Japanese calendar.)
66  * )
67  * $(TR
68  * $(TD $(LINK2 #Korean, Korean))
69  * $(TD Represents the Korean calendar.)
70  * )
71  * $(TR
72  * $(TD $(LINK2 #NumberFormat, NumberFormat))
73  * $(TD Determines how numbers are formatted, according to the current culture.)
74  * )
75  * $(TR
76  * $(TD $(LINK2 #Region, Region))
77  * $(TD Provides information about a region.)
78  * )
79  * $(TR
80  * $(TD $(LINK2 #Taiwan, Taiwan))
81  * $(TD Represents the Taiwan calendar.)
82  * )
83  * $(TR
84  * $(TD $(LINK2 #ThaiBuddhist, ThaiBuddhist))
85  * $(TD Represents the Thai Buddhist calendar.)
86  * )
87  * )
88  *
89  * $(MEMBERTABLE
90  * $(TR
91  * $(TH Struct)
92  * $(TH Description)
93  * )
94  * $(TR
95  * $(TD $(LINK2 #Time, Time))
96  * $(TD Represents time expressed as a date and time of day.)
97  * )
98  * $(TR
99  * $(TD $(LINK2 #TimeSpan, TimeSpan))
100  * $(TD Represents a time interval.)
101  * )
102  * )
103  */
104
105 module tango.text.locale.Core;
106
107 private import  tango.core.Exception;
108
109 private import  tango.text.locale.Data;
110
111 private import  tango.time.Time;
112
113 private import  tango.time.chrono.Hijri,
114                 tango.time.chrono.Korean,
115                 tango.time.chrono.Taiwan,
116                 tango.time.chrono.Hebrew,
117                 tango.time.chrono.Calendar,
118                 tango.time.chrono.Japanese,
119                 tango.time.chrono.Gregorian,
120                 tango.time.chrono.ThaiBuddhist;
121        
122 version (Windows)
123          private import tango.text.locale.Win32;
124
125 version (Posix)
126          private import tango.text.locale.Posix;
127
128
129 // Initializes an array.
130 private template arrayOf(T) {
131   private T[] arrayOf(T[] params ...) {
132     return params.dup;
133   }
134 }
135
136
137 /**
138  * Defines the types of cultures that can be retrieved from Culture.getCultures.
139  */
140 public enum CultureTypes {
141   Neutral = 1,             /// Refers to cultures that are associated with a language but not specific to a country or region.
142   Specific = 2,            /// Refers to cultures that are specific to a country or region.
143   All = Neutral | Specific /// Refers to all cultures.
144 }
145
146
147 /**
148  * $(ANCHOR _IFormatService)
149  * Retrieves an object to control formatting.
150  *
151  * A class implements $(LINK2 #IFormatService_getFormat, getFormat) to retrieve an object that provides format information for the implementing type.
152  * Remarks: IFormatService is implemented by $(LINK2 #Culture, Culture), $(LINK2 #NumberFormat, NumberFormat) and $(LINK2 #DateTimeFormat, DateTimeFormat) to provide locale-specific formatting of
153  * numbers and date and time values.
154  */
155 public interface IFormatService {
156
157   /**
158    * $(ANCHOR IFormatService_getFormat)
159    * Retrieves an object that supports formatting for the specified _type.
160    * Returns: The current instance if type is the same _type as the current instance; otherwise, null.
161    * Params: type = An object that specifies the _type of formatting to retrieve.
162    */
163   Object getFormat(TypeInfo type);
164
165 }
166
167 /**
168  * $(ANCHOR _Culture)
169  * Provides information about a culture, such as its name, calendar and date and number format patterns.
170  * Remarks: tango.text.locale adopts the RFC 1766 standard for culture names in the format <language>"-"<region>.
171  * <language> is a lower-case two-letter code defined by ISO 639-1. <region> is an upper-case
172  * two-letter code defined by ISO 3166. For example, "en-GB" is UK English.
173  * $(BR)$(BR)There are three types of culture: invariant, neutral and specific. The invariant culture is not tied to
174  * any specific region, although it is associated with the English language. A neutral culture is associated with
175  * a language, but not with a region. A specific culture is associated with a language and a region. "es" is a neutral
176  * culture. "es-MX" is a specific culture.
177  * $(BR)$(BR)Instances of $(LINK2 #DateTimeFormat, DateTimeFormat) and $(LINK2 #NumberFormat, NumberFormat) cannot be created for neutral cultures.
178  * Examples:
179  * ---
180  * import tango.io.Stdout, tango.text.locale.Core;
181  *
182  * void main() {
183  *   Culture culture = new Culture("it-IT");
184  *
185  *   Stdout.formatln("englishName: {}", culture.englishName);
186  *   Stdout.formatln("nativeName: {}", culture.nativeName);
187  *   Stdout.formatln("name: {}", culture.name);
188  *   Stdout.formatln("parent: {}", culture.parent.name);
189  *   Stdout.formatln("isNeutral: {}", culture.isNeutral);
190  * }
191  *
192  * // Produces the following output:
193  * // englishName: Italian (Italy)
194  * // nativeName: italiano (Italia)
195  * // name: it-IT
196  * // parent: it
197  * // isNeutral: false
198  * ---
199  */
200 public class Culture : IFormatService {
201
202   private const int LCID_INVARIANT = 0x007F;
203
204   private static Culture[char[]] namedCultures;
205   private static Culture[int] idCultures;
206   private static Culture[char[]] ietfCultures;
207
208   private static Culture currentCulture_;
209   private static Culture userDefaultCulture_; // The user's default culture (GetUserDefaultLCID).
210   private static Culture invariantCulture_; // The invariant culture is associated with the English language.
211   private Calendar calendar_;
212   private Culture parent_;
213   private CultureData* cultureData_;
214   private bool isReadOnly_;
215   private NumberFormat numberFormat_;
216   private DateTimeFormat dateTimeFormat_;
217
218   static this() {
219     invariantCulture_ = new Culture(LCID_INVARIANT);
220     invariantCulture_.isReadOnly_ = true;
221
222     userDefaultCulture_ = new Culture(nativeMethods.getUserCulture());
223     if (userDefaultCulture_ is null)
224       // Fallback
225       userDefaultCulture_ = invariantCulture;
226     else
227       userDefaultCulture_.isReadOnly_ = true;
228   }
229
230   static ~this() {
231     namedCultures = null;
232     idCultures = null;
233     ietfCultures = null;
234   }
235
236   /**
237    * Initializes a new Culture instance from the supplied name.
238    * Params: cultureName = The name of the Culture.
239    */
240   public this(char[] cultureName) {
241     cultureData_ = CultureData.getDataFromCultureName(cultureName);
242   }
243
244   /**
245    * Initializes a new Culture instance from the supplied culture identifier.
246    * Params: cultureID = The identifer (LCID) of the Culture.
247    * Remarks: Culture identifiers correspond to a Windows LCID.
248    */
249   public this(int cultureID) {
250     cultureData_ = CultureData.getDataFromCultureID(cultureID);
251   }
252
253   /**
254    * Retrieves an object defining how to format the specified type.
255    * Params: type = The TypeInfo of the resulting formatting object.
256    * Returns: If type is typeid($(LINK2 #NumberFormat, NumberFormat)), the value of the $(LINK2 #Culture_numberFormat, numberFormat) property. If type is typeid($(LINK2 #DateTimeFormat, DateTimeFormat)), the
257    * value of the $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) property. Otherwise, null.
258    * Remarks: Implements $(LINK2 #IFormatService_getFormat, IFormatService.getFormat).
259    */
260   public Object getFormat(TypeInfo type) {
261     if (type is typeid(NumberFormat))
262       return numberFormat;
263     else if (type is typeid(DateTimeFormat))
264       return dateTimeFormat;
265     return null;
266   }
267
268 version (Clone)
269 {
270   /**
271    * Copies the current Culture instance.
272    * Returns: A copy of the current Culture instance.
273    * Remarks: The values of the $(LINK2 #Culture_numberFormat, numberFormat), $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) and $(LINK2 #Culture_calendar, calendar) properties are copied also.
274    */
275   public Object clone() {
276     Culture culture = cast(Culture)cloneObject(this);
277     if (!culture.isNeutral) {
278       if (dateTimeFormat_ !is null)
279         culture.dateTimeFormat_ = cast(DateTimeFormat)dateTimeFormat_.clone();
280       if (numberFormat_ !is null)
281         culture.numberFormat_ = cast(NumberFormat)numberFormat_.clone();
282     }
283     if (calendar_ !is null)
284       culture.calendar_ = cast(Calendar)calendar_.clone();
285     return culture;
286   }
287 }
288
289   /**
290    * Returns a read-only instance of a culture using the specified culture identifier.
291    * Params: cultureID = The identifier of the culture.
292    * Returns: A read-only culture instance.
293    * Remarks: Instances returned by this method are cached.
294    */
295   public static Culture getCulture(int cultureID) {
296     Culture culture = getCultureInternal(cultureID, null);
297
298 version (Posix) {
299     if (culture is null)
300         error ("Culture not found - if this was not tried set by the application, Tango\n"
301             ~ "will expect that a locale is set via environment variables LANG or LC_ALL.");
302 }
303
304     return culture;
305   }
306
307   /**
308    * Returns a read-only instance of a culture using the specified culture name.
309    * Params: cultureName = The name of the culture.
310    * Returns: A read-only culture instance.
311    * Remarks: Instances returned by this method are cached.
312    */
313   public static Culture getCulture(char[] cultureName) {
314     if (cultureName is null)
315        error("Value cannot be null.");
316     Culture culture = getCultureInternal(0, cultureName);
317     if (culture is null)
318       error("Culture name " ~ cultureName ~ " is not supported.");
319     return culture;
320   }
321
322   /**
323     * Returns a read-only instance using the specified name, as defined by the RFC 3066 standard and maintained by the IETF.
324     * Params: name = The name of the language.
325     * Returns: A read-only culture instance.
326     */
327   public static Culture getCultureFromIetfLanguageTag(char[] name) {
328     if (name is null)
329       error("Value cannot be null.");
330     Culture culture = getCultureInternal(-1, name);
331     if (culture is null)
332       error("Culture IETF name " ~ name ~ " is not a known IETF name.");
333     return culture;
334   }
335
336   private static Culture getCultureInternal(int cultureID, char[] cname) {
337     // If cultureID is - 1, name is an IETF name; if it's 0, name is a culture name; otherwise, it's a valid LCID.
338     char[] name = cname;
339     foreach (i, c; cname)
340        if (c is '_') {
341          name = cname.dup;
342          name[i] = '-';
343          break;
344        }
345
346     // Look up tables first.
347     if (cultureID == 0) {
348       if (Culture* culture = name in namedCultures)
349         return *culture;
350     }
351     else if (cultureID > 0) {
352       if (Culture* culture = cultureID in idCultures)
353         return *culture;
354     }
355     else if (cultureID == -1) {
356       if (Culture* culture = name in ietfCultures)
357         return *culture;
358     }
359
360     // Nothing found, create a new instance.
361     Culture culture;
362
363     try {
364       if (cultureID == -1) {
365         name = CultureData.getCultureNameFromIetfName(name);
366         if (name is null)
367           return null;
368       }
369       else if (cultureID == 0)
370         culture = new Culture(name);
371       else if (userDefaultCulture_ !is null && userDefaultCulture_.id == cultureID) {
372         culture = userDefaultCulture_;
373       }
374       else
375         culture = new Culture(cultureID);
376     }
377     catch (LocaleException) {
378       return null;
379     }
380
381     culture.isReadOnly_ = true;
382
383     // Now cache the new instance in all tables.
384     ietfCultures[culture.ietfLanguageTag] = culture;
385     namedCultures[culture.name] = culture;
386     idCultures[culture.id] = culture;
387
388     return culture;
389   }
390
391   /**
392    * Returns a list of cultures filtered by the specified $(LINK2 constants.html#CultureTypes, CultureTypes).
393    * Params: types = A combination of CultureTypes.
394    * Returns: An array of Culture instances containing cultures specified by types.
395    */
396   public static Culture[] getCultures(CultureTypes types) {
397     bool includeSpecific = (types & CultureTypes.Specific) != 0;
398     bool includeNeutral = (types & CultureTypes.Neutral) != 0;
399
400     int[] cultures;
401     for (int i = 0; i < CultureData.cultureDataTable.length; i++) {
402       if ((CultureData.cultureDataTable[i].isNeutral && includeNeutral) || (!CultureData.cultureDataTable[i].isNeutral && includeSpecific))
403         cultures ~= CultureData.cultureDataTable[i].lcid;
404     }
405
406     Culture[] result = new Culture[cultures.length];
407     foreach (int i, int cultureID; cultures)
408       result[i] = new Culture(cultureID);
409     return result;
410   }
411
412   /**
413    * Returns the name of the Culture.
414    * Returns: A string containing the name of the Culture in the format &lt;language&gt;"-"&lt;region&gt;.
415    */
416   public override char[] toString() {
417     return cultureData_.name;
418   }
419
420   public override int opEquals(Object obj) {
421     if (obj is this)
422       return true;
423     Culture other = cast(Culture)obj;
424     if (other is null)
425       return false;
426     return other.name == name; // This needs to be changed so it's culturally aware.
427   }
428
429   /**
430    * $(ANCHOR Culture_current)
431    * $(I Property.) Retrieves the culture of the current user.
432    * Returns: The Culture instance representing the user's current culture.
433    */
434   public static Culture current() {
435     if (currentCulture_ !is null)
436       return currentCulture_;
437
438     if (userDefaultCulture_ !is null) {
439       // If the user has changed their locale settings since last we checked, invalidate our data.
440       if (userDefaultCulture_.id != nativeMethods.getUserCulture())
441         userDefaultCulture_ = null;
442     }
443     if (userDefaultCulture_ is null) {
444       userDefaultCulture_ = new Culture(nativeMethods.getUserCulture());
445       if (userDefaultCulture_ is null)
446         userDefaultCulture_ = invariantCulture;
447       else
448         userDefaultCulture_.isReadOnly_ = true;
449     }
450
451     return userDefaultCulture_;
452   }
453   /**
454    * $(I Property.) Assigns the culture of the _current user.
455    * Params: value = The Culture instance representing the user's _current culture.
456    * Examples:
457    * The following examples shows how to change the _current culture.
458    * ---
459    * import tango.io.Print, tango.text.locale.Common;
460    *
461    * void main() {
462    *   // Displays the name of the current culture.
463    *   Println("The current culture is %s.", Culture.current.englishName);
464    *
465    *   // Changes the current culture to el-GR.
466    *   Culture.current = new Culture("el-GR");
467    *   Println("The current culture is now %s.", Culture.current.englishName);
468    * }
469    *
470    * // Produces the following output:
471    * // The current culture is English (United Kingdom).
472    * // The current culture is now Greek (Greece).
473    * ---
474    */
475   public static void current(Culture value) {
476     checkNeutral(value);
477     nativeMethods.setUserCulture(value.id);
478     currentCulture_ = value;
479   }
480
481   /**
482    * $(I Property.) Retrieves the invariant Culture.
483    * Returns: The Culture instance that is invariant.
484    * Remarks: The invariant culture is culture-independent. It is not tied to any specific region, but is associated
485    * with the English language.
486    */
487   public static Culture invariantCulture() {
488     return invariantCulture_;
489   }
490
491   /**
492    * $(I Property.) Retrieves the identifier of the Culture.
493    * Returns: The culture identifier of the current instance.
494    * Remarks: The culture identifier corresponds to the Windows locale identifier (LCID). It can therefore be used when
495    * interfacing with the Windows NLS functions.
496    */
497   public int id() {
498     return cultureData_.lcid;
499   }
500
501   /**
502    * $(ANCHOR Culture_name)
503    * $(I Property.) Retrieves the name of the Culture in the format &lt;language&gt;"-"&lt;region&gt;.
504    * Returns: The name of the current instance. For example, the name of the UK English culture is "en-GB".
505    */
506   public char[] name() {
507     return cultureData_.name;
508   }
509
510   /**
511    * $(I Property.) Retrieves the name of the Culture in the format &lt;languagename&gt; (&lt;regionname&gt;) in English.
512    * Returns: The name of the current instance in English. For example, the englishName of the UK English culture
513    * is "English (United Kingdom)".
514    */
515   public char[] englishName() {
516     return cultureData_.englishName;
517   }
518
519   /**
520    * $(I Property.) Retrieves the name of the Culture in the format &lt;languagename&gt; (&lt;regionname&gt;) in its native language.
521    * Returns: The name of the current instance in its native language. For example, if Culture.name is "de-DE", nativeName is
522    * "Deutsch (Deutschland)".
523    */
524   public char[] nativeName() {
525     return cultureData_.nativeName;
526   }
527
528   /**
529    * $(I Property.) Retrieves the two-letter language code of the culture.
530    * Returns: The two-letter language code of the Culture instance. For example, the twoLetterLanguageName for English is "en".
531    */
532   public char[] twoLetterLanguageName() {
533     return cultureData_.isoLangName;
534   }
535
536   /**
537    * $(I Property.) Retrieves the three-letter language code of the culture.
538    * Returns: The three-letter language code of the Culture instance. For example, the threeLetterLanguageName for English is "eng".
539    */
540   public char[] threeLetterLanguageName() {
541     return cultureData_.isoLangName2;
542   }
543
544   /**
545    * $(I Property.) Retrieves the RFC 3066 identification for a language.
546    * Returns: A string representing the RFC 3066 language identification.
547    */
548   public final char[] ietfLanguageTag() {
549     return cultureData_.ietfTag;
550   }
551
552   /**
553    * $(I Property.) Retrieves the Culture representing the parent of the current instance.
554    * Returns: The Culture representing the parent of the current instance.
555    */
556   public Culture parent() {
557     if (parent_ is null) {
558       try {
559         int parentCulture = cultureData_.parent;
560         if (parentCulture == LCID_INVARIANT)
561           parent_ = invariantCulture;
562         else
563           parent_ = new Culture(parentCulture);
564       }
565       catch {
566         parent_ = invariantCulture;
567       }
568     }
569     return parent_;
570   }
571
572   /**
573    * $(I Property.) Retrieves a value indicating whether the current instance is a neutral culture.
574    * Returns: true is the current Culture represents a neutral culture; otherwise, false.
575    * Examples:
576    * The following example displays which cultures using Chinese are neutral.
577    * ---
578    * import tango.io.Print, tango.text.locale.Common;
579    *
580    * void main() {
581    *   foreach (c; Culture.getCultures(CultureTypes.All)) {
582    *     if (c.twoLetterLanguageName == "zh") {
583    *       Print(c.englishName);
584    *       if (c.isNeutral)
585    *         Println("neutral");
586    *       else
587    *         Println("specific");
588    *     }
589    *   }
590    * }
591    *
592    * // Produces the following output:
593    * // Chinese (Simplified) - neutral
594    * // Chinese (Taiwan) - specific
595    * // Chinese (People's Republic of China) - specific
596    * // Chinese (Hong Kong S.A.R.) - specific
597    * // Chinese (Singapore) - specific
598    * // Chinese (Macao S.A.R.) - specific
599    * // Chinese (Traditional) - neutral
600    * ---
601    */
602   public bool isNeutral() {
603     return cultureData_.isNeutral;
604   }
605
606   /**
607    * $(I Property.) Retrieves a value indicating whether the instance is read-only.
608    * Returns: true if the instance is read-only; otherwise, false.
609    * Remarks: If the culture is read-only, the $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) and $(LINK2 #Culture_numberFormat, numberFormat) properties return
610    * read-only instances.
611    */
612   public final bool isReadOnly() {
613     return isReadOnly_;
614   }
615
616   /**
617    * $(ANCHOR Culture_calendar)
618    * $(I Property.) Retrieves the calendar used by the culture.
619    * Returns: A Calendar instance respresenting the calendar used by the culture.
620    */
621   public Calendar calendar() {
622     if (calendar_ is null) {
623       calendar_ = getCalendarInstance(cultureData_.calendarType, isReadOnly_);
624     }
625     return calendar_;
626   }
627
628   /**
629    * $(I Property.) Retrieves the list of calendars that can be used by the culture.
630    * Returns: An array of type Calendar representing the calendars that can be used by the culture.
631    */
632   public Calendar[] optionalCalendars() {
633     Calendar[] cals = new Calendar[cultureData_.optionalCalendars.length];
634     foreach (int i, int calID; cultureData_.optionalCalendars)
635       cals[i] = getCalendarInstance(calID);
636     return cals;
637   }
638
639   /**
640    * $(ANCHOR Culture_numberFormat)
641    * $(I Property.) Retrieves a NumberFormat defining the culturally appropriate format for displaying numbers and currency.
642    * Returns: A NumberFormat defining the culturally appropriate format for displaying numbers and currency.
643   */
644   public NumberFormat numberFormat() {
645     checkNeutral(this);
646     if (numberFormat_ is null) {
647       numberFormat_ = new NumberFormat(cultureData_);
648       numberFormat_.isReadOnly_ = isReadOnly_;
649     }
650     return numberFormat_;
651   }
652   /**
653    * $(I Property.) Assigns a NumberFormat defining the culturally appropriate format for displaying numbers and currency.
654    * Params: values = A NumberFormat defining the culturally appropriate format for displaying numbers and currency.
655    */
656   public void numberFormat(NumberFormat value) {
657     checkReadOnly();
658     numberFormat_ = value;
659   }
660
661   /**
662    * $(ANCHOR Culture_dateTimeFormat)
663    * $(I Property.) Retrieves a DateTimeFormat defining the culturally appropriate format for displaying dates and times.
664    * Returns: A DateTimeFormat defining the culturally appropriate format for displaying dates and times.
665    */
666   public DateTimeFormat dateTimeFormat() {
667     checkNeutral(this);
668     if (dateTimeFormat_ is null) {
669       dateTimeFormat_ = new DateTimeFormat(cultureData_, calendar);
670       dateTimeFormat_.isReadOnly_ = isReadOnly_;
671     }
672     return dateTimeFormat_;
673   }
674   /**
675    * $(I Property.) Assigns a DateTimeFormat defining the culturally appropriate format for displaying dates and times.
676    * Params: values = A DateTimeFormat defining the culturally appropriate format for displaying dates and times.
677    */
678   public void dateTimeFormat(DateTimeFormat value) {
679     checkReadOnly();
680     dateTimeFormat_ = value;
681   }
682
683   private static void checkNeutral(Culture culture) {
684     if (culture.isNeutral)
685       error("Culture '" ~ culture.name ~ "' is a neutral culture. It cannot be used in formatting and therefore cannot be set as the current culture.");
686   }
687
688   private void checkReadOnly() {
689     if (isReadOnly_)
690       error("Instance is read-only.");
691   }
692
693   private static Calendar getCalendarInstance(int calendarType, bool readOnly=false) {
694     switch (calendarType) {
695       case Calendar.JAPAN:
696         return new Japanese();
697       case Calendar.TAIWAN:
698         return new Taiwan();
699       case Calendar.KOREA:
700         return new Korean();
701       case Calendar.HIJRI:
702         return new Hijri();
703       case Calendar.THAI:
704         return new ThaiBuddhist();
705       case Calendar.HEBREW:
706         return new Hebrew;
707       case Calendar.GREGORIAN_US:
708       case Calendar.GREGORIAN_ME_FRENCH:
709       case Calendar.GREGORIAN_ARABIC:
710       case Calendar.GREGORIAN_XLIT_ENGLISH:
711       case Calendar.GREGORIAN_XLIT_FRENCH:
712         return new Gregorian(cast(Gregorian.Type) calendarType);
713       default:
714         break;
715     }
716     return new Gregorian();
717   }
718
719 }
720
721 /**
722  * $(ANCHOR _Region)
723  * Provides information about a region.
724  * Remarks: Region does not represent user preferences. It does not depend on the user's language or culture.
725  * Examples:
726  * The following example displays some of the properties of the Region class:
727  * ---
728  * import tango.io.Print, tango.text.locale.Common;
729  *
730  * void main() {
731  *   Region region = new Region("en-GB");
732  *   Println("name:              %s", region.name);
733  *   Println("englishName:       %s", region.englishName);
734  *   Println("isMetric:          %s", region.isMetric);
735  *   Println("currencySymbol:    %s", region.currencySymbol);
736  *   Println("isoCurrencySymbol: %s", region.isoCurrencySymbol);
737  * }
738  *
739  * // Produces the following output.
740  * // name: