Forum: Compiler & IDEs Mehrsprachig programmieren für AVR


von Sebastian B. (sebastian_)


Lesenswert?

Hi,

in einem avr Programm hat man die Strings ja in der Regel als PSTR().

Wie macht man so ein Programm mehrsprachig ?

Die Sprache muss nicht wechselbar sein (das Programm würde dann auch 
durch die vielen Strings zu gross werden), sondern für jede Sprache soll 
eine eigene Version compiliert werden.

danke
Sebastian

von me (Gast)


Lesenswert?

schau mal nach "compiler direktiven" / "compiler switches"

von Huch (Gast)


Lesenswert?

>Wie macht man so ein Programm mehrsprachig ?

Nun, für Anfänger fangen wir da mal ganz einfach an:

1. In einem String steht "Hello world".
Das ist Englisch. Gut, nich?
2. Ändern wir den String zu "Helpo world".
Das ist ein Wortspiel, immer noch Englisch. Gut ne?
3. Korrigieren wir den String zu "Salut monde".
Das ist kein Englisch. Das mögen die Franzosen nicht.
Ist Fränzösisch. Eine andere Sprache. Pas mal, nes pas?

Das ist doch, das was Du wolltest oder? Einen Text in eine andere 
Sprache umsetzen?

Was war jetzt nochmal das Problem?

von Sebastian B. (sebastian_)


Lesenswert?

me schrieb:
> schau mal nach "compiler direktiven" / "compiler switches"

damit kenn ich mich aus, aber welches Design Pattern schlägst du konkret 
vor?

von Klaus W. (mfgkw)


Lesenswert?

Das kommt etwas drauf an: wieviele Sprachen, kommen später
welche dazu, wie einfach/ausfuchst soll es ein....

Ein schlichter und praktikabler Ansatz könnte etwa so aussehen
(noch um ein paar PROGMEM etc. bereichert):

prg.c:
1
...
2
#include "texte.h"
3
...
4
  puts( TEXT_INTRO_HALLO );
5
  printf( TEXT_NAME_FMT_S_ALTER_FMT_D"\n", "Klaus", 16 );
6
...

de/texte.h:
1
#ifndef _TEXTE_H_INCLUDED
2
#define _TEXTE_H_INCLUDED
3
4
#define TEXT_INTRO_HALLO              "Willkommen zu dem tollen Programm"
5
#define TEXT_NAME_FMT_S_ALTER_FMT_D   "Mein Name ist %s, mein Alter ist %d"
6
7
#endif /* ifndef _TEXTE_H_INCLUDED */


en/texte .h:
1
#ifndef _TEXTE_H_INCLUDED
2
#define _TEXTE_H_INCLUDED
3
4
#define TEXT_INTRO_HALLO              "Hi"
5
#define TEXT_NAME_FMT_S_ALTER_FMT_D   "My name is %s and I am %d years old"
6
7
8
#endif /* ifndef _TEXTE_H_INCLUDED */

Kompiliert wird dann je nach gewünschter Sprache mit:
1
avr-gcc ... -I de ... prg.c -o ...
2
avr-gcc ... -I en ... prg.c -o ...
bzw.
1
LANG=de
2
avr-gcc ... -I $(LANG) ... prg.c -o ...

von Sebastian B. (sebastian_)


Lesenswert?

Huch schrieb:
> Was war jetzt nochmal das Problem?

wenn ich alle Texte im Programm austausche ist es doch deswegen nicht 
mehrsprachig.
Versuch erstmal mal mein Problem zu verstehen.

von Sebastian B. (sebastian_)


Lesenswert?

Klaus Wachtler schrieb:
> Das kommt etwas drauf an: wieviele Sprachen, kommen später
> welche dazu, wie einfach/ausfuchst soll es ein....
>
> Ein schlichter und praktikabler Ansatz könnte etwa so aussehen
> (noch um ein paar PROGMEM etc. bereichert):

an sowas hab ich auch schon gedacht, gefällt mir aber irgendwie nicht.

Gibts nicht vielleicht irgenwelche Makros mit denen man das so basteln 
kann, das zumindest der Text einer Sprache, im Programm-Code sichtbar 
bleibt und nur die anderen Sprachen in Header-Files stehen ?

von Huch (Gast)


Lesenswert?

>Versuch erstmal mal mein Problem zu verstehen.
Umgekehrt wird ein Schuh, daraus. Versuche Du erstmal Dein Problem 
korrekt zu beschreiben. Du willst ja was von uns.

Eine Frage wie nach einem "Designpattern" ist da schon viel hilfreicher, 
weil auch ein anderes Niveau anzunehmen ist. Ein Anfänger fragt nicht 
nach "Designpatterns". Aber so klang das für mich nach: Wie definiert 
man zwei verschiedene konstante Strings.

von Sebastian B. (sebastian_)


Lesenswert?

Huch schrieb:
>>Versuch erstmal mal mein Problem zu verstehen.
> Umgekehrt wird ein Schuh, daraus. Versuche Du erstmal Dein Problem
> korrekt zu beschreiben. Du willst ja was von uns.
>
> Eine Frage wie nach einem "Designpattern" ist da schon viel hilfreicher,
> weil auch ein anderes Niveau anzunehmen ist. Ein Anfänger fragt nicht
> nach "Designpatterns". Aber so klang das für mich nach: Wie definiert
> man zwei verschiedene konstante Strings.

sorry, aber deine Antwort war einfach komplett sinnloser Müll. Soeinen 
Käse würd ich nichtmal nem Anfänger erzählen, es sei denn ich will ihn 
verarschen.

Meine Frage war konkret genug um darauf eine sinnvolle Anwort zu geben, 
wie dies zB. Klaus ja getan hat.

von Klaus W. (mfgkw)


Lesenswert?

Sebastian Böhm schrieb:
> Klaus Wachtler schrieb:
> ...
> an sowas hab ich auch schon gedacht, gefällt mir aber irgendwie nicht.

Jetzt bin ich aber fast beleidigt.

>
> Gibts nicht vielleicht irgenwelche Makros mit denen man das so basteln
> kann, das zumindest der Text einer Sprache, im Programm-Code sichtbar
> bleibt und nur die anderen Sprachen in Header-Files stehen ?

Das gibt es auch.

Dazu schreibst du dir z.B. den deutschen Text hin, und läßt
für die anderen Sprachen ein Programm rüberrackern, das alle
deutschen Texte durch andere ersetzt, wenn es einen passenden
Eintrag in einer Tabelle hat.
Das kann man direkt machen, oder indem man den zu ersetzenden
Text noch speziell markiert printf( I18N("hallo") ).
Aber das gefällt mir dann wieder nicht (was dir egal sein
dürfte).

Ein Mittelweg ist, das so wie oben mit den Makros zu machen
und den Makros halt Namen zu geben, aus denen der Text
ersichtlich ist. Macht ja nix, wenn sie etwas länger werden.

von adfix (Gast)


Lesenswert?

Hallo Sebastian,

mit gettext http://de.wikipedia.org/wiki/GNU_gettext kann man sowas 
machen. Dein String "Hallo" ersetzt Du durch _("Hallo").

Der String wird dann allerdings zur Laufzeit übersetzt. Das ist auf 
einem PC kein Problem, auf einem Atmel frisst das etwas Resourcen.

Wäre das eine Alternative ?

adfix

von Sebastian B. (sebastian_)


Lesenswert?

adfix schrieb:
> Wäre das eine Alternative ?

leider nein. Zuviel Text, das passt in den kleinen Atmel nicht rein. :-)

von Huch (Gast)


Lesenswert?

Wie Du meinst, Sebastian. Ich wollte Dir nur etwas demonstrieren.
Aber scheinbar ist das kein Gewinn für Dich. Lass' ich es also.

von Sebastian B. (sebastian_)


Lesenswert?

Klaus Wachtler schrieb:
> Das gibt es auch.
>
> Dazu schreibst du dir z.B. den deutschen Text hin, und läßt
> für die anderen Sprachen ein Programm rüberrackern, das alle
> deutschen Texte durch andere ersetzt,

optimal wäre es so, das der Text der Primärsprache an Ort und Stelle im 
Code steht und die anderen Sprache mittels eines einfaches Switches im 
Makefile (also ein define) aktiviert werden können.

Hat da jemand ein fertiges, bewährtes Makro das auch mit PSTR() umgehen 
kann?

von Sebastian B. (sebastian_)


Lesenswert?

Huch schrieb:
> Wie Du meinst, Sebastian. Ich wollte Dir nur etwas demonstrieren.
> Aber scheinbar ist das kein Gewinn für Dich. Lass' ich es also.

deine Demonstration war meiner Meinung nach übertrieben.

von Rolf Magnus (Gast)


Lesenswert?

Sebastian Böhm schrieb:
> Klaus Wachtler schrieb:
>> Das gibt es auch.
>>
>> Dazu schreibst du dir z.B. den deutschen Text hin, und läßt
>> für die anderen Sprachen ein Programm rüberrackern, das alle
>> deutschen Texte durch andere ersetzt,
>
> optimal wäre es so, das der Text der Primärsprache an Ort und Stelle im
> Code steht und die anderen Sprache mittels eines einfaches Switches im
> Makefile (also ein define) aktiviert werden können.
>
> Hat da jemand ein fertiges, bewährtes Makro das auch mit PSTR() umgehen
> kann?

Das wird so einfach mit einem Makro nicht gehen. Wie Klaus schon meint, 
müßtest du dir da ein Programm/Skript basteln, das sozusagen als 
zusätzlicher Präpropzessor über deinen Code geht und die Strings vor 
Übergabe an den Compiler ersetzt.
Dann kann man auch gettext (ohne die Laufzeitkomponente) verwenden, um 
die Übersetzungen zu erzeugen.

von Klaus W. (mfgkw)


Lesenswert?

Sebastian Böhm schrieb:
> optimal wäre es so, das der Text der Primärsprache an Ort und Stelle im
> Code steht

Der Grund, weswegen mir das nicht so gefällt ist, ist der:
Ich kann mir durchaus Situationen vorstellen, wo ein kurzer
knapper Text unterschiedlich zu übersetzen wäre, je nach
Situation, in der er steht.

Nach deiner Vorstellung wäre er aber nur anhand seines
Wortlauts immer gleich zu übersetzen.
Gerade weil dann aber die fremdsprachliche Variante
wahrscheinlich nie mehr von einem entsprechend Sprachkundigen
so genau angeschaut wird, bevor es zum Kunden geht, habe ich
dabei etwas Magenschmerzen.

Bei der #define-Variante überlegt man sich die Übersetzung
hoffentlich zu einem Zeitpunkt, wo man die konkrete
Programmsituation vor Augen hat.

Deswegen sollst du jetzt nicht auf deine Vorstellung
verzichten, für dich mag es anders aussehen.

von Huch (Gast)


Lesenswert?

Sebastian Böhm schrieb:
> Huch schrieb:
>> Wie Du meinst, Sebastian. Ich wollte Dir nur etwas demonstrieren.
>> Aber scheinbar ist das kein Gewinn für Dich. Lass' ich es also.
>
> deine Demonstration war meiner Meinung nach übertrieben.

Mag sein, aber Du kennst sicher den Spruch, das nur gehört/gelesen wird, 
wer übertreibt.

Andererseits hast Du mich ja garnicht darum gebeten Dir was zu 
demonstrieren. Tut mir leid, wenn ich Dich gestört haben sollte. Lebe 
und denke einfach so weiter, als sei nichts gescheh'n und alles in 
Ordnung.
Wird schon stimmen.

von Sebastian B. (sebastian_)


Lesenswert?

Rolf Magnus schrieb:
> Das wird so einfach mit einem Makro nicht gehen. Wie Klaus schon meint,
> müßtest du dir da ein Programm/Skript basteln, das sozusagen als
> zusätzlicher Präpropzessor über deinen Code geht und die Strings vor
> Übergabe an den Compiler ersetzt.
> Dann kann man auch gettext (ohne die Laufzeitkomponente) verwenden, um
> die Übersetzungen zu erzeugen.

ja ok, so werd ichs machen.

ich werd die strings markieren: /*TEXTID:1*/PSTR('xxx'), so das das 
Skript sie findet auch wenn ich den Original Text geändert habe.

von Edi R. (edi_r)


Lesenswert?

Wenn ich Dich richtig verstehe, willst Du zwar alle Sprachen im 
Quelltext vorbereitet haben, aber die jeweilige Sprachversion erst beim 
Compilieren festlegen. Ist das richtig?

z. B. sowas:
1
#ifdef deutsch
2
#define TEXT_INTRO_HALLO              "Willkommen zu dem tollen Programm"
3
#define TEXT_NAME_FMT_S_ALTER_FMT_D   "Mein Name ist %s, mein Alter ist %d"
4
#endif
5
6
#ifdef englisch
7
#define TEXT_INTRO_HALLO              "Hi"
8
#define TEXT_NAME_FMT_S_ALTER_FMT_D   "My name is %s and I am %d years old"
9
#endif
10
11
#ifdef tschechisch
12
#define TEXT_INTRO_HALLO              "Ahoj"
13
#define TEXT_NAME_FMT_S_ALTER_FMT_D   "Jmenuji se %s a je mi %d let"
14
#endif

Im Makefile musst Du dann nur noch "deutsch", "englisch", "tschechisch" 
oder was auch immer definieren. (Ich bin jetzt zu faul zum Nachschauen, 
wie.)

Verwenden kannst Du das dann so:
1
PSTR(TEXT_INTRO_HALLO)

von Sebastian B. (sebastian_)


Lesenswert?

Klaus Wachtler schrieb:
> Der Grund, weswegen mir das nicht so gefällt ist, ist der:
> Ich kann mir durchaus Situationen vorstellen, wo ein kurzer
> knapper Text unterschiedlich zu übersetzen wäre, je nach
> Situation, in der er steht.

wie ich in meinem letzten Postion beschrieben habe, bekommt ja jeder 
Text eine ID, so das das Problem gelöst ist.

>
> Nach deiner Vorstellung wäre er aber nur anhand seines
> Wortlauts immer gleich zu übersetzen.

mir schon klar das das nicht geht.


trotzdem danke für deine Hilfe, meine wichtigste Priorität ist aber das 
ich nicht immer noch in eine zweite Datei schauen muss um den exakten 
Text zu sehen, der Code soll auch gleich Primärquelle für die 
Primärsprache sein.

Wenn ich dann zB. einen Text so ändere, das klar ist das die Übersetzung 
nicht mehr passt, brauch ich nur die ID zu verändern, somit wird dann 
auch automatisch eine neue Übersetzung fällig.

Ich denke dieses Konzept hat keine Nachteile (ausser das man es nicht 
nur über defines macht und somit halt noch ein Skript braucht, was aber 
trivial ist)

von Klaus F. (kfalser)


Lesenswert?

Edi R. schrieb:
> z. B. sowas:
> #ifdef deutsch
> #define TEXT_INTRO_HALLO              "Willkommen zu dem tollen Programm"
> #define TEXT_NAME_FMT_S_ALTER_FMT_D   "Mein Name ist %s, mein Alter ist %d"
> #endif
>
> #ifdef englisch
> #define TEXT_INTRO_HALLO              "Hi"
> #define TEXT_NAME_FMT_S_ALTER_FMT_D   "My name is %s and I am %d years old"
> #endif
>
> #ifdef tschechisch
> #define TEXT_INTRO_HALLO              "Ahoj"
> #define TEXT_NAME_FMT_S_ALTER_FMT_D   "Jmenuji se %s a je mi %d let"
> #endif

In diesem Ansatz sieht man schon den größten Nachteil dieser Methode.
Ich muss immer eine Übersetzung finden, in der die Reihenfolge der 
einzusetzenden Substrings passt.
Es kann aber durchaus Sprachen geben, bei denen eine korrekte 
Übersetzung eine Umstellung der Teilstrings notwendig macht.

von Guter Rat (Gast)


Lesenswert?

Wenn das Programm mit allen Sprachen nicht ins Memory paßt,

mach doch einfach folgendes:

Für jede Sprache eine eigene Text-Datei, die eingebunden wird.
Die Dateien sehent dann so aus: (Beispiel)

Deutsche Datei:

Text_label_1: "Hallo Welt"
Text_label_2: "es regnet    "


Englische Datei:
Text_label_1: "hallo world"
Text_label_2: "it is raining"

Im Programm wird über das Label der Text aufgerufen
print Text_label_1;

Funktioniert prima, Vorsicht ist allerdings bei den Textlängen
angesagt, die müssen halt passen.

Bei umschaltbaren Sprachen, wenn das Memory reicht:
Texte als Array definieren und der Index ist die Sprache.

Habe das mehrfach mit Erfolg eingesetzt.
(C-Compiler von Keil für 8051, sollte beim AVR aber auch gehen)

von Εrnst B. (ernst)


Lesenswert?

Wenns nur wenige, vorher feststehende Sprachen sind:
1
#if deutsch
2
# define TEXT(de,en) PSTR(de)
3
#else
4
# define TEXT(de,en) PSTR(en)
5
#endif
6
7
8
// später:
9
10
puts(TEXT("Hallo Welt","Hello World"));

von Sebastian B. (sebastian_)


Lesenswert?

Guter Rat schrieb:
> Für jede Sprache eine eigene Text-Datei, die eingebunden wird.
> Die Dateien sehent dann so aus: (Beispiel)
>
> Deutsche Datei:
>
> Text_label_1: "Hallo Welt"
> Text_label_2: "es regnet    "
>
>
> Englische Datei:
> Text_label_1: "hallo world"
> Text_label_2: "it is raining"

ich weis, ich hätte aber gern den Text einer der Sprachen, direkt um 
Code stehen.

von Sebastian B. (sebastian_)


Lesenswert?

Εrnst B✶ schrieb:
> puts(TEXT("Hallo Welt","Hello World"));

das ist eigentlich auch nicht schlecht.

optimal wäre jedoch ein makro, wo nur eine Sprache direkt im puts() 
steht und alle anderen texte in einem headerfile.

von Loonix (Gast)


Lesenswert?

Sebastian Böhm schrieb:
> ich weis, ich hätte aber gern den Text einer der Sprachen, direkt um
> Code stehen.

Kannst du da nicht einfach Kommentare anwenden? Es ist doch irgendwie 
unpraktisch, einen hart-codierten String hernach durch einen anderen zu 
ersetzen.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian Böhm schrieb:

> wie ich in meinem letzten Postion beschrieben habe, bekommt ja jeder
> Text eine ID, so das das Problem gelöst ist.

Wenn du dem Text sowieso eine ID gibts, kannst du auch gleich zur 
Makrolösung greifen.

> trotzdem danke für deine Hilfe, meine wichtigste Priorität ist aber das
> ich nicht immer noch in eine zweite Datei schauen muss um den exakten
> Text zu sehen, der Code soll auch gleich Primärquelle für die
> Primärsprache sein.

Dann schreib dir den deutschen Text als Kommentar dazu.

Du hast sowieso immer das Problem, dass dir die Texte auseinanderlaufen 
werden, also kannst du auch den Text im Kommentar vermerken

> Wenn ich dann zB. einen Text so ändere, das klar ist das die Übersetzung
> nicht mehr passt, brauch ich nur die ID zu verändern, somit wird dann
> auch automatisch eine neue Übersetzung fällig.

Du hast noch nie Programme übersetzt :-)

Die Hauptprobleme bei Übersetzungen sind:

* Textlängen
  Du hast Schirmlayouts (egal ob LCD oder ein Windows-Dialog) auf
  bestimmte Textlängen hingetrimmt.
  In einer anderen Sprache ist der eigentlich richtige
  Übersetzungstext aber länger. D.h. dein komplettes Layout kommt dir
  durcheinander.

* unterschiedlicher Satzbau
  unterschiedliche Sprachen haben auch unterschiedliche Eigenheiten,
  wie Sätze korrekt gebildet werden. Da tauschen dann auch schon mal
  in den Text einzubauende variable Teile die Plätze.

* kulturelle Unterschiede
  Beispiel: Bei uns ist es bei der Ausgabe eines Namens meistens üblich
  den Vornamen vor den Familiennamen zu schreiben. Drum heißt das Teil
  ja auch Vorname.
  Als ich das bei einem Wettbewerb natürlich auch mit ein paar Chinesen
  gemacht habe, wurde ich sofort korrigiert. Dort ist der Familienname
  das wichtigste. Und erst dann kommt der Vorname der Person. Bei uns
  spielt das keine grosse Rolle, aber Chinesen stehen drauf.

* ganz banale Dinge, wie zb
  wir verwenden ein Dezimalkomma. Amerikaner einen Dezimalpunkt
  (und lass dich ja nicht darauf ein, Tausenderpunkte zu setzen. Gibt
   nur Ärger! Vor allen dann in Eingaben)
  Datum:   Tag/Monat/Jahr   versus
           Monat/Tag/Jahr   versus
           Jahr/Monat/Tag
  übliche Uhrzeitangabe: 24 Stunden oder 12 Stunden mit AM/PM Angabe
              (viele Ami kann man mit einer 24 Stunden Angabe komplett
               verwirren)

von Sebastian B. (sebastian_)


Lesenswert?

Karl heinz Buchegger schrieb:
> Dann schreib dir den deutschen Text als Kommentar dazu.

wenn ich in der Primärsprache was ändere, will ich nicht den Text in 
zwei Dateien ändern müssen. Daher soll ein Text, direkt da stehen.

> Du hast noch nie Programme übersetzt :-)

doch hab ich, nur nicht in C.
Wie man sowas vom Umgang mit den Texten her handelt und was da die 
Standard Probleme sind weis ich, ich such nur nach einer technischen 
Lösung, die meine Ansprüche erfüllt.


Bei diesem Projekt kommen nur einzelne Worte vor, keine Sätze.
Es handelt sich dabei nur um eine Menüstruktur auf dem Display und 
einzelne kurze Meldungen. (sowas wie: "Error: connection lost")

Jeder Text bekommt ne ID, wenn ein solcher Text sich im Original 
ändernt, bekommt der übersetzter das mit, er sieht dann den alten Text 
(den er schonmal übersetzt hat) und den neuen Text. Hinweise wie 
maximale länge, kann er natürlich auch sehen. Ausserdem liegen ihm 
Screenshots von allen Programmsituationen vor in denen die Text-IDs zu 
sehen sind. Aber wie gesagt die Prozess-Abläufe bei der eigentlichen 
Übersetzung sind bereits ausgereift.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian Böhm schrieb:

> Jeder Text bekommt ne ID, wenn ein solcher Text sich im Original
> ändernt, bekommt der übersetzter das mit,

Wie bekommt er das denn mit?

> er sieht dann den alten Text
> (den er schonmal übersetzt hat) und den neuen Text.

Hast du die entsprechenden Tools dafür?

Für Windows hab ich früher gerne WinTrans benutzt. Das macht genau 
sowas. Aber auch dieses Tool ist darauf angewiesen, dass man Texte als 
Textresource anlegt und auch so verwendet.

> Hinweise wie
> maximale länge, kann er natürlich auch sehen.

Wow.
Und wer pflegt das alles?


Das man das alles mit den richtigen Tools machen kann - zweifellos. Die 
Frage ist immer: wie praxistauglich ist das alles. Nicht heute, nicht 
morgen. Sondern in einem halben oder ganzen Jahr :-) Dort wird es dann 
nämlich interessant, wie gut der Prozess dann noch gepflegt wird.

Selbst mit WinTrans blieben dann noch Leichen im Keller.

Aber im Endeffekt: Du hast die Entscheidungsgewalt. Ich kann nur auf 
Dinge hinweisen, die mir untergekommen sind.

von Sebastian B. (sebastian_)


Lesenswert?

Karl heinz Buchegger schrieb:
> Sebastian Böhm schrieb:
>
>> Jeder Text bekommt ne ID, wenn ein solcher Text sich im Original
>> ändernt, bekommt der übersetzter das mit,
>
> Wie bekommt er das denn mit?

das zeigt ihm die Software.

>
>> er sieht dann den alten Text
>> (den er schonmal übersetzt hat) und den neuen Text.
>
> Hast du die entsprechenden Tools dafür?

ja. selbstentwickelt.


> Wow.
> Und wer pflegt das alles?

ist kein Problem.


> Das man das alles mit den richtigen Tools machen kann - zweifellos. Die
> Frage ist immer: wie praxistauglich ist das alles. Nicht heute, nicht
> morgen. Sondern in einem halben oder ganzen Jahr :-) Dort wird es dann
> nämlich interessant, wie gut der Prozess dann noch gepflegt wird.

funktioniert gut, die Prozesse sind eingespielt, das läuft hier so schon 
seit 10 Jahren.

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.