summary refs log tree commit diff stats
path: root/libotr/libgpg-error-1.42/src/w32-gettext.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgpg-error-1.42/src/w32-gettext.c')
-rw-r--r--libotr/libgpg-error-1.42/src/w32-gettext.c2016
1 files changed, 2016 insertions, 0 deletions
diff --git a/libotr/libgpg-error-1.42/src/w32-gettext.c b/libotr/libgpg-error-1.42/src/w32-gettext.c
new file mode 100644
index 0000000..7c4c9b0
--- /dev/null
+++ b/libotr/libgpg-error-1.42/src/w32-gettext.c
@@ -0,0 +1,2016 @@
+/* w32-gettext.h - A simple gettext implementation for Windows targets.
+   Copyright (C) 1995, 1996, 1997, 1999, 2005, 2007,
+                 2008, 2010 Free Software Foundation, Inc.
+
+   This file is part of libgpg-error.
+
+   libgpg-error is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libgpg-error is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#if !defined (_WIN32) && !defined (__CYGWIN32__)
+#  error This module may only be build for Windows or Cygwin32
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <stdint.h>
+#include <locale.h>
+#include <windows.h>
+
+#ifdef JNLIB_IN_JNLIB
+#include "libjnlib-config.h"
+#endif
+
+#ifndef jnlib_malloc
+# define jnlib_malloc(a)    malloc ((a))
+# define jnlib_calloc(a,b)  calloc ((a), (b))
+# define jnlib_free(a)      free ((a))
+# define jnlib_xstrdup(a)   not_used
+#endif /*!jnlib_malloc*/
+
+#include "init.h"
+#include "gpgrt-int.h"
+#include "protos.h"
+
+/* Override values initialized by gpgrt_w32_override_locale.  If NAME
+ * is not the empty string LANGID will be used.  */
+static struct
+{
+  unsigned short active;  /* If not zero this override is active. */
+  unsigned short langid;
+  char name[28];
+} override_locale;
+
+
+
+
+/* localname.c from gettext BEGIN.  */
+
+/* Determine the current selected locale.
+   Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library General Public License as published
+   by the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+/* Written by Ulrich Drepper <drepper@gnu.org>, 1995.  */
+/* Win32 code written by Tor Lillqvist <tml@iki.fi>.  */
+/* Renamed _nl_locale_name, removed unused args, removed include files,
+   non-W32 code and changed comments <wk@gnupg.org>.  */
+
+/* Mingw headers don't have latest language and sublanguage codes.  */
+#ifndef LANG_AFRIKAANS
+#define LANG_AFRIKAANS 0x36
+#endif
+#ifndef LANG_ALBANIAN
+#define LANG_ALBANIAN 0x1c
+#endif
+#ifndef LANG_AMHARIC
+#define LANG_AMHARIC 0x5e
+#endif
+#ifndef LANG_ARABIC
+#define LANG_ARABIC 0x01
+#endif
+#ifndef LANG_ARMENIAN
+#define LANG_ARMENIAN 0x2b
+#endif
+#ifndef LANG_ASSAMESE
+#define LANG_ASSAMESE 0x4d
+#endif
+#ifndef LANG_AZERI
+#define LANG_AZERI 0x2c
+#endif
+#ifndef LANG_BASQUE
+#define LANG_BASQUE 0x2d
+#endif
+#ifndef LANG_BELARUSIAN
+#define LANG_BELARUSIAN 0x23
+#endif
+#ifndef LANG_BENGALI
+#define LANG_BENGALI 0x45
+#endif
+#ifndef LANG_BURMESE
+#define LANG_BURMESE 0x55
+#endif
+#ifndef LANG_CAMBODIAN
+#define LANG_CAMBODIAN 0x53
+#endif
+#ifndef LANG_CATALAN
+#define LANG_CATALAN 0x03
+#endif
+#ifndef LANG_CHEROKEE
+#define LANG_CHEROKEE 0x5c
+#endif
+#ifndef LANG_DIVEHI
+#define LANG_DIVEHI 0x65
+#endif
+#ifndef LANG_EDO
+#define LANG_EDO 0x66
+#endif
+#ifndef LANG_ESTONIAN
+#define LANG_ESTONIAN 0x25
+#endif
+#ifndef LANG_FAEROESE
+#define LANG_FAEROESE 0x38
+#endif
+#ifndef LANG_FARSI
+#define LANG_FARSI 0x29
+#endif
+#ifndef LANG_FRISIAN
+#define LANG_FRISIAN 0x62
+#endif
+#ifndef LANG_FULFULDE
+#define LANG_FULFULDE 0x67
+#endif
+#ifndef LANG_GAELIC
+#define LANG_GAELIC 0x3c
+#endif
+#ifndef LANG_GALICIAN
+#define LANG_GALICIAN 0x56
+#endif
+#ifndef LANG_GEORGIAN
+#define LANG_GEORGIAN 0x37
+#endif
+#ifndef LANG_GUARANI
+#define LANG_GUARANI 0x74
+#endif
+#ifndef LANG_GUJARATI
+#define LANG_GUJARATI 0x47
+#endif
+#ifndef LANG_HAUSA
+#define LANG_HAUSA 0x68
+#endif
+#ifndef LANG_HAWAIIAN
+#define LANG_HAWAIIAN 0x75
+#endif
+#ifndef LANG_HEBREW
+#define LANG_HEBREW 0x0d
+#endif
+#ifndef LANG_HINDI
+#define LANG_HINDI 0x39
+#endif
+#ifndef LANG_IBIBIO
+#define LANG_IBIBIO 0x69
+#endif
+#ifndef LANG_IGBO
+#define LANG_IGBO 0x70
+#endif
+#ifndef LANG_INDONESIAN
+#define LANG_INDONESIAN 0x21
+#endif
+#ifndef LANG_INUKTITUT
+#define LANG_INUKTITUT 0x5d
+#endif
+#ifndef LANG_KANNADA
+#define LANG_KANNADA 0x4b
+#endif
+#ifndef LANG_KANURI
+#define LANG_KANURI 0x71
+#endif
+#ifndef LANG_KASHMIRI
+#define LANG_KASHMIRI 0x60
+#endif
+#ifndef LANG_KAZAK
+#define LANG_KAZAK 0x3f
+#endif
+#ifndef LANG_KONKANI
+#define LANG_KONKANI 0x57
+#endif
+#ifndef LANG_KYRGYZ
+#define LANG_KYRGYZ 0x40
+#endif
+#ifndef LANG_LAO
+#define LANG_LAO 0x54
+#endif
+#ifndef LANG_LATIN
+#define LANG_LATIN 0x76
+#endif
+#ifndef LANG_LATVIAN
+#define LANG_LATVIAN 0x26
+#endif
+#ifndef LANG_LITHUANIAN
+#define LANG_LITHUANIAN 0x27
+#endif
+#ifndef LANG_MACEDONIAN
+#define LANG_MACEDONIAN 0x2f
+#endif
+#ifndef LANG_MALAY
+#define LANG_MALAY 0x3e
+#endif
+#ifndef LANG_MALAYALAM
+#define LANG_MALAYALAM 0x4c
+#endif
+#ifndef LANG_MALTESE
+#define LANG_MALTESE 0x3a
+#endif
+#ifndef LANG_MANIPURI
+#define LANG_MANIPURI 0x58
+#endif
+#ifndef LANG_MARATHI
+#define LANG_MARATHI 0x4e
+#endif
+#ifndef LANG_MONGOLIAN
+#define LANG_MONGOLIAN 0x50
+#endif
+#ifndef LANG_NEPALI
+#define LANG_NEPALI 0x61
+#endif
+#ifndef LANG_ORIYA
+#define LANG_ORIYA 0x48
+#endif
+#ifndef LANG_OROMO
+#define LANG_OROMO 0x72
+#endif
+#ifndef LANG_PAPIAMENTU
+#define LANG_PAPIAMENTU 0x79
+#endif
+#ifndef LANG_PASHTO
+#define LANG_PASHTO 0x63
+#endif
+#ifndef LANG_PUNJABI
+#define LANG_PUNJABI 0x46
+#endif
+#ifndef LANG_RHAETO_ROMANCE
+#define LANG_RHAETO_ROMANCE 0x17
+#endif
+#ifndef LANG_SAAMI
+#define LANG_SAAMI 0x3b
+#endif
+#ifndef LANG_SANSKRIT
+#define LANG_SANSKRIT 0x4f
+#endif
+#ifndef LANG_SERBIAN
+#define LANG_SERBIAN 0x1a
+#endif
+#ifndef LANG_SINDHI
+#define LANG_SINDHI 0x59
+#endif
+#ifndef LANG_SINHALESE
+#define LANG_SINHALESE 0x5b
+#endif
+#ifndef LANG_SLOVAK
+#define LANG_SLOVAK 0x1b
+#endif
+#ifndef LANG_SOMALI
+#define LANG_SOMALI 0x77
+#endif
+#ifndef LANG_SORBIAN
+#define LANG_SORBIAN 0x2e
+#endif
+#ifndef LANG_SUTU
+#define LANG_SUTU 0x30
+#endif
+#ifndef LANG_SWAHILI
+#define LANG_SWAHILI 0x41
+#endif
+#ifndef LANG_SYRIAC
+#define LANG_SYRIAC 0x5a
+#endif
+#ifndef LANG_TAGALOG
+#define LANG_TAGALOG 0x64
+#endif
+#ifndef LANG_TAJIK
+#define LANG_TAJIK 0x28
+#endif
+#ifndef LANG_TAMAZIGHT
+#define LANG_TAMAZIGHT 0x5f
+#endif
+#ifndef LANG_TAMIL
+#define LANG_TAMIL 0x49
+#endif
+#ifndef LANG_TATAR
+#define LANG_TATAR 0x44
+#endif
+#ifndef LANG_TELUGU
+#define LANG_TELUGU 0x4a
+#endif
+#ifndef LANG_THAI
+#define LANG_THAI 0x1e
+#endif
+#ifndef LANG_TIBETAN
+#define LANG_TIBETAN 0x51
+#endif
+#ifndef LANG_TIGRINYA
+#define LANG_TIGRINYA 0x73
+#endif
+#ifndef LANG_TSONGA
+#define LANG_TSONGA 0x31
+#endif
+#ifndef LANG_TSWANA
+#define LANG_TSWANA 0x32
+#endif
+#ifndef LANG_TURKMEN
+#define LANG_TURKMEN 0x42
+#endif
+#ifndef LANG_UKRAINIAN
+#define LANG_UKRAINIAN 0x22
+#endif
+#ifndef LANG_URDU
+#define LANG_URDU 0x20
+#endif
+#ifndef LANG_UZBEK
+#define LANG_UZBEK 0x43
+#endif
+#ifndef LANG_VENDA
+#define LANG_VENDA 0x33
+#endif
+#ifndef LANG_VIETNAMESE
+#define LANG_VIETNAMESE 0x2a
+#endif
+#ifndef LANG_WELSH
+#define LANG_WELSH 0x52
+#endif
+#ifndef LANG_XHOSA
+#define LANG_XHOSA 0x34
+#endif
+#ifndef LANG_YI
+#define LANG_YI 0x78
+#endif
+#ifndef LANG_YIDDISH
+#define LANG_YIDDISH 0x3d
+#endif
+#ifndef LANG_YORUBA
+#define LANG_YORUBA 0x6a
+#endif
+#ifndef LANG_ZULU
+#define LANG_ZULU 0x35
+#endif
+#ifndef SUBLANG_ARABIC_SAUDI_ARABIA
+#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
+#endif
+#ifndef SUBLANG_ARABIC_IRAQ
+#define SUBLANG_ARABIC_IRAQ 0x02
+#endif
+#ifndef SUBLANG_ARABIC_EGYPT
+#define SUBLANG_ARABIC_EGYPT 0x03
+#endif
+#ifndef SUBLANG_ARABIC_LIBYA
+#define SUBLANG_ARABIC_LIBYA 0x04
+#endif
+#ifndef SUBLANG_ARABIC_ALGERIA
+#define SUBLANG_ARABIC_ALGERIA 0x05
+#endif
+#ifndef SUBLANG_ARABIC_MOROCCO
+#define SUBLANG_ARABIC_MOROCCO 0x06
+#endif
+#ifndef SUBLANG_ARABIC_TUNISIA
+#define SUBLANG_ARABIC_TUNISIA 0x07
+#endif
+#ifndef SUBLANG_ARABIC_OMAN
+#define SUBLANG_ARABIC_OMAN 0x08
+#endif
+#ifndef SUBLANG_ARABIC_YEMEN
+#define SUBLANG_ARABIC_YEMEN 0x09
+#endif
+#ifndef SUBLANG_ARABIC_SYRIA
+#define SUBLANG_ARABIC_SYRIA 0x0a
+#endif
+#ifndef SUBLANG_ARABIC_JORDAN
+#define SUBLANG_ARABIC_JORDAN 0x0b
+#endif
+#ifndef SUBLANG_ARABIC_LEBANON
+#define SUBLANG_ARABIC_LEBANON 0x0c
+#endif
+#ifndef SUBLANG_ARABIC_KUWAIT
+#define SUBLANG_ARABIC_KUWAIT 0x0d
+#endif
+#ifndef SUBLANG_ARABIC_UAE
+#define SUBLANG_ARABIC_UAE 0x0e
+#endif
+#ifndef SUBLANG_ARABIC_BAHRAIN
+#define SUBLANG_ARABIC_BAHRAIN 0x0f
+#endif
+#ifndef SUBLANG_ARABIC_QATAR
+#define SUBLANG_ARABIC_QATAR 0x10
+#endif
+#ifndef SUBLANG_AZERI_LATIN
+#define SUBLANG_AZERI_LATIN 0x01
+#endif
+#ifndef SUBLANG_AZERI_CYRILLIC
+#define SUBLANG_AZERI_CYRILLIC 0x02
+#endif
+#ifndef SUBLANG_BENGALI_INDIA
+#define SUBLANG_BENGALI_INDIA 0x01
+#endif
+#ifndef SUBLANG_BENGALI_BANGLADESH
+#define SUBLANG_BENGALI_BANGLADESH 0x02
+#endif
+#ifndef SUBLANG_CHINESE_MACAU
+#define SUBLANG_CHINESE_MACAU 0x05
+#endif
+#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
+#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
+#endif
+#ifndef SUBLANG_ENGLISH_JAMAICA
+#define SUBLANG_ENGLISH_JAMAICA 0x08
+#endif
+#ifndef SUBLANG_ENGLISH_CARIBBEAN
+#define SUBLANG_ENGLISH_CARIBBEAN 0x09
+#endif
+#ifndef SUBLANG_ENGLISH_BELIZE
+#define SUBLANG_ENGLISH_BELIZE 0x0a
+#endif
+#ifndef SUBLANG_ENGLISH_TRINIDAD
+#define SUBLANG_ENGLISH_TRINIDAD 0x0b
+#endif
+#ifndef SUBLANG_ENGLISH_ZIMBABWE
+#define SUBLANG_ENGLISH_ZIMBABWE 0x0c
+#endif
+#ifndef SUBLANG_ENGLISH_PHILIPPINES
+#define SUBLANG_ENGLISH_PHILIPPINES 0x0d
+#endif
+#ifndef SUBLANG_ENGLISH_INDONESIA
+#define SUBLANG_ENGLISH_INDONESIA 0x0e
+#endif
+#ifndef SUBLANG_ENGLISH_HONGKONG
+#define SUBLANG_ENGLISH_HONGKONG 0x0f
+#endif
+#ifndef SUBLANG_ENGLISH_INDIA
+#define SUBLANG_ENGLISH_INDIA 0x10
+#endif
+#ifndef SUBLANG_ENGLISH_MALAYSIA
+#define SUBLANG_ENGLISH_MALAYSIA 0x11
+#endif
+#ifndef SUBLANG_ENGLISH_SINGAPORE
+#define SUBLANG_ENGLISH_SINGAPORE 0x12
+#endif
+#ifndef SUBLANG_FRENCH_LUXEMBOURG
+#define SUBLANG_FRENCH_LUXEMBOURG 0x05
+#endif
+#ifndef SUBLANG_FRENCH_MONACO
+#define SUBLANG_FRENCH_MONACO 0x06
+#endif
+#ifndef SUBLANG_FRENCH_WESTINDIES
+#define SUBLANG_FRENCH_WESTINDIES 0x07
+#endif
+#ifndef SUBLANG_FRENCH_REUNION
+#define SUBLANG_FRENCH_REUNION 0x08
+#endif
+#ifndef SUBLANG_FRENCH_CONGO
+#define SUBLANG_FRENCH_CONGO 0x09
+#endif
+#ifndef SUBLANG_FRENCH_SENEGAL
+#define SUBLANG_FRENCH_SENEGAL 0x0a
+#endif
+#ifndef SUBLANG_FRENCH_CAMEROON
+#define SUBLANG_FRENCH_CAMEROON 0x0b
+#endif
+#ifndef SUBLANG_FRENCH_COTEDIVOIRE
+#define SUBLANG_FRENCH_COTEDIVOIRE 0x0c
+#endif
+#ifndef SUBLANG_FRENCH_MALI
+#define SUBLANG_FRENCH_MALI 0x0d
+#endif
+#ifndef SUBLANG_FRENCH_MOROCCO
+#define SUBLANG_FRENCH_MOROCCO 0x0e
+#endif
+#ifndef SUBLANG_FRENCH_HAITI
+#define SUBLANG_FRENCH_HAITI 0x0f
+#endif
+#ifndef SUBLANG_GERMAN_LUXEMBOURG
+#define SUBLANG_GERMAN_LUXEMBOURG 0x04
+#endif
+#ifndef SUBLANG_GERMAN_LIECHTENSTEIN
+#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
+#endif
+#ifndef SUBLANG_KASHMIRI_INDIA
+#define SUBLANG_KASHMIRI_INDIA 0x02
+#endif
+#ifndef SUBLANG_MALAY_MALAYSIA
+#define SUBLANG_MALAY_MALAYSIA 0x01
+#endif
+#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
+#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
+#endif
+#ifndef SUBLANG_NEPALI_INDIA
+#define SUBLANG_NEPALI_INDIA 0x02
+#endif
+#ifndef SUBLANG_PUNJABI_INDIA
+#define SUBLANG_PUNJABI_INDIA 0x01
+#endif
+#ifndef SUBLANG_ROMANIAN_ROMANIA
+#define SUBLANG_ROMANIAN_ROMANIA 0x01
+#endif
+#ifndef SUBLANG_SERBIAN_LATIN
+#define SUBLANG_SERBIAN_LATIN 0x02
+#endif
+#ifndef SUBLANG_SERBIAN_CYRILLIC
+#define SUBLANG_SERBIAN_CYRILLIC 0x03
+#endif
+#ifndef SUBLANG_SINDHI_INDIA
+#define SUBLANG_SINDHI_INDIA 0x00
+#endif
+#ifndef SUBLANG_SINDHI_PAKISTAN
+#define SUBLANG_SINDHI_PAKISTAN 0x01
+#endif
+#ifndef SUBLANG_SPANISH_GUATEMALA
+#define SUBLANG_SPANISH_GUATEMALA 0x04
+#endif
+#ifndef SUBLANG_SPANISH_COSTA_RICA
+#define SUBLANG_SPANISH_COSTA_RICA 0x05
+#endif
+#ifndef SUBLANG_SPANISH_PANAMA
+#define SUBLANG_SPANISH_PANAMA 0x06
+#endif
+#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
+#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
+#endif
+#ifndef SUBLANG_SPANISH_VENEZUELA
+#define SUBLANG_SPANISH_VENEZUELA 0x08
+#endif
+#ifndef SUBLANG_SPANISH_COLOMBIA
+#define SUBLANG_SPANISH_COLOMBIA 0x09
+#endif
+#ifndef SUBLANG_SPANISH_PERU
+#define SUBLANG_SPANISH_PERU 0x0a
+#endif
+#ifndef SUBLANG_SPANISH_ARGENTINA
+#define SUBLANG_SPANISH_ARGENTINA 0x0b
+#endif
+#ifndef SUBLANG_SPANISH_ECUADOR
+#define SUBLANG_SPANISH_ECUADOR 0x0c
+#endif
+#ifndef SUBLANG_SPANISH_CHILE
+#define SUBLANG_SPANISH_CHILE 0x0d
+#endif
+#ifndef SUBLANG_SPANISH_URUGUAY
+#define SUBLANG_SPANISH_URUGUAY 0x0e
+#endif
+#ifndef SUBLANG_SPANISH_PARAGUAY
+#define SUBLANG_SPANISH_PARAGUAY 0x0f
+#endif
+#ifndef SUBLANG_SPANISH_BOLIVIA
+#define SUBLANG_SPANISH_BOLIVIA 0x10
+#endif
+#ifndef SUBLANG_SPANISH_EL_SALVADOR
+#define SUBLANG_SPANISH_EL_SALVADOR 0x11
+#endif
+#ifndef SUBLANG_SPANISH_HONDURAS
+#define SUBLANG_SPANISH_HONDURAS 0x12
+#endif
+#ifndef SUBLANG_SPANISH_NICARAGUA
+#define SUBLANG_SPANISH_NICARAGUA 0x13
+#endif
+#ifndef SUBLANG_SPANISH_PUERTO_RICO
+#define SUBLANG_SPANISH_PUERTO_RICO 0x14
+#endif
+#ifndef SUBLANG_SWEDISH_FINLAND
+#define SUBLANG_SWEDISH_FINLAND 0x02
+#endif
+#ifndef SUBLANG_TAMAZIGHT_ARABIC
+#define SUBLANG_TAMAZIGHT_ARABIC 0x01
+#endif
+#ifndef SUBLANG_TAMAZIGHT_LATIN
+#define SUBLANG_TAMAZIGHT_LATIN 0x02
+#endif
+#ifndef SUBLANG_TIGRINYA_ETHIOPIA
+#define SUBLANG_TIGRINYA_ETHIOPIA 0x00
+#endif
+#ifndef SUBLANG_TIGRINYA_ERITREA
+#define SUBLANG_TIGRINYA_ERITREA 0x01
+#endif
+#ifndef SUBLANG_URDU_PAKISTAN
+#define SUBLANG_URDU_PAKISTAN 0x01
+#endif
+#ifndef SUBLANG_URDU_INDIA
+#define SUBLANG_URDU_INDIA 0x02
+#endif
+#ifndef SUBLANG_UZBEK_LATIN
+#define SUBLANG_UZBEK_LATIN 0x01
+#endif
+#ifndef SUBLANG_UZBEK_CYRILLIC
+#define SUBLANG_UZBEK_CYRILLIC 0x02
+#endif
+
+/* Return an XPG style locale name
+     language[_territory[.codeset]][@modifier].
+   Don't even bother determining the codeset; it's not useful in this
+   context, because message catalogs are not specific to a single
+   codeset.  The result must not be freed; it is statically
+   allocated.  */
+static const char *
+my_nl_locale_name (const char *categoryname)
+{
+  const char *retval;
+  LANGID langid;
+  int primary, sub;
+
+  if (override_locale.active)
+    {
+      if (*override_locale.name)
+        return override_locale.name;
+      langid = override_locale.langid;
+    }
+  else
+    {
+      LCID lcid;
+
+      /* Let the user override the system settings through environment
+       *  variables, as on POSIX systems.  */
+      retval = getenv ("LC_ALL");
+      if (retval != NULL && retval[0] != '\0')
+        return retval;
+      retval = getenv (categoryname);
+      if (retval != NULL && retval[0] != '\0')
+        return retval;
+      retval = getenv ("LANG");
+      if (retval != NULL && retval[0] != '\0')
+        return retval;
+
+      /* Use native Win32 API locale ID.  */
+      lcid = GetThreadLocale ();
+      /* Strip off the sorting rules, keep only the language part.  */
+      langid = LANGIDFROMLCID (lcid);
+    }
+
+  /* Split into language and territory part.  */
+  primary = PRIMARYLANGID (langid);
+  sub = SUBLANGID (langid);
+
+  /* Dispatch on language.
+     For details about languages, see https://www.ethnologue.com/ .  */
+  switch (primary)
+    {
+    case LANG_AFRIKAANS: return "af_ZA";
+    case LANG_ALBANIAN: return "sq_AL";
+    case LANG_AMHARIC: return "am_ET";
+    case LANG_ARABIC:
+      switch (sub)
+	{
+	case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
+	case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
+	case SUBLANG_ARABIC_EGYPT: return "ar_EG";
+	case SUBLANG_ARABIC_LIBYA: return "ar_LY";
+	case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
+	case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
+	case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
+	case SUBLANG_ARABIC_OMAN: return "ar_OM";
+	case SUBLANG_ARABIC_YEMEN: return "ar_YE";
+	case SUBLANG_ARABIC_SYRIA: return "ar_SY";
+	case SUBLANG_ARABIC_JORDAN: return "ar_JO";
+	case SUBLANG_ARABIC_LEBANON: return "ar_LB";
+	case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
+	case SUBLANG_ARABIC_UAE: return "ar_AE";
+	case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
+	case SUBLANG_ARABIC_QATAR: return "ar_QA";
+	}
+      return "ar";
+    case LANG_ARMENIAN: return "hy_AM";
+    case LANG_ASSAMESE: return "as_IN";
+    case LANG_AZERI:
+      switch (sub)
+	{
+	/* FIXME: Adjust this when Azerbaijani locales appear on Unix.  */
+	case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
+	case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
+	}
+      return "az";
+    case LANG_BASQUE:
+      return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR".  */
+    case LANG_BELARUSIAN: return "be_BY";
+    case LANG_BENGALI:
+      switch (sub)
+	{
+	case SUBLANG_BENGALI_INDIA: return "bn_IN";
+	case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
+	}
+      return "bn";
+    case LANG_BULGARIAN: return "bg_BG";
+    case LANG_BURMESE: return "my_MM";
+    case LANG_CAMBODIAN: return "km_KH";
+    case LANG_CATALAN: return "ca_ES";
+    case LANG_CHEROKEE: return "chr_US";
+    case LANG_CHINESE:
+      switch (sub)
+	{
+	case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
+	case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
+	case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
+	case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
+	case SUBLANG_CHINESE_MACAU: return "zh_MO";
+	}
+      return "zh";
+    case LANG_CROATIAN:		/* LANG_CROATIAN == LANG_SERBIAN
+				 * What used to be called Serbo-Croatian
+				 * should really now be two separate
+				 * languages because of political reasons.
+				 * (Says tml, who knows nothing about Serbian
+				 * or Croatian.)
+				 * (I can feel those flames coming already.)
+				 */
+      switch (sub)
+	{
+	case SUBLANG_DEFAULT: return "hr_HR";
+	case SUBLANG_SERBIAN_LATIN: return "sr_CS";
+	case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
+	}
+      return "hr";
+    case LANG_CZECH: return "cs_CZ";
+    case LANG_DANISH: return "da_DK";
+    case LANG_DIVEHI: return "div_MV";
+    case LANG_DUTCH:
+      switch (sub)
+	{
+	case SUBLANG_DUTCH: return "nl_NL";
+	case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
+	}
+      return "nl";
+    case LANG_EDO: return "bin_NG";
+    case LANG_ENGLISH:
+      switch (sub)
+	{
+	/* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
+	 * English was the language spoken in England.
+	 * Oh well.
+	 */
+	case SUBLANG_ENGLISH_US: return "en_US";
+	case SUBLANG_ENGLISH_UK: return "en_GB";
+	case SUBLANG_ENGLISH_AUS: return "en_AU";
+	case SUBLANG_ENGLISH_CAN: return "en_CA";
+	case SUBLANG_ENGLISH_NZ: return "en_NZ";
+	case SUBLANG_ENGLISH_EIRE: return "en_IE";
+	case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
+	case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
+	case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
+	case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
+	case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
+	case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
+	case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
+	case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
+	case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
+	case SUBLANG_ENGLISH_INDIA: return "en_IN";
+	case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
+	case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
+	}
+      return "en";
+    case LANG_ESTONIAN: return "et_EE";
+    case LANG_FAEROESE: return "fo_FO";
+    case LANG_FARSI: return "fa_IR";
+    case LANG_FINNISH: return "fi_FI";
+    case LANG_FRENCH:
+      switch (sub)
+	{
+	case SUBLANG_FRENCH: return "fr_FR";
+	case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
+	case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
+	case SUBLANG_FRENCH_SWISS: return "fr_CH";
+	case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
+	case SUBLANG_FRENCH_MONACO: return "fr_MC";
+	case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
+	case SUBLANG_FRENCH_REUNION: return "fr_RE";
+	case SUBLANG_FRENCH_CONGO: return "fr_CG";
+	case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
+	case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
+	case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
+	case SUBLANG_FRENCH_MALI: return "fr_ML";
+	case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
+	case SUBLANG_FRENCH_HAITI: return "fr_HT";
+	}
+      return "fr";
+    case LANG_FRISIAN: return "fy_NL";
+    case LANG_FULFULDE: return "ful_NG";
+    case LANG_GAELIC:
+      switch (sub)
+	{
+	case 0x01: /* SCOTTISH */ return "gd_GB";
+	case 0x02: /* IRISH */ return "ga_IE";
+	}
+      return "C";
+    case LANG_GALICIAN: return "gl_ES";
+    case LANG_GEORGIAN: return "ka_GE";
+    case LANG_GERMAN:
+      switch (sub)
+	{
+	case SUBLANG_GERMAN: return "de_DE";
+	case SUBLANG_GERMAN_SWISS: return "de_CH";
+	case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
+	case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
+	case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
+	}
+      return "de";
+    case LANG_GREEK: return "el_GR";
+    case LANG_GUARANI: return "gn_PY";
+    case LANG_GUJARATI: return "gu_IN";
+    case LANG_HAUSA: return "ha_NG";
+    case LANG_HAWAIIAN:
+      /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
+	 or Hawaii Creole English ("cpe_US", 600000 speakers)?  */
+      return "cpe_US";
+    case LANG_HEBREW: return "he_IL";
+    case LANG_HINDI: return "hi_IN";
+    case LANG_HUNGARIAN: return "hu_HU";
+    case LANG_IBIBIO: return "nic_NG";
+    case LANG_ICELANDIC: return "is_IS";
+    case LANG_IGBO: return "ibo_NG";
+    case LANG_INDONESIAN: return "id_ID";
+    case LANG_INUKTITUT: return "iu_CA";
+    case LANG_ITALIAN:
+      switch (sub)
+	{
+	case SUBLANG_ITALIAN: return "it_IT";
+	case SUBLANG_ITALIAN_SWISS: return "it_CH";
+	}
+      return "it";
+    case LANG_JAPANESE: return "ja_JP";
+    case LANG_KANNADA: return "kn_IN";
+    case LANG_KANURI: return "kau_NG";
+    case LANG_KASHMIRI:
+      switch (sub)
+	{
+	case SUBLANG_DEFAULT: return "ks_PK";
+	case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
+	}
+      return "ks";
+    case LANG_KAZAK: return "kk_KZ";
+    case LANG_KONKANI:
+      /* FIXME: Adjust this when such locales appear on Unix.  */
+      return "kok_IN";
+    case LANG_KOREAN: return "ko_KR";
+    case LANG_KYRGYZ: return "ky_KG";
+    case LANG_LAO: return "lo_LA";
+    case LANG_LATIN: return "la_VA";
+    case LANG_LATVIAN: return "lv_LV";
+    case LANG_LITHUANIAN: return "lt_LT";
+    case LANG_MACEDONIAN: return "mk_MK";
+    case LANG_MALAY:
+      switch (sub)
+	{
+	case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
+	case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
+	}
+      return "ms";
+    case LANG_MALAYALAM: return "ml_IN";
+    case LANG_MALTESE: return "mt_MT";
+    case LANG_MANIPURI:
+      /* FIXME: Adjust this when such locales appear on Unix.  */
+      return "mni_IN";
+    case LANG_MARATHI: return "mr_IN";
+    case LANG_MONGOLIAN:
+      return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN".  */
+    case LANG_NEPALI:
+      switch (sub)
+	{
+	case SUBLANG_DEFAULT: return "ne_NP";
+	case SUBLANG_NEPALI_INDIA: return "ne_IN";
+	}
+      return "ne";
+    case LANG_NORWEGIAN:
+      switch (sub)
+	{
+	case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO";
+	case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
+	}
+      return "no";
+    case LANG_ORIYA: return "or_IN";
+    case LANG_OROMO: return "om_ET";
+    case LANG_PAPIAMENTU: return "pap_AN";
+    case LANG_PASHTO:
+      return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF".  */
+    case LANG_POLISH: return "pl_PL";
+    case LANG_PORTUGUESE:
+      switch (sub)
+	{
+	case SUBLANG_PORTUGUESE: return "pt_PT";
+	/* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
+	   Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
+	case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
+	}
+      return "pt";
+    case LANG_PUNJABI:
+      switch (sub)
+	{
+	case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
+	}
+      return "pa";
+    case LANG_RHAETO_ROMANCE: return "rm_CH";
+    case LANG_ROMANIAN:
+      switch (sub)
+	{
+	case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
+	}
+      return "ro";
+    case LANG_RUSSIAN:
+      return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD".  */
+    case LANG_SAAMI: /* actually Northern Sami */ return "se_NO";
+    case LANG_SANSKRIT: return "sa_IN";
+    case LANG_SINDHI:
+      switch (sub)
+	{
+	case SUBLANG_SINDHI_INDIA: return "sd_IN";
+	case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
+	}
+      return "sd";
+    case LANG_SINHALESE: return "si_LK";
+    case LANG_SLOVAK: return "sk_SK";
+    case LANG_SLOVENIAN: return "sl_SI";
+    case LANG_SOMALI: return "so_SO";
+    case LANG_SORBIAN:
+      /* FIXME: Adjust this when such locales appear on Unix.  */
+      return "wen_DE";
+    case LANG_SPANISH:
+      switch (sub)
+	{
+	case SUBLANG_SPANISH: return "es_ES";
+	case SUBLANG_SPANISH_MEXICAN: return "es_MX";
+	case SUBLANG_SPANISH_MODERN:
+	  return "es_ES@modern";	/* not seen on Unix */
+	case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
+	case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
+	case SUBLANG_SPANISH_PANAMA: return "es_PA";
+	case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
+	case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
+	case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
+	case SUBLANG_SPANISH_PERU: return "es_PE";
+	case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
+	case SUBLANG_SPANISH_ECUADOR: return "es_EC";
+	case SUBLANG_SPANISH_CHILE: return "es_CL";
+	case SUBLANG_SPANISH_URUGUAY: return "es_UY";
+	case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
+	case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
+	case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
+	case SUBLANG_SPANISH_HONDURAS: return "es_HN";
+	case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
+	case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
+	}
+      return "es";
+    case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
+    case LANG_SWAHILI: return "sw_KE";
+    case LANG_SWEDISH:
+      switch (sub)
+	{
+	case SUBLANG_DEFAULT: return "sv_SE";
+	case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
+	}
+      return "sv";
+    case LANG_SYRIAC: return "syr_TR"; /* An extinct language.  */
+    case LANG_TAGALOG: return "tl_PH";
+    case LANG_TAJIK: return "tg_TJ";
+    case LANG_TAMAZIGHT:
+      switch (sub)
+	{
+	/* FIXME: Adjust this when Tamazight locales appear on Unix.  */
+	case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
+	case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin";
+	}
+      return "ber_MA";
+    case LANG_TAMIL:
+      return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG".  */
+    case LANG_TATAR: return "tt_RU";
+    case LANG_TELUGU: return "te_IN";
+    case LANG_THAI: return "th_TH";
+    case LANG_TIBETAN: return "bo_CN";
+    case LANG_TIGRINYA:
+      switch (sub)
+	{
+	case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
+	case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
+	}
+      return "ti";
+    case LANG_TSONGA: return "ts_ZA";
+    case LANG_TSWANA: return "tn_BW";
+    case LANG_TURKISH: return "tr_TR";
+    case LANG_TURKMEN: return "tk_TM";
+    case LANG_UKRAINIAN: return "uk_UA";
+    case LANG_URDU:
+      switch (sub)
+	{
+	case SUBLANG_URDU_PAKISTAN: return "ur_PK";
+	case SUBLANG_URDU_INDIA: return "ur_IN";
+	}
+      return "ur";
+    case LANG_UZBEK:
+      switch (sub)
+	{
+	case SUBLANG_UZBEK_LATIN: return "uz_UZ";
+	case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
+	}
+      return "uz";
+    case LANG_VENDA:
+      return "ve_ZA";
+    case LANG_VIETNAMESE: return "vi_VN";
+    case LANG_WELSH: return "cy_GB";
+    case LANG_XHOSA: return "xh_ZA";
+    case LANG_YI: return "sit_CN";
+    case LANG_YIDDISH: return "yi_IL";
+    case LANG_YORUBA: return "yo_NG";
+    case LANG_ZULU: return "zu_ZA";
+    default: return "C";
+    }
+}
+
+/* localname.c from gettext END.  */
+
+
+
+/* Support functions.  */
+
+static GPG_ERR_INLINE uint32_t
+do_swap_u32 (uint32_t i)
+{
+  return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+
+#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data))
+
+
+/* We assume to have `unsigned long int' value with at least 32 bits.  */
+#define HASHWORDBITS 32
+
+/* The so called `hashpjw' function by P.J. Weinberger
+   [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+   1986, 1987 Bell Telephone Laboratories, Inc.]  */
+static GPG_ERR_INLINE unsigned long
+hash_string (const char *str_param)
+{
+  unsigned long int hval, g;
+  const char *str = str_param;
+
+  hval = 0;
+  while (*str != '\0')
+    {
+      hval <<= 4;
+      hval += (unsigned long int) *str++;
+      g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
+      if (g != 0)
+	{
+	  hval ^= g >> (HASHWORDBITS - 8);
+	  hval ^= g;
+	}
+    }
+  return hval;
+}
+
+
+/* Generic message catalog and gettext stuff.  */
+
+/* The magic number of the GNU message catalog format.	*/
+#define MAGIC	      0x950412de
+#define MAGIC_SWAPPED 0xde120495
+
+/* Revision number of the currently used .mo (binary) file format.  */
+#define MO_REVISION_NUMBER 0
+
+
+/* Header for binary .mo file format.  */
+struct mo_file_header
+{
+  /* The magic number.	*/
+  uint32_t magic;
+  /* The revision number of the file format.  */
+  uint32_t revision;
+  /* The number of strings pairs.  */
+  uint32_t nstrings;
+  /* Offset of table with start offsets of original strings.  */
+  uint32_t orig_tab_offset;
+  /* Offset of table with start offsets of translation strings.  */
+  uint32_t trans_tab_offset;
+  /* Size of hashing table.  */
+  uint32_t hash_tab_size;
+  /* Offset of first hashing entry.  */
+  uint32_t hash_tab_offset;
+};
+
+
+struct string_desc
+{
+  /* Length of addressed string.  */
+  uint32_t length;
+  /* Offset of string in file.	*/
+  uint32_t offset;
+};
+
+
+struct overflow_space_s
+{
+  struct overflow_space_s *next;
+  uint32_t idx;
+  uint32_t length;
+  char d[1];
+};
+
+struct loaded_domain
+{
+  char *data;
+  char *data_native; /* Data mapped to the native version of the
+                        string.  (Allocated along with DATA). */
+  int must_swap;
+  uint16_t nstrings; /* Number of strings.  */
+  uint16_t *mapped;  /* Array of mapping indicators:
+                        0   := Not mapped (original utf8).
+                        1   := Mapped to native encoding in overflow space.
+                        >=2 := Mapped to native encoding. The value
+                               gives the length of the mapped string.
+                               Because the terminating nul is included
+                               in the length and an empty string is
+                               not allowed, values are always > 1.  */
+  struct overflow_space_s *overflow_space;
+  struct string_desc *orig_tab;
+  struct string_desc *trans_tab;
+  uint32_t hash_size;
+  uint32_t *hash_tab;
+};
+
+
+/* The list of domains we we are aware of.  This list is protected by
+   the criticla section DOMAINLIST_ACCESS_CS.  */
+static struct domainlist_s *domainlist;
+
+/* A critical section to guard access to the domainlist.  */
+static CRITICAL_SECTION domainlist_access_cs;
+
+/* The name of the current domain.  This is a malloced string.  This
+   is a gobal variable which is not thread-safe.  */
+static char *current_domainname;
+
+
+
+/* Constructor for this module.  This can only be used if we are a
+   DLL.  If used as a static lib we can't control the process set; for
+   example it might be used with a main module which is not build with
+   mingw and thus does not know how to call the constructors.  */
+#ifdef DLL_EXPORT
+static void module_init (void) _GPG_ERR_CONSTRUCTOR;
+#endif
+static void
+module_init (void)
+{
+  static int init_done;
+
+  if (!init_done)
+    {
+      InitializeCriticalSection (&domainlist_access_cs);
+      init_done = 1;
+    }
+}
+
+#if !defined(DLL_EXPORT) || !defined(_GPG_ERR_HAVE_CONSTRUCTOR)
+void
+_gpg_w32__init_gettext_module (void)
+{
+  module_init ();
+}
+#endif
+
+
+/* Free the domain data.  */
+static void
+free_domain (struct loaded_domain *domain)
+{
+  struct overflow_space_s *os, *os2;
+
+  jnlib_free (domain->data);
+  jnlib_free (domain->mapped);
+  for (os = domain->overflow_space; os; os = os2)
+    {
+      os2 = os->next;
+      jnlib_free (os);
+    }
+  jnlib_free (domain);
+}
+
+
+static struct loaded_domain *
+load_domain (const char *filename)
+{
+  HANDLE fh;
+  DWORD size;
+  struct mo_file_header *data = NULL;
+  struct loaded_domain *domain = NULL;
+  size_t to_read;
+  char *read_ptr;
+
+  {
+    wchar_t *wfilename = _gpgrt_utf8_to_wchar (filename);
+
+    if (!wfilename)
+      fh = INVALID_HANDLE_VALUE;
+    else
+      fh = CreateFileW (wfilename, GENERIC_READ, FILE_SHARE_WRITE, NULL,
+                        OPEN_EXISTING, 0, NULL);
+    xfree (wfilename);
+  }
+  if (fh == INVALID_HANDLE_VALUE)
+    return NULL;
+
+  size = GetFileSize (fh, NULL);
+  if (size == INVALID_FILE_SIZE)
+    {
+      CloseHandle (fh);
+      return NULL;
+    }
+
+  data = (2*size <= size)? NULL : jnlib_malloc (2*size);
+  if (!data)
+    {
+      CloseHandle (fh);
+      return NULL;
+    }
+
+  to_read = size;
+  read_ptr = (char *) data;
+  do
+    {
+      BOOL res;
+      DWORD nb;
+
+      res = ReadFile (fh, read_ptr, to_read, &nb, NULL);
+      if (! res || nb < to_read)
+	{
+	  CloseHandle (fh);
+	  jnlib_free (data);
+	  return NULL;
+	}
+      read_ptr += nb;
+      to_read -= nb;
+    }
+  while (to_read > 0);
+  CloseHandle (fh);
+
+  /* Using the magic number we can test whether it really is a message
+     catalog file.  */
+  if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED)
+    {
+      /* The magic number is wrong: not a message catalog file.  */
+      jnlib_free (data);
+      return NULL;
+    }
+
+  domain = jnlib_calloc (1, sizeof *domain);
+  if (!domain)
+    {
+      jnlib_free (data);
+      return NULL;
+    }
+  domain->data = (char *) data;
+  domain->data_native = (char *) data + size;
+  domain->must_swap = data->magic != MAGIC;
+
+  /* Fill in the information about the available tables.  */
+  switch (SWAPIT (domain->must_swap, data->revision))
+    {
+    case MO_REVISION_NUMBER:
+      {
+        uint32_t nstrings;
+
+        /* Because we use 16 bit values for the mapping array, we
+           can't support more that 65534 strings (65535 would be okay,
+           but it is often used as a special value).  A PO file with
+           that many translations is very unlikely given that GnuPG
+           with its very large number of strings has only about 1600
+           strings + variants.  */
+        nstrings = SWAPIT (domain->must_swap, data->nstrings);
+        if (nstrings > 65534)
+          goto bailout;
+        domain->nstrings = nstrings;
+        domain->orig_tab = (struct string_desc *)
+          ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset));
+        domain->trans_tab = (struct string_desc *)
+          ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset));
+        domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size);
+        domain->hash_tab = (uint32_t *)
+          ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset));
+      }
+      break;
+
+    default: /* This is an invalid revision.	*/
+      goto bailout;
+    }
+
+  /* Allocate an array to keep track of code page mappings.  */
+  domain->mapped = jnlib_calloc (domain->nstrings, sizeof *domain->mapped);
+  if (domain->mapped)
+    return domain; /* Okay.  */
+
+ bailout:
+  jnlib_free (data);
+  jnlib_free (domain);
+  return NULL;
+}
+
+
+/* Return a malloced wide char string from an UTF-8 encoded input
+   string STRING.  Caller must free this value. On failure returns
+   NULL.  The result of calling this function with STRING set to NULL
+   is not defined.  If LENGTH is zero and RETLEN NULL the fucntion
+   assumes that STRING is a nul-terminated string and returns a
+   (wchar_t)0-terminated string.  */
+static wchar_t *
+utf8_to_wchar (const char *string, size_t length, size_t *retlen)
+{
+  int n;
+  wchar_t *result;
+  size_t nbytes;
+  int cbmultibyte;
+
+  if (!length && !retlen)
+    cbmultibyte = -1;
+  else
+    cbmultibyte = length;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, cbmultibyte, NULL, 0);
+  if (n < 0 || (n+1) <= 0)
+    return NULL;
+
+  nbytes = (size_t)(n+1) * sizeof(*result);
+  if (nbytes / sizeof(*result) != (n+1))
+    {
+      _gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+  result = jnlib_malloc (nbytes);
+  if (!result)
+    return NULL;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, cbmultibyte, result, n);
+  if (n < 0)
+    {
+      jnlib_free (result);
+      return NULL;
+    }
+  if (retlen)
+    *retlen = n;
+  return result;
+}
+
+
+/* Convert an UTF8 string to a WCHAR string.  Caller should use
+ * _gpgrt_free_wchar to release the result. */
+wchar_t *
+_gpgrt_utf8_to_wchar (const char *string)
+{
+  return utf8_to_wchar (string, 0, NULL);
+}
+
+
+/* We provide a dedicated release function to be sure that we don't
+ * use a somehow mapped free function but the one which matches the
+ * used alloc.  */
+void
+_gpgrt_free_wchar (wchar_t *wstring)
+{
+  if (wstring)
+    jnlib_free (wstring);
+}
+
+
+/* Helper for wchar_to_native and wchar_to_utf8.  */
+static char *
+wchar_to_cp (const wchar_t *string, size_t length, size_t *retlen,
+             unsigned int cpno)
+{
+  int n;
+  char *result;
+
+  n = WideCharToMultiByte (cpno, 0, string, length, NULL, 0, NULL, NULL);
+  if (n < 0 || (n+1) <= 0)
+    {
+      _gpgrt_w32_set_errno (-1);
+      return NULL;
+    }
+
+  result = jnlib_malloc (n+1);
+  if (!result)
+    return NULL;
+
+  n = WideCharToMultiByte (cpno, 0, string, length, result, n, NULL, NULL);
+  if (n < 0)
+    {
+      _gpgrt_w32_set_errno (-1);
+      jnlib_free (result);
+      return NULL;
+    }
+  result[n] = 0;
+  if (retlen)
+    *retlen = n;
+  return result;
+}
+
+
+/* Return a malloced string encoded in the native console codepage
+   from the wide char input string STRING.
+   Caller must free this value. On failure returns NULL.
+   The result of calling this function with STRING set to NULL
+   is not defined. */
+static char *
+wchar_to_native (const wchar_t *string, size_t length, size_t *retlen)
+{
+  unsigned int cpno = GetConsoleOutputCP ();
+
+  /* GetConsoleOutputCP returns the 8-Bit codepage that should be used
+     for console output. If the codepage is not returned we fall back
+     to the codepage GUI programs should use (CP_ACP). */
+  if (!cpno)
+    cpno = GetACP ();
+
+  return wchar_to_cp (string, length, retlen, cpno);
+}
+
+
+/* Convert a WCHAR string to UTF-8.  Caller should use xfree to
+ * release the result.  Returns NULL on error and sets ERRNO. */
+char *
+_gpgrt_wchar_to_utf8 (const wchar_t *string, size_t length)
+{
+  return wchar_to_cp (string, length, NULL, CP_UTF8);
+}
+
+
+/* Convert UTF8 to the native codepage.  Caller must free the return value. */
+static char *
+utf8_to_native (const char *string, size_t length, size_t *retlen)
+{
+  wchar_t *wstring;
+  char *result;
+  size_t newlen;
+
+  wstring = utf8_to_wchar (string, length, &newlen);
+  if (wstring)
+    {
+      result = wchar_to_native (wstring, newlen, &newlen);
+      jnlib_free (wstring);
+    }
+  else
+    result = NULL;
+  *retlen = result? newlen : 0;
+  return result;
+}
+
+
+
+/* Specify that the DOMAINNAME message catalog will be found
+   in DIRNAME rather than in the system locale data base.  */
+const char *
+_gpg_w32_bindtextdomain (const char *domainname, const char *dirname)
+{
+  const char *catval_full;
+  char *catval;
+  char *fname;
+  const char *retvalue;
+
+  if (!dirname)
+    {
+      struct domainlist_s *dl;
+
+      retvalue = NULL;
+      EnterCriticalSection (&domainlist_access_cs);
+      {
+        for (dl = domainlist; dl; dl = dl->next)
+          if (!strcmp (dl->name, domainname))
+            {
+              retvalue = dl->dname;
+              break;
+            }
+      }
+      LeaveCriticalSection (&domainlist_access_cs);
+      return retvalue;
+    }
+
+  /* DIRNAME is "$INSTALLDIR\share\locale".  */
+
+  /* First find out the category value.  */
+  catval = NULL;
+  catval_full = my_nl_locale_name ("LC_MESSAGES");
+
+  /* Normally we would have to loop over all returned locales and
+     search for the right file.  See gettext intl/dcigettext.c for all
+     the gory details.  Here, we only support the basic category, and
+     ignore everything else.  */
+  if (catval_full)
+    {
+      char *p;
+
+      catval = jnlib_malloc (strlen (catval_full) + 1);
+      if (catval)
+	{
+	  strcpy (catval, catval_full);
+	  p = strchr (catval, '_');
+	  if (p)
+	    *p = '\0';
+	}
+    }
+  if (!catval)
+    return NULL;
+
+  /* Now build the filename string.  The complete filename is this:
+     DIRNAME + \ + CATVAL + \LC_MESSAGES\ + DOMAINNAME + .mo  */
+  {
+    int len = (strlen (dirname) + 1 + strlen (catval) + 13
+               + strlen (domainname) + 3 + 1);
+    char *p;
+
+    fname = jnlib_malloc (len);
+    if (!fname)
+      {
+	jnlib_free (catval);
+	return NULL;
+      }
+
+    p = fname;
+    strcpy (p, dirname);
+    p += strlen (dirname);
+    *(p++) = '\\';
+    strcpy (p, catval);
+    p += strlen (catval);
+    strcpy (p, "\\LC_MESSAGES\\");
+    p += 13;
+    strcpy (p, domainname);
+    p += strlen (domainname);
+    strcpy (p, ".mo");
+  }
+
+  jnlib_free (catval);
+
+  /* Store the domain information in the domainlist.  */
+  {
+    struct domainlist_s *item, *dl;
+    char *rel_ptr1 = NULL;
+    char *rel_ptr2 = NULL;
+
+    item = jnlib_calloc (1, sizeof *dl + strlen (domainname));
+    if (!item)
+      {
+        jnlib_free (fname);
+        return NULL;
+      }
+    strcpy (item->name, domainname);
+    item->dname = jnlib_malloc (strlen (dirname) +1);
+    if(!item->dname)
+      {
+        jnlib_free (item);
+        jnlib_free (fname);
+        return NULL;
+      }
+    strcpy (item->dname, dirname);
+    retvalue = item->dname;
+
+    EnterCriticalSection (&domainlist_access_cs);
+    {
+      for (dl = domainlist; dl; dl = dl->next)
+        if (!strcmp (dl->name, domainname))
+          break;
+      if (!dl) /* First time called for this domainname. */
+        {
+          item->fname = fname;
+          fname = NULL;
+          item->next = domainlist;
+          domainlist = item;
+          item = NULL;
+        }
+      else /* Update only.  */
+        {
+          rel_ptr1 = dl->fname;
+          dl->fname = fname;
+          fname = NULL;
+          rel_ptr2 = dl->dname;
+          dl->dname = item->dname;
+          item->dname = NULL;
+        }
+    }
+    LeaveCriticalSection (&domainlist_access_cs);
+
+    jnlib_free (item);
+    jnlib_free (rel_ptr1);
+    jnlib_free (rel_ptr2);
+  }
+
+  return retvalue;
+}
+
+
+
+
+static const char *
+get_plural (const char *data, size_t datalen, unsigned long nplural)
+{
+  const char *p;
+  int idx;
+
+  /* We only support the Germanic rule.  */
+  idx = (nplural == 1? 0 : 1);
+
+  for (; idx; idx--)
+    {
+      p = strchr (data, 0) + 1;
+      if (p >= data+datalen)
+        return "ERROR in GETTEXT (bad plural entry)";
+      datalen -= (p-data);
+      data = p;
+    }
+  return data;
+}
+
+
+static const char*
+get_string (struct loaded_domain *domain, uint32_t idx,
+            int use_plural, unsigned long nplural)
+{
+  struct tls_space_s *tls = get_tls ();
+  struct overflow_space_s *os;
+  const char *trans;  /* Pointer to the translated entry.  */
+  size_t translen;    /* Length of that entry.  */
+
+  if (idx > 65534)
+    return "ERROR in GETTEXT (too many strings)";
+
+  if (tls->gt_use_utf8)
+    {
+      trans = (domain->data
+               + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
+      translen = SWAPIT(domain->must_swap, domain->trans_tab[idx].length);
+    }
+  else if (!domain->mapped[idx])
+    {
+      /* Not yet mapped.  Map from utf-8 to native encoding now.  */
+      const char *p_utf8;
+      size_t plen_utf8, buflen;
+      char *buf;
+
+      p_utf8 = (domain->data
+                + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
+      plen_utf8 = SWAPIT(domain->must_swap, domain->trans_tab[idx].length);
+
+      /* We need to include the nul, so that the utf8->wchar->native
+         conversion chain works correctly and the nul is stored after
+         the conversion. */
+      if (p_utf8[plen_utf8])
+        {
+          trans = "ERROR in MO file"; /* Terminating zero is missing.  */
+          translen = 0;
+          goto leave;
+        }
+      plen_utf8++;
+
+      buf = utf8_to_native (p_utf8, plen_utf8, &buflen);
+      if (!buf)
+        {
+          trans = "ERROR in GETTEXT MALLOC";
+          translen = 0;
+        }
+      else if (buflen <= plen_utf8 && buflen > 1)
+        {
+          /* Copy into the DATA_NATIVE area. */
+          char *p_tmp;
+
+          p_tmp = (domain->data_native
+                   + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
+          memcpy (p_tmp, buf, buflen);
+          domain->mapped[idx] = buflen;
+          trans = p_tmp;
+          translen = buflen;
+        }
+      else
+        {
+          /* There is not enough space for the translation (or for
+             whatever reason an empty string is used): Store it in the
+             overflow_space and mark that in the mapped array.
+             Because UTF-8 strings are in general longer than the
+             Windows native encoding, we expect that this won't happen
+             too often and thus we use a linked list to manage this
+             space. */
+          os = jnlib_malloc (sizeof *os + buflen);
+          if (os)
+            {
+              os->idx = idx;
+              memcpy (os->d, buf, buflen);
+              os->length = buflen;
+              os->next = domain->overflow_space;
+              domain->overflow_space = os;
+              domain->mapped[idx] = 1;
+              trans = os->d;
+              translen = os->length;
+            }
+          else
+            {
+              trans = "ERROR in GETTEXT MALLOC";
+              translen = 0;
+            }
+        }
+      if (translen)
+        translen--;  /* TRANSLEN shall be the size without the nul.  */
+      jnlib_free (buf);
+    }
+  else if (domain->mapped[idx] == 1)
+    {
+      /* The translated string is in the overflow_space. */
+      for (os=domain->overflow_space; os; os = os->next)
+        if (os->idx == idx)
+          break;
+      if (os)
+        {
+          trans = os->d;
+          translen = os->length;
+        }
+      else
+        {
+          trans = "ERROR in GETTEXT (overflow space)\n";
+          translen = 0;
+        }
+    }
+  else
+    {
+      trans = (domain->data_native
+               + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
+      translen = domain->mapped[idx];
+    }
+
+ leave:
+  if (use_plural && translen)
+    return get_plural (trans, translen, nplural);
+  else
+    return trans;
+}
+
+
+static const char *
+do_gettext (const char *domainname,
+            const char *msgid, const char *msgid2, unsigned long nplural)
+{
+  struct domainlist_s *dl;
+  struct loaded_domain *domain;
+  int load_failed;
+  uint32_t top, bottom, nstr;
+  char *filename;
+
+  if (!domainname)
+    domainname = current_domainname? current_domainname : "";
+
+  /* FIXME: The whole locking stuff is a bit questionable because
+     gettext does not claim to be thread-safe.  We need to investigate
+     this further.  */
+
+  load_failed = 0;
+  domain = NULL;
+  filename = NULL;
+  EnterCriticalSection (&domainlist_access_cs);
+  {
+    for (dl = domainlist; dl; dl = dl->next)
+      if (!strcmp (dl->name, domainname))
+        {
+          load_failed = dl->load_failed;
+          domain = dl->domain;
+          break;
+        }
+    if (dl && !domain && !load_failed && dl->fname)
+      {
+        filename = jnlib_malloc (strlen (dl->fname) + 1);
+        if (filename)
+          strcpy (filename, dl->fname);
+      }
+  }
+  LeaveCriticalSection (&domainlist_access_cs);
+  if (!dl)
+    goto not_found; /* DOMAINNAME not bound.  */
+  if (filename)
+    {
+      /* No attempt so far to load the MO file.  Try now.  */
+      int updated = 0;
+
+      domain = load_domain (filename);
+      jnlib_free (filename);
+      filename = NULL;
+      EnterCriticalSection (&domainlist_access_cs);
+      {
+        for (dl = domainlist; dl; dl = dl->next)
+          if (!strcmp (dl->name, domainname))
+            {
+              if (domain)
+                dl->domain = domain;
+              else
+                dl->load_failed = 1;
+              updated = 1;
+              break;
+            }
+      }
+      LeaveCriticalSection (&domainlist_access_cs);
+      if (!updated)
+        {
+          /* Ooops - lost the domain.  */
+          free_domain (domain);
+          domain = NULL;
+        }
+    }
+
+  if (!domain)
+    goto not_found; /* No MO file.  */
+
+  /* First try to use the hash table.  */
+  if (domain->hash_size > 2 && domain->hash_tab)
+    {
+      /* Use the hashing table.  */
+      uint32_t len = strlen (msgid);
+      uint32_t hash_val = hash_string (msgid);
+      uint32_t idx = hash_val % domain->hash_size;
+      uint32_t incr = 1 + (hash_val % (domain->hash_size - 2));
+
+      while ( (nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx])) )
+        {
+          nstr--;
+          if (nstr < domain->nstrings
+              && SWAPIT(domain->must_swap,
+                        domain->orig_tab[nstr].length) >= len
+              && !strcmp (msgid, (domain->data
+                                  + SWAPIT(domain->must_swap,
+                                           domain->orig_tab[nstr].offset))))
+            {
+              return get_string (domain, nstr, !!msgid2, nplural);
+            }
+
+          if (idx >= domain->hash_size - incr)
+            idx -= domain->hash_size - incr;
+          else
+            idx += incr;
+	}
+    }
+
+  /* Now we try the default method: binary search in the sorted array
+     of messages.  */
+  bottom = 0;
+  top = domain->nstrings;
+  while (bottom < top)
+    {
+      int cmp_val;
+
+      nstr = (bottom + top) / 2;
+      cmp_val = strcmp (msgid, (domain->data
+                                + SWAPIT(domain->must_swap,
+                                         domain->orig_tab[nstr].offset)));
+      if (cmp_val < 0)
+        top = nstr;
+      else if (cmp_val > 0)
+        bottom = nstr + 1;
+      else
+        {
+          return get_string (domain, nstr, !!msgid2, nplural);
+        }
+    }
+
+ not_found:
+  /* We use the standard Germanic rule if plural has been requested.  */
+  return msgid2? (nplural == 1? msgid : msgid2) : msgid;
+}
+
+
+const char *
+_gpg_w32_textdomain (const char *domainname)
+{
+  char *string;
+
+  if (!domainname)
+    {
+      if (!current_domainname)
+        _gpg_err_set_errno (0);
+    }
+  else
+    {
+      string = malloc (strlen (domainname) + 1);
+      if (!string)
+        return NULL;
+      strcpy (string, domainname);
+      current_domainname = string;
+    }
+  return current_domainname;
+}
+
+
+/* A direct implementation of gettext instead of a macro calling
+   dngettext.  This is so that the caller does not need to push dummy
+   values on the stack.  The used domain is the first one registered
+   with bindtextdomain.  */
+const char *
+_gpg_w32_gettext (const char *msgid)
+{
+  return do_gettext (NULL, msgid, NULL, 0);
+}
+
+
+/* A direct implementation of dgettext instead of a macro calling
+   dngettext.  This is so that the caller does not need to push dummy
+   values on the stack.  */
+const char *
+_gpg_w32_dgettext (const char *domainname, const char *msgid)
+{
+  return do_gettext (domainname, msgid, NULL, 0);
+}
+
+
+/* Our implementation of dngettext.  This is the most genereic
+   function we have; a macro implements ngettext.  */
+const char *
+_gpg_w32_dngettext (const char *domainname, const char *msgid1,
+			const char *msgid2, unsigned long int n)
+{
+  /* We use the simple Germanic plural rule.  */
+  return do_gettext (domainname, msgid1, msgid2, n);
+}
+
+
+/* Return the locale name as used by gettext.  The return value will
+   never be NULL. */
+const char *
+_gpg_w32_gettext_localename (void)
+{
+  const char *s;
+
+  s = my_nl_locale_name ("LC_MESSAGES");
+  return s? s:"";
+}
+
+
+/* With a VALUE of 1 switch the gettext functions into utf8 mode.
+   That is the strings are returned without translation to the native
+   charset.  A VALUE of 0 switches back to translated strings.  A VALUE
+   of -1 returns the current value. */
+int
+_gpg_w32_gettext_use_utf8 (int value)
+{
+  struct tls_space_s *tls = get_tls ();
+  int last = tls->gt_use_utf8;
+  if (value != -1)
+    tls->gt_use_utf8 = value;
+  return last;
+}
+
+
+/* Force the use of the locale NAME or if NAME is NULL the locale
+ * derived from LANGID will be used.  This function is not thread-safe
+ * and must be used early - even before gpgrt_check_version. */
+void
+gpgrt_w32_override_locale (const char *name, unsigned short langid)
+{
+  if (name)
+    {
+      strncpy (override_locale.name, name, sizeof (override_locale.name) - 1);
+      override_locale.name[sizeof (override_locale.name) - 1] = 0;
+    }
+  else
+    *override_locale.name = 0;
+  override_locale.langid = langid;
+  override_locale.active = 1;
+}
+
+
+#ifdef TEST
+int
+main (int argc, char **argv)
+{
+  const char atext1[] =
+    "Warning: You have entered an insecure passphrase.%%0A"
+    "A passphrase should be at least %u character long.";
+  const char atext2[] =
+    "Warning: You have entered an insecure passphrase.%%0A"
+    "A passphrase should be at least %u characters long.";
+
+  if (argc)
+    {
+      argc--;
+      argv++;
+    }
+
+  _gpg_err_w32_bindtextdomain ("gnupg2", "c:/programme/gnu/gnupg/share/locale");
+
+  printf ("locale is `%s'\n", _gpg_err_w32_gettext_localename ());
+  fputs ("text with N=1:\n", stdout);
+  fputs (_gpg_err_w32_ngettext (atext1, atext2, 1), stdout);
+  fputs ("\n\ntext with N=2:\n", stdout);
+  fputs (_gpg_err_w32_ngettext (atext1, atext2, 2), stdout);
+  fputs ("\nready\n", stdout);
+
+  return 0;
+}
+/*
+ *No-Local Variables:
+ *  compile-command: "i586-mingw32msvc-gcc -DTEST -Wall -g w32-gettext.c"
+ * End:
+ */
+#endif /*TEST*/