Source of the locale information
================================
The locale information stored in culture_info.go are created by a C# little program.
I have run it in Microsoft Visual Studio Express 2013.
GetCultureInfo locale_info.txt locale_info.log
locale_info.txt contains the "LANGINFO_MAP" variable definition, which has just been cut and pasted into culture_info.go
-------------------- Program.cs ---------------------
using System;
using System.Globalization;
using System.Text;
using System.IO;
using System.Collections.Generic;
// This program write the locale information in a file in utf8
// It has been written quickly, so it is certainly poor style, but it is not meant to be used often.
namespace GetCultureInfo
{
class Program
{
static void Main(string[] args)
{
string filename = "";
string filename_log = "";
StreamWriter sw = null;
StreamWriter sw_log = null;
var culture_list = new List<string>();
// check arguments
if (args.Length != 1 && args.Length != 2)
{
Console.WriteLine("ERROR: bad arguments count");
Environment.Exit(0);
}
// if "-list" of "--list" argument
if (args.Length == 1)
{
if (args[0] == "-list" || args[0] == "--list")
{
print_culture_list();
Environment.Exit(0);
}
Console.WriteLine("ERROR: bad arguments");
Environment.Exit(0);
}
// create output file and log file
filename = args[0];
filename_log = args[1];
sw = open_streamwriter(filename);
if (sw == null)
{
Environment.Exit(0);
}
sw_log = open_streamwriter(filename_log);
if (sw_log == null)
{
Environment.Exit(0);
}
// prepare culture list
fill_culture_list(culture_list);
// write culture info to file
sw.WriteLine("var LANGINFO_MAP = map[string]*Langinfo{");
foreach (string culturename in culture_list)
{
write_culture_info(culturename, sw, sw_log);
}
sw.WriteLine("}");
sw.WriteLine("");
sw.Close();
sw_log.Close();
// Console.ReadLine();
}
static bool write_culture_info(string culturename, StreamWriter sw, StreamWriter sw_log) // returns false if failure
{
System.Globalization.CultureInfo ci = null;
System.Globalization.DateTimeFormatInfo dtfi = null;
System.Globalization.NumberFormatInfo nfi = null;
System.Globalization.Calendar cal = null;
string[] lng_daynames = { };
string[] lng_daynames_abbr = { };
string[] lng_monthnames = { };
string[] lng_monthnames_abbr = { };
string[] lng_monthnames_genitive = { };
string[] lng_monthnames_genitive_abbr = { };
string lng_AM_symbol = "";
string lng_PM_symbol = "";
System.DayOfWeek lng_firstdayofweek = 0;
string lng_date_separator = "";
string lng_time_separator = "";
string lng_datetime_pattern_full = "";
string lng_date_pattern_long = "";
string lng_date_pattern_short = "";
string lng_time_pattern_long = "";
string lng_time_pattern_short = "";
string lng_DMY = "";
string lng_number_decimal_separator = "";
string lng_number_group_separator = "";
int[] lng_number_grouping = { };
// get locale object
ci = new CultureInfo(culturename, false); // so that settings modified by the user on configuration panel don't override the returned CultureInfo
dtfi = ci.DateTimeFormat;
nfi = ci.NumberFormat;
// write INFO
info_writeln(sw_log, "INFO: === {0, -12} {1, -52} ===", culturename, ci.EnglishName);
if (ci.Name != culturename)
{
info_writeln(sw_log, "ERROR: {0} name is different from ci.Name \"{1}\"", culturename, ci.Name);
sw_log.Close();
return false;
}
// change to Gregorian calendar
cal = ci.Calendar;
if (cal.GetType() != typeof(GregorianCalendar)) // check if default calendar is gregorian
{
info_writeln(sw_log, "INFO: {0} has not a gregorian calendar, but {1}.", culturename, cal);
cal = alternate_gregorian_calendar(ci.OptionalCalendars);
if (cal == null)
{
info_writeln(sw_log, "INFO: {0} has no gregorian calendar available. This CultureInfo is skipped.", culturename);
return false;
}
info_writeln(sw_log, "INFO: {0} has new gregorian calendar of type {1}.", culturename, ((GregorianCalendar)cal).CalendarType);
dtfi.Calendar = cal;
}
// get date and time locale info
lng_daynames = dtfi.DayNames;
lng_daynames_abbr = dtfi.AbbreviatedDayNames;
lng_monthnames = dtfi.MonthNames;
lng_monthnames_abbr = dtfi.AbbreviatedMonthNames;
lng_monthnames_genitive = dtfi.MonthGenitiveNames;
lng_monthnames_genitive_abbr = dtfi.AbbreviatedMonthGenitiveNames;
lng_AM_symbol = dtfi.AMDesignator;
lng_PM_symbol = dtfi.PMDesignator;
lng_firstdayofweek = dtfi.FirstDayOfWeek;
lng_date_separator = dtfi.DateSeparator;
lng_time_separator = dtfi.TimeSeparator;
lng_datetime_pattern_full = dtfi.FullDateTimePattern;
lng_date_pattern_long = dtfi.LongDatePattern;
lng_date_pattern_short = dtfi.ShortDatePattern;
lng_time_pattern_long = dtfi.LongTimePattern;
lng_time_pattern_short = dtfi.ShortTimePattern;
lng_DMY = get_DMA_from_short_format(lng_date_pattern_short, sw_log);
// some cleanup
if (lng_date_separator == ". ") // for dsb-DE, hsb-DE, sk-SK
{
lng_date_separator = ".";
}
if (lng_datetime_pattern_full.IndexOf("\\") >= 0) // for mt-MT (Maltese)
{
lng_datetime_pattern_full = lng_datetime_pattern_full.Replace("\\", "\\\\");
}
if (lng_date_pattern_long.IndexOf("\\") >= 0) // for mt-MT (Maltese)
{
lng_date_pattern_long = lng_date_pattern_long.Replace("\\", "\\\\");
}
// write culture name and opening bracket
sw.WriteLine(" \"{0}\": {{ // {1}", culturename.ToLower(), ci.EnglishName);
// write info
sw.WriteLine(" Lng_locale_name: \"{0}\",", ci.Name);
sw.WriteLine(" Lng_locale_description: \"{0}\",", ci.EnglishName);
sw.WriteLine(" Lng_daynames: {0},", concat_days_array(lng_daynames, sw_log));
sw.WriteLine(" Lng_daynames_abbr: {0},", concat_days_array(lng_daynames_abbr, sw_log));
sw.WriteLine(" Lng_monthnames: {0},", concat_months_array(lng_monthnames, sw_log));
sw.WriteLine(" Lng_monthnames_abbr: {0},", concat_months_array(lng_monthnames_abbr, sw_log));
sw.WriteLine(" Lng_monthnames_genitive: {0},", concat_months_array(lng_monthnames_genitive, sw_log));
sw.WriteLine(" Lng_monthnames_genitive_abbr: {0},", concat_months_array(lng_monthnames_genitive_abbr, sw_log));
sw.WriteLine(" Lng_AM_symbol: \"{0}\",", lng_AM_symbol);
sw.WriteLine(" Lng_PM_symbol: \"{0}\",", lng_PM_symbol);
sw.WriteLine(" Lng_firstdayofweek: {0},", (int)lng_firstdayofweek);
sw.WriteLine(" Lng_date_separator: '{0}',", lng_date_separator);
sw.WriteLine(" Lng_time_separator: '{0}',", lng_time_separator);
sw.WriteLine(" Lng_datetime_pattern_full: \"{0}\",", lng_datetime_pattern_full);
sw.WriteLine(" Lng_date_pattern_long: \"{0}\",", lng_date_pattern_long);
sw.WriteLine(" Lng_date_pattern_short: \"{0}\",", lng_date_pattern_short);
sw.WriteLine(" Lng_time_pattern_long: \"{0}\",", lng_time_pattern_long);
sw.WriteLine(" Lng_time_pattern_short: \"{0}\",", lng_time_pattern_short);
sw.WriteLine(" Lng_DMY: \"{0}\",", lng_DMY);
// get number format info
lng_number_decimal_separator = nfi.NumberDecimalSeparator;
lng_number_group_separator = nfi.NumberGroupSeparator;
lng_number_grouping = nfi.NumberGroupSizes;
if (lng_number_grouping.Length != 1)
{ // info for unusual grouping
info_writeln(sw_log, "INFO: {0} has unusual grouping of {1}.", culturename, concat_grouping_array(lng_number_grouping));
}
sw.WriteLine(" Lng_number_decimal_point: '{0}',", lng_number_decimal_separator);
sw.WriteLine(" Lng_number_group_separator: '{0}',", escape_single_quote(lng_number_group_separator));
sw.WriteLine(" Lng_number_grouping: {0},", concat_grouping_array(lng_number_grouping));
// write end bracket
sw.WriteLine(" },");
sw.WriteLine("");
return true;
}
// return a gregorian calendar from a Calendar list
static GregorianCalendar alternate_gregorian_calendar(Calendar[] calendar_list)
{
GregorianCalendar gregcal;
GregorianCalendarTypes gregcal_type;
// try to return a Localized gregorian calendar, if any
foreach (Calendar optcal in calendar_list)
{
if (optcal.GetType() == typeof(GregorianCalendar))
{
gregcal = (GregorianCalendar)optcal;
gregcal_type = gregcal.CalendarType;
if (gregcal_type == GregorianCalendarTypes.Localized)
{
return gregcal;
}
}
}
// try to return a USEnglish gregorian calendar, if any
foreach (Calendar optcal in calendar_list)
{
if (optcal.GetType() == typeof(GregorianCalendar))
{
gregcal = (GregorianCalendar)optcal;
gregcal_type = gregcal.CalendarType;
if (gregcal_type == GregorianCalendarTypes.USEnglish)
{
return gregcal;
}
}
}
// try to return the first gregorian calendar available, if any
foreach (Calendar optcal in calendar_list)
{
if (optcal.GetType() == typeof(GregorianCalendar))
{
gregcal = (GregorianCalendar)optcal;
return gregcal;
}
}
return null;
}
static string concat_months_array(string[] ss, StreamWriter sw_log)
{
string result = "";
if (ss.Length != 13)
{
info_writeln(sw_log, "ERROR: there should be 13 months in the array");
sw_log.Close();
Environment.Exit(0);
}
if (ss[12] != "")
{
info_writeln(sw_log, "ERROR: 13rd month should be empty string: {0} found", ss[12]);
sw_log.Close();
Environment.Exit(0);
}
result = String.Join("\", \"", ss, 0, 12);
return "[12]string{\"" + result + "\"}";
}
static string concat_days_array(string[] ss, StreamWriter sw_log)
{
string result = "";
if (ss.Length != 7)
{
info_writeln(sw_log, "ERROR: 8th day detected: \"{0}\"", ss[7]);
sw_log.Close();
Environment.Exit(0);
}
result = String.Join("\", \"", ss);
return "[7]string{\"" + result + "\"}";
}
static string concat_grouping_array(int[] ss)
{
string result = "";
result = String.Join(", ", ss);
return "[]int{" + result + "}";
}
static string escape_single_quote(string s)
{
string result;
result = s.Replace("\'", "\\'");
return result;
}
// find the natural order for day, month, and year, from the date short format.
// returns "DMY", MDY", or "YMD"
static string get_DMA_from_short_format(string fmt, StreamWriter sw_log)
{
string fmt_bak = fmt;
fmt = fmt.Replace("yyyy", "Y"); // simplify year to one char "Y"
fmt = fmt.Replace("yyy", "Y");
fmt = fmt.Replace("yy", "Y");
fmt = fmt.Replace("MMMM", "M"); // simplify month to one char "M"
fmt = fmt.Replace("MMM", "M");
fmt = fmt.Replace("MM", "M");
fmt = fmt.Replace("M", "M");
fmt = fmt.Replace("dddd", "D"); // simplify day to one char "D"
fmt = fmt.Replace("ddd", "D");
fmt = fmt.Replace("dd", "D");
fmt = fmt.Replace("d", "D");
fmt = fmt.Replace(".", ""); // remove punctuations
fmt = fmt.Replace("-", "");
fmt = fmt.Replace("/", "");
fmt = fmt.Replace(" ", "");
fmt = fmt.Replace("г", ""); // remove this character for bulgarian format
fmt = fmt.Replace("'", "");
if (fmt.Length != 3)
{
info_writeln(sw_log, "ERROR: invalid character in date short string: \"{0}\"", fmt_bak);
sw_log.Close();
Environment.Exit(0);
}
if (!(fmt == "DMY" || fmt == "MDY" || fmt == "YMD"))
{
info_writeln(sw_log, "ERROR: invalid day-month-year info in date short string: \"{0}\"", fmt_bak);
sw_log.Close();
Environment.Exit(0);
}
return fmt;
}
static void fill_culture_list(List<string> culture_list)
{
// fill list with cultures
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
culture_list.Add(ci.Name);
}
// remove some locales
culture_list.Remove("gsw-FR"); // gsw is swiss german, but MS tells its Alsatian
// culture_list.Remove("dsb-DE"); // Lower Sorbian (Germany). lng_date_separator is '. '. Too few speakers.
// culture_list.Remove("hsb-DE"); // Upper Sorbian (Germany). lng_date_separator is '. ' Too few speakers.
// culture_list.Remove("mt-MT"); // Maltese (Malta).
// sort in alphabetical order
culture_list.Sort();
}
static void print_culture_list()
{
var culture_list = new List<string>();
fill_culture_list(culture_list);
foreach (string culturename in culture_list)
{
CultureInfo ci = new CultureInfo(culturename, false);
Console.WriteLine("{0, -12} {1}", ci.Name, ci.EnglishName);
}
}
static StreamWriter open_streamwriter(string filename)
{
StreamWriter sw;
if (filename == "")
{
Console.WriteLine("ERROR: Bad filename");
return null;
}
if (File.Exists(filename))
{
Console.WriteLine("ERROR: file \"{0}\" already exists", filename);
return null;
}
sw = File.CreateText(filename);
return sw;
}
// write formatted string on console and sw_log
static void info_writeln(StreamWriter sw_log, string fmt, params Object[] objs)
{
Console.WriteLine(fmt, objs);
sw_log.WriteLine(fmt, objs);
}
}
}
------------------------------------