Laden...

Lokalisierung von Exceptions

Erstellt von Kabelsalat vor 16 Jahren Letzter Beitrag vor 16 Jahren 2.967 Views
Kabelsalat Themenstarter:in
369 Beiträge seit 2006
vor 16 Jahren
Lokalisierung von Exceptions

Hallo,

Das .Net Framework erzeugt Mitteilungstexte der Ausnahmen in der jeweiligen Landessprache (vorausgesetzt das entsprechende Sprachpaket ist installiert). Prinzipiell finde ich das richtig und somit nutze ich die .Net-Lokalisierungsfunktionen bei der Erzeugung von Exception-Objekten.

Lokalisierte Mitteilungstexte machen es dem Entwickler, der das zur Verfügung gestellte Framework nutzt, einfacher Programmierfehler zu verstehen. Außerdem kann man die Exception-Message logischer Ausnahmen (etwa FileNotFoundException) auch direkt an den Benutzer ausgeben.

Die meisten Ausnahmen werden jedoch durch falsche Verwendung des Frameworks durch den Programmierer ausgelöst. Krzysztof Cwalina (API designer bei Microsoft und Verantwortlich für die .Net Designrichtlinien), bezeichnet diesen Typ von Ausnahmebedingung als "usage error". Er schätzt das es sich bei 95% der Ausnahmebedingungen um diesen Typ handelt. Da diese Ausnahmen Programmierfehler aufzeigen, ergibt es wenig Sinn die Mitteilungstexte an den Benutzer auszugeben. Vielmehr sollte diesem eine Nachricht im Stil von "Ein schwerwiegender Fehler ist aufgetreten. Ihre Arbeit wurde gespeichert und kann nach einem Neustart der Anwendung fortgesetzt werden. Sie können zur Behebung des Fehlers beitragen, in dem sie die Datei ErrorLog.txt an den Entwickler senden." gezeigt werden. Das Ausnahme-Objekt würde in diesem Szenario serialisiert und zusammen mit ergänzenden Informationen in der Datei ErrorLog.txt gespeichert.

Bisher konnte ich bei diesem Ansatz keine Schwierigkeiten erkennen. Die Lektüre des Buches Richtlinien für das Framework-Design verleitete mich jedoch zum Nachdenken: Einer der Kommentatoren war der Meinung, Exception-Messages gehörten nicht übersetzt. Eine Begründung nannte er jedoch nicht. Eigentlich liegt das Problem auch auf der Hand. Man muss nur an folgendes, einfaches Szenario denken:

Die Dictionary<T, T> Klasse wird verwendet. Durch einen Programmierfehler wird versucht einen bereits vorhandenen Schlüssel nochmals hinzuzufügen. Eine ArgumentException wird ausgelöst. Da es sich bei diesem Fehler um einen "usage error" handelt, wird dem Anwendungsbenutzer die zuvor geschilderte, allgemeine Fehlermeldung gezeigt. Er kommt der Bitte nach und übermittelt dem Entwickler die Datei ErrorLog.txt. Dieser findet jedoch bloß eine kryptische Exception-Message vor: "-;5<5=B A B5< 65 :;NG>< C65 1K; 4>102;5=." (hier sollte russischer Text mit kyrillischen Zeichen stehen - die Forensoftware kommt damit aber leider nicht klar). Hintergrund: Der Anwender verwendete eine russische Version des .Net Frameworks. Mittels des StackTrace wäre es dem Entwickler in diesem Fall sehr einfach möglich gewesen den Hintergrund der Ausnahme herauszufinden. Auch hätte er sehr schnell gewusst, dass der englische Mitteilungstext "An item with the same key has already been added." lautet. Nicht in jeder Fall ist jedoch so einfach gestrickt. Denkt etwa an .Net Remoting und die Meldung "This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server." (RemotingException). Selbst mit StackTrace wird es in diesem Fall bei einer fremdsprachigen Fehlermeldung nicht einfach den Grund für die Ausnahme zu ermitteln.

Ich habe vor bei Microsoft Connect einen Verbesserungsvorschlag einzureichen. Allerdings würde ich das Probleme zunächst gerne hier diskutieren.

Ich selber habe folgende Lösungsvorschläge. Sie sind der Brauchbarkeit nach geordnet (am wenigsten brauchbare Vorschläge kommen zuerst):

  1. Lokalisierte Mitteilungstexte werden nur ausgegeben, wenn die Anwendung mit aktiviertem Debug-Flag übersetzt wurde. Zur Entwurfszeit würde die Arbeit des Entwicklers durch lokalisierte Exception-Messages erleichtert und auch nach dem Auslieferung gäbe es keine Probleme, da dann die neutrale Sprache (Englisch) verwendet würde.

-> Dieser Ansatz bringt Schwierigkeiten mit sich: Mitteilungstexte logischer Ausnahmen (FileNotFoundException...) könnten nicht mehr direkt an den Benutzer ausgegeben werden. Außerdem taugt diese Überlegung nicht als Vorschlag an Microsoft, da es sich um einen "breaking change" handelt.

  1. Hinzufügen eines ErrorCode zu jeder Ausnahme. Dieser würde das Rekonstruieren der ursprünglichen Fehlermeldung ermöglichen. Außerdem würde auch eine zusätzliche Möglichkeit zur programmatischen Unterscheidung von Ausnahmen geschaffen (siehe auch ErrorCode or Method to identify exceptions).

-> ErrorCodes sind schwer zu warten und nicht besonders intuitiv. Es ist daher praktisch unvermeidbar, dass mit der Zeit für eine bestimmte Ausnahmesituation mehrere ErrorCodes existieren. Auch braucht man eine vollständige Dokumentation um die ErrorCodes einem bestimmten Fehlercode zuzuordnen. Eigentlich selbstverständlich, fehlt es realen Projekten jedoch häufig an einer qualitativ hochwertigen Dokumentation. Im Anfangsstadium mag das nicht besonders tragisch sein, bei fortgeschrittenem Projektstatus und gerade in Verbindung mit ErrorCodes ist Chaos jedoch unvermeidbar. Außerdem sollten ErrorCodes bei einer guten Ausnahme-Hierarchie nicht notwendig sein. In Krzysztof Cwalinas Blog gibt es ebenfalls einen Artikel zu diesem Thema.

  1. Hinzufügen einer "NeutralLanguageMessage" Eigenschaft zur Exception-Basisklasse. Jeder bestehenden Exception sollte ein zusätzlicher Konstruktor hinzugefügt werden, der das Festlegen des Eigenschaftswert ermöglicht. Das .Net Framework sollte von dieser Eigenschaft Gebrauch machen.

-> In meinen Augen die beste Lösung. Der Entwickler sieht im Debugger weiterhin lokalisierte Fehlermeldungen. In Logdateien kann jedoch der englische Mitteilungstext geschrieben werden. Auch handelt es sich bei der vorgeschlagenen Änderung nicht um einen "breaking change", da bestehende Funktionalität nicht geändert wird, sondern lediglich ein neues Feature hinzugefügt wird. Bestehender Code wird ohne Überarbeitung eben weiterhin nur die lokalisierte Nachricht zur Verfügung stellen.

Diese Lösungsansätze machen jedoch allesamt Änderungen am .Net Framework erforderlich (die evtl. nie stattfinden werden). Aus diesem Grund interessiere ich mich nach Alternativen, die bereits heute umsetzbar sind. Leider ist mir bis jetzt noch keine zündende Idee gekommen.

Am einfachsten wäre es, wenn man die Kultur für Ausnahme-Fehlermeldungen gesondert einstellen könnte. Die einzige Möglichkeit das zu realisieren, wäre die UICulture Eigenschaft für diesen Zweck zu missbrauchen. Die Kultur für die UI Lokalisierung müsste dann jedoch in einer nicht vorgesehenen Eigenschaft in eigenem Code gespeichert werden. Dieser Ansatz hätte einige Nachteile zur Folge. Insbesondere müsste dem ResourceManager immer ein CultureInfo Objekt übergeben werden. Dies bedingt auch, dass die von Visual Studio erzeugte statische Klasse, die den streng typisierten Zugriff auf die Resourcendateien nicht mehr verwendet werden kann. Es müsste also ein angepasster Code-Generator verwendet werden.

Alles in allem halte ich dieses Workaround für nicht besonders praktikabel. Für weitere Ratschläge wäre ich daher dankbar.

Kabelsalat

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Kabelsalat,

Allerdings würde ich das Probleme zunächst gerne hier diskutieren.

alles was du schreibst ist nachvollziehbar und die Schlussforderungen/Bewertungen sind in meinen Augen richtig.

Lösung 3 wäre sicher am besten.

Alles in allem halte ich dieses Workaround für nicht besonders praktikabel.

bin nicht mal sicher, dass der beschriebene Workaround funktioniert. Einen anderen/besseren sehe ich aber für die im Framework definierten Exceptions auch nicht.

herbivore

0
767 Beiträge seit 2005
vor 16 Jahren

Lösung 3 wäre sicher am besten.

/signed.
Ich hab in dieser Richtung auch schon einige Überlegungen gemacht, weil wir in unseren Anwendungen sehr häufig Fehlermeldungen an den Benutzer ausgeben, die sich "weniger dramatisch" anhören als sie vielleicht sind (liegt halt auch am Marketing). Im Error-Log steht dann die echte Exception mit möglichs viel Info um dem Problem auf den Grund zu gehen.

Momentan ist das aber in praktisch jedem catch Block individuell angepasst.

Original von Kabelsalat
Lokalisierte Mitteilungstexte machen es dem Entwickler, der das zur Verfügung gestellte Framework nutzt, einfacher Programmierfehler zu verstehen.

ne.
Wir entwickeln mit englischemn VS und englischem Framework. Aus Versehen war auf einem Live system dann mal das deutsche Framework installiert... und plötzlich war die Rede von ungültigen Ansichtszuständen... In dem Fall gings noch ohne überlegen... aber stutzig macht mich sowas schon.

Warum muss MS echt jeden Mist übersetzen? Das sind Fachausdrücke. Hier gehts nicht um Kultur. Der Satz "Der Viewstate ist ungültig" sagt mehr aus als "Der Ansichtszustand ist ungültig", weils nämlich in den Properties des Page Objekts für den Request auch ein "ViewState" gibt.

Ich denke mit schaudern an die Office Produkte, wo Excel mit =SUM(...) nichts anfangen kann, weil ich =SUMME(...) schreiben muss.

Auch im WinForms find ich das katastrophal. Da steht beim Form im PropertyEditor "Hindergrundfarbe" und wenn ichs anprogrammieren will, muss ich form.BackgroundColor schreiben... überflüssiges doppeltes nachdenken nötig, welches die Produktivität sicher nicht steigert.

(ups... Thread entführt).

Um nochmal zum ursprünglichen Punkt zu kommen:
Ich find den Vorschlag mit der "NeutralLanguageMessage" nicht schlecht. Ich mach das für meine Exceptions so, dass die exception.Message NICHT das ist, was an den User geht, weil das eben auch von Microsoft oder sonstwoher kommen kann. Wenn die Exception eine von mir ist (== von meiner ExceptionBase abgeleitet), dann kann ich die "UserfriendlyErrorMessage" an den User geben und den rest komplett loggen. Ist die Exception nicht von mir, wird sie zwar auch komplett geloggt, aber die Message für den User ist eine lokalisierte StandardMessage ala "Es ist ein interner Fehler aufgetreten").

loop:
btst #6,$bfe001
bne.s loop
rts

Kabelsalat Themenstarter:in
369 Beiträge seit 2006
vor 16 Jahren

Original von 0815Coder

Warum muss MS echt jeden Mist übersetzen? Das sind Fachausdrücke. Hier gehts nicht um Kultur. Der Satz "Der Viewstate ist ungültig" sagt mehr aus als "Der Ansichtszustand ist ungültig", weils nämlich in den Properties des Page Objekts für den Request auch ein "ViewState" gibt.

Ansich widerstrebt mir "Denglisch". Wenn es sich jedoch um Übersetzungen von Fehlermeldungen handelt, die sich primär an den Entwickler richten, lege ich meine Abneigung beiseite. Aus rein pragmatischen Gründen, vermeide ich in diesem Fall das zwanghafte Übersetzen englischer Fachbegriffe: Lieber ein Wort zu wenig übersetzt als eines zu viel. Aus Gründen, die ich hier - da ohne Bezug zum eigentlichen Thema - allerdings nicht erörtern möchte, halte ich gerade bei kommerziellen Produkten Übersetzungen jedoch für notwendig. Das bezieht sich auch auf Exceptionmessages, die nie an den Endbenutzer ausgegeben werden sollten. Bei der Syntax hört der Spaß natürlich auf. Bei eigenen Projekten achte ich darauf, das Projekt zumindest für die Lokalisierung vorzubereiten (ExceptionBuilder-Pattern, Verwendung von Ressourcen, etc.). I.d.R. verfasse ich die Deutsche Übersetzung auch gleich selber. Dadurch werde ich gezwungen nochmals über den Inhalt des Textes nachzudenken, was hilft die englische Version (die zuvor meistens bloß durchschnittlich ausfällt) und teilweise sogar den Programmcode zu verbessern.

Original von 0815Coder
Um nochmal zum ursprünglichen Punkt zu kommen:
Ich find den Vorschlag mit der "NeutralLanguageMessage" nicht schlecht. Ich mach das für meine Exceptions so, dass die exception.Message NICHT das ist, was an den User geht, weil das eben auch von Microsoft oder sonstwoher kommen kann. Wenn die Exception eine von mir ist (== von meiner ExceptionBase abgeleitet), dann kann ich die "UserfriendlyErrorMessage" an den User geben und den rest komplett loggen. Ist die Exception nicht von mir, wird sie zwar auch komplett geloggt, aber die Message für den User ist eine lokalisierte StandardMessage ala "Es ist ein interner Fehler aufgetreten").

Leider lassen sich auf diese Weise keine Standardausnahmen (ArgumentException) ergänzen. Eine Möglichkeit bestünde jedoch darin, die Exception.Data Eigenschaft für diesen Zweck zu nutzen.

S
8.746 Beiträge seit 2005
vor 16 Jahren

Ich gebe niemals Exception-Texte an den Nutzer aus, deswegen sehe ich auch keinen Sinn für eine Übersetzung.

L
333 Beiträge seit 2007
vor 16 Jahren

So eine "InvariantLanguageMessage", wie sie Microsoft vermutlich eher nennen würde, klingt schon interessant.

Wenn du mal ein bisschen mit dem .NET Reflector im Framework rumschaust, wirst du bald feststellen, dass dort intern Zeichenketten angegeben sind, die dem Resource Manager übergeben werden, um eine lokalisierte Fehlermeldung zu erhalten. Diese Zeichenketten sind oft halbwegs verständlich und könnten m.E. durchaus als Schlüssel verwendet werden. Zumindest kann man eine Exception, die man bei der Verwendung von Framework-Methoden erhält, im Quelltext gut wiederfinden und oft besser verstehen.

(Hab ich heute schon erwähnt, dass der .NET Reflector mein Lieblingswerkzeug ist? 🙂)

Kabelsalat Themenstarter:in
369 Beiträge seit 2006
vor 16 Jahren

Original von svenson
Ich gebe niemals Exception-Texte an den Nutzer aus, deswegen sehe ich auch keinen Sinn für eine Übersetzung.

Original von LonelyPixel
Wenn du mal ein bisschen mit dem .NET Reflector im Framework rumschaust, wirst du bald feststellen, dass dort intern Zeichenketten angegeben sind, die dem Resource Manager übergeben werden, um eine lokalisierte Fehlermeldung zu erhalten. Diese Zeichenketten sind oft halbwegs verständlich und könnten m.E. durchaus als Schlüssel verwendet werden. Zumindest kann man eine Exception, die man bei der Verwendung von Framework-Methoden erhält, im Quelltext gut wiederfinden und oft besser verstehen.

In der Tat hat auch mir die Kombination Reflector + StackTrace schon öfters weitergeholfen (wenn auch aus anderen Gründen als lokalisierten Exception-Messages). Generell stöbere ich auch ganz gern, etwa in Rotor (Shared Source CLI), da es einem hilft .Net und das Framework zu verstehen.

Kabelsalat Themenstarter:in
369 Beiträge seit 2006
vor 16 Jahren
49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Kabelsalat,

wer eine Windows Live ID oder ein Passport-Konto Konto hat und Kabelsalats Verbesserungsvorschlag unterstützen müsste, kann unter dem genannten Link eine positive Bewertung dafür abgeben.

herbivore

L
333 Beiträge seit 2007
vor 16 Jahren

Määh, noch eine Lizenzbestätigung. Was steht denn da drin, ich hab keine 2 Stunden Zeit, mir das alles durchzulesen. Hab leider nur nen gewöhnlichen Passport-Account, der reicht für Connect leider nicht ganz.

S
8.746 Beiträge seit 2005
vor 16 Jahren

Momentan adressiert nix dieses Problem. Schon in der Beschreibung für das Language Pack heisst es : "lokalisiert Fehlermeldungen und andere Texte". Unbrauchbar, weil unklar per Definition.

Ist aber mehr als eine neue Klasse. Es muss eine richtiges Ressourcen-Konzept unter Einbeziehung (multiple installierter) Language Packs geben.

L
333 Beiträge seit 2007
vor 16 Jahren

Ach ja, früher gab es Error-Codes. Das war eine Zahl, die hat der Entwickler dann in sein Error-Lookup-Programm eingetippt und dafür eine Fehlermeldung in seiner eigenen Systemsprache erhalten. (Das Programm hab ich mir letztens mal wieder aus der VC6-CD rausgezogen, kann man auch in .NET-Zeiten noch brauchen.)

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo LonelyPixel,

deine Fürsprache für diesen Vorschlag

  1. Hinzufügen eines ErrorCode zu jeder Ausnahme.

kommt ein wenig spät. 🙂

herbivore

L
333 Beiträge seit 2007
vor 16 Jahren

Oh, stimmt. Der Thread ist schon wieder zu lang/alt. 😉