How to handle strings in code

N

N4709L

Would you please review the methods that we use to Globalize our software
applications? I would like to obtain your critique of the practices that we
use and have outlined below.



In our Module Main we declare a Public (global) variable for a
ResoureManager that is used throughout the application for strings that
appear within our code.



Public rm As ResourceManager



Then, within our Sub Main, our code begins with the following:



Function Main(ByVal CmdArgs() As String) As Integer



' Use the current language and culture that has been selected using

' Regional and Language Options in Control Panel. Otherwise, Resource
Manager

' will use GetUserDefaultUILanguage, which is the system's installation
language

' and culture.

Try

Thread.CurrentThread.CurrentUICulture =
Thread.CurrentThread.CurrentCulture

rm = New ResourceManager("ProblemReportUtility.ProblemReportUtility", _

System.Reflection.Assembly.GetExecutingAssembly())

Catch ex As Exception

' Do not translate the error message below, because ResourceManager
failed.

MsgBox("Unable to set the current user interface culture and create a
new resource manager to handle language strings." _

& vbCrLf & vbCrLf _

& ex.Message, MsgBoxStyle.Critical Or MsgBoxStyle.OKOnly, _

"Problem Report and Enhancement Utility")

Return Err.Number

End Try



Now we are ready whenever a string might be required. When a string must be
used within the code we do three important things:

1.. We provide a comment line that documents the actual string that is
returned from the Resource Manager.
2.. We use rm.GetString to fetch the actual translated string.
3.. We use String.Format and place holders like {0} and {1} for tokens
that must be inserted into the string.


The actual code looks like this:



' "This report was originally addressed to {0} on {1}."

strMessage = String.Format(rm.GetString("strReportAddressedTo"), _

g_strSendReportTo, FormatDateTime(Now, DateFormat.LongDate))



We include the string as a comment, to simplify the process of locating the
appropriate section of the code when we must trouble-shoot the application
and we know what message was displayed. Of course, we are careful to use
tokens like {0} very sparingly because we are aware of the translation
difficulties that it presents. Nonetheless, where required, it is much
better than simply using string concatenation to build up a string!



Are there any comments or suggestions that you might have on the above?



We have a few specific questions and concerns about the above procedures.



Our strings are maintained in a .resx file. Unfortunately, the software
developer must provide a unique name for each string and there appears that
the VisualStudio development environment does not ensure that string names
within the .resx file are unique. When two or more strings have the same
Name, the ResourceManager may return either. This is very difficult to
debug.



Secondly, if the string Name that is passed to the .GetString method does
not appear in the .resx file, then an empty string is returned. Frequently,
this results in a Message Box that is completely empty! In a few "worst
case" situations, the empty string may actually cause the application to
fail in unexpected ways. This is also very difficult to troubleshoot. We
would have preferred that GetString raise an error event or return its
argument if no matching Name were found. Or it could return "No string found
with the Name: " & strArg. Is there a better approach to this? Our
alternative is to provide our own .GetString-like method that handles this
type of failure in a more debug-friendly manner. Do others not run into this
type of problem? Is there a better approach?



Finally, it is a chore to write code following the above style whenever an
in-code string must be utilized. Oh how we wish that VisualStudio could have
provided a facility for handling strings that must be translated! For
example, imagine how much easier our life would be if VisualStudio
recognized special strings that were marked using, for example, tilde before
the opening quote character. Such a string would be automatically placed
into the .resx file and a guaranteed unique string Name would be inserted
into the application at that point. There would be no need for a comment,
and when the string had to be corrected, there would be only one place in
the source that would require updating. And most importantly, there would
never be a mismatch between the string Name in the code and the Name in the
..resx file, and never a duplicate. Here's what the code would look like if
this concept were implemented by VisualStudio.NET:



strMessage = String.Format(rm.GetString(~"This report was originally
addressed to {0} on {1}."), _

g_strSendReportTo, FormatDateTime(Now, DateFormat.LongDate))



Are you aware of any tools that would accomplish this as cleanly and easily
as the above example shows?



Thank you very much!
 
F

Felix Wang

Hi,

Thanks for posting. I have done some research on your code. I don't think
there is any particular problem. However, I am not very sure about whether
you are aware of the built-in localization support for WinForm application
in VS.Net.

If we select the form by clicking it, we have 2 properties in the
Properties Window, namely "Localizable" and "Language". If we set
"Localizable" to true, and open the code editor, we can see that VS.Net
will generate lots of ResourceManager related code for us. This will lessen
our work on localizing Windows controls. If we change the "Language"
property, and edit the properties of Windows controls, the modification
will be written to corresponding resource files. For example, if we set
"Language" to Chinese Simplified and modify the Text of a TextBox, the
change will be saved to "Form1.zh-CHS.resx". The localizaed resource file
will be built into a satellite assembly and the default value of the
TextBox.Text, which is used for fallback, will not be changed. VS.Net will
help us to manage the name and values. We only need to handle those
resource strings not directly used in the Windows controls.

As far as your three concerns, I would like to summarize them as following:

1. Duplicate values in RESX are not detected.
2. Missing values yeilds "Nothing" (or "null" in C#) when "GetObject". It
is more desirable that we have an alternative mechanism to throw an
exception here.
3. It will be better if we have an easier way to handle resource strings,
for example, using a special character to inform the compiler to put the
string into the RESX file automatically.

If I have misunderstood you, please correct me. I will pass your
suggestions to our colleagues in the product team for their consideration.
In fact, improving the quality and usability of our products is a
never-ending process. We always appreciate and comments and suggestions
from our end-users.

The followings are a few links to the localization and globalization topic
on the MSDN website:

Tutorial:Resources and Localization Using the .NET Framework SDK
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptutorials
/html/Resources_and_Localization_using_the__NET_Framework_SDK.asp

Globalizing and Localizing Applications
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/
vboriInternationalization.asp?frame=true

Walkthrough: Localizing Windows Forms
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/
vbwlkWalkthroughLocalizingWindowsForms.asp?frame=true

I hope the information I have provided here is useful to you. If you have
any concerns or new findings regarding this issue, please feel free post
here.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top