@@ -714,12 +714,41 @@ cache_locale_time(void)
714714
715715#if defined(WIN32 )&& defined(LC_MESSAGES )
716716/*
717- *Convert Windows locale name to the ISO formatted one
718- *if possible.
717+ * Convert a Windows setlocale() argument to a Unix-style one.
719718 *
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
723752 */
724753static char *
725754IsoLocaleName (const char * winlocname )
@@ -738,6 +767,34 @@ IsoLocaleName(const char *winlocname)
738767loct = _create_locale (LC_CTYPE ,winlocname );
739768if (loct != NULL )
740769{
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
741798char isolang [32 ],
742799isocrty [32 ];
743800LCID lcid ;
@@ -752,6 +809,7 @@ IsoLocaleName(const char *winlocname)
752809if (!GetLocaleInfoA (lcid ,LOCALE_SISO3166CTRYNAME ,isocrty ,sizeof (isocrty )))
753810return NULL ;
754811snprintf (iso_lc_messages ,sizeof (iso_lc_messages )- 1 ,"%s_%s" ,isolang ,isocrty );
812+ #endif
755813return iso_lc_messages ;
756814}
757815return NULL ;