I'm working on a project and I'm just starting to do all the work necessary to globalize the application. One thing that comes up quite often is whether to globalize the exception messages, but ensuring that string.Format uses CultureInfo.CurrentCulture instead of CultureInfo.InvariantCulture. Additionally this would mean that exception messages would be stored in resource files that can be marked as culture-specific.
So the question is, should exception messages be globalized or should be be left in either the InvariantCulture or the author's country; in my case en-US.
Exception messages should rarely be displayed directly to the user. You need to think of the consumer for each string. Obviously pieces of text in the user interface need internationalizing, but if an exception message is only going to be seen by support (or is going to be visible to the user and then emailed to support when they click a button) then where's the benefit of translating it?
If you go too far, you could not only waste time and effort (and i18n can take a lot of effort) but you'll also make your support life harder as well. You really don't want to have to read log files written in a foreign language and translate them back to your native tongue.
It makes sense for Microsoft to internationalize their exception messages, because they will be read by developers from all over the world - but unless you're multinational with developers in multiple countries who don't share a common language, I wouldn't translate message which are really meant for dev/support.
typically, I don't.
Globalize strings that may be seen by a user, and you don't let your exception messages percolate up to the UI, right?
Right? :)
If you are going to be the one to deal with the exceptions, then either leave them in a language you can understand, or give them codes so you can look them up in your native language.
I assume by globalize, you mean i18n compliant which is usually called internationalize. Yes, internationalize all visible parts of the GUI, including diagnostic messages. The log file, which is where developers should go to get the real information such as the stack trace, should not be internationalized.
Related
I need to make a short premise: I am a software architect with more than 20 years of experience, not a junior asking directions. This is not to say "I know it all" (quite the contrary in fact) but just to give context and state that I have come across a legitimate doubt about something I thought was common knowledge and best practice and have done so for all this time.
I am working on different projects for different clients. I always check method's parameters for not being null and for other non valid states. A common precondition check you can find in my code is:
if (param == null) { throw new ArgumentNullException(nameof(param)); }
or
this.myField = myParam ?? throw new ArgumentNullException(nameof(myParam));
Also bear in mind that I use exceptions sparingly, I do not do user input validation with exceptions, I just use them to check and/or signal invalid states in the code, thus programming errors. It's extremely rare to find a try/catch block in my code at all.
One of my clients just asked me, without much margin to debate, to replace any similar occurrence with the use of custom exceptions. Meaning I am to define a CustomerNameArgumentNullException, CustomerNameFileNotFoundException, etc. and use those wherever I would use a standard exception.
Now I will comply, I have no right to debate the client request, but their lead programmer was pretty strong about this point on how this is the right way to go, that using default exceptions makes code less readable and also that custom exceptions make more easy to see what-is-what in Azure Application Insights. I tried to point out that he has the fully qualified name of the method that raised the exception so he can know which program, in which assembly and namespace and such but again, there was not much room to debate and it was not my place to do so.
So I've been wondering if he's actually right and I've been doing exceptions wrong all this time. If anyone has some more insight and/or some material I can read about that supports this theory.
Thanks.
While normally I'd suggest that a question like this should be closed as opinion-based, in this case there's really clear guidance from Microsoft:
Use the predefined .NET exception types
Introduce a new exception class only when a predefined one doesn't apply. For example:
Throw an InvalidOperationException exception if a property set or method call is not appropriate given the object's current state.
Throw an ArgumentException exception or one of the predefined classes that derive from ArgumentException if invalid parameters are passed.
In other words, your customer is asking you to go against guidance from the platform authors.
You may not be able to change the customer's mind to follow the guidance, but you can be confident that your approach is the recommended one, and their approach goes against that.
Following conventions like this is particularly important in Open Source projects - it's one thing to decide that you'll have your own conventions when only your team will work with the code, but if an application uses 10 different Open Source libraries, each of which has decided to create its own conventions, that's a nightmare.
There are two sides of the coin. Sure MS recommends this
Using custom exceptions gives you some advantages and disadvantages.
Advantages:
Abstraction
You can log telemetry data before you raise an exception. If not for custom exceptions, you'd have to catch an exception, log data and re-throw.
Customizing exception and error handling as needed by the app/services, etc
Disadvantages:
Telemetry data will have no stack trace if you are throwing custom exceptions.
Code maintenance and rigorous testing
There are various other things that come into picture, but catching an exception, logging metrics and then re-throwing (to preserve stack trace) the same exception is expensive.
Just my thoughts.
We maintain an ASP web app, which has a publicly visible interface that has to be localised into a large number of languages, and a private interface that still needs localisation, but only into a subset of the languages.
As much as possible, when we localise we put them into different resource files according to whether the string could appear on the public interface, or only the private one. However, inevitably mistakes are made, and I'd like to find ways to find resources that have been classified incorrectly. There's a lot of code shared between them, so the assembly that some code is in is not sufficient to determine this.
One way of doing this would be to record the resource name & location of every resource that gets accessed via the public interface, which allows us to (a) detect any that have been misclassified as private, and (b) investigate any that have been categorised as public but don't appear in this list. It looks like this might be possible by providing custom resource providers that wrap the default ones but record resource keys.
An alternative, but potentially more useful, option would be to record when a resource couldn't be found in a specific culture, and the system has had to fall back to the invariant culture resource. This will help us track down any untranslated messages. However, I'm struggling to find a way to do this.
Are there any good solutions here to avoid me writing my own? How do others manage similar scenarios? We'd rather avoid the cost of unnecessarily translating strings that can only be seen in the private interface into languages that it's not supported for.
In the interest of full disclosure, I'm the (sole) author of a commercial localization program for Visual Studio. I therefore stand to profit if you decide to research and purchase it. I'm not here to sell you a copy of it though (I don't work that way). I'm trying to legitimately help you and my program may be able to (though it's still unclear to me at this stage). You'ld also have to be open to a paid solution of course, assuming you can't find a better way. If I knew of a way for free I'd post it here. In fact, if my app didn't take so long to originally develop I would have given it away for free. I suggest you download the evaluation copy at http://hexadigm.com/FreeDownLoads.aspx (developer's version) to get an idea of what it can do (and ideally read about it on the site first). The evaluation version can only translate 10% of your strings however so it may be unwieldy to properly test what you're after. The program may have potential ways to deal with your situation though, if I understand it correctly, but it remains to be seen (for instance, you could bundle your public and private strings into separate ".trn" files, which you'll learn about if you research the app, but you obviously need to identify these strings first of course - how my app can help in that regard is still unclear). The upshot is you'll need to get a basic understanding of the program first though. It may be better to contact me offline at support#hexadigm.com. I don't believe any further discussion here will benefit other users but if the moderators feel otherwise then they can weigh in (I'd be happy to discuss it here if they wish, since the app does address various localization deficiencies in Visual Studio, but I don't want to violate the site's rules - I'm not here to promote the app so I won't discuss any specifics without their approval).
Very often in .NET methods throw generic errors like e.g.
int.Parse("test")
throws an exception with this message:
Input string was not in a correct format.
Now it would save a lot of trouble for many people if it just had the parameter value to help debug things easier:
Input string "test" was not in a correct format.
This seems like a natural and easy thing to have, yet .NET does not do it in many places like e.g. parsing. Is there is any reason or conceptual problem with doing that or is it just a "missing feature"?
I suspect that the reason is primarily for security reasons. Some concerns with displaying/rendering the text to be parsed in the message returned are (but not limited to)
The text to be parsed may be very long. This is would be problematic from a memory usage and display perspective not to mention developer's habits of logging exception messages (not unreasonably).
The text may contain characters that mess with the formatting (e.g., tab, LF, CR, etc.)
The text may contain sensitive data. On this point, it's worth nothing that most developers, at least starting out, generally log or display error messages at an exception level by default. Not including the text here means there's no unintended data leak to catch the unwary.
It's conceivable (though unlikely) that an exploit could be found whereby a malformed piece of text could have a nasty unintended side effect.
Additionally, the value being parsed is being supplied by the caller which leaves them the option of deciding if it's best to log the content or not - it's not int.Parse()'s place to return the value in the exception message.
All in all, displaying a concise message without the originally supplied value is a judicious decision on part of MS to save us from ourselves as well as follow security best practices.
I'm working on a website that will deployed internationally. Very big site, but for the sake of simplicity, all we're concerned about is my Error.aspx with c# code behind. I'd like to make this custom error page as dynamic as possible. There's at least a handful of languages we need to read this page in right now, and more to come. This page needs to work independently and without a database to reference.
I'd like to have some text, and have the appropriate translation appear based on the language appropriate for that domain... e.g. ".com" = English, ".ca/fr" = French, ".mx" = Spanish... you get the idea.
What's the best way to do this?
I've looked into API's, but the decent ones have a cost threshold, and while it might look really helpful, this is just pretty standard error message text, that's unlikely to change, so that seems like overkill to have a dynamic translator. It might help with scalability, but it's extra money indefinitely, when it will only save vs hard-coding on the handful of occasions where we add another language/country/domain.
The other idea I had was to simply hardcode it in the c#. parse out Request.URL and get the domain, and make a ever-growing switch statement which would assign the appropriate text. (As an aside, I'm also trying to find a better way to do this, but is the country code something that would be an available piece of information from either the request object or server?) This way would be independent, precise, and the only drawback on a concrete level would be the cost of adding new languages, or changing every string (probably not that many, at least at first) if the content of the error message needed to be adjusted. But this feels like bad practice.
I've been researching this for a day now, but I haven't found any alternatives to these 2 options. What are the best practices for handling small amounts of text for translation, without the use of a CMS?
There is an easy built-in way to handle localization in ASP.NET Web Forms. It uses the Language Preference settings in the client's browser to select the language. Posting the steps of setting it up would be redundant since there's lots of information on this subject available online. Here is a good tutorial.
EDIT:
It might be a good idea to read up on HTML resource files. That is the HTML standard for handling different languages (referred to as localization). And it is what ASP.NET uses in the background when creating a local resource for a server control.
Consider a C# GUI application which uses a FileStream to read a file, chosen by the user through an "Open File" dialog.
In case the read fails with one of the exceptions, what is the correct way to report the failure to the user, in an user-friendly manner?
Should I invent my own message for each of those exceptions, or is there a way of obtaining a localized, user-friendly message that I could present verbatim to the user?
Edit
I'm asking whether .NET itself is able to provide me with a descriptive string that I can present (and which would be consistent with other .NET programs). I know that I can roll up my own, but I'd like to avoid that if there's a standard alternative.
You can have a set of localizable user exceptions with one of them being say FileUploadError. You can put a localized general information there. Throwing a few technical details might be a bit challenging, as it can be quite hard to get the right balance between technical details and a simple step that a user needs to take to fix an error.
My suggestion would be:
Have one user level FileUploadErrorException
Have a details property in it
Depending on the actual exception, suggest a user to try a few things
If you are catching an exception thrown by one of the .Net framework's File classes, then it is likely that the contents of the exception's .Message property will already be localized. The .Message property is supposed to contain localized, human readable text. How 'friendly' it is depends, I guess, but it might contain something you can embed within a more general and friendly paragraph.
Assuming you might write some method AlertUserWithMessage() to display the error to the user, this might be useful:
try
{
fileStream.Read(...); // or some other operation
}
catch(Exception e)
{
AlertUserWithMessage(e.Message);
}
If you want to include additional information that might be helpful to a support person diagnosing the problem, then you can also get the stack trace as a string from the exception.
try
{
fileStream.Read(...); // or some other operation
}
catch(Exception e)
{
AlertUserWithMessageAndStackTrace(e.Message, e.StackTrace);
}
Exception messages are by nature technical and describe what went wrong (at implementation level), as opposed to how to solve an end user's problem. On the other hand the intent of an error message presented to the user is to explain what failed and what action to take to remedy the problem. Exceptions messages and end-user error messages don't have the same purpose and aren't written for the same audience.
So for decent user experience, it is much better to map these exceptions to localized user-friendly advice on how to get around the problem. Sure, for technical users it could be nice to have some diagnostic feature that could give details of the exception (in which case having exception messages in English doesn't matter that much--English is really the world's technical language), or just point them to a log with all the details. But just throwing an exception message, even localized, at an end user is likely to baffle them.
For this reason I don't think localizing exception messages is much use. It's true that the .NET framework has localized exception messages for major languages, but I think that's more because there are developers who use these languages as their base language and do not necessarily have a good command of English. So the audience of these localized exception messages is still developers, not end users of a software product built in .NET.