@@ -714,12 +714,41 @@ cache_locale_time(void)
714
714
715
715
#if defined(WIN32 ) && defined(LC_MESSAGES )
716
716
/*
717
- * Convert Windows locale name to the ISO formatted one
718
- * if possible.
717
+ * Convert a Windows setlocale() argument to a Unix-style one.
719
718
*
720
- * This function returns NULL if conversion is impossible,
721
- * otherwise returns the pointer to a static area which
722
- * contains the iso formatted locale name.
719
+ * Regardless of platform, we install message catalogs under a Unix-style
720
+ * LL[_CC][.ENCODING][@VARIANT] naming convention. Only LC_MESSAGES settings
721
+ * following that style will elicit localized interface strings.
722
+ *
723
+ * Before Visual Studio 2012 (msvcr110.dll), Windows setlocale() accepted "C"
724
+ * (but not "c") and strings of the form <Language>[_<Country>][.<CodePage>],
725
+ * case-insensitive. setlocale() returns the fully-qualified form; for
726
+ * example, setlocale("thaI") returns "Thai_Thailand.874". Internally,
727
+ * setlocale() and _create_locale() select a "locale identifier"[1] and store
728
+ * it in an undocumented _locale_t field. From that LCID, we can retrieve the
729
+ * ISO 639 language and the ISO 3166 country. Character encoding does not
730
+ * matter, because the server and client encodings govern that.
731
+ *
732
+ * Windows Vista introduced the "locale name" concept[2], closely following
733
+ * RFC 4646. Locale identifiers are now deprecated. Starting with Visual
734
+ * Studio 2012, setlocale() accepts locale names in addition to the strings it
735
+ * accepted historically. It does not standardize them; setlocale("Th-tH")
736
+ * returns "Th-tH". setlocale(category, "") still returns a traditional
737
+ * string. Furthermore, msvcr110.dll changed the undocumented _locale_t
738
+ * content to carry locale names instead of locale identifiers.
739
+ *
740
+ * MinGW headers declare _create_locale(), but msvcrt.dll lacks that symbol.
741
+ * IsoLocaleName() always fails in a MinGW-built postgres.exe, so only
742
+ * Unix-style values of the lc_messages GUC can elicit localized messages. In
743
+ * particular, every lc_messages setting that initdb can select automatically
744
+ * will yield only C-locale messages. XXX This could be fixed by running the
745
+ * fully-qualified locale name through a lookup table.
746
+ *
747
+ * This function returns a pointer to a static buffer bearing the converted
748
+ * name or NULL if conversion fails.
749
+ *
750
+ * [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd373763.aspx
751
+ * [2] http://msdn.microsoft.com/en-us/library/windows/desktop/dd373814.aspx
723
752
*/
724
753
static char *
725
754
IsoLocaleName (const char * winlocname )
@@ -738,6 +767,34 @@ IsoLocaleName(const char *winlocname)
738
767
loct = _create_locale (LC_CTYPE , winlocname );
739
768
if (loct != NULL )
740
769
{
770
+ #if (_MSC_VER >= 1700 ) /* Visual Studio 2012 or later */
771
+ size_t rc ;
772
+ char * hyphen ;
773
+
774
+ /* Locale names use only ASCII, any conversion locale suffices. */
775
+ rc = wchar2char (iso_lc_messages , loct -> locinfo -> locale_name [LC_CTYPE ],
776
+ sizeof (iso_lc_messages ), NULL );
777
+ _free_locale (loct );
778
+ if (rc == -1 || rc == sizeof (iso_lc_messages ))
779
+ return NULL ;
780
+
781
+ /*
782
+ * Since the message catalogs sit on a case-insensitive filesystem, we
783
+ * need not standardize letter case here. So long as we do not ship
784
+ * message catalogs for which it would matter, we also need not
785
+ * translate the script/variant portion, e.g. uz-Cyrl-UZ to
786
+ * uz_UZ@cyrillic. Simply replace the hyphen with an underscore.
787
+ *
788
+ * Note that the locale name can be less-specific than the value we
789
+ * would derive under earlier Visual Studio releases. For example,
790
+ * French_France.1252 yields just "fr". This does not affect any of
791
+ * the country-specific message catalogs available as of this writing
792
+ * (pt_BR, zh_CN, zh_TW).
793
+ */
794
+ hyphen = strchr (iso_lc_messages , '-' );
795
+ if (hyphen )
796
+ * hyphen = '_' ;
797
+ #else
741
798
char isolang [32 ],
742
799
isocrty [32 ];
743
800
LCID lcid ;
@@ -752,6 +809,7 @@ IsoLocaleName(const char *winlocname)
752
809
if (!GetLocaleInfoA (lcid , LOCALE_SISO3166CTRYNAME , isocrty , sizeof (isocrty )))
753
810
return NULL ;
754
811
snprintf (iso_lc_messages , sizeof (iso_lc_messages ) - 1 , "%s_%s" , isolang , isocrty );
812
+ #endif
755
813
return iso_lc_messages ;
756
814
}
757
815
return NULL ;
0 commit comments