Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

558 lines
17 KiB

  1. #
  2. # Read the NLS locale.txt file and create culture.xml that can be used to
  3. # generate culture.nlp file.
  4. #
  5. use strict "vars";
  6. #
  7. # Hashtable for information of all of the locales.
  8. # The key is locale ID like 0401, and the
  9. # value is another hashtable.
  10. #
  11. my %gLocaleTable;
  12. Main();
  13. sub Main
  14. {
  15. if ($#ARGV < 2)
  16. {
  17. ShowUsage();
  18. exit 1;
  19. }
  20. ParseLocaleFile($ARGV[0]);
  21. ParseLocaleFile($ARGV[1]);
  22. ParseLocaleFile($ARGV[2]);
  23. GenerateCultureTable();
  24. return 0;
  25. }
  26. sub SortLCID
  27. {
  28. my $primaryLangID1 = hex($a) & 0x1ff; # The lower 9 bits is the primary LangID.
  29. my $primaryLangID2 = hex($b) & 0x1ff; # The lower 9 bits is the primary LangID.
  30. if ($primaryLangID1 != $primaryLangID2)
  31. {
  32. return ($primaryLangID1 - $primaryLangID2);
  33. }
  34. return ($a cmp $b);
  35. }
  36. #
  37. # Globals used:
  38. # gLocaleTable
  39. #
  40. sub GenerateCultureTable()
  41. {
  42. my $localeID;
  43. print "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
  44. print "<LOCALEDATA xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">\n";
  45. my @keys = (keys %gLocaleTable);
  46. @keys = sort SortLCID @keys;
  47. foreach $localeID (@keys)
  48. {
  49. # print "$localeID\n";
  50. GenerateCultureData($gLocaleTable{$localeID});
  51. }
  52. print "</LOCALEDATA>";
  53. }
  54. #
  55. # Show the command usage.
  56. #
  57. sub ShowUsage
  58. {
  59. print "NLPTrans.pl [the path to locale.txt] [the path to NeutralLocale.txt] [the path to LocaleEx.txt]";
  60. }
  61. #
  62. # Globals used:
  63. # $gLocaleTable
  64. #
  65. sub ParseLocaleFile
  66. {
  67. my ($fileName) = @_;
  68. my $gTotalLocales = 0;
  69. my $gTotalLocalesFound = 0;
  70. #
  71. # Reference to a hashtable which stores the locale informatin for this locale.
  72. #
  73. my $phLocaleData;
  74. my $isFirstLocale;
  75. my $localeID;
  76. my $refName;
  77. my $valueCount;
  78. my $i;
  79. if (!(open LOCALEFILE, $fileName))
  80. {
  81. print "Error in opening $ARGV[0]\n";
  82. exit 1;
  83. }
  84. #
  85. # Test if this is a LOCALE tag.
  86. # Match [Beginning of line] [Optional spaces] LOCALE [Spaces] [Digits]
  87. #
  88. while (<LOCALEFILE>)
  89. {
  90. if (/^\s*LOCALE\s+([0-9]+)/)
  91. {
  92. $gTotalLocales = $1;
  93. ### print "Total locales to be processed: $gTotalLocales\n";
  94. last;
  95. }
  96. }
  97. if ($gTotalLocales == 0)
  98. {
  99. print "ERROR: LOCALE tag is not found.";
  100. exit 1;
  101. }
  102. $isFirstLocale = 1;
  103. #
  104. # Find every BEGINLOCALE tag.
  105. #
  106. while (<LOCALEFILE>)
  107. {
  108. if (/^$/ || /^\s+$/)
  109. {
  110. #
  111. # Skip blank lines.
  112. #
  113. next;
  114. }
  115. #
  116. # Match [Beginning of line] [Optional spaces]BEGINLOCLAE [spaces] [alphanumeric chars] [spaces] ; [spaces] [Anything after]
  117. #
  118. elsif (/^\s*BEGINLOCALE\s+(\w+)\s+; (.*)/)
  119. {
  120. #
  121. # Find the BEGINLOCALE
  122. #
  123. $gTotalLocalesFound++;
  124. if ($isFirstLocale)
  125. {
  126. $isFirstLocale = 0;
  127. } else
  128. {
  129. #
  130. # Store the information found in this locale.
  131. #
  132. }
  133. $localeID = $1;
  134. $refName = $2;
  135. my $Win32LCID = $localeID;
  136. $phLocaleData = $gLocaleTable{$localeID};
  137. if (!defined($phLocaleData))
  138. {
  139. my %localeData;
  140. $gLocaleTable{$localeID} = $phLocaleData = \%localeData;
  141. $$phLocaleData{"WIN32LCID"} = $Win32LCID;
  142. # print "Create $localeID, $phLocaleData\n";
  143. }
  144. $$phLocaleData{"_RefName"} = $refName;
  145. } elsif (/ENDLOCALE/)
  146. {
  147. last;
  148. } elsif (/^\s*(\w+)\s+([0-9]+)\s+(\S.*)/)
  149. {
  150. my @multipleValues;
  151. # local @multipleValues;
  152. #
  153. # Match [Beginning of line] [Optional spaces] [alphanumeric chars] [spaces] [numbers] [spaces] [Non-space] [anything else]
  154. # This is the case with multiple values.
  155. #
  156. my $fieldName = $1;
  157. my $fieldCount = $2;
  158. my $fieldValue = $3;
  159. $valueCount = 0;
  160. $multipleValues[0] = $3;
  161. for ($i = 1; $i < $fieldCount; $i++)
  162. {
  163. $_ = <LOCALEFILE>;
  164. #if (!())
  165. #{
  166. # print "Out of data.\n";
  167. # exit 1;
  168. #}
  169. if (/^\s+(\S.*)/)
  170. {
  171. $fieldValue = $1;
  172. } else
  173. {
  174. print "Out of data.\n";
  175. exit 1;
  176. }
  177. $multipleValues[$i] = $fieldValue;
  178. }
  179. ($fieldName, $fieldValue) = CheckForMultipleValues($localeID, $fieldName, \@multipleValues);
  180. $$phLocaleData{$fieldName} = $fieldValue;
  181. } elsif (/^\s*(\w+)\s+(\S.*)/)
  182. {
  183. my $fieldName = $1;
  184. my $fieldValue = $2;
  185. ($fieldName, $fieldValue) = CheckForValue($fieldName, $fieldValue);
  186. # print "[$localeID] [$fieldName] [$fieldValue]\n";
  187. $$phLocaleData{$fieldName} = $fieldValue;
  188. } else
  189. {
  190. print "UNKNOWN: $_\n";
  191. }
  192. }
  193. if ($gTotalLocales != $gTotalLocalesFound)
  194. {
  195. print "ERROR: The number of locales is not correct.\n";
  196. print " BEGINLOCALE expected: $gTotalLocales.\n";
  197. print " BEGINLOCALE found: $gTotalLocalesFound.\n";
  198. exit 1;
  199. }
  200. close LOCALEFILE;
  201. }
  202. sub GenerateCultureData
  203. {
  204. my ($localeDataRef) = @_;
  205. my $refName = $$localeDataRef{"_RefName"};
  206. print " <LOCALE ID=\"" . $$localeDataRef{"ILANGUAGE"}. "\" RefName=\"" . $refName . "\" version=\"nlsplus1.0\">\n";
  207. PrintElement(2, "ILANGUAGE", GetHashData($localeDataRef, "ILANGUAGE"));
  208. PrintElement(2, "IPARENT", GetHashData($localeDataRef, "IPARENT")); # NLS+
  209. PrintElement(2, "WIN32LCID", GetHashData($localeDataRef, "WIN32LCID"));
  210. PrintElement(2, "SNAME", GetHashData($localeDataRef, "SNAME")); # NLS+
  211. PrintElement(2, "SENGLANGUAGE", GetHashData($localeDataRef, "SENGLANGUAGE"));
  212. PrintElement(2, "SABBREVLANGNAME", GetHashData($localeDataRef, "SABBREVLANGNAME"));
  213. PrintElement(2, "SISO639LANGNAME", GetHashData($localeDataRef, "SISO639LANGNAME"));
  214. PrintElement(2, "SISO639LANGNAME2", GetHashData($localeDataRef, "SISO639LANGNAME2")); # NLS+
  215. PrintElement(2, "SNATIVELANGNAME", GetHashData($localeDataRef, "SNATIVELANGNAME"));
  216. PrintElement(2, "IDEFAULTANSICODEPAGE", GetHashData($localeDataRef, "IDEFAULTANSICODEPAGE"));
  217. PrintElement(2, "IDEFAULTOEMCODEPAGE", GetHashData($localeDataRef, "IDEFAULTOEMCODEPAGE"));
  218. PrintElement(2, "IDEFAULTMACCODEPAGE", GetHashData($localeDataRef, "IDEFAULTMACCODEPAGE"));
  219. PrintElement(2, "IDEFAULTEBCDICCODEPAGE", GetHashData($localeDataRef, "IDEFAULTEBCDICCODEPAGE"));
  220. PrintElement(2, "SLIST", GetHashData($localeDataRef, "SLIST"));
  221. PrintElement(2, "SDECIMAL", GetHashData($localeDataRef, "SDECIMAL"));
  222. PrintElement(2, "STHOUSAND", GetHashData($localeDataRef, "STHOUSAND"));
  223. PrintElement(2, "SGROUPING", GetHashData($localeDataRef, "SGROUPING"));
  224. PrintElement(2, "IDIGITS", GetHashData($localeDataRef, "IDIGITS"));
  225. PrintElement(2, "INEGNUMBER", GetHashData($localeDataRef, "INEGNUMBER"));
  226. PrintElement(2, "SCURRENCY", GetHashData($localeDataRef, "SCURRENCY"));
  227. PrintElement(2, "SMONDECIMALSEP", GetHashData($localeDataRef, "SMONDECIMALSEP"));
  228. PrintElement(2, "SMONTHOUSANDSEP", GetHashData($localeDataRef, "SMONTHOUSANDSEP"));
  229. PrintElement(2, "SMONGROUPING", GetHashData($localeDataRef, "SMONGROUPING"));
  230. PrintElement(2, "ICURRDIGITS", GetHashData($localeDataRef, "ICURRDIGITS"));
  231. PrintElement(2, "ICURRENCY", GetHashData($localeDataRef, "ICURRENCY"));
  232. PrintElement(2, "INEGCURR", GetHashData($localeDataRef, "INEGCURR"));
  233. PrintElement(2, "SPOSITIVESIGN", GetHashData($localeDataRef, "SPOSITIVESIGN"));
  234. PrintElement(2, "SNEGATIVESIGN", GetHashData($localeDataRef, "SNEGATIVESIGN"));
  235. PrintElement(2, "INEGATIVEPERCENT", GetHashData($localeDataRef, "INEGATIVEPERCENT")); # NLS+
  236. PrintElement(2, "IPOSITIVEPERCENT", GetHashData($localeDataRef, "IPOSITIVEPERCENT")); # NLS+
  237. PrintElement(2, "SPERCENT", GetHashData($localeDataRef, "SPERCENT")); # NLS+
  238. PrintElement(2, "SNAN", GetHashData($localeDataRef, "SNAN")); # NLS+
  239. PrintElement(2, "SPOSINFINITY", GetHashData($localeDataRef, "SPOSINFINITY")); # NLS+
  240. PrintElement(2, "SNEGINFINITY", GetHashData($localeDataRef, "SNEGINFINITY")); # NLS+
  241. PrintElementMultipleValues(2, "STIMEFORMAT", GetHashData($localeDataRef, "STIMEFORMAT"));
  242. PrintElementMultipleValues(2, "SSHORTTIME", GetHashData($localeDataRef, "SSHORTTIME")); # NLS+
  243. PrintElement(2, "STIME", GetHashData($localeDataRef, "STIME"));
  244. PrintElement(2, "S1159", GetHashData($localeDataRef, "S1159"));
  245. PrintElement(2, "S2359", GetHashData($localeDataRef, "S2359"));
  246. PrintElementMultipleValues(2, "SSHORTDATE", GetHashData($localeDataRef, "SSHORTDATE"));
  247. PrintElement(2, "SDATE", GetHashData($localeDataRef, "SDATE"));
  248. PrintElementMultipleValues(2, "SYEARMONTH", GetHashData($localeDataRef, "SYEARMONTH"));
  249. PrintElementMultipleValues(2, "SLONGDATE", GetHashData($localeDataRef, "SLONGDATE"));
  250. PrintElement(2, "SMONTHDAY", GetHashData($localeDataRef, "SMONTHDAY")); # NLS+
  251. PrintElement(2, "ICALENDARTYPE", GetHashData($localeDataRef, "ICALENDARTYPE"));
  252. PrintElement(2, "IOPTIONALCALENDAR", GetHashData($localeDataRef, "IOPTIONALCALENDAR"));
  253. PrintElement(2, "IFIRSTDAYOFWEEK", GetHashData($localeDataRef, "IFIRSTDAYOFWEEK"));
  254. PrintElement(2, "IFIRSTWEEKOFYEAR", GetHashData($localeDataRef, "IFIRSTWEEKOFYEAR"));
  255. PrintMultipleElements(2, "SDAYNAME", $localeDataRef, "SDAYNAME", 1, 7);
  256. PrintMultipleElements(2, "SABBREVDAYNAME", $localeDataRef, "SABBREVDAYNAME", 1, 7);
  257. PrintMultipleElements(2, "SMONTHNAME", $localeDataRef, "SMONTHNAME", 1, 13);
  258. PrintMultipleElements(2, "SABBREVMONTHNAME", $localeDataRef, "SABBREVMONTHNAME", 1, 13);
  259. my $engDisplayName;
  260. if (defined($localeDataRef->{"SENGCOUNTRY"}))
  261. {
  262. $engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE") . " (" . GetHashData($localeDataRef, "SENGCOUNTRY") . ")";
  263. } else
  264. {
  265. #
  266. # Specail case for zh-CHT/zh-CHS.
  267. #
  268. if ($localeDataRef->{"ILANGUAGE"} eq "0004")
  269. {
  270. $engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE") . " (Simplified)";
  271. } elsif ($localeDataRef->{"ILANGUAGE"} eq "7c04")
  272. {
  273. $engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE") . " (Traditional)";
  274. } else
  275. {
  276. $engDisplayName = GetHashData($localeDataRef, "SENGLANGUAGE");
  277. }
  278. }
  279. PrintElement(2, "SENGDISPLAYNAME", $engDisplayName); # NLS+
  280. my $nativeDisplayName;
  281. if (defined($localeDataRef->{"SNATIVECTRYNAME"}))
  282. {
  283. $nativeDisplayName = GetHashData($localeDataRef, "SNATIVELANGNAME") . " (" . GetHashData($localeDataRef, "SNATIVECTRYNAME") . ")";
  284. } else
  285. {
  286. $nativeDisplayName = GetHashData($localeDataRef, "SNATIVELANGNAME");
  287. }
  288. PrintElement(2, "SNATIVEDISPLAYNAME", $nativeDisplayName);# NLS+
  289. print " </LOCALE>\n";
  290. #foreach $fieldName (keys %localeData)
  291. #{
  292. # # print "$fieldName\n";
  293. #}
  294. }
  295. sub GetHashData
  296. {
  297. my ($phHash, $key) = @_;
  298. my $result = $phHash->{$key};
  299. if (!defined($result))
  300. {
  301. print "Data not found for [$key]\n";
  302. exit 1;
  303. }
  304. return ($result);
  305. }
  306. sub PrintElement
  307. {
  308. my ($indentLevel, $tagName, $content) = @_;
  309. PrintIndent($indentLevel);
  310. print "<$tagName>$content</$tagName>\n";
  311. }
  312. sub PrintIndent
  313. {
  314. my ($indentLevel) = @_;
  315. my $i;
  316. for ($i = 0; $i < $indentLevel; $i++)
  317. {
  318. print " ";
  319. }
  320. }
  321. sub PrintElementMultipleValues
  322. {
  323. my ($indentLevel, $tagName, $arrayRef) = @_;
  324. my $i;
  325. PrintIndent($indentLevel);
  326. print "<$tagName>\n";
  327. PrintIndent($indentLevel + 1);
  328. print "<DefaultValue>" . $$arrayRef[0] . "</DefaultValue>\n";
  329. for ($i = 1; $i <= $#{$arrayRef}; $i++)
  330. {
  331. PrintIndent($indentLevel + 1);
  332. print "<OptionValue>" . $$arrayRef[$i] . "</OptionValue>\n";
  333. }
  334. PrintIndent($indentLevel);
  335. print "</$tagName>\n";
  336. }
  337. sub PrintMultipleElements
  338. {
  339. my ($indentLevel, $tagPrefix, $hashRef, $nlsTagPrefix, $fromRange, $toRange) = @_;
  340. my $i;
  341. my $tagName;
  342. my $nlsTagName;
  343. for ($i = $fromRange; $i <= $toRange; $i++)
  344. {
  345. $tagName = $tagPrefix . $i;
  346. $nlsTagName = $nlsTagPrefix . $i;
  347. PrintElement($indentLevel, $tagName, $$hashRef{$nlsTagName});
  348. }
  349. }
  350. sub CheckForValue
  351. {
  352. my ($fieldName, $fieldValue) = @_;
  353. if ($fieldName eq "SGROUPING")
  354. {
  355. $fieldValue = ConvertGrouping($fieldValue);
  356. } elsif ($fieldName eq "SMONGROUPING")
  357. {
  358. $fieldValue = ConvertGrouping($fieldValue);
  359. } elsif ($fieldName eq "SPOSITIVESIGN")
  360. {
  361. if ($fieldValue eq "\\x0000" || $fieldValue eq "\\X0000")
  362. {
  363. $fieldValue = "+";
  364. }
  365. } elsif ($fieldName eq "IOPTIONALCALENDAR")
  366. {
  367. $fieldValue = ConvertCalendars($fieldValue);
  368. } elsif ($fieldName eq "IFIRSTDAYOFWEEK")
  369. {
  370. $fieldValue = ConvertWeekday($fieldValue);
  371. } elsif ($fieldName =~ /SDAYNAME([0-9]+)/)
  372. {
  373. my $day = $1;
  374. if ($day == 7)
  375. {
  376. $day = 1;
  377. } else
  378. {
  379. $day++;
  380. }
  381. $fieldName = "SDAYNAME" . $day;
  382. } elsif ($fieldName =~ /SABBREVDAYNAME([0-9]+)/)
  383. {
  384. my $day = $1;
  385. if ($day == 7)
  386. {
  387. $day = 1;
  388. } else
  389. {
  390. $day++;
  391. }
  392. $fieldName = "SABBREVDAYNAME" . $day;
  393. }
  394. return ($fieldName, $fieldValue);
  395. }
  396. sub ConvertGrouping
  397. {
  398. my ($groupStr) = @_;
  399. if ($groupStr eq "3;0")
  400. {
  401. $groupStr = "3";
  402. } elsif ($groupStr eq "0;0")
  403. {
  404. $groupStr = "0";
  405. } elsif ($groupStr eq "3;2;0")
  406. {
  407. $groupStr = "3;2";
  408. } elsif ($groupStr eq "3")
  409. {
  410. $groupStr = "3;0";
  411. } else
  412. {
  413. print "ERROR: Don't know how to convert grouping string: [$groupStr].\n";
  414. exit(1);
  415. }
  416. return ($groupStr);
  417. }
  418. #
  419. # Convert NLS weekday to NLS+ weekday
  420. # NLS: 0=Mon, 1=Tue, 2=Wed, 3=Thu, 4=Fri, 5=Sat, 6=Sun
  421. # NLS+: 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat
  422. #
  423. sub ConvertWeekday
  424. {
  425. my ($weekday) = @_;
  426. if ($weekday == 6)
  427. {
  428. $weekday = 0;
  429. } elsif ($weekday >= 0 && $weekday <= 5)
  430. {
  431. $weekday++;
  432. } else
  433. {
  434. print "ERROR: Incorrect NLS weekday value: [$weekday].\n";
  435. exit(1);
  436. }
  437. return ($weekday);
  438. }
  439. sub CheckForMultipleValues
  440. {
  441. my ($localeID, $fieldName, $pMultipleValues) = @_;
  442. my $fieldValue = $pMultipleValues;
  443. if ($fieldName eq "IOPTIONALCALENDAR")
  444. {
  445. $fieldValue = ConvertCalendars($localeID, $pMultipleValues);
  446. }
  447. return ($fieldName, $fieldValue) ;
  448. }
  449. #
  450. # Convert NLS IOPTIONALCALENDAR values to NLS+ values.
  451. #
  452. sub ConvertCalendars
  453. {
  454. my ($localeID, $pArrayRef) = @_;
  455. my $result = "";
  456. my $i;
  457. my $calID;
  458. my $hasCalendar = 0;
  459. for ($i = 0; $i <= $#{$pArrayRef}; $i++)
  460. {
  461. #
  462. # Match [Numbers] [\xffff] [anything else]
  463. #
  464. if ($$pArrayRef[$i] =~ /([0-9]+)\\xffff.*/i)
  465. {
  466. $calID = $1;
  467. #
  468. # If the $calID is zero, we can skip it.
  469. #
  470. if ($calID >= 1)
  471. {
  472. if ($hasCalendar)
  473. {
  474. $result = $result . ";";
  475. }
  476. $result = $result . $calID;
  477. $hasCalendar = 1;
  478. }
  479. }
  480. }
  481. if ($localeID =~ /[0-9][0-9]09/)
  482. {
  483. # if this is an English locale, and calendar is
  484. # Gregorian (localized), Add Greogrian (US English) as well.
  485. if ($result eq "1")
  486. {
  487. $result = "1;2";
  488. }
  489. } elsif ($localeID eq "0404")
  490. {
  491. # In the case of Taiwan, add TaiwanCalendar
  492. # 1 = Gregorian (Localized)
  493. # 2 = Gregorian (USEnglish)
  494. # 4 = Taiwan
  495. $result = "1;2;4";
  496. }
  497. return ($result);
  498. }