setlocale() for LC_MESSAGES to non-existing locale fails
<p>For an embedded software project, I am adding support for translations and since we are running an embedded Linux I went for using libc <code>gettext()</code>. We do not have any locale definitions whatsoever installed, so I only try to set the <code>LC_MESSAGES</code> locale to my desired locale:</p>

<pre><code>setlocale(LC_MESSAGES, "fake");
</code></pre>

<p>(I am using the name <code>fake</code> with a <code>fake.mo</code> file to do a pseudo-translation before I get my hands on proper translations).</p>

<p>This works fine when linked statically, it returns a locale handle, <code>bindtextdomain()</code> and friends all work fine and I get my "translated" string out of it:</p>

<pre><code>setlocale() returned "fake"
current textdomain is "ewe"
current base directory is "/opt/btech/probe/share/locale/WA"
current LC_MESSAGES locale is "fake"
gettext("Error") ==&gt; "Ḗřřǿř"
</code></pre>

<p>Now, when I compile this dynamically, it doesn't work. Neither on the target device, nor locally on my PC (with the files installed the same way). The <code>setlocale()</code> call fails, returning a <code>NULL</code> pointer and setting errno to <code>ENOENT</code> (file not found). At the point of <code>setlocale()</code> I haven't pointed <code>bindtextdomain()</code> to where my files are at, but switching the calls around doesn't help.</p>

<p>Am I doing things wrong, is my working example from above wrong and shouldn't really work? Do I need locale definitions for anything I call <code>setlocale()</code> on, even for <code>LC_MESSAGES</code>?</p>

<p>This is the source of the test binary:</p>

<pre><code>#include &lt;libintl.h&gt;
#include &lt;locale.h&gt;
#include &lt;stdio.h&gt;

int main()
{
    const char *l = setlocale(LC_MESSAGES, "fake");

    printf("setlocale() returned \"%s\"\n", l);

    bind_textdomain_codeset("ewe", "UTF-8");
    bindtextdomain("ewe", "/opt/btech/probe/share/locale/WA");
    textdomain("ewe");

    printf("current textdomain is \"%s\"\n", textdomain(NULL));
    printf("current base directory is \"%s\"\n", bindtextdomain(textdomain(NULL), NULL));
    printf("current LC_MESSAGES locale is \"%s\"\n", setlocale(LC_MESSAGES, NULL));
    printf("gettext(\"Error\") ==&gt; \"%s\"\n", gettext("Error"));

    return 0;
}
</code></pre>

<p>This is the output when compiled dynamically (either for target or host):</p>

<pre><code>setlocale() returned "(null)"
current textdomain is "ewe"
current base directory is "/opt/btech/probe/share/locale/WA"
current LC_MESSAGES locale is "C"
gettext("Error") ==&gt; "Error"
</code></pre>

<p><em>EDIT</em>: Compiling the test binary as static on my host (x64 Linux) also makes it work, so there is something special with the static compile.</p>

<p>Additional question: Can I force gettext to load a specific mo file directly?  Basically I would like to have a replacement for <code>bindtextdomain()</code> that takes a file name argument instead.</p>

<p><em>EDIT 2</em>: So, I eventually found <a href="https://stackoverflow.com/a/1564879/2501078">this post</a> saying that I can get <code>gettext()</code> to load any translation as long as I have a valid <code>setlocale()</code> call first. So, my current workaround is to actually generate a <code>/usr/lib/locale/locale-archive</code> containing only the <code>en_US</code> locale, calling <code>setlocale(LC_MESSAGES, "en_US"); setenv("LANGUAGE", "fake");</code>, which ends up loading the correct message catalog. Still feels like an ugly workaround, and I still don't understand why the static link works without it.</p>