C: Programm mit Textanzeige für mehrere Sprachen

Gast #4224625
Lesenswert?

Hallo zusammen,
In unsrerm aktuellen C-Programm für eine MCU werden Meldetexte in 
englischer Sprache auf einem Textdisplay ausgegeben:

  lcd_clear();
  lcd_puts("Cylinder stroke");
  lcd_goto (1,0);
  lcd_puts("in mm:");

Jetzt kommt die Forderung, das Programm mehrsprachig zu gestalten.
Wie würde man soetwas am Besten umsetzen ? Es sind viele Texte 
vorhanden.

char eng,span,potugisisch;
eng = 0;
span = 1;
portugisisch=0;

lcd_clear();
if (eng=1)       lcd_puts("Cylinder stroke");
if (spanisch=1)       lcd_puts("Text in Spanisch");
if (portugisisch=1)  lcd_puts("Text in Portugisisch");
lcd_goto (1,0);
if (eng=1)       lcd_puts("in mm:");
if (spanisch=1)       lcd_puts("Text in Spanisch");
if (portugisisch=1)  lcd_puts("Text in Portugisisch");


Gibt es keinen besseren Weg ?
Also mit so einer Art Texttabellen arbeiten, oder so ?
Bitte um Vorschläge...
Danke
Gast #4224644
Lesenswert?

Üblicherweise definiert man dann Strings bzw. arrays mit entsprechenden 
Strings je Sprache und nutzt dann je nach Einstellung das eine oder 
andere. (also keine hard codierten Texte mehr!)
Kommt ein wenig auf den verfügbaren Speicher an, ob man alle oder nur 
eine/ausgewählte Sprache(n) mit installiert (linkt). Oder man macht das 
über Header-files, d.h. je nach gewählter Sprache wird ein anderes 
header-file genutzt.
Gast #4224651
Lesenswert?

... was Dir aber kein Tool abnimmt ist die Problematik, die sich daraus 
ergibt, dass die eine Sprache "langatmig" ist - im wahrsten Sinne des 
Wortes - und die andere kurz und prägnant.
Also ein Menü immer für den "ungünstigsten" Fall ausgelegt sein muss.
#4224665
Lesenswert?

@ DirkF (Gast)

>Jetzt kommt die Forderung, das Programm mehrsprachig zu gestalten.
>Wie würde man soetwas am Besten umsetzen ? Es sind viele Texte
>vorhanden.

>char eng,span,potugisisch;
>eng = 0;
>span = 1;
>portugisisch=0;

so schon mal nicht ;-)

>lcd_clear();
>if (eng=1)       lcd_puts("Cylinder stroke");
>if (spanisch=1)       lcd_puts("Text in Spanisch");
>if (portugisisch=1)  lcd_puts("Text in Portugisisch");
>lcd_goto (1,0);
>if (eng=1)       lcd_puts("in mm:");
>if (spanisch=1)       lcd_puts("Text in Spanisch");
>if (portugisisch=1)  lcd_puts("Text in Portugisisch");

Um Gottes Willen, NEIN!

>Gibt es keinen besseren Weg ?

Sicher. Große Frameworks ala QT bieten dafür integrierte Funktionen an. 
Kleine Programme in reinem C müssen das per Hand machen.

>Also mit so einer Art Texttabellen arbeiten, oder so ?

Ja.

Ich hab das mal so gemacht. (Sind nur Ausschnitte)

globals.h
1
// display texts
2

3
typedef struct {
4
    PGM_P msg_netto;
5
    PGM_P msg_brutto;
6
    PGM_P msg_SPL;
7
    PGM_P msg_UW1;
8
    PGM_P msg_UW2;
9
    PGM_P msg_PRF;
10
    PGM_P msg_dis_normal;
11
    PGM_P msg_dis_flip;
12
    PGM_P msg_video_on;
13
    PGM_P msg_video_off;
14
    PGM_P msg_result;
15
    PGM_P msg_halftime_A;         
16
    PGM_P msg_halftime_B;
17
    PGM_P msg_penalty;
18
    PGM_P msg_timeout;
19
    PGM_P msg_half_time;
20
    PGM_P menus[25];
21
} language_t;


Ein Struct, welches Zeiger auf alle Texte des Programms enthält.

Die Texte stehen dann in

globals.c
1
// english text definitions
2

3
/*************************************************************************
4

5
 some text messeages
6
 
7
*************************************************************************/
8

9
char en_msg_netto[]  PROGMEM = "Horn stops timer";
10
char en_msg_brutto[] PROGMEM = "Timer always on ";
11
char en_msg_SPL[] PROGMEM ="GaL";               // Game leader
12
char en_msg_UW1[] PROGMEM ="UW1";               // Under water referee 1
13
char en_msg_UW2[] PROGMEM ="UW2";               // Under water referee 1
14
char en_msg_PRF[] PROGMEM ="PrW";               // Protocol writer
15
char en_msg_dis_normal[] PROGMEM ="normal";     
16
char en_msg_dis_flip[]   PROGMEM ="fliped";
17
char en_msg_video_on[] PROGMEM ="ON";
18
char en_msg_video_off[] PROGMEM ="OFF";
19
char en_msg_result[] PROGMEM ="Final Result";
20
// short form for 1st, 2nd, 3rd, half time, NO ASCII encoding, MAX7456 code!
21
char en_msg_halftime_A [3] PROGMEM = {0x01, 0x02, 0x03};   // "123"          
22
char en_msg_halftime_B [3] PROGMEM = {0x6A, 0x6B, 0x6C};   // "st nd rd", special chars          
23
char en_msg_penalty[] PROGMEM = "PT";   // penalty throw
24
char en_msg_timeout[] PROGMEM = "TO";   // time out
25
char en_msg_half_time[] PROGMEM = "HT";   // half time break
26
/*************************************************************************
27

28
 display definitions
29

30
*************************************************************************/
31

32

33
char  en_d_0[64] PROGMEM = "     Setup      "
34
                "   Half Time    "
35
               "                "
36
               "< (+ Goals -) > ";
37

38
char  en_d_1[64] PROGMEM = "     Setup      "
39
               "  Penalty throw "
40
               "         s      "
41
               "< (+ Goals -) > ";
42

43
char  en_d_2[64] PROGMEM = "     Setup      "
44
               "   Penalty Time "
45
               "                "
46
               "< (+ Goals -) > ";
47

48
char  en_d_3[64] PROGMEM = "     Setup      "
49
               "Add on play time"
50
               "                "
51
               "< (+ Goals -) > ";
52

53
char  en_d_4[64] PROGMEM = "   Start Game   "  
54
               "HT       PT     "    // HT half time, PT penalty throw
55
               "PT       TO     "    // penalty time, TO time out
56
               " <            > ";
57

58
char  en_d_5[64] PROGMEM = "STOP:           "
59
               "Goals:          "
60
               "Penaltys:       "
61
               "                ";
62

63
char  en_d_6[64] PROGMEM = "STOP:           "
64
               "Goals:          "
65
               "Penaltys:       "
66
               "Wait for START  ";
67

68
char  en_d_7[64] PROGMEM = "Time:           "
69
               "Goals:          "
70
               "Penaltys:       "
71
               "  Timer running ";
72

73
char  en_d_8[64] PROGMEM = "Underwaterrugby "
74
               " Timer + Horn   "
75
               "     Torpedo    "
76
               "   Dresden e.V. ";
77
 
78
char  en_d_9[64] PROGMEM = " Penalty Throw  "
79
               "    running     "
80
               "                "
81
               "   Abort ?      ";
82

83
char en_d_10[64] PROGMEM = "                "   
84
               "   English      "       // Language Setup
85
               "                "
86
               " <            > ";
87

88
char en_d_11[64] PROGMEM = "    Add on      "
89
               "   play time?   "
90
               "                "
91
               "START or STOP   ";
92

93
char en_d_12[64] PROGMEM = "     Setup      "
94
               "  Video Output  "
95
               "                "
96
               "< (+ Goals -) > ";
97

98
char en_d_13[64] PROGMEM = " Penalty Throw  "
99
               "     ready      "
100
               "                "
101
               " Wait for START ";
102

103
char en_d_14[64] PROGMEM = " Penalty Throw  "
104
               "     running    "
105
               "                "
106
               "                ";
107

108
char en_d_15[64] PROGMEM = " Penalty Throw  "
109
               "    finished    "
110
               "                "
111
               "  Press START   ";
112

113
char en_d_16[64] PROGMEM = "     Setup      "
114
               "External Display"
115
               "                "
116
               "< (+ Goals -) > ";
117

118
char en_d_17[64] PROGMEM = "    Time out    "
119
               "                "
120
               "                "
121
               " STOP for End   ";
122

123
char en_d_18[64] PROGMEM = "     Setup      "
124
               "   Time out     "
125
               "                "
126
               "< (+ Goals -) > ";
127

128
char en_d_19[64] PROGMEM = "Abort?          "
129
               "Goals:          "
130
               "Penaltys:       "
131
               "   Press STOP   ";
132

133
char en_d_20[64] PROGMEM = "     Setup      "
134
               "   Game Mode    "
135
               "                "
136
               "< (+ Goals -) > ";
137

138
char en_d_21[64] PROGMEM = " Half time break"
139
               "                "
140
               "                "
141
               "                ";
142

143
char en_d_22[64] PROGMEM = "     Setup6     "
144
               " Half time break"
145
               "                "
146
               "< (+ Goals -) > ";
147

148
char en_d_23[64] PROGMEM = "  Game finished "
149
               "    Result      "
150
               "                "
151
               "                ";
152
char en_d_24[64] PROGMEM = "     Select     "
153
               "   Game         "
154
               "Bl:             "
155
               "Wt:             ";
156

157
// stuct array for language text access
158

159
language_t languages[LANGUAGE_MAX+1] PROGMEM = {
160
    // german
161
    {de_msg_netto, de_msg_brutto, de_msg_SPL, de_msg_UW1, de_msg_UW2, de_msg_PRF,
162
     de_msg_dis_normal, de_msg_dis_flip, de_msg_video_on, de_msg_video_off, de_msg_result,
163
     de_msg_halftime_A, de_msg_halftime_B, de_msg_penalty, de_msg_timeout, de_msg_half_time,
164
     {de_d_0, de_d_1, de_d_2, de_d_3, de_d_4, de_d_5, de_d_6, de_d_7, de_d_8, de_d_9, 
165
      de_d_10, de_d_11, de_d_12, de_d_13, de_d_14,de_d_15, de_d_16, de_d_17, de_d_18, de_d_19,
166
      de_d_20, de_d_21, de_d_22, de_d_23, de_d_24}},
167

168
    //english      
169
    {en_msg_netto, en_msg_brutto, en_msg_SPL, en_msg_UW1, en_msg_UW2, en_msg_PRF,
170
     en_msg_dis_normal, en_msg_dis_flip, en_msg_video_on, en_msg_video_off, en_msg_result,
171
     en_msg_halftime_A, en_msg_halftime_B, en_msg_penalty, en_msg_timeout, en_msg_half_time, 
172
     {en_d_0, en_d_1, en_d_2, en_d_3, en_d_4, en_d_5, en_d_6, en_d_7, en_d_8, en_d_9, 
173
      en_d_10, en_d_11, en_d_12, en_d_13, en_d_14,en_d_15, en_d_16, en_d_17, en_d_18, en_d_19,
174
      en_d_20, en_d_21, en_d_22, en_d_23, en_d_24}}
175
      
176
    };

Am Ende gibt es ein Array von typ language_t, wo alle Sprachen 
zusammengefasst sind, der Index gibt die Sprache an.

Im Programm hat man dann keine direkten Texte mehr, nur noch Verweise 
auf die Member von language_t. Etwa so.
1
  Print_Menu((PGM_P)pgm_read_word(&languages[settings.language].menus[0])
2
Print_Msg((PGM_P)pgm_read_word(&languages[settings.language].msg_dis_normal));

Das sieht durch die pgm_read_word() Funktion vom avr gcc ein wenig wild 
aus, kann man aber mit einer modernen Compilerversion deutlich 
entschärfen. Der Sprachenindex ist eine Variable.
1
Print_Menu(&languages[settings.language].menus[0]);
2
Print_Msg(&languages[settings.language].msg_dis_normal);

Sicher nicht die perfekte Lösung (Weil man keine echten Texgte mehr im 
Programm sieht), aber für kleine bis mittlere Sachen ein brauchbarer 
Kompromiss.
Gast #4224820
Lesenswert?

DirkF schrieb:

> In unsrerm aktuellen C-Programm für eine MCU werden Meldetexte in
> englischer Sprache auf einem Textdisplay ausgegeben:

> Jetzt kommt die Forderung, das Programm mehrsprachig zu gestalten.
> Wie würde man soetwas am Besten umsetzen ? Es sind viele Texte
> vorhanden.

Komische Frage, schließlich ist das kein ganz neues Problem. Natürlich 
benutzt man dazu Lookup-Tables, ist doch logisch, naheliegend und 
überaus trivial. Das einzige Problem ist hier der mit der Zahl der 
unterstützten Sprachen wachsende Speicherbedarf für die konstanten 
Strings und die konstanten Lookup-Tabellen. Also der Flash-Space.

Komplizierter ist schon, wenn es nicht nur darum geht, konstante Strings 
in der richtigen Sprache auszugeben, sondern diese Strings auch noch 
eingebettete variable Bestandteile haben und diese dann auch noch in der 
"richtigen" (zur Sprache passenden) Lokalisierung ausgegeben werden 
müssen.

Aber auch dann ist man weiter bei Lookup-Tabellen, nur daß diese auch 
noch Funktions-Zeiger enthalten müssen. Letztlich (programmiertechnisch 
gesehen) aber ebenfalls absolut trivialer Scheiß, nur viel Fleißarbeit.

Der Hauptaufwand entsteht bei der "Übersetzung". Wenn das nicht jemand 
macht, der 1. versteht, worum es sachlich überhaupt geht, und 2. den für 
die Anwendung einschlägigen Slang sowohl in der Quellsprache als auch in 
der Zielsprache beherrscht, dann wird quasi unvermeidlich für den 
Anwender unverständliche Scheiße dabei rauskommen.

Wir als Deutsche können das Ergebnis lausiger Lokalisierungen aus der 
Quellsprache Englisch oft genug selber erleben, und das obwohl Englisch 
und Deutsch vergleichsweise nahe Verwandte sind und es sicher in beiden 
Sprachräumen kein Problem ist, einen Muttersprachler des jeweils anderen 
aufzutreiben.

Bei "exotischere" Sprachen gibt es genau denselben Effekt, nur noch viel 
stärker ausgeprägt.
#4224840
Lesenswert?

Interessant wird das, wenn man die Grammatik (Reihenfolge von Elementen) 
berücksichtigen muss. Also z.B. das Datumsformat "yyyy/dd/mm" (US) 
gegenüber "dd.mm.yyyy" (DE).

Wenn man sowieso schon eine printf()-Bibliothek hat, kann man sich 
daraus kleine Templates mit positionsgebundenen Argumenten bauen (z.B. 
"%1$d/%2$d/%3$d" fuer englisches, "%3$d.%2$d.%1$d" für deutsches Datum).

Und zum Schluss: Portugiesisch schreibt man mit "ie" in der Mitte.
(Firma: Torrox.de) #4224847
Lesenswert?

S. R. schrieb:
> Wenn man sowieso schon eine printf()-Bibliothek hat, kann man sich
> daraus kleine Templates mit positionsgebundenen Argumenten bauen (z.B.
> "%1$d/%2$d/%3$d" fuer englisches, "%3$d.%2$d.%1$d" für deutsches Datum).

Aber das gibt es doch schon längst, nennt sich gettext und läuft auch 
nicht nur unter Unix; inkl. Tools um die Übersetzungen zu pflegen.

Dabei dient eine Übersetzung als Schlüssel (muss nicht die Englisch 
sein):
1
  lcd_clear();
2
  lcd_puts(_("Cylinder stroke"));
3
  lcd_goto (1,0);
4
  lcd_puts(_("in mm:"));

_ ist hier eine Funktion, die das übergebene Stringliteral als Schlüssel 
für die Suche nach der entsprechenden Übersetzung sucht.

Vorteil ist, dass man auf eine bereits gut getestete Lösung zurück 
greifen kann mit jeder Menge Tools und die meisten Softwareentwickler 
werden diese Lösung auf anhieb verstehen.
Gast #4224944
Lesenswert?

Hallo Torsten.
>>_ ist hier eine Funktion, die das übergebene Stringliteral als Schlüssel
>>für die Suche nach der entsprechenden Übersetzung sucht.

Tja, aber dann wird meine Zykluszeit drastisch ansteigen, wenn er bei 
jeder Textausgabe erst in einer "Datenbank" suchen muss.

Gruß Dirk
(Firma: Torrox.de) #4224952
Lesenswert?

Dirk F schrieb:
> Hallo Torsten.
>>>_ ist hier eine Funktion, die das übergebene Stringliteral als Schlüssel
>>>für die Suche nach der entsprechenden Übersetzung sucht.
>
> Tja, aber dann wird meine Zykluszeit drastisch ansteigen, wenn er bei
> jeder Textausgabe erst in einer "Datenbank" suchen muss.

Naja, Du must die Daten ja nicht in einer "Datenbank" ablegen. Du 
könntest Sie z.B. auch im Flash ablegen. Wenn Du deinem Linker erklären 
kannst, dass er alle Duplikate von String-Literalen entfernen soll, dann 
reicht sogar die Adresse des Literals als Key.

Wenn Du einfach gerne das Rad neu erfinden möchtest, dann mach das doch 
einfach. Macht evtl. viel Spaß und man lernt ne Menge dabei ;-)
Gast #4225007
Lesenswert?

S. R. schrieb:
> gegenüber "dd.mm.yyyy" (DE).

Guck dir mal die aktuelle Normung für Datumsformate an, als da wären
ISO 8601 und EN 28601. Die DIN 1355 aus dem Jahre 1943 mit deinem 
DE-Datumsformat wurde schon vor 20 Jahren durch die EN 28601 mit u.a. 
dem Format "yyyy-mm-dd" abgelöst.

Oder schreibst du sonst bei Zahlen auch die höchstwertige Stelle 
irgendwo weit hinten? ;-)
Gast #4225014
Lesenswert?

Wolfgang schrieb:
> Die DIN 1355 aus dem Jahre 1943 mit deinem
> DE-Datumsformat wurde schon vor 20 Jahren durch die EN 28601 mit u.a.
> dem Format "yyyy-mm-dd" abgelöst.

Das ist mir - hoeflich formuliert - schei..egal.

Ich will in einer Anzeige das Datum als dd.mm.yyyy sehen.(Punkt)
In der Verwendung als Dateinamen sieht das ganz anders aus, klar.

wendelsberg
#4225022
Lesenswert?

Wolfgang schrieb:
> Guck dir mal die aktuelle Normung für Datumsformate an, als da wären
> ISO 8601 und EN 28601. Die DIN 1355 aus dem Jahre 1943 mit deinem
> DE-Datumsformat wurde schon vor 20 Jahren durch die EN 28601 mit u.a.
> dem Format "yyyy-mm-dd" abgelöst.

Schön für ISO 8601 und EN 28601, relativ egal für mich. Innerhalb 
Deutschlands ist dd.mm.yyyy das gebräuchliche Format, also zeige ich ein 
Datum in deutsch lokalisierter Software auch so an.

Offiziell hat auch UK das metrische System. Verkehrsschilder geben 
Entfernungen trotzdem in Yards und Meilen an.
Gast #4225032
Lesenswert?

Wolfgang schrieb:
> wendelsberg schrieb:
>> In der Verwendung als Dateinamen sieht das ganz anders aus, klar.
>
> Was hat die DIN ISO 8601 jetzt speziell mit Dateinamen zu tun.

Dort verwende ich yyyy_mm_dd.xxx weil diese sich von selbst sortieren.

Die Verwendung von:
S. R. schrieb:
> Datumsformat "yyyy/dd/mm" (US)
ist allerdings vollkommener Bloedsinn, deswegen kommt das fuer mich 
nirgendwo in Frage.

wendelsberg
Gast #4225115
Lesenswert?

Hallo zusammen,
also das hört sich ja alles recht kompliziert an. Es schein so zu sein, 
dass es keine fertige Lösung gibt, um die Sprache während der Laufzeit 
umzuschalten.

Ich könnte auch damit leben, wenn für eine andere Sprache das Programm 
neu kompiliert werden muss.
Irgendwie bekomme ich die Syntax aber für so etwas nich hin:
1
#define spanish  
2

3
#ifdef spanish  
4
#define TEXT1  Text1_auf_spanisch
5
#define TEXT2  Text2_auf_spanisch
6
#endif
7

8
#ifdef deutsch  
9
#define Text1  "Text1_auf_deutsch"
10
#define Text2  "Text2_auf_deutsch"
11
#endif
12

13
  lcd_clear();
14
  lcd_puts(TEXT1);
15
  lcd_goto (1,0);
16
  lcd_puts(TEXT2);

Wer kann helfen ?
#4225129
Lesenswert?

DirkF schrieb:

> Wer kann helfen ?

Du dir selbst.

Was ist der augenfälligste Unterschied zwischne
1
#define TEXT1  Text1_auf_spanisch

und
1
#define Text1  "Text1_auf_deutsch"

Welches ist die richtige Version?
Ersetz mal in beiden Fällen in
1
  lcd_puts(TEXT1);

das Makro.
Das eine mal kommt raus
1
  lcd_puts(Text1_auf_spanisch);

und das andere mal kommt raus
1
  lcd_puts("Text1_auf_deutsch");

(Makros sind nur Textersetzungen. Ein Text wird an der verwendenden 
Stelle durch einen anderen Text ersetzt)
Welche von beiden Versionen ist syntaktisch korrekt und warum?
Wie muss daher das Makro aussehen?

(Wenn du mit Makros arbeitest und nicht verstehst, warum du einen Fehler 
kriegst, dann mach ersetz einfach an der verwendenden Stelle den 
Makronamen mit dem beim Makro angegebenen Ersatztext und sieh dir dieses 
Ergebnis an, was daran falsch ist. Was anderes machen Präprozessor und 
Compiler auch nicht. D.h.: im wesentlichen)
Gast #4225210
Lesenswert?

Danke Karl-Heinz,
hat funktioniert.
Sorry bin halt noch nicht so gut im C-Programmieren....
Gruß Dirk
1
#define spanish  
2

3
#ifdef spanish  
4
#define TEXT1  "Text1_auf_spanisch"
5
#define TEXT2  "Text2_auf_spanisch"
6
#endif
7

8
lcd_puts(TEXT1);
9
lcd_puts(TEXT2);
Gast #4225240
Lesenswert?

ich wuerd's so irgendwie implementieren (es würde sich sogar noch etwas 
weiter kürzen lassen):
1
struct language {
2
    char *english_text;
3
    char *german_text;
4
etc.
5
} lang_array[]={
6
   { "Hello", "Hallo" }
7
};
8

9
#define ENGLISH 1
10
#define GERMAN  2
11

12
void printf_t(char *txt) {
13
    int i;
14
    for(i=0;i<sizeof(language)/sizeof(language[0]);i++) {
15
          if (strcmp(lang_array[i].english_text, txt)==0) {
16
               break;
17
          }
18
    }
19

20
    if (i==sizeof(language)/sizeof(language[0]))
21
       printf("%s", txt);
22
       return;
23

24
    switch(global_selected_language) {
25
    case ENGLISH:
26
          printf(lang_array[i].english_text);
27
          break;
28
    etc.
29
    }
30
}
31

32
printf_t("text in english");
#4225534
Lesenswert?

DirkF schrieb:
> Hallo Spock,
> danke für Deinen Vorschlag.
> Sehe ich dass richtig, dass bei Deiner Lösung die SPrache auch während
> der Laufzeit umgestellt werden könnte, also nicht  nur vor dem
> Compilerlauf ?

Schon.
Aber auf Kosten von Speicher und Laufzeit.

Auf einem PC kein Problem. Auf einem kleinen µC wirds das aber ganz 
schnell.
#4225552
Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Aber auf Kosten von Speicher und Laufzeit.

Oh WEHH!!

>Auf einem PC kein Problem. Auf einem kleinen µC wirds das aber ganz
>schnell.

Laute, übertreibt's mal nicht! Auch "kleine" uC haben heute ziemlich 
viel Speicher! Wir reden hier nicht über 1kB Flash PIC12 oder so!

Diese Methode läuft prima und ist kaum langsamer als ein normales 
Printf!

Beitrag "Re: C: Programm mit Textanzeige für mehrere Sprachen"

Dass man für jede Sprache nochmal grob den gleichen Spreicher für die 
Texte braucht ist wohl klar. So what! Was kostet ein 128kB Flash uC 
heute?
#4225553
Lesenswert?

Wenn es nicht zur Laufzeit geschehen muß, ist die Sache nicht gewaltig 
aufwendig. Bei mir gibt es einfach eine Datei texts_deu.h, die 
mitgelinkt wird. Bei einer anderen Sprachversion eine texts_eng.h. Darin 
steht etwas wie:
1
constflash char MT_NULL[]     = {'\0'};
2
constflash char MT_RETURN[]   = "zurück";
3
constflash char MT_YES[]      = "Ja";
4
constflash char MT_NO[]       = "Nein";
5
constflash char MT_CANCEL[]   = "Abbrechen";
6
constflash char MT_ABORT[]    = "Abbrechen";
7
constflash char MT_RETRY[]    = "Nochmal versuchen";
8
constflash char MT_CONTINUE[] = "Weiter";
9
constflash char MT_PREFSMENU[]    = "Einstellungen";
10
constflash char MT_INFOSCREEN[]   = "Firmware-Info";
11
constflash char MT_PRESSKEYTOLEAVE[] = "Beenden mit Taster";
12
constflash char MT_SAVEANDRET[]    = "\033vspeichern\033f & \033vzurück\033f";
13
constflash char MT_VAR_TONMIN[]    = "t\033son,min      \033n :  %2uµs";
14
constflash char MT_VAR_TOFFMIN[]   = "t\033soff,min     \033n :  %2uµs";

Und im Programm die entsprechenden printf-Anweisungen. Das hat selbst 
bei einem rein deutschsprachigen Programm den Vorteil, daß im Quelltext 
die kurzen englischen Bezeichner stehen (kein 
Deutsch-Englisch-Mischmasch) und die Quelltexte dann besser lesbar sind.
Gast #4225557
Lesenswert?

// ansatz für eine bei der compilation berücksichtigte sprache
// vorteil:  es steht nur das im code was drin stehen soll
// nachteil: kein wechsel durch anwender nach kompilation

im makefile dann das compiler flagg -D entsprechend

für deutsch
-DDEUTSCH

für englisch
-DENGISCH

für sonstige ( oder anpassen )
-DENGLISCH


language_paket.h
1
..
2
..
3

4
#ifdef DEUTSCH  
5
#define Cylinder_stroke  "Zylinderhub"
6
#define in_mm            "in mm:"
7
// usw
8
#endif
9

10
#ifdef ENGLISCH  
11
#define Cylinder_stroke  "Cylinder Stroke"
12
#define in_mm            "in mm:" // oder andere einheit
13
                                  // mit umrechnungsfunktion in inches
14
                                  // 100 mm sind ca 3,93701 inches also
15
                                  // du brauchst dann float! als ergebnis
16
// formel mm / 25,4 = inches
17
#define mm2inch           .....
18

19
// usw
20
#endif
Gast #4225569
Lesenswert?

wenn du also voreinstellung DEUTSCH in der compiler flagg benutzt,
dann wird dein Cylinder_stroke umgewandelt in "Zylinderhub"
1
  lcd_clear();
2
  lcd_puts(_(Cylinder_stroke));
3
  lcd_goto (1,0);
4
  lcd_puts(_(in_mm));


wenn du voreinstellung ENGLISCH in der compiler flagg benutzt,
dann wird dein Cylinder_stroke umgewandelt in "Cylinder stroke"
Gast #4225575
Lesenswert?

Karl H. schrieb:
> Schon.
> Aber auf Kosten von Speicher und Laufzeit.
>
> Auf einem PC kein Problem. Auf einem kleinen µC wirds das aber ganz
> schnell.

Speicher wird's das Gleiche benötigen, Laufzeit kommt auf den Controller 
drauf an, man kann's aber natürlich noch optimieren.
Der Vorteil ist schon mal falls irgendwo die Übersetzung nicht da ist 
das dann wenigstens auf das Fallback zurückgegriffen wird.

Effizienter kann man's bezüglich dem Speicher nicht mehr gestalten (jede 
extra IF Abfrage wäre zudem zusätzlicher Speicherverbrauch), aber wie 
schon von jemand anderem erwähnt -- in diesem Fall sind die paar Bytes 
mehr oder weniger absolut kein Grund.

Man kann auch mit einem Index arbeiten und sich das strcmp sparen, ist 
dann halt nicht so komfortabel zum Programmieren...


#include <stdio.h>

#define HALLO_WELT 0
struct lang {
        char *german;
        char *english;
} foo[]={
 [HALLO_WELT]={"hallo", "Welt"}
};

#define GERMAN 0
#define ENGLISH 1
int language=GERMAN;
int printf_t(int idx) {
        switch(language) {
        case GERMAN:
                printf("%s\n",foo[idx].german);
                break;
        case ENGLISH:
                printf("%s\n",foo[idx].english);
                break;
        }

        return 0;
}
int main() {
        printf("%s\n", foo[HALLO_WELT].german);
        printf("%s\n", foo[HALLO_WELT].english);
        printf_t(HALLO_WELT);
        language=ENGLISH;
        printf_t(HALLO_WELT);
        return 0;
}
Gast #4225576
Lesenswert?

push#
noch ein vorteil
kommt jetzt einer weitere sprache dazu, ergänzt du das
language_paket.h
1
..
2
..
3

4
#ifdef DEUTSCH  
5
#define Cylinder_stroke  "Zylinderhub"
6
#define in_mm            "in mm:"
7
// usw
8
#endif
9

10
#ifdef ENGLISCH  
11
#define Cylinder_stroke  "Cylinder Stroke"
12
#define in_mm            "in mm:" // oder andere einheit
13
                                  // mit umrechnungsfunktion in inches
14
                                  // 100 mm sind ca 3,93701 inches also
15
                                  // du brauchst dann float! als ergebnis
16
// formel mm / 25,4 = inches
17
#define mm2inch           .....
18

19
// usw
20
#endif
21

22

23
#ifdef PORTUGAL
24
#define Cylinder_stroke  "Cylinder Stroke"
25
#define in_mm            "in mm:" // oder andere einheit wie oben
26
#endif

und am programm quelltext muss nichts geändert werden.


den ansatz für in der laufzeit änderebare sprache müsstest du das ganze 
soweit abändern, dass du dir ein enum anlegst:

> char eng,span,potugisisch;
> eng = 0;
> span = 1;
> portugisisch=0;

so denke ich würde ich es nicht machen, da würde ich enum verwenden
1
enum language { eng, span, portugisisch=0 };

und über eine 'setup variable' am anfang des programms die sprache 
einstellen, den text dann über ein array of struct vorhalten und über 
den idx ( index ) des gewählten enum ausgeben.
ändert der benutzer über setup funktion die sprache, ändert sich nur der 
idx zur passenden array of struct passage.

..
#4225591
Lesenswert?

.. schrieb:
> dann über ein array of struct vorhalten

Nö.

Man muß nur ein einziges Struct vorhalten, das alle Texte in einer 
Sprache enthält und beim Start aus dem Flash geladen wird. Dann spart 
man sich die zusätzliche Indizierung.

Also so:
1
printf(txt.abort);
und nicht
1
printf(txt[lang].abort);

Es sei denn, man ist extrem eng im SRAM und das txt-Struct paßt nicht 
mehr hinein - dann muß man den Index die ganze Zeit mitschleppen.
Gast #4225595
Lesenswert?

speicher optimierung:

du könntest dann mit dynamischer speicherverwaltung arbeiten,
und zur laufzeit und bedarfszeit mit malloc() /  calloc()
realloc() arbeiten, und dabei immer wieder den alten speicher
entweder neu nutzen, oder freigeben und neu anfordern.
somit ist immer nur ein sprachpaket im speicher.

ich würde sogar ein standard sprachpaket setzen ( englisch )
und bei bedarf den belegeten speicher mit deutsch neu belegen..

es macht also keinen unterschied, nur das file selbst wird
etwas grösser für das flash, was aber ins ram oder auf dem stack
kommt, entscheidest dann du.

..
Gast #4225605
Lesenswert?

char lcd_buffer[33];
char hrs = 13;
char Language = 0;  // Englisch gewählt

flash char* Messages[][3] = {
/*         Englisch          Deutsch            Franzoesisch   */
/* 0 */    "Please wait",    "Bitte warten",    "attendre",
/* 1 */    "Hours: %u",      "Stunden: %u",     "heure: %u"
};

  lcd_clear();
  sprintf(lcd_buffer, Messages[0][Language]);        // "Please wait"
  lcd_puts(lcd_buffer);
  lcd_goto (1,0);
  sprintf(lcd_buffer, Messages[1][Language], hrs);   // "Hours: 13"
  lcd_puts(lcd_buffer);
Gast #4225611
Lesenswert?

VladimirM schrieb:
> char lcd_buffer[33];
> char hrs = 13;
> char Language = 0;  // Englisch gewählt
>
> flash char* Messages[][3] = {
> /*         Englisch          Deutsch            Franzoesisch   */
> /* 0 */    "Please wait",    "Bitte warten",    "attendre",
> /* 1 */    "Hours: %u",      "Stunden: %u",     "heure: %u"
> };
>
>   lcd_clear();
>   sprintf(lcd_buffer, Messages[0][Language]);        // "Please wait"
>   lcd_puts(lcd_buffer);
>   lcd_goto (1,0);
>   sprintf(lcd_buffer, Messages[1][Language], hrs);   // "Hours: 13"
>   lcd_puts(lcd_buffer);

danke!

;-)
Gast #4225636
Lesenswert?

Hallo zusammen,
vielen Dank für die zahlreichen Antworten. Hat mir sehr geholfen.
Habe mich jetzt für diese Version entschieden, ist leicht umzusetzen.
Dann muss halt eine Sonderversion für eine andere Sprache compiliert 
werden und im Werk vor Auslieferung neu geflashed werden.
Kann man dann auch so bequem an ein Übersetzungsbüro zum Ausfüllen 
senden.
Und am wichtigsten: Der Quelltext bleibt gut lesbar, auch für einen 
Kollegen in der Urlaubszeit !!!!

//Nur die gewünschte Sprache auskommentieren und neu kompilieren
#define ENGLISH         // Standardsprache
//#define SPANISH
//#define PORTUGUESE
//#define GERMAN


#ifdef ENGLISH //
//      Diese Spalte            Hier Sprachtext eintragen
//      nicht verändern!        "...max.20 Zeichen..."
#define temperature          "temperature "
#define in_Celsius              "in Celsius:"
#define Contact_force           "Contact force"
#endif

lcd_puts(temperature);

Gruß Dirk
Gast #4225658
Lesenswert?

DirkF schrieb:
>
> //Nur die gewünschte Sprache auskommentieren und neu kompilieren

das könntest du mit dem compiler flag -D erledigen Dirk.
-D steht für Define und macht nichts anderes als du
deine zu brauchende Sprache im programm code zu definieren mit

#define DEUTSCH

=

gcc -DDeutsch ......

Beitrag "c code beta, release je nach gesetzter auswahl compilieren"

und es muss gar keiner an den code
sondern nur das werk das makefile aufrufen.

wenn du ein datenbankmangement einsetzt, kannst du über die adresse
des kunden und des auftrags sogar ein automatisches makefile anlegen.

so mache ich das z.b. mit serialisierung / unique id

-DAUFTRAG
#4225678
Lesenswert?

VladimirM schrieb:
> char lcd_buffer[33];
> char hrs = 13;
> char Language = 0;  // Englisch gewählt
>
> flash char* Messages[][3] = {
> /*         Englisch          Deutsch            Franzoesisch   */
> /* 0 */    "Please wait",    "Bitte warten",    "attendre",
> /* 1 */    "Hours: %u",      "Stunden: %u",     "heure: %u"
> };
>
>   lcd_clear();
>   sprintf(lcd_buffer, Messages[0][Language]);        // "Please wait"
>   lcd_puts(lcd_buffer);
>   lcd_goto (1,0);
>   sprintf(lcd_buffer, Messages[1][Language], hrs);   // "Hours: 13"
>   lcd_puts(lcd_buffer);

Besser anders rum, dann spart man sich pro Aufruf einen index:
1
flash char *Messages[][] =
2
{
3
  /* EN */ { "Please wait",  "Hours: %u" },
4
  /* FR */ { "Attendre svp", "Heure: %u" },
5
  /* DE */ { "Bitte Warten", "Stunden: %u" }
6
} 
7

8
#define ENGLISH  0
9
#define FRANCAIS 1
10
#define DEUTSCH  2
11

12
#define WAIT  0
13
#define HOURS 1
14

15
#define _(x) Language[x]
16

17
static char **Language;
18

19
#if I_WANT_A_FUNCTION_FOR_SETLANGUAGE /* :-) */
20
void setLanguage (uint8 lang)
21
{ /* TODO check lang for validity */
22
  Language = Messages[lang];
23
}
24
#else
25
#define setLanguage(x) Language = Messages[x]
26
#endif
27

28
...
29

30
setLanguage(ENGLISH);
31
sprintf(lcd_buffer, _(WAIT));
32
lcd_puts(lcd_buffer);
Gast #4226996
Lesenswert?

Wolfgang schrieb:
> S. R. schrieb:
>> gegenüber "dd.mm.yyyy" (DE).
>
> Guck dir mal die aktuelle Normung für Datumsformate an, als da wären
> ISO 8601 und EN 28601. Die DIN 1355 aus dem Jahre 1943 mit deinem
> DE-Datumsformat wurde schon vor 20 Jahren durch die EN 28601 mit u.a.
> dem Format "yyyy-mm-dd" abgelöst.
ISO8601 beschreibt ein Format für den Datenaustausch. Damit sind 
Maschinen gemeint, die Daten z.B. über XML, CSV oder fixed Format 
austauschen, keine Menschen. Für den Menschen hat ein Datum in der 
landesüblichen Form ausgegeben zu werden.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren