Entwickler-Ecke

C# - Die Sprache - Resource-Dateien per Quelltext in C# einbinden und nutzen


Ares - Mo 14.06.10 17:41
Titel: Resource-Dateien per Quelltext in C# einbinden und nutzen
Hallo!

Ich habe bislang viel mit Delphi gearbeitet. Für die Erstellung eines Programms in unterschiedlichen Sprachen habe ich dort immer mit String-Resourcen gearbeitet die per bedingter Compilierung in das Programm eingebunden wurden. Nun suche ich nach einer Möglichkeit dieses Prinzip auf C# zu übertragen.

Eine Resource-Datei sieht also z.B. so aus:
deutsche "Text_DE.txt"

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
STRINGTABLE
BEGIN
  1000, "OK"
  1001, "Abbrechen"
  1002, "Weiter"
  1003, "Zurück"
  1005, "Fertigstellen"
END


deutsche "Text_EN.txt"

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
STRINGTABLE
BEGIN
  1000, "OK"
  1001, "Cancel"
  1002, "Next"
  1003, "Back"
  1005, "Finish"
END


Dies wird dann mit BCC32 in eine RES-Dateien compiliert die in das Programm eingebunden werde.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
{$IFDEF langEN}
  {$R 'C:\Projekte\Texte\Texte_EN.RES'}
{$ELSE}
  {$R 'C:\Projekte\Texte\Texte_DE.RES'}
{$ENDIF}

...

function GetString(ID: Integer): String;
var
  p: PChar;
  loadResult: integer;
begin
  p := StrAlloc(1024);
  try
    loadResult := LoadString(hInstance, ID, p, 1023);
    if loadResult <> 0 then begin
      Result := p ;
  finally
    StrDispose(p);
  end;
end;

...

procedure ButtonClick(Sender: TObject);
begin
   ShowMessage(GetString(1000)); // Zeigt "OK" an...
end;



Nun Arbeite ich mit Visual Studio und C#. Lässt sich dieses Prinzip der Übersetzung hier auch nutzen?


Bei meinen bisherigen Nachforschungen bin ich nur auf die Möglichkeit gestoßen .RESX Dateien zu verwenden. Soweit ich das verstanden habe kann man diese aber nur in VS direkt im Projekt verwalten. Zudem ist das XML-Format dieser Dateien natürlich komplett anders als das der klassischen Resourcedateien.

Über die Zeit habe ich eine recht umfangreiche Sammlung von Standardtexten in fertigen Resourcedateien gesammelt. Diese würde ich natürlich gerne weiter verwenden, Lässt sich das oben beschriebene Prinzip also auch mit C# nutzen?

Eigentlich benötig ich 5 Dinge:
1. Erstellung von Texdateien
2. Übersetzung in Resource-Dateien
3. Bedingte Compilierung um je nach Sprache unterschiedliche Texte zu laden
4. Möglichkeit Resource-Dateien per Quelltext einzubinden
5. Möglichkeit auf enthaltene Resourcen per Quelltext zuzugreifen.

Für Schritt 1 und 2 könnte ich weiterhin einen Texteditor und BCC32 verwenden. Die Bedingte Complierung ist soweit ich gesehen habe in C# mit "#define xy=true", "#if xy" und "#endif" kein Problem.

Bleiben also noch die Schritte 3-4 für die ich bislang keine Lösung gefunden habe. Kennt jemand eine Lösung?

Besten Dank
Ares


Christian S. - Mo 14.06.10 17:49

Hm, die Lokalisierung von Anwendungen in .NET läuft (bei WinForms) so: http://www.c-sharp-forum.de/viewtopic.php?p=455380#455380

Bedingte Kompilieren ist da eher unüblich :gruebel:


Ares - Mo 14.06.10 18:02

Hallo Christian,

vielen Dank für die schnelle Antwort! Ja, das das Resourcen nicht der übliche Weg sind C# Projekte zu lokalisieren habe ich auch schon rausgefunden :-) Wie gesagt habe ich nur Quellen darüber gefunden wie man die RESX-Dateien, etc. verwendet...

Sicherlich hat die "normale .NET Methode" für die Lokalisierung auch viele Vorteile. Bei mir wäre aber der riesengroße Nachteil, dass ich meine ganzen bestehenden Übersetzungen nicht mehr verwenden könnte. Bislang muss jeden Text nur einmal übersetzten und kann diesen dann in beliebigen Delphi-Programmen und Projekten verwenden.

Wenn ich das Ganze nun auf die .NET Methode umstelle wäre der Aufwand enorm hoch. Zudem will ich in Zukunft mit .NET und Delphi parallel arbeiten. Da wäre ein gemeinsames System der Übersetzung von sehr großem Vorteil...

Ist die "Delphi-Methode" also auf .NET übertragbar oder lässt sich diese hier gar nicht anwenden?


Christian S. - Mo 14.06.10 18:17

Was Du machen könntest, ist, Dir aus Deinen Text-Dateien die "normalen" resx-Dateien von .NET generiert. Ich habe gerade mal geschaut, Du musst da im Prinzip eine leere, von Visual Studio erzeugte resx-Datei nehmen und den von mir markierten Teil jeweils anhängen:

XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Test" xml:space="preserve">
    <value>Testwert</value>
  </data>
  <data name="Test2" xml:space="preserve">
    <value>Testwert2</value>
  </data>
  <data name="Test3" xml:space="preserve">
    <value>Testwert3</value>
  </data>  
  <data name="Test4" xml:space="preserve">
    <value>Testwert4</value>
  </data>
    
</root>


Netterweise generiert Visual Studio dann daraus auch wieder die Klasse, um bequem auf die Eigenschaften zugreifen zu können. Über verschiedene Build-Konfigurationen in Visual Studio könntest Du dabei dann die resx-Datei jeweils aus einer anderen Sprache erzeugen.

Grüße
Christian