#
# Read the NLS locale.txt file and create culture.xml that can be used to
# generate culture.nlp file.
#
use strict "vars";
#
# Hashtable for information of all of the locales.
# The key is locale ID like 0401, and the
# value is another hashtable.
#
my %gLocaleTable;
Main();
sub Main
{
if ($#ARGV < 2)
{
ShowUsage();
exit 1;
}
ParseLocaleFile($ARGV[0]);
ParseLocaleFile($ARGV[1]);
ParseLocaleFile($ARGV[2]);
GenerateCultureTable();
return 0;
}
sub SortLCID
{
my $primaryLangID1 = hex($a) & 0x1ff; # The lower 9 bits is the primary LangID.
my $primaryLangID2 = hex($b) & 0x1ff; # The lower 9 bits is the primary LangID.
if ($primaryLangID1 != $primaryLangID2)
{
return ($primaryLangID1 - $primaryLangID2);
}
return ($a cmp $b);
}
#
# Globals used:
# gLocaleTable
#
sub GenerateCultureTable()
{
my $localeID;
print "\n";
print "\n";
my @keys = (keys %gLocaleTable);
@keys = sort SortLCID @keys;
foreach $localeID (@keys)
{
# print "$localeID\n";
GenerateCultureData($gLocaleTable{$localeID});
}
print "";
}
#
# Show the command usage.
#
sub ShowUsage
{
print "NLPTrans.pl [the path to locale.txt] [the path to NeutralLocale.txt] [the path to LocaleEx.txt]";
}
#
# Globals used:
# $gLocaleTable
#
sub ParseLocaleFile
{
my ($fileName) = @_;
my $gTotalLocales = 0;
my $gTotalLocalesFound = 0;
#
# Reference to a hashtable which stores the locale informatin for this locale.
#
my $phLocaleData;
my $isFirstLocale;
my $localeID;
my $refName;
my $valueCount;
my $i;
if (!(open LOCALEFILE, $fileName))
{
print "Error in opening $ARGV[0]\n";
exit 1;
}
#
# Test if this is a LOCALE tag.
# Match [Beginning of line] [Optional spaces] LOCALE [Spaces] [Digits]
#
while ()
{
if (/^\s*LOCALE\s+([0-9]+)/)
{
$gTotalLocales = $1;
### print "Total locales to be processed: $gTotalLocales\n";
last;
}
}
if ($gTotalLocales == 0)
{
print "ERROR: LOCALE tag is not found.";
exit 1;
}
$isFirstLocale = 1;
#
# Find every BEGINLOCALE tag.
#
while ()
{
if (/^$/ || /^\s+$/)
{
#
# Skip blank lines.
#
next;
}
#
# Match [Beginning of line] [Optional spaces]BEGINLOCLAE [spaces] [alphanumeric chars] [spaces] ; [spaces] [Anything after]
#
elsif (/^\s*BEGINLOCALE\s+(\w+)\s+; (.*)/)
{
#
# Find the BEGINLOCALE
#
$gTotalLocalesFound++;
if ($isFirstLocale)
{
$isFirstLocale = 0;
} else
{
#
# Store the information found in this locale.
#
}
$localeID = $1;
$refName = $2;
my $Win32LCID = $localeID;
$phLocaleData = $gLocaleTable{$localeID};
if (!defined($phLocaleData))
{
my %localeData;
$gLocaleTable{$localeID} = $phLocaleData = \%localeData;
$$phLocaleData{"WIN32LCID"} = $Win32LCID;
# print "Create $localeID, $phLocaleData\n";
}
$$phLocaleData{"_RefName"} = $refName;
} elsif (/ENDLOCALE/)
{
last;
} elsif (/^\s*(\w+)\s+([0-9]+)\s+(\S.*)/)
{
my @multipleValues;
# local @multipleValues;
#
# Match [Beginning of line] [Optional spaces] [alphanumeric chars] [spaces] [numbers] [spaces] [Non-space] [anything else]
# This is the case with multiple values.
#
my $fieldName = $1;
my $fieldCount = $2;
my $fieldValue = $3;
$valueCount = 0;
$multipleValues[0] = $3;
for ($i = 1; $i < $fieldCount; $i++)
{
$_ = ;
#if (!())
#{
# print "Out of data.\n";
# exit 1;
#}
if (/^\s+(\S.*)/)
{
$fieldValue = $1;
} else
{
print "Out of data.\n";
exit 1;
}
$multipleValues[$i] = $fieldValue;
}
($fieldName, $fieldValue) = CheckForMultipleValues($localeID, $fieldName, \@multipleValues);
$$phLocaleData{$fieldName} = $fieldValue;
} elsif (/^\s*(\w+)\s+(\S.*)/)
{
my $fieldName = $1;
my $fieldValue = $2;
($fieldName, $fieldValue) = CheckForValue($fieldName, $fieldValue);
# print "[$localeID] [$fieldName] [$fieldValue]\n";
$$phLocaleData{$fieldName} = $fieldValue;
} else
{
print "UNKNOWN: $_\n";
}
}
if ($gTotalLocales != $gTotalLocalesFound)
{
print "ERROR: The number of locales is not correct.\n";
print " BEGINLOCALE expected: $gTotalLocales.\n";
print " BEGINLOCALE found: $gTotalLocalesFound.\n";
exit 1;
}
close LOCALEFILE;
}
sub GenerateCultureData
{
my ($localeDataRef) = @_;
my $refName = $$localeDataRef{"_RefName"};
print " \n";
PrintElement(2, "ILANGUAGE", GetHashData($localeDataRef, "ILANGUAGE"));
PrintElement(2, "IPARENT", GetHashData($localeDataRef, "IPARENT")); # NLS+
PrintElement(2, "WIN32LCID", GetHashData($localeDataRef, "WIN32LCID"));
PrintElement(2, "SNAME", GetHashData($localeDataRef, "SNAME")); # NLS+
PrintElement(2, "SENGLANGUAGE", GetHashData($localeDataRef, "SENGLANGUAGE"));
PrintElement(2, "SABBREVLANGNAME", GetHashData($localeDataRef, "SABBREVLANGNAME"));
PrintElement(2, "SISO639LANGNAME", GetHashData($localeDataRef, "SISO639LANGNAME"));
PrintElement(2, "SISO639LANGNAME2", GetHashData($localeDataRef, "SISO639LANGNAME2")); # NLS+
PrintElement(2, "SNATIVELANGNAME", GetHashData($localeDataRef, "SNATIVELANGNAME"));
PrintElement(2, "IDEFAULTANSICODEPAGE", GetHashData($localeDataRef, "IDEFAULTANSICODEPAGE"));
PrintElement(2, "IDEFAULTOEMCODEPAGE", GetHashData($localeDataRef, "IDEFAULTOEMCODEPAGE"));
PrintElement(2, "IDEFAULTMACCODEPAGE", GetHashData($localeDataRef, "IDEFAULTMACCODEPAGE"));
PrintElement(2, "IDEFAULTEBCDICCODEPAGE", GetHashData($localeDataRef, "IDEFAULTEBCDICCODEPAGE"));
PrintElement(2, "SLIST", GetHashData($localeDataRef, "SLIST"));
PrintElement(2, "SDECIMAL", GetHashData($localeDataRef, "SDECIMAL"));
PrintElement(2, "STHOUSAND", GetHashData($localeDataRef, "STHOUSAND"));
PrintElement(2, "SGROUPING", GetHashData($localeDataRef, "SGROUPING"));
PrintElement(2, "IDIGITS", GetHashData($localeDataRef, "IDIGITS"));
PrintElement(2, "INEGNUMBER", GetHashData($localeDataRef, "INEGNUMBER"));
PrintElement(2, "SCURRENCY", GetHashData($localeDataRef, "SCURRENCY"));
PrintElement(2, "SMONDECIMALSEP", GetHashData($localeDataRef, "SMONDECIMALSEP"));
PrintElement(2, "SMONTHOUSANDSEP", GetHashData($localeDataRef, "SMONTHOUSANDSEP"));
PrintElement(2, "SMONGROUPING", GetHashData($localeDataRef, "SMONGROUPING"));
PrintElement(2, "ICURRDIGITS", GetHashData($localeDataRef, "ICURRDIGITS"));
PrintElement(2, "ICURRENCY", GetHashData($localeDataRef, "ICURRENCY"));
PrintElement(2, "INEGCURR", GetHashData($localeDataRef, "INEGCURR"));
PrintElement(2, "SPOSITIVESIGN", GetHashData($localeDataRef, "SPOSITIVESIGN"));
PrintElement(2, "SNEGATIVESIGN", GetHashData($localeDataRef, "SNEGATIVESIGN"));
PrintElement(2, "INEGATIVEPERCENT", GetHashData($localeDataRef, "INEGATIVEPERCENT")); # NLS+
PrintElement(2, "IPOSITIVEPERCENT", GetHashData($localeDataRef, "IPOSITIVEPERCENT")); # NLS+
PrintElement(2, "SPERCENT", GetHashData($localeDataRef, "SPERCENT")); # NLS+
PrintElement(2, "SNAN", GetHashData($localeDataRef, "SNAN")); # NLS+
PrintElement(2, "SPOSINFINITY", GetHashData($localeDataRef, "SPOSINFINITY")); # NLS+
PrintElement(2, "SNEGINFINITY", GetHashData($localeDataRef, "SNEGINFINITY")); # NLS+
PrintElementMultipleValues(2, "STIMEFORMAT", GetHashData($localeDataRef, "STIMEFORMAT"));
PrintElementMultipleValues(2, "SSHORTTIME", GetHashData($localeDataRef, "SSHORTTIME")); # NLS+
PrintElement(2, "STIME", GetHashData($localeDataRef, "STIME"));
PrintElement(2, "S1159", GetHashData($localeDataRef, "S1159"));
PrintElement(2, "S2359", GetHashData($localeDataRef, "S2359"));
PrintElementMultipleValues(2, "SSHORTDATE", GetHashData($localeDataRef, "SSHORTDATE"));
PrintElement(2, "SDATE", GetHashData($localeDataRef, "SDATE"));
PrintElementMultipleValues(2, "SYEARMONTH", GetHashData($localeDataRef, "SYEARMONTH"));
PrintElementMultipleValues(2, "SLONGDATE", GetHashData($localeDataRef, "SLONGDATE"));
PrintElement(2, "SMONTHDAY", GetHashData($localeDataRef, "SMONTHDAY")); # NLS+
PrintElement(2, "ICALENDARTYPE", GetHashData($localeDataRef, "ICALENDARTYPE"));
PrintElement(2, "IOPTIONALCALENDAR", GetHashData($localeDataRef, "IOPTIONALCALENDAR"));
PrintElement(2, "IFIRSTDAYOFWEEK", GetHashData($localeDataRef, "IFIRSTDAYOFWEEK"));
PrintElement(2, "IFIRSTWEEKOFYEAR", GetHashData($localeDataRef, "IFIRSTWEEKOFYEAR"));
PrintMultipleElements(2, "SDAYNAME", $localeDataRef, "SDAYNAME", 1, 7);
PrintMultipleElements(2, "SABBREVDAYNAME", $localeDataRef, "SABBREVDAYNAME", 1, 7);
PrintMultipleElements(2, "SMONTHNAME", $localeDataRef, "SMONTHNAME", 1, 13);
PrintMultipleElements(2, "SABBREVMONTHNAME", $localeDataRef, "SABBREVMONTHNAME", 1, 13);
my $engDisplayName;
if (defined($localeDataRef->{"SENGCOUNTRY"}))
{
$engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE") . " (" . GetHashData($localeDataRef, "SENGCOUNTRY") . ")";
} else
{
#
# Specail case for zh-CHT/zh-CHS.
#
if ($localeDataRef->{"ILANGUAGE"} eq "0004")
{
$engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE") . " (Simplified)";
} elsif ($localeDataRef->{"ILANGUAGE"} eq "7c04")
{
$engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE") . " (Traditional)";
} else
{
$engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE");
}
}
PrintElement(2, "SENGDISPLAYNAME", $engDisplayName); # NLS+
my $nativeDisplayName;
if (defined($localeDataRef->{"SNATIVECTRYNAME"}))
{
$nativeDisplayName = GetHashData($localeDataRef, "SNATIVELANGNAME") . " (" . GetHashData($localeDataRef, "SNATIVECTRYNAME") . ")";
} else
{
$nativeDisplayName = GetHashData($localeDataRef, "SNATIVELANGNAME");
}
PrintElement(2, "SNATIVEDISPLAYNAME", $nativeDisplayName);# NLS+
print " \n";
#foreach $fieldName (keys %localeData)
#{
# # print "$fieldName\n";
#}
}
sub GetHashData
{
my ($phHash, $key) = @_;
my $result = $phHash->{$key};
if (!defined($result))
{
print "Data not found for [$key]\n";
exit 1;
}
return ($result);
}
sub PrintElement
{
my ($indentLevel, $tagName, $content) = @_;
PrintIndent($indentLevel);
print "<$tagName>$content$tagName>\n";
}
sub PrintIndent
{
my ($indentLevel) = @_;
my $i;
for ($i = 0; $i < $indentLevel; $i++)
{
print " ";
}
}
sub PrintElementMultipleValues
{
my ($indentLevel, $tagName, $arrayRef) = @_;
my $i;
PrintIndent($indentLevel);
print "<$tagName>\n";
PrintIndent($indentLevel + 1);
print "" . $$arrayRef[0] . "\n";
for ($i = 1; $i <= $#{$arrayRef}; $i++)
{
PrintIndent($indentLevel + 1);
print "" . $$arrayRef[$i] . "\n";
}
PrintIndent($indentLevel);
print "$tagName>\n";
}
sub PrintMultipleElements
{
my ($indentLevel, $tagPrefix, $hashRef, $nlsTagPrefix, $fromRange, $toRange) = @_;
my $i;
my $tagName;
my $nlsTagName;
for ($i = $fromRange; $i <= $toRange; $i++)
{
$tagName = $tagPrefix . $i;
$nlsTagName = $nlsTagPrefix . $i;
PrintElement($indentLevel, $tagName, $$hashRef{$nlsTagName});
}
}
sub CheckForValue
{
my ($fieldName, $fieldValue) = @_;
if ($fieldName eq "SGROUPING")
{
$fieldValue = ConvertGrouping($fieldValue);
} elsif ($fieldName eq "SMONGROUPING")
{
$fieldValue = ConvertGrouping($fieldValue);
} elsif ($fieldName eq "SPOSITIVESIGN")
{
if ($fieldValue eq "\\x0000" || $fieldValue eq "\\X0000")
{
$fieldValue = "+";
}
} elsif ($fieldName eq "IOPTIONALCALENDAR")
{
$fieldValue = ConvertCalendars($fieldValue);
} elsif ($fieldName eq "IFIRSTDAYOFWEEK")
{
$fieldValue = ConvertWeekday($fieldValue);
} elsif ($fieldName =~ /SDAYNAME([0-9]+)/)
{
my $day = $1;
if ($day == 7)
{
$day = 1;
} else
{
$day++;
}
$fieldName = "SDAYNAME" . $day;
} elsif ($fieldName =~ /SABBREVDAYNAME([0-9]+)/)
{
my $day = $1;
if ($day == 7)
{
$day = 1;
} else
{
$day++;
}
$fieldName = "SABBREVDAYNAME" . $day;
}
return ($fieldName, $fieldValue);
}
sub ConvertGrouping
{
my ($groupStr) = @_;
if ($groupStr eq "3;0")
{
$groupStr = "3";
} elsif ($groupStr eq "0;0")
{
$groupStr = "0";
} elsif ($groupStr eq "3;2;0")
{
$groupStr = "3;2";
} elsif ($groupStr eq "3")
{
$groupStr = "3;0";
} else
{
print "ERROR: Don't know how to convert grouping string: [$groupStr].\n";
exit(1);
}
return ($groupStr);
}
#
# Convert NLS weekday to NLS+ weekday
# NLS: 0=Mon, 1=Tue, 2=Wed, 3=Thu, 4=Fri, 5=Sat, 6=Sun
# NLS+: 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat
#
sub ConvertWeekday
{
my ($weekday) = @_;
if ($weekday == 6)
{
$weekday = 0;
} elsif ($weekday >= 0 && $weekday <= 5)
{
$weekday++;
} else
{
print "ERROR: Incorrect NLS weekday value: [$weekday].\n";
exit(1);
}
return ($weekday);
}
sub CheckForMultipleValues
{
my ($localeID, $fieldName, $pMultipleValues) = @_;
my $fieldValue = $pMultipleValues;
if ($fieldName eq "IOPTIONALCALENDAR")
{
$fieldValue = ConvertCalendars($localeID, $pMultipleValues);
}
return ($fieldName, $fieldValue) ;
}
#
# Convert NLS IOPTIONALCALENDAR values to NLS+ values.
#
sub ConvertCalendars
{
my ($localeID, $pArrayRef) = @_;
my $result = "";
my $i;
my $calID;
my $hasCalendar = 0;
for ($i = 0; $i <= $#{$pArrayRef}; $i++)
{
#
# Match [Numbers] [\xffff] [anything else]
#
if ($$pArrayRef[$i] =~ /([0-9]+)\\xffff.*/i)
{
$calID = $1;
#
# If the $calID is zero, we can skip it.
#
if ($calID >= 1)
{
if ($hasCalendar)
{
$result = $result . ";";
}
$result = $result . $calID;
$hasCalendar = 1;
}
}
}
if ($localeID =~ /[0-9][0-9]09/)
{
# if this is an English locale, and calendar is
# Gregorian (localized), Add Greogrian (US English) as well.
if ($result eq "1")
{
$result = "1;2";
}
} elsif ($localeID eq "0404")
{
# In the case of Taiwan, add TaiwanCalendar
# 1 = Gregorian (Localized)
# 2 = Gregorian (USEnglish)
# 4 = Taiwan
$result = "1;2;4";
}
return ($result);
}