Forum: Compiler & IDEs C: Programm mit Textanzeige für mehrere Sprachen


von DirkF (Gast)


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

: Verschoben durch User
von Amateur (Gast)


Lesenswert?

Such mal nach der Stichworten:

Internationalisierung (I18N)

oder:

Lokalisierung (L10N)

Es gibt dazu einen Satz an Tools, da nicht nur Du ein Problem haben 
könntest, sondern auch der Anwender.

von Bestromer (Gast)


Lesenswert?

...interessantes Problem, Texttabellen klingt doch im ersten Moment gut?

von micha (Gast)


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.

von micha (Gast)


Lesenswert?

Lustig wird es übrigens, wenn man auch noch andere  Einheiten (z.B. 
US-"inch" statt "cm") berücksichtigen muss ;-)

von Amateur (Gast)


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.

von Falk B. (falk)


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.

von c-hater (Gast)


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.

von Hans Ulli K. (Gast)


Lesenswert?

In Linux wird das z.B. mit gettext gemacht

https://de.wikipedia.org/wiki/GNU_gettext

Im Prinzip gibt es nur die englische Ausgabe, wo dann mit einer 
Stringersetzung die entsprechende Übersetzung ausgegeben wird.

von S. R. (svenska)


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.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


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.

von S. R. (svenska)


Lesenswert?

Torsten R. schrieb:
> 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.

Richtig, allerdings habe ich gettext auf einem nackten AVR nicht zur 
Verfügung, im Gegensatz zu printf. (Ich gehöre zu der Fraktion, die den 
Wert von printf größer als dessen Codegröße schätzt.)

von Dirk F (Gast)


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

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


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 ;-)

von Wolfgang (Gast)


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? ;-)

von wendelsberg (Gast)


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

von S. R. (svenska)


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.

von Wolfgang (Gast)


Lesenswert?

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.

Aber natürlich kannst du auf deiner Anzeige das Datum so darstellen, wie 
du möchtest, auch mit "(Punkt)".

von wendelsberg (Gast)


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

von DirkF (Gast)


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 ?

: Bearbeitet durch User
von Karl H. (kbuchegg)


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)

: Bearbeitet durch User
von DirkF (Gast)


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);

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

DirkF schrieb:

> Sorry bin halt noch nicht so gut im C-Programmieren....

Hat mit 'gut sein' eher weniger zu tun.
Sondern mit 'gut bzw. aufmerksam beobachten'.
Aber das wirst du schon noch bis zum Erbrechen feststellen, dass 70% in 
der Entwicklungsarbeit darin besteht, Dinge zu bemerken, die Lieschen 
Müller nicht sieht.

: Bearbeitet durch User
von Spock (Gast)


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");

: Bearbeitet durch User
von Spock (Gast)


Lesenswert?

(da sind natürlich einige Fehler enthalten sizeof language -> sizeof 
lang_array etc., aber der Ablauf sollte klar sein)

von DirkF (Gast)


Lesenswert?

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 ?

von Karl H. (kbuchegg)


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.

von Falk B. (falk)


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?

von Walter T. (nicolas)


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.

: Bearbeitet durch User
von .. (Gast)


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

von .. (Gast)


Lesenswert?

push#
weiterer vorteil
du proggst dein programm mit namen der variablen,
am besten dann in deiner muttersprache.

von .. (Gast)


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"

von Spock (Gast)


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;
}

von .. (Gast)


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.

..

von .. (Gast)


Lesenswert?

c-hater schrieb:

sinngemäss schreibst du von meiner seele im eigenen post:


> ..absolut trivialer Scheiß, ..

;-)

von .. (Gast)


Lesenswert?

..und die wortwahl triffst du auch selber

;-)

von Walter T. (nicolas)


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.

von .. (Gast)


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.

..

von .. (Gast)


Lesenswert?

Walter T. schrieb:
> .. schrieb:
>> dann über ein array of struct vorhalten
>
> Nö.

hast ja recht, bin doch schon bei der speicher optimierung,
eins nach dem anderen ;-)
..

von VladimirM (Gast)


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);

von .. (Gast)


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!

;-)

von DirkF (Gast)


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

von .. (Gast)


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

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> Was kostet ein 128kB Flash uC
> heute?

na das vierfache oder mehr

Arduino m328p 5,- (oder viel billiger)
Arduino mighty m1284p 22,-€ +FTDI

von Eric B. (beric)


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);

: Bearbeitet durch User
von Markus (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.