In today’s interconnected world, it’s important that online applications support different cultures.
Even if most of us that spend a lot of time online are accustomed to the USA date and number formats, people always prefer to see numbers and dates formatted in a familiar way. People don’t like to think about if the date’s first digit is day or month, or if it’s decimal delimiter or digit grouping mark.
The date 03/02/2010 means completely different thing in Australia and USA – it’s February the 3rd in the former and March the 2nd in latter! (dd/mm/yyyy vs mm/dd/yyyy)
Even if we assume that the common internet user can read the shown format based on the website’s supposed location, localization and internationalization (i18n) could greatly improve readability and usability.
Some cultures supported in Windows
I have been working on a problem considering DateTime formatting in .NET recently, and I decided to have a look at the cultures and formats that are supported on my machine.
It’s really interesting to see this, here is a subset with interesting formats highlighted. If you like, you can see the full results here.
Name | DisplayName | ShortDatePattern | FullDateTimePattern | Currency (decimals) | NaNSymbol | RTL |
---|---|---|---|---|---|---|
am-ET | Amharic (Ethiopia) | d/M/yyyy | dddd ‘፣’ MMMM d ‘ቀን’ yyyy h:mm:ss tt | ETB (2) | NAN | |
ar-AE | Arabic (U.A.E.) | dd/MM/yyyy | dd MMMM, yyyy hh:mm:ss tt | د.إ. (2) | ليس برقم | RTL |
ar-BH | Arabic (Bahrain) | dd/MM/yyyy | dd MMMM, yyyy hh:mm:ss tt | د.ب. (3) | ليس برقم | RTL |
az-Cyrl-AZ | Azeri (Cyrillic, Azerbaijan) | dd.MM.yyyy | d MMMM yyyy H:mm:ss | ман. (2) | NaN | |
bg-BG | Bulgarian (Bulgaria) | d.M.yyyy ‘г.’ | dd MMMM yyyy ‘г.’ HH:mm:ss ‘ч.’ | лв. (2) | NaN | |
bo-CN | Tibetan (PRC) | yyyy/M/d | yyyy’ལོའི་ཟླ’ M’ཚེས’ d HH:mm:ss | ¥ (2) | ཨང་ཀི་མིན་པ། | |
ca-ES | Catalan (Catalan) | dd/MM/yyyy | dddd, d’ / ‘MMMM’ / ‘yyyy HH:mm:ss | € (2) | NeuN | |
co-FR | Corsican (France) | dd/MM/yyyy | dddd d MMMM yyyy HH:mm:ss | € (2) | Mica numericu | |
cs-CZ | Czech (Czech Republic) | d.M.yyyy | d. MMMM yyyy H:mm:ss | Kč (2) | Není číslo | |
de-AT | German (Austria) | dd.MM.yyyy | dddd, dd. MMMM yyyy HH:mm:ss | € (2) | n. def. | |
dsb-DE | Lower Sorbian (Germany) | d. M. yyyy | dddd, ‘dnja’ d. MMMM yyyy H:mm:ss | € (2) | njedefinowane | |
el-GR | Greek (Greece) | d/M/yyyy | dddd, d MMMM yyyy h:mm:ss tt | € (2) | μη αριθμός | |
en-IN | English (India) | dd-MM-yyyy | dd MMMM yyyy HH:mm:ss | Rs. (2) | NaN | |
en-ZA | English (South Africa) | yyyy/MM/dd | dd MMMM yyyy hh:mm:ss tt | R (2) | NaN | |
es-AR | Spanish (Argentina) | dd/MM/yyyy | dddd, dd’ de ‘MMMM’ de ‘yyyy hh:mm:ss tt | $ (2) | NeuN | |
et-EE | Estonian (Estonia) | d.MM.yyyy | d. MMMM yyyy’. a.’ H:mm:ss | kr (2) | avaldamatu | |
fy-NL | Frisian (Netherlands) | d-M-yyyy | dddd d MMMM yyyy H:mm:ss | € (2) | NaN | |
gsw-FR | Alsatian (France) | dd/MM/yyyy | dddd d MMMM yyyy HH:mm:ss | € (2) | Ohne Nummer | |
gu-IN | Gujarati (India) | dd-MM-yy | dd MMMM yyyy HH:mm:ss | રૂ (2) | NaN | |
hu-HU | Hungarian (Hungary) | yyyy.MM.dd. | yyyy. MMMM d. H:mm:ss | Ft (2) | nem szám | |
it-CH | Italian (Switzerland) | dd.MM.yyyy | dddd, d. MMMM yyyy HH:mm:ss | fr. (2) | Non un numero reale | |
ja-JP | Japanese (Japan) | yyyy/MM/dd | yyyy’年’M’月’d’日’ H:mm:ss | ¥ (0) | NaN (非数値) | |
ka-GE | Georgian (Georgia) | dd.MM.yyyy | yyyy ‘წლის’ dd MM, dddd H:mm:ss | Lari (2) | NaN | |
nl-BE | Dutch (Belgium) | d/MM/yyyy | dddd d MMMM yyyy H:mm:ss | € (2) | NaN (Niet-een-getal) |
Here’s the code I have used. I ran it in LinqPad, the output is provided using the Dump extension method and then exported the results to HTML.
var cultures = System.Globalization.CultureInfo.
GetCultures(System.Globalization.CultureTypes.SpecificCultures).
Select(c =>
{
return new {
Name = c.Name,
DisplayName = c.DisplayName,
ShortDatePattern = c.DateTimeFormat.
ShortDatePattern,
FullDateTimePattern = c.DateTimeFormat.
FullDateTimePattern,
Currency = String.Format(
"{0} ({1})",
c.NumberFormat.CurrencySymbol,
c.NumberFormat.CurrencyDecimalDigits
),
NaNSymbol = c.NumberFormat.NaNSymbol,
RTL = c.TextInfo.IsRightToLeft ? "RTL" : ""
};
}
).OrderBy(c => c.Name).ToList();
cultures.Dump();
The cultures applied
Then I wanted to see these formats in action. So I altered the program a bit.
var cultures = System.Globalization.CultureInfo.
GetCultures(System.Globalization.CultureTypes.SpecificCultures).
Select(c =>
{
return new {
Name = c.Name,
DisplayName = c.DisplayName,
ShortDate = DateTime.Parse("2010-12-16T13:25:43").
ToString(c.DateTimeFormat.
ShortDatePattern, c),
FullDateTimePattern = DateTime.Parse("2010-12-16T13:25:43").
ToString(c.DateTimeFormat.
FullDateTimePattern, c),
Currency = (578349026.7584901).ToString("c", c)
};
}
).OrderBy(c => c.Name).ToList();
cultures.Dump();
Here are some interesting results produced this way, again a highlighted subset, while you can see the full results here.
Name | DisplayName | ShortDate | FullDateTimePattern | Currency |
---|---|---|---|---|
am-ET | Amharic (Ethiopia) | 16/12/2010 | ሐሙስ ፣ ዲሴምበር 16 ቀን 2010 1:25:43 ከሰዓት | ETB578349,026.76 |
ar-AE | Arabic (U.A.E.) | 16/12/2010 | 16 ديسمبر, 2010 01:25:43 م | د.إ. 578,349,026.76 |
ar-BH | Arabic (Bahrain) | 16/12/2010 | 16 ديسمبر, 2010 01:25:43 م | د.ب. 578,349,026.758 |
az-Cyrl-AZ | Azeri (Cyrillic, Azerbaijan) | 16.12.2010 | 16 декабр 2010 13:25:43 | 578 349 026,76 ман. |
bn-BD | Bengali (Bangladesh) | 16-12-10 | 16 ডিসেম্বর 2010 13.25.43 | ৳ 57,83,49,026.76 |
bo-CN | Tibetan (PRC) | 2010/12/16 | 2010ལོའི་ཟླ 12ཚེས 16 13:25:43 | ¥578349,026.76 |
de-AT | German (Austria) | 16.12.2010 | Donnerstag, 16. Dezember 2010 13:25:43 | € 578.349.026,76 |
de-CH | German (Switzerland) | 16.12.2010 | Donnerstag, 16. Dezember 2010 13:25:43 | Fr. 578’349’026.76 |
de-DE | German (Germany) | 16.12.2010 | Donnerstag, 16. Dezember 2010 13:25:43 | 578.349.026,76 € |
en-CA | English (Canada) | 16/12/2010 | December-16-10 1:25:43 PM | $578,349,026.76 |
eu-ES | Basque (Basque) | 2010/12/16 | osteguna, 2010.eko abenduak 16 13:25:43 | 578.349.026,76 € |
fa-IR | Persian | 12/16/2010 | الخميس, ديسمبر 16, 2010 01:25:43 ب.ظ | ريال 578,349,026/76 |
gu-IN | Gujarati (India) | 16-12-10 | 16 ડિસેમ્બર 2010 13:25:43 | રૂ 57,83,49,026.76 |
hr-HR | Croatian (Croatia) | 16.12.2010. | 16. prosinca 2010. 13:25:43 | 578.349.026,76 kn |
hu-HU | Hungarian (Hungary) | 2010.12.16. | 2010. december 16. 13:25:43 | 578 349 026,76 Ft |
ig-NG | Igbo (Nigeria) | 16/12/2010 | Ojo’bo, Onwa iri n’ibua 16, 2010 1:25:43 Efifie | N 578,349,026.76 |
ja-JP | Japanese (Japan) | 2010/12/16 | 2010年12月16日 13:25:43 | ¥578,349,027 |
kk-KZ | Kazakh (Kazakhstan) | 16.12.2010 | 16 желтоқсан 2010 ж. 13:25:43 | Т578 349 026-76 |
prs-AF | Dari (Afghanistan) | 10/01/32 | 10/01/1432 1:25:43 غ.و | ؋578,349,026.76 |
zh-CN | Chinese (Simplified, PRC) | 2010/12/16 | 2010年12月16日 13:25:43 | ¥578,349,026.76 |
Lessons learned
Some things I learned with this experiment –
- Same language or country doesn’t mean same formatting if there are different cultures.
- Date patterns are more versatile then I could have imagined.
- Arabic cultures have a completely different calendar then the western world, for example, 16th December 2010 is 10th Haram 1432 in Afghanistan.
- Date part order is completely arbitrary, “M/d/y”, “y/M/d”, “d/M/y/” and so on.
- Date part separator could be a dot, slash, dash…
- Japanese Yen is shown only as a rounded number.
- Germans write Euro symbol (€) before the amount, while the Austrians write it afterwards.
- Decimal grouping symbol is really versatile, could be a dot, a comma, single quote, blank space… For example, Swiss use single quote (‘).
- Decimal separator could be a comma, dot, slash or dash…
- While most cultures group digits by three, some group them by two like Bengali (Bangladesh).
There is A LOT of different formats out there, so if you want to do any kind of custom formatting and keep the culture specific formats, you have to keep this in mind and deploy a solution accordingly. Additional links on this subject:
- Go Global Developer Center (MSDN)
- CultureInfo Class (MSDN)
- Codes for the Representation of Names of Languages (Alpha-3 codes arranged alphabetically by the English name of language)
- National Language Support (NLS) API Reference (MSDN)
- A_Localization_Horror_Story:_It_Could_Happen_To_You
- Internationalization (I18n) Activity (W3C)
- Internationalization and localization (Wikipedia)
- World different calendars (Wikipedia)
Leave a Reply