This appendix contains a list of the new features in the .NET Framework 2.0 and Visual Studio 2005 that are relevant to internationalization. The appendix is useful if you already have a good knowledge of internationalization in the .NET Framework 1.1 and Visual Studio 2003 and want to get up to speed as quickly as possible. It is also useful if you are trying to decide whether to start a new project in your familiar .NET Framework 1.1 and Visual Studio 2003 or make the leap to the more recent version. The appendix is mostly a list of pointers to sections of this book where the relevant features are covered in more detail.
If you are looking for a complete list of changes between any two versions of the .NET Framework, download LibCheck.exe
from http://www.microsoft.com/downloads. This tool compares two versions of the .NET Framework and lists every difference.
This section covers the compatibility between the two versions of the .NET Framework and Visual Studio.
Visual Studio 2005 serializes components on a form using a model called Property Reflection (see Chapter 4, “Windows Forms Specifics”). Visual Studio 2003, however, serializes components using a model called Property Assignment. When you open a Visual Studio 2003 solution in Visual Studio 2005, it prompts you to convert the solution, giving you an opportunity to back up the old solution. The forms files (i.e., the .cs
, .resx
, and culture-neutral and culture-specific .resx
files) are all initially unchanged and remain compatible with Visual Studio 2003. However, after a form has been changed, the source and resx files are written out using Visual Studio 2005’s Property Reflection model. The resulting code and resx files are now different. Although Visual Studio 2003 doesn’t use the Property Reflection model, the resulting code and resx files are recognizable and can be opened and compiled using Visual Studio 2003 (assuming that the form contains only components and code that both platforms recognize). Unfortunately, Visual Studio 2003 fails to understand that the form’s Localizable
property should be true
and sets it to false
. When you set it to true
again, Visual Studio 2003 naturally rewrites the source file and resx file, and the form returns to Visual Studio 2003’s Property Assignment model.
The upshot of all this is that both versions of Visual Studio can read each other’s form files (as long as you use components that are present in both versions of the framework). However, when you make any change to a form, the version of Visual Studio you are using writes out the form again using the model that it uses to write forms. Because Visual Studio 2003 doesn’t understand Visual Studio 2005’s serialization of the form’s Localizable
property, you must set this to true
again; this constitutes a change, which, therefore, means that the form is converted back to Visual Studio 2003’s model. You should also be aware that the scenario of opening Visual Studio 2005 forms in Visual Studio 2003 is not an officially supported model, so although this is often possible, you are on your own with regard to support.
The Visual Studio 2005 Windows Forms Designer adds many enhancements beyond the Visual Studio 2003 Windows Forms Designer, but it also removes one area of functionality. In the Visual Studio 2003 Windows Forms Designer, you can add new controls to any language version of a form. For example, with the French version of a form selected in the designer, you can add a new button to the form and it will be added to all forms. The Visual Studio 2005 Windows Forms Designer, however, requires that you first change back to the default language before adding new controls. Instead of viewing this as a step backward in Visual Studio 2005, you should understand that Visual Studio 2003 should not have allowed new controls to be added to forms other than the default language form, but this practice was not explicitly prevented.
The format of the text returned by the CultureInfo DisplayName
and English-Name
properties for some cultures with scripts has changed. The format used in the .NET Framework 1.1 is to delimit the script entirely in its own parentheses. For example, the culture for the Azeri language in Azerbaijan using the Latin script (“az-AZ-Latn
”) has this EnglishName
:
Azeri (Latin) (Azerbaijan)
However, the .NET Framework 2.0 includes the script in the same parentheses as the country:
Azeri (Latin, Azerbaijan)
If you have logic that parses the name to extract its component information, you need to update this logic. Note that this change does not apply to new cultures with script suffixes that were introduced in the .NET Framework 2.0. For example, the “sr-BALatn
” culture’s EnglishName
is “Serbian (Latin) (Bosnia and Herzegovina)
”.
The order of the cultures returned from the CultureInfo.GetCultures
method is different between the two versions of the framework. The order in both versions of the .NET Framework is unsorted and unspecified, but they are nonetheless different.
The logic used to determine the DefaultFont
property of System.Windows.Forms. Control
is slightly more sophisticated in the .NET Framework 2.0. Because Control
is the base class for all Windows Forms controls, this affects all controls. The difference is that on Arabic Windows, Control.DefaultFont
now defaults to Tahoma, 8 point.
The logic used in the CultureInfo.Equals
method has changed. In the .NET Framework 1.1, CultureInfo.Equals
tests equality with another CultureInfo
by comparing their locale IDs (LCIDs). In the .NET Framework 2.0, this comparison does not work because custom cultures all share the same LCID. Thus, a Spanish (United States)
custom culture has the same LCID as a Bengali (Bangladesh)
custom culture. In the .NET Framework 2.0, the CultureInfo.Equals
method assumes that two cultures are equal if they have the same name and the same CompareInfo
objects. (A test based simply on a name would be incorrect because alternate sort orders have the same culture name but different sort orders.) I have not found any circumstance in which this difference causes an incompatibility.
The .NET Framework 2.0 introduces new calendar classes. These new calendars classes are available to the cultures for which they are relevant through the CultureInfo.OptionalCalendars
array property. Consequently, the lengths of these arrays and, perhaps more important, the order of the elements of these arrays are different in some cultures (e.g., Arabic (Saudi Arabia)
).
The month and day names returned by the DateTimeFormatInfo
, MonthNames
, and DayNames
array properties have changed for the Arabic (Morocco)
, Divehi (Maldives)
, Kannada (India)
, and Norwegian (Nynorsk) (Norway)
cultures (i.e., ar-MA
, div-MV
, kn-IN
, and nn-NO
).
In addition, the currency symbols have been updated for several cultures, including Turkish (Turkey)
(i.e., tr-TR
), for which the currency symbol in the .NET Framework 1.1 is “TL
” (Türk Lirasi); however, in the .NET Framework 2.0, the currency symbol is “YTL
” (Yeni Türk Lirasi), regardless of the version of Windows and whether Windows Updates is turned on.
The Visual Studio 2005 Resource Editor includes support for adding files such as bitmaps to resx resource files. The resulting entry in the resx file is of type ResXfileref
. The ResXFileRef
class is supported in both the .NET Framework 1.1 and 2.0. The problem (from the point of view of code that reads resources), however, is that the Visual Studio 2005 Resource Editor uses relative paths (see the “ResX File References” section in Chapter 10, “Resource Administration”). If you process resx files using the ResXResourceReader
class, in most cases your code that reads resx files will fail if it tries to read a .NET Framework 2.0 resx file because it won’t know where to find the referenced files. A number of solutions exist, but the simplest is to set the ResXResourceReader.BasePath
property to the path where the referenced files are located.
The serialization of the Form.Localizable
property to resx files has changed. In the .NET Framework 1.1, this property was represented as data in the resx file like this:
<data name="$this.Localizable" type="System.Boolean, mscorlib,
Version=1.0.5000.0, Culture=neutral,PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
In the .NET Framework 2.0, however, the same property is represented like this:
<metadata name="$this.Localizable" type="System.Boolean, mscorlib,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
The difference is that the Form.Localizable
property is now treated as meta-data instead of data. This has an impact on any code that reads resx files using the ResXResourceReader.GetEnumerator()
method. The following code adds all the entries in a resx file to a TextBox
:
ResXResourceReader reader =
new ResXResourceReader(@"....Form1.resx");
IDictionaryEnumerator enumerator = reader.GetEnumerator();
while (enumerator.MoveNext())
{
DictionaryEntry entry = enumerator.Entry;
string value = String.Empty;
if (entry.Value != null)
value = entry.Value.ToString();
textBox1.Text += entry.Key.ToString() + ", " + value +
System.Environment.NewLine;
}
In the .NET Framework 1.1, this code includes the $this.Localizable
entry. In the .NET Framework 2.0, it does not. To read this entry in the .NET Framework 2.0, you need to use the new ResXResourceReader.GetMetadataEnumerator
method:
ResXResourceReader reader =
new ResXResourceReader(@"....Form1.resx");
IDictionaryEnumerator enumerator = reader.GetMetadataEnumerator();
while(enumerator.MoveNext())
{
DictionaryEntry entry = enumerator.Entry;
textBox1.Text += entry.Key.ToString() + ", " +
entry.Value.ToString() + System.Environment.NewLine;
}
This code results in just a single entry (i.e., $this.Localizable
).
In addition, the change from data to metadata affects any FxCop rule that reads resource data looking for the Form.Localizable
property. See the “Form. Localizable
must be true
” rule in Chapter 13, “Testing Internationalization Using FxCop,” for an example.
The deployment story for the .NET Framework has improved. In both .NET Framework 1.1 and 2.0, the .NET Framework redistributable (dotnetfx.exe
) installs an English (United States)
version of the framework. This has not changed. However, the packaging of the user interface used during the installation process has. In the .NET Framework 1.1, you could distribute different language versions of the .NET Framework redistributable. So if you distributed the German .NET Framework redistributable, the setup user interface would be in German, and the English version of the framework would be installed. In the .NET Framework 2.0, however, there is just a single .NET Framework redistributable that contains the localized user interface for all supported languages. The user interface used during installation is determined by the language version of the operating system. In addition to the installation languages supported by the .NET Framework 1.1, the .NET Framework 2.0 supports Arabic and Hebrew.
If you download the .NET Framework 2.0 redistributable from http://www.microsoft.com/downloads, be aware that the combo box that offers you a choice of languages simply refers to the language of the Web page from which the redistributable can be downloaded. The dotnetfx.exe
on each and every page is 100 percent identical.
Arabic and Hebrew have been added to the list of .NET Framework Language Packs. The list of language versions for Visual Studio 2005 is the same as for Visual Studio 2003.
This section describes enhancements to the .NET Framework classes, paying particular attention to the System.Globalization
namespace.
The IdnMapping
class provides support for international domain names. See the “International Domain Name Mapping” section of Chapter 6, “Globalization.”
Some cultures support more than one solution for sorting data. The .NET Framework 1.1 allows these alternate sort orders to be specified when a new CultureInfo
is created by providing the locale ID (LCID), which represents the language, region, and sort order. The following code creates a CultureInfo
object for Spanish in Spain using the traditional sort order:
CultureInfo cultureInfo = new CultureInfo(0x0000040A);
This is still supported in the .NET Framework 2.0, but the .NET Framework 2.0 supports an alternative solution when the language, region, and sort order can be specified as a string:
CultureInfo cultureInfo = new CultureInfo("es-ES_tradnl");
You can see from this example that the sort order (“tradnl
”) is a suffix of the region (“ES
”). The sort order can be specified for only alternate sort orders—in other words, you cannot specify the Spanish default International (Modern)
sort order using “es-ES-Intl
”. The complete list of alternate sort order identifiers is listed in the “Alternate Sort Orders” section of Chapter 6.
This enhancement is an important one because it enables developers to support a single data type (i.e., string) for storing and transmitting culture identifiers. Without this enhancement, developers must support both string and integer data types to be able to represent all cultures with all sort orders.
The CultureTypes
enumeration has four new members: FrameworkCultures
, ReplacementCultures
, UserCustomCulture
, and WindowsOnlyCultures
, which are used in CultureInfo.GetCultures
. See the “CultureInfo.GetCultures
and CultureTypes
Enumeration” section in Chapter 6.
CultureInfo
has a new property, IetfLanguageTag
, which gets the RFC 3066(bis) standard identification for a language.
CultureInfo
has a new method called GetCultureInfo
, which provides caching support for CultureInfo
objects. The first call to CultureInfo.GetCultureInfo
creates a CultureInfo
method as normal, but subsequent calls for the same CultureInfo
get the cached copy. The benefit is better performance. However, all cached cultures are read-only and, more important, do not accept user overrides (accepting user overrides is a recommended practice); if you want to accept user overrides, you should not use this method. CultureInfo
has a similar method called GetCultureInfoByIetfLanguageTag
that performs the same operation but accepts an IETF language tag instead of a culture name.
The String.Compare
method has a new overload, String.Compare(string, string, StringComparison)
, which accepts a StringComparison
enumeration. This provides a more convenient way of specifying how a string comparison should be performed instead of having to remember what String.Compare
or String.CompareTo
overload to call.
DateTime
has a new property called Kind
, which is a DateTimeKind
enumeration. This enables developers to specify whether the DateTime
is local time, coordinated universal time (UTC), or unspecified (the default). This is used in conjunction with the new “K
” DateTime
format specifier, and it provides developers with control over the serialization of dates that include time zones.
DateTimeFormatInfo
has two new properties, AbbreviatedMonthGenitiveNames
and MonthGenitiveNames
, which surface the names of months when they are used in their genitive form (see the “Genitive Date Support” section in Chapter 6). The .NET Framework 1.1 supports genitive month names but does not expose the names for you to use for your own purposes.
DateTimeFormatInfo
also has a new ShortestDayName
property, which returns an array of the shortest day names (e.g., “Su
”, “Mo
”, “Tu
”, “We
”, “Th
”, “Fr
”, “Sa
”).
Two new methods, TryParse
and TryParseExact
, are siblings of the Parse
and ParseExact
methods. They enable you to attempt to parse a date without throwing an exception. Both methods return a Boolean indicating the success of the parsing operation.
The .NET Framework 2.0 adds eight new Calendar
classes: EastAsianLunisolar-Calendar (abstract)
, ChineseLunisolarCalendar
, JapaneseLunisolar Calendar
, KoreanLunisolarCalendar
, TaiwanLunisolarCalendar
, Jalaali Calendar
, PersianCalendar
, and UmAlQuraCalendar
. See the “Calendars” section in Chapter 6.
Calendar.AlgorithmType
is a read-only property that enables you to determine whether the calendar is a solar calendar, a lunar calendar, or both. Calendar.IsReadOnly
is a read-only property indicating whether the calendar’s properties are read-only.
Calendar.MaxSupportedDateTime
and Calendar.MinSupportedDateTime
are read-only properties indicating the upper and lower bounds of the calendar.
Calendar.GetLeapMonth
returns a month number of the leap month in a given year and, optionally, an era. The month number is 0
if the year does not have a leap month. Calendar.ReadOnly
is a static method that returns a read-only calendar object.
CompareInfo
has a new Name
property, which provides a string identifier for the CompareInfo
. Typically, this name is the same culture string used to identify a CultureInfo
(e.g., “es-ES
” for Spanish (Spain)
international sort), but for alternate sort orders, this includes the sort suffix (e.g., “es-ES_tradnl
” for Spanish (Spain)
traditional sort).
CompareInfo
has a new static method, IsSortable
, which returns true
if a character or string is sortable. A character or string is sortable if all its characters are known to the .NET Framework’s sort tables. In this situation, String.Compare
compares all characters in the string. However, if a string contains characters that are not known to the .NET Framework’s sort tables, String.Compare
simply ignores those characters. In this situation, a more accurate test for equality can be achieved using String.CompareOrdinal
, which compares the Unicode code points of all characters, regardless of their presence or absence in the .NET Framework’s sort tables.
RegionInfo
has new properties to help with internationalizing currency names: CurrencyEnglishName
and CurrencyNativeName
. RegionInfo.GeoId
is a numeric geographical identifier for the region. It is useful for uniquely identifying a region and also for use with the Win32 GetGeoInfo
function. See the “Geographical Information” section in Chapter 6. RegionInfo.NativeName
returns the name of the region that is used in that region.
TextInfo.CultureName
returns the name of the culture to which the TextInfo
is attached. TextInfo.IsReadOnly
indicates whether the TextInfo
object is read-only. TextInfo.IsRightToLeft
indicates whether the associated language is a right-to-left language (in the .NET Framework 1.1, this is achievable only by hard-coding a known list of right-to-left cultures). TextInfo.LCID
is the locale ID of the associated language.
TextInfo.ReadOnly
is a static method that returns a read-only TextInfo
object.
NumberFormatInfo
has two new properties, DigitSubstitution
and Native Digits
, which provide information about the digit systems used for formatting. DigitSubstitution
is a DigitShapes
enumeration that is either None
, Context
, or NativeNational
. NativeDigits
is an array of strings of the digits used for number formatting. Both properties are purely informational and have no effect in the .NET Framework 2.0. They exist for you to use for your own purposes and in expectation of better support in a future version of the .NET Framework. The following code shows their values for English (United States)
and Arabic (Saudi Arabia)
:
CultureInfo cultureInfo = new CultureInfo("en-US");
textBox1.Text +=
cultureInfo.NumberFormat.DigitSubstitution.ToString() +
":- " +
ArrayToString(cultureInfo.NumberFormat.NativeDigits) +
System.Environment.NewLine;
cultureInfo = new CultureInfo("ar-SA");
textBox1.Text +=
cultureInfo.NumberFormat.DigitSubstitution.ToString() +
":- " +
ArrayToString(cultureInfo.NumberFormat.NativeDigits) +
System.Environment.NewLine;
(ArrayToString
is a simple custom method to convert an array to a string.) The result is this:
None:- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Context:
DigitSubstitution
is None
for all cultures except for Arabic, Kyrgyz, Mongolian, and Persian-specific cultures.
ResourceReader
has a new method called GetResourceData
, which reads a resource as an array of bytes. The purpose of this method is to allow data of any type to be read from a .resources
file. The problem that it solves is that it is not normally possible to read data from a .resources
file if the data cannot be deserialized. Typically, data cannot be deserialized if the type is unknown to the application that is deserializing the data. So if one application stores, say, a BusinessObject
type in a .resources
file and the application reading the file does not have a reference to the assembly containing the BusinessObject
type, the attempt to deserialize the BusinessObject
will fail. However, the GetResourceData
method allows the data for this resource to be retrieved as an array of bytes. The following example retrieves a resource entry called “String1
” from “Form1Resources.resources
”:
ResourceReader reader =
new ResourceReader("Form1Resources.resources");
string resourceType;
byte[] resourceData;
reader.GetResourceData(
"String1", out resourceType, out resourceData);
textBox1.Text +=
"ResourceType: " + resourceType + System.Environment.NewLine +
"ResourceData: " +
System.Text.Encoding.UTF8.GetString(resourceData);
The result is this:
ResourceType: ResourceTypeCode.String
ResourceData: &This is the resource value for String1
Of course, this particular exercise is unnecessary because the string type can always be deserialized, but it shows the method’s behaviour.
ResXResourceReader
has a new property, BasePath
, which specifies the path where files referenced in relative file references can be found. ResX file references exist in both the .NET Framework 1.1 and 2.0, and are described in the “ResX File References” section in Chapter 10. Another new property, UseResXDataNodes
, is a Boolean value indicating whether the resource entries’ values are the simple values that they are in the .NET Framework 1.1 or are ResXDataNode
objects. The default is false
, so it is compatible with the .NET Framework 1.1. The benefit of the ResXDataNode
objects is that they contain comments and file references. See the “ResXDataNodes and Comments
” section in Chapter 10.
ResXResourceReader
has a new method called GetMetadataEnumerator
. This method returns an enumerator for a resx’s metadata. The Form.Localizable
property is treated as data in the .NET Framework 1.1 but as metadata in the .NET Framework 2.0. The GetMetaDataEnumerator
method provides a means by which these metadata values can be retrieved. See the “ResX Changes Break Code That Uses ResXResourceReader
” section of this appendix for more details.
ResXResourceWriter
has a new method called AddAlias
, which adds an assembly alias to the resx file. After ResXResourceWriter.Generate
is called, the resx file contains a corresponding assembly element:
<assembly alias="System.Windows.Forms" name="System.Windows.Forms,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
Subsequent entries in the resx file need to refer to only the alias instead of the full assembly name:
<data name="button1.ImeMode"
type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
The result is a smaller resx file.
In addition, ResXResourceWriter
has a new method called AddMetadata
, which adds metadata entries to a resx file. Such entries are intended to be used for design-time properties such as Form.Localizable
. Metadata entries are read using the new ResXResourceReader.GetMetadataEnumerator
method.
String has two new methods, Normalize
and IsNormalized
, which are used to normalize strings. The problem that they solve comes from the fact that some Unicode characters can be represented in more than one way (by using several combined Uni-code characters). The binary representations are different, but the characters that they represent are the same. If their binary representations were compared, they would appear to be different, even though they result in the same character. Unicode supports a concept called normalization that resolves these representations to a simpler form, and the Normalize
and IsNormalized
methods implement this process.
The String
and StringInfo
classes also have a new property, LengthInText-Elements
, and a method, SubstringByTextElements
, which together enable you to process strings in terms of their text elements instead of their characters. Many scripts (e.g., Japanese Hiragana) combine characters to form text elements, and it is often meaningless to process individual characters in such scripts.
The String.Compare
method has several new overloads that accept a new StringComparison
enumeration that simplifies string comparisons. For example, calling String.Compare
with the StringComparison.Ordinal
value is the same as calling String.CompareOrdinal
. Microsoft now recommends using ordinal comparisons for culture-insensitive comparisons. See the “Sort Orders” section of Chapter 6 for more details on ordinal comparisons.
The .NET Framework 2.0 introduces a new class, CharUnicodeInfo
, which provides information about a Unicode character. The information is drawn from the Unicode Character Database for Unicode 4.1. It has four static methods (GetDecimalDigitValue
, GetDigitValue
, GetNumericValue
, and GetUnicodeCate-gory
) to retrieve various kinds of information about a character. Putting aside the 0
to 9
digits that we already know about, Unicode defines numerous code points for characters that have a numeric meaning. For example, the Unicode character ½
(U+00BD
) is one half, so CharUnicodeInfo.GetNumericValue
returns 0.5
for this character. A similar effect is true for Roman numerals (e.g.,“I
” is 1
), Tamil characters (e.g., U+0BF2
is 1000
), and Tibetan characters (e.g., U+0F32
is half nine
).
resx files in both the .NET Framework 1.1 and 2.0 support file references. This means that a file can be referred to instead of being embedded in the resx file. The resulting resource in the resource assembly is exactly the same as for a resource that is embedded, however, so this is simply a development issue. The important point here is that file references are now the default for the Visual Studio 2005 Resource Editor, so any file that you add to a resource, by default, simply has a reference to the file. A copy of the file is added to a local Resources
folder (in a Windows Forms application) or the App_ GlobalResources
or App_LocalResources
folder (in an ASP.NET application), and the reference is to the file in this folder instead of the original file. In addition, the file reference is a relative reference instead of an absolute reference.
ResourceManager
has a new method called GetStream
, which returns an UnmanagedMemoryStream
for a resource given the name of that resource. The method is not CLS compliant.
The .NET Framework 2.0 enables you to specify that the location of the fallback resources is a satellite assembly. In the .NET Framework 1.1, the only choice was that fallback resources were in the invariant or fallback assembly. The downside to this approach is that there is no separation between resources and code. See the “NeutralResourcesLanguageAttribute
and UltimateResourceFallback Location
” section in Chapter 3, “An Introduction to Internationalization.”
The Base Class Library Samples includes two new utilities for manipulating resources, which are collectively referred to as the Managed Resource Viewer. Although they are not specific to the .NET Framework 2.0, they were released during the same time period, so I have included them in this appendix. ResView
is a resource viewer, and ResExtract
extracts resources from a resource assembly. See http://msdn.microsoft.com/netframework/downloads/samples/bclsamples/ for more details.
The .NET Framework 2.0 and Visual Studio 2005 support a concept of strongly typed resources. So instead of writing this:
MessageBox.Show(resourceManager.GetString("InsufficientFunds"));
You can write this:
MessageBox.Show(Form1Resources.InsufficientFunds);
You gain several benefits from this. The resource entry name is checked at design time instead of runtime, so typos are eliminated. The property is strongly typed, which gives compile-time type checking. The resource class (Form1Resources
, in this example) encapsulates the ResourceManager
, so it is not necessary to manage it yourself. Strongly-typed resources are initially covered in Chapter 3 but are also covered again in several other chapters. If you are staying with the .NET Framework 1.1, see the “Strongly-Typed Resources in the .NET Framework 1.1” section in Chapter 3 for an equivalent solution.
The .NET Framework 2.0 supports a concept of custom cultures. This concept existed in the .NET Framework 1.1, but it was primitive and difficult to gain any real benefit from. This improved implementation is recognized by the .NET Framework 2.0, the .NET Framework 2.0 SDK, and Visual Studio 2005. A custom culture is a culture that you define. It can be a modification of an existing culture, a combination of existing cultures, or a completely new culture in its own right. This idea has huge potential, which is why this book includes a whole chapter on this subject: Chapter 11, “Custom Cultures.”
Visual Studio’s Resource Editor has had an overhaul for Visual Studio 2005. Apart from its visual appearance, the main feature is that it does not handle all resources as strings. It enables you to manage bitmaps, icons, audio, and other files as resources.
This section details the .NET Framework 2.0 and Visual Studio 2005 enhancements which are specific to Windows Forms applications.
Visual Studio 2005 supports a model for serializing Windows Forms called property reflection. Instead of properties being serialized one by one as they are in Visual Studio 2003’s property assignment model, properties are loaded using reflection by searching for resources with names that match the control and its properties. The end result is no different from the end result of Visual Studio 2003 in terms of functionality. The difference lies in the performance of forms that have large numbers of controls, so property reflection is said to scale better than property assignment. See Chapter 4.
In the .NET Framework 1.1, several controls have an AutoSize
property, but many do not. In the .NET Framework 2.0, the AutoSize
property has been moved to the System.Windows.Forms.Control
base class, meaning that all controls now have an AutoSize
property. You will find that a few controls (e.g., ListBox
) hide their AutoSize
property in the Form Designer, but putting these controls aside this means that significantly more controls in Windows Forms 2.0 have an AutoSize
property. See the “AutoSize
” section in Chapter 8, “Best Practices.”
The default for Label.AutoSize
remains unchanged in the .NET Framework 2.0 and is still false
. However, Visual Studio 2005 treats this control differently from Visual Studio 2003: When a Label
control is added to a form, its AutoSize
property is automatically set to true
. The effect is that it appears that the default has changed from false
to true
. This is helpful because it is more usual to want Label
controls to be autosized on a localized form. Note that the LinkLabel
control inherits from Label
, so the same change applies to LinkLabel
controls.
A similar effect can be seen for CheckBox
and RadioButton
controls. These controls do not have an AutoSize
property in the .NET Framework 1.1. In the .NET Framework 2.0, the default value for AutoSize
for CheckBoxes
and RadioButtons
is false
, but Visual Studio 2005 automatically sets it to true
.
Some controls (Button
, DataGridViewColumn
, Form
, GroupBox
, Panel
, Splitter-Panel
, TabPage
, ToolStripContentPanel
, UserControl
) have a new property called AutoSizeMode
that can be set to determine whether the control should automatically grow and shrink as necessary or grow only as necessary. See the “Auto-SizeMode
” section in Chapter 8.
Some controls (Button
, CheckBox
, Label
, RadioButton
) have a new AutoEllipsis
property, which automatically displays an ellipsis in the text when there is insufficient room to display the whole text. This is useful for controls that must be localized but whose size must not change (such as controls on a sculpted form). The full text is still available as a ToolTip. See the “AutoEllipsis
” section in Chapter 8.
The Form
control, together with a number of other Windows Forms controls, now has a RightToLeftLayout
property. This Boolean property is used in conjunction with the RightToLeft
property and takes effect only when RightToLeft
is Yes
. Its purpose is to relocate controls within the form so that the controls appear as if they have been laid out correctly for a right-to-left language instead of a left-to-right language. In addition, it correctly mirrors a form’s title bar so that the System Menu, Close, Maximize, and Minimize buttons are repositioned correctly. See the “Right-to-Left Languages and Mirroring in Windows Forms Applications” section of Chapter 7, “Middle East and East Asian Cultures,” for more details.
The .NET Framework 2.0 includes two new controls, TableLayoutPanel
and FlowLayoutPanel
, which bring the power of HTML’s table and flow layout to Windows Forms. These are significant controls and can have a considerable impact on the way you design your forms for localization and the subsequent role that a translator/localizer might take. Using these controls means that your forms can automatically adapt to controls that resize as a consequence of their text changing size. Well-designed forms, therefore, do not need to be redesigned for different cultures, and a single form can fit all cultures. This drastically reduces the localization effort. See the “TableLayoutPanel
and FlowLayoutPanel
” section in Chapter 8.
Windows Forms 2.0 introduces a new component called BackgroundWorker
, which simplifies moving work to a background thread. This control is relevant to internationalization because, unlike the primitive Thread
class that it replaces, Back-groundWorker
does not provide you with direct access to the background thread upon which it is based. You can still set the BackgroundWorker
’s Thread’s CurrentCulture
and CurrentUICulture
, but these must be set in the DoWork
event handler:
public void BeginBackgroundWorker()
{
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork +=
new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerAsync();
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
// do some work
}
WinRes in the .NET Framework 1.1 SDK is difficult to use, for several reasons. WinRes in the .NET Framework 2.0 SDK is considerably improved, so if you rejected this tool previously, you should take a fresh look at it in 2.0 for small to medium-sized projects (for large projects, consider using one of the commercially available tools).
First and foremost, WinRes now understands the resx files that Visual Studio 2005 creates. It supports two file modes: Visual Studio File Mode and Single File Mode (the only mode used in WinRes 1.1). This means that you can read and write resx files in both Visual Studio 2005 and also WinRes 2.0 without having to commit to one tool.
WinRes 2.0 has significantly better error reporting. WinRes 1.1 had a handful of cryptic and unhelpful error messages, which lead to a lot of thrashing around trying to identify the real problem. WinRes 2.0 has more descriptive error messages.
WinRes 2.0 is more resilient than its predecessor. WinRes 1.1 refused to load a form if it found a single fault on the form. WinRes 2.0 loads all that it can load and reports the problems about the failed components.
WinRes 2.0 supports loading forms that inherit from other forms when the controls on those other forms have public visibility. Although this support is not absolute, it is considerably better than WinRes 1.1’s nonexistent support.
Finally, WinRes 2.0 offers many of the same design and productivity improvements that you see in Visual Studio 2005’s Forms Designer (e.g., snap lines).
See the “Windows Resource Localization Editor (WinRes)” section in Chapter 4.
Visual Studio 2005 is a quantum leap beyond Visual Studio 2003 in terms of internationalization of ASP.NET applications. As with so many features in the .NET Framework 2.0 and Visual Studio 2005, this subject alone justifies the upgrade.
Visual Studio 2005 enables you to localize forms with the same kind of productivity and efficiency that Visual Studio provides for Windows Forms applications. Select Tools, Generate Local Resources from Visual Studio 2005’s menu; all the Localizable
property values are moved to an associated resx file, and a “meta:resourcekey
” attribute referring to those resources is added to the control. See the “Localizability in Visual Studio 2005” section in Chapter 5, “ASP.NET Specifics.”
The <globalization>
section of Web.config
has always had culture
and uiCulture
attributes, which enable you to specify the CurrentCulture
and CurrentUICulture
of an entire Web site or folder. In ASP.NET 2.0, however, these attributes can be set to “auto
” to automatically pick up the user’s preferred settings from the HTTP header. See the “Application-Wide Automatic Culture Recognition” section in Chapter 5.
The Page
class now supports Culture
and UICulture
attributes, which work in the same way as the <globalization>
element’s culture
and uiCulture
attributes, except that they apply to a single page. See the “Automatic Culture Recognition for Individual Pages” section in Chapter 5.
The Page
class has a new method called InitializeCulture
, which can be overridden to set the culture. This method is called before all the page’s events so that it occurs early in the pipeline. You would use this method if the “auto
” settings did not provide the functionality you are looking for. See the “Manual Culture Recognition for Individual Pages” section in Chapter 5.
In ASP.NET 1.1, no properties of any control are marked with the Localizable
attribute. This is because Visual Studio 2003 does not offer any localization support for ASP.NET applications, so the presence or absence of the Localizable(true)
attribute makes no difference. In ASP.NET 2.0, you will find that many properties of Web controls are marked as Localizable(true)
, and this is how Visual Studio 2005 can localize pages. What is important to note here is that only a few HTML control properties are marked as Localizable(true)
. In general, this means that if you want to localize your ASP.NET applications, you must use Web controls instead of HTML controls.
The Localize
control inherits from the Literal
control and adds no new properties, methods, or events. At runtime, the Localize
control is identical to the Literal
control. The difference between the two controls lies in Visual Studio 2005’s handling of these controls at design time. The Localize
control uses the Localize Designer
, whereas the Literal
control uses the LiteralDesigner
. The purpose of both the Localize
control and the Literal
control is to allow text to be placed in a control that can be localized—your choice between the two controls is determined by your preference of design-time support.
By default, ASP.NET 2 applications monitor their associated resx files at runtime. When one of their associated resx files changes, ASP.NET unloads the application domain, rebuilds the associated resource assemblies, and reloads the application. This means that translators can modify resx files and see their changes immediately. In addition, the resources used in Web sites can be updated without needing to manually rebuild the application. Of course, this unloads the application domain, and any state in that domain will be lost. See the “ASP.NET 2.0 Translation/Localization Strategies” section in Chapter 14, “The Translator.”
18.189.22.136