C gettext in externer Datei führt zu Compiler-Fehler

Photon

Rear Admiral Pro
🎅 Nikolaus-Rätsel-Elite
Registriert
Apr. 2006
Beiträge
5.204
Hallo Community,

ich versuche gerade, wie in https://www.computerbase.de/forum/t...riablen-aus-externer-datei-zugreifen.2096354/ beschrieben, ein Programm mittels gettext übersetzbar zu machen. Folgendes funktioniert:

C:
// main.h

#include <stdio.h>
#include <stdlib.h>

#include <libintl.h>
#include <locale.h>

// main.c

#include "main.h"

int main()
{

  #define _(STRING) gettext(STRING)

  setlocale (LC_ALL, "");
  bindtextdomain ("hello", "/usr/share/locale/");
  textdomain ("hello");

  const char *message    = _("Hello World!");

  printf("%s", message);

  return EXIT_SUCCESS;
}

Sobald ich jedoch versuche, den zu übersetzenden String in eine externe Datei zu packen, also

C:
// hello.h

extern const char *message;


// hello.c

#include "hello.h"

#include <libintl.h>
#include <locale.h>

#define _(STRING) gettext(STRING)

setlocale (LC_ALL, "");
bindtextdomain ("hello", "/usr/share/locale/");
textdomain ("hello");

const char *message    = _("Hello World!");


// main.h

#include <stdio.h>
#include <stdlib.h>

#include "hello.h"


// main.c

#include "main.h"

int main()
{
  printf("%s", message);

  return EXIT_SUCCESS;
}

bekomme ich folgende Compiler-Fehler:

Code:
$ gcc hello.c main.c -o test
In Datei, eingebunden von /usr/include/locale.h:29,
                 von hello.c:4:
hello.c:8:12: Fehler: expected declaration specifiers or »...« before numeric constant
    8 | setlocale (LC_ALL, "");
      |            ^~~~~~
hello.c:8:20: Fehler: expected declaration specifiers or »...« before string constant
    8 | setlocale (LC_ALL, "");
      |                    ^~
hello.c:9:17: Fehler: expected declaration specifiers or »...« before string constant
    9 | bindtextdomain ("hello", "/usr/share/locale/");
      |                 ^~~~~~~
hello.c:9:26: Fehler: expected declaration specifiers or »...« before string constant
    9 | bindtextdomain ("hello", "/usr/share/locale/");
      |                          ^~~~~~~~~~~~~~~~~~~~
hello.c:10:13: Fehler: expected declaration specifiers or »...« before string constant
   10 | textdomain ("hello");
      |             ^~~~~~~
hello.c:6:19: Fehler: Initialisierungselement ist nicht konstant
    6 | #define _(STRING) gettext(STRING)
      |                   ^~~~~~~
hello.c:12:27: Anmerkung: bei Substitution des Makros »_«
   12 | const char *message     = _("Hello World!");

Ich hab versucht die Fehlermeldung zu recherchieren, aber sie scheint wohl in diversen Situationen aufzutreten, die in meinen Augen nichts mit der vorliegenden Situation zu tun haben. Was übersehe ich da?

Vielen Dank,
Photon
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: nERdWIN
Lösung
Du kannst in hello.c zunächst die Originaltexte als globale Variablen ablegen:
C:
const char *message= "Hello World!";
Das Übersetzen mit gettext() muss dann aber per Aufruf aus der main-Funktion heraus erfolgen. Natürlich kannst du in hello.h/hello.c auch eine Art setup-Funktion definieren, welche die übersetzten Texte ebenfalls in globalen Variablen speichert. Dann müsste main() nur noch setup() rufen.
Funktionen (hier setlocale) können nur aus einer anderen Funktion heraus aufgerufen werden.
 
Ah! Das erklärt's wohl, vielen Dank! Was wäre denn die beste Herangehensweise, um diese Limitation zu umgehen, wenn man in der Datei hello.c einfach nur eine Liste von String-Variablen haben möchte, die dann in der main.c verwendet werden sollen, jedoch mit gettext übersetzt werden sollen?
 
Du kannst in hello.c zunächst die Originaltexte als globale Variablen ablegen:
C:
const char *message= "Hello World!";
Das Übersetzen mit gettext() muss dann aber per Aufruf aus der main-Funktion heraus erfolgen. Natürlich kannst du in hello.h/hello.c auch eine Art setup-Funktion definieren, welche die übersetzten Texte ebenfalls in globalen Variablen speichert. Dann müsste main() nur noch setup() rufen.
 
  • Gefällt mir
Reaktionen: Photon
Photon schrieb:
Ah! Das erklärt's wohl, vielen Dank! Was wäre denn die beste Herangehensweise, um diese Limitation zu umgehen, wenn man in der Datei hello.c einfach nur eine Liste von String-Variablen haben möchte, die dann in der main.c verwendet werden sollen, jedoch mit gettext übersetzt werden sollen?
linken statt inkludieren.
 
@foofoobar Sorry, bin Anfänger, kann leider mit dem Stichwort allein nicht viel anfangen. :)

@ph4nt0m Nun sieht es so aus:

C:
// hello.h

extern const char *message;


// hello.c

#include "hello.h"

const char *message    = "Hello World!";


// main.h

#include <stdio.h>
#include <stdlib.h>

#include "hello.h"


// main.c

#include "main.h"

#include <libintl.h>
#include <locale.h>

#define _(STRING) gettext(STRING)

setlocale (LC_ALL, "");
bindtextdomain ("hello", "/usr/share/locale/");
textdomain ("hello");

int main()
{
  printf("%s", _(message));

  return EXIT_SUCCESS;
}

Der Compiler meckert aber trotzdem:

Code:
$ gcc hello.c main.c -o test
In Datei, eingebunden von /usr/include/locale.h:29,
                 von main.c:4:
main.c:8:12: Fehler: expected declaration specifiers or »...« before numeric constant
    8 | setlocale (LC_ALL, "");
      |            ^~~~~~
main.c:8:20: Fehler: expected declaration specifiers or »...« before string constant
    8 | setlocale (LC_ALL, "");
      |                    ^~
main.c:9:17: Fehler: expected declaration specifiers or »...« before string constant
    9 | bindtextdomain ("hello", "/usr/share/locale/");
      |                 ^~~~~~~
main.c:9:26: Fehler: expected declaration specifiers or »...« before string constant
    9 | bindtextdomain ("hello", "/usr/share/locale/");
      |                          ^~~~~~~~~~~~~~~~~~~~
main.c:10:13: Fehler: expected declaration specifiers or »...« before string constant
   10 | textdomain ("hello");
      |             ^~~~~~~

Zumindest ist die letzte Fehlermeldung, die das ursprüngliche Problem war, weg, trotzdem würde ich gerne das Minimalbeispiel kompilieren können, um zu überprüfen, ob wirklich alles passt, bevor ich mit dem Abändern des eigentlichen Programms anfange.

edit: Gerade noch einen kleinen Fehler in hello.c ausgebessert, der Compiler-Output kommt aber von der verbesserten Variante, hab bloß beim Posten nicht aufgepasst.
 
Zuletzt bearbeitet:
Du rufst die Funktionen setlocale usw. nach wie vor nicht aus deiner main-Funktion heraus auf. Auch der Aufruf von gettext() in hello.c wird so nicht funktionieren, daher hatte ich vorhin ja ein anderes Vorgehen vorgeschlagen.
 
Das extern Keyword wird ja eigentlich schon benutzt (siehe hello.h), oder?

Nun habe ich die Variante mit der setup-Funktion versucht:

C:
// hello.h

void setup_gettext();

extern const char *message;


// hello.c

#include "hello.h"

#include <libintl.h>
#include <locale.h>

#define _(STRING) gettext(STRING)

const char *message;

void setup_gettext() {

    setlocale (LC_ALL, "");
    bindtextdomain ("hello", "/usr/share/locale/");
    textdomain ("hello");

    *message    = _("Hello World!");
}


// main.h

#include <stdio.h>
#include <stdlib.h>

#include "hello.h"


// main.c

#include "main.h"

int main()
{
  setup_gettext();

  printf("%s", message);

  return EXIT_SUCCESS;
}

Nun wird die Variable message einmal in hello.h gelistet, dann in hello.c deklariert und in setup_gettext definiert. Das funktioniert auch. Aber ich frage mich, ob da nicht irgendeine Redundanz ist, ob man wirklich die Variable an drei Stellen haben muss?
 
Photon schrieb:
Nun wird die Variable message einmal in hello.h gelistet, dann in hello.c deklariert und in setup_gettext definiert. Das funktioniert auch. Aber ich frage mich, ob da nicht irgendeine Redundanz ist, ob man wirklich die Variable an drei Stellen haben muss?
Dein Beispiel ist auch recht akademisch, extern benutzt man eigentlich nur wenn man von mehr als einer *.c drauf zugreift. In deinem vermuteten Szenario würde man eher die *.h und *.c für die Texte per script erzeugen und dieses Script dann im Makefile als "Precompiler" einbinden.
 
Tatsächlich ist es auch so, das Projekt besteht aus einer Hauptdatei und mehreren Zusatzdateien, eine von ihnen enthält die zu übersetzenden Strings, auf welche dann in der Haupt-, aber auch in mehreren der Zusatzdateien zugegriffen wird. Also:

main.c
lib1.c
lib2.c
lib3.c
lstrings.c

In allen vier Dateien stecken nun Variablen, die auf Strings aus lstrings.c zugreifen. Das alles ist in dem Minimalbeispiel natürlich nicht abgebildet. Wie wäre es also in dem Fall am schlausten umzusetzen?
 
Photon schrieb:
In allen vier Dateien stecken nun Variablen, die auf Strings aus lstrings.c zugreifen. Das alles ist in dem Minimalbeispiel natürlich nicht abgebildet. Wie wäre es also in dem Fall am schlausten umzusetzen?
Dann passt das schon, lstrings.[ch] könnte man aus einer Quelle erzeugen, und die Erzeugung/Abhängigkeit per Makefile steuern.
lstrings.h entsprechend inkludieren und im Makefile die entsprechende Abhängigkeit definieren.
 
Ok, dann lass ich das so und gehe einfach mit Suchen&Ersetzen mit RegExp drüber, damit es initial passt (um die 120 Strings), künftige Änderungen, falls es denn überhaupt welche geben wird, dürften dann eh marginal sein, sodass das Entwerfen eines Generator-Skripts sich nicht lohnt.
 
@Micke Dafür muss man einfach beim Erstellen von "Diskussion" auf "Frage" wechseln. :)

Auswahl_001_07_55_21.png
 

Ähnliche Themen

Zurück
Oben