FxCop Globalization Rules


FxCop includes a set of rules under the heading "Globalization Rules." These rules check that your assemblies meet various internationalization standards. I briefly discuss each of these rules in turn, to highlight their pros and cons, and as a means of laying a foundation for new rules in the next section.

To use the Globalization rules, the control flow analysis setting must be enabled, which, by default, it is. If you find that the Globalization rules are not catching errors that you suspect that they should, you should check this setting. In FxCop, select Tools, Settings...; select the Analysis Engines tab; select the Introspection engine; click the Settings button; and check the Enable Control Flow Analysis check box. This setting cannot be changed from within Visual Studio 2005.


"Avoid duplicate accelerators"

This rule is a great idea. It catches controls that use the same accelerator key in the same parent (typically a form). So if you define two labels with the texts "&Customer" and "&Contact", FxCop will catch the error and report "Define unique accelerators for the following controls in Form1 that all currently use &C as an accelerator: Form1.label1, Form1.label2". Note that the rule works by reading through the resources in the fallback assemblies, so this rule applies only if you set Form.Localizable to true. It also compares accelerator keys only on the same form, so, not unreasonably, it cannot detect clashes caused by combining forms at runtime. Also note that the rule does not apply to menu items.

An important limitation of this rule and all FxCop rules is that FxCop's analysis engine is limited to analyzing resources in the fallback assembly only. Support for analyzing resources in a satellite assembly is planned for a future release.


"Do not hardcode locale specific strings"

This rule checks for code that contains literals that refer to culture-specific environment special folders. Special folders are folders such as "Program Files". In non-English versions of Windows, the names of special folders are localized, so if your application refers to a path by its English name, it will fail (in the German version of Windows, for example, this folder is called "Programme"). The following code results in one error (for "\System32"):

 string windowsFolder = @"\Windows"; string systemFolder = @"\System32"; Text = "The System folder is " + windowsFolder + systemFolder; 


The solution is to use Environment.GetFolderPath and Environment. SpecialFolder:

 Text = "The System folder is " +     System.Environment.GetFolderPath(     Environment.SpecialFolder.System); 


This rule is a good idea, but its pattern matching errs on the side of caution. The folder names cannot be even slightly disguised for the rule to apply, so the following assignments are not caught by this rule:

 string systemDataFileName = @"C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"; string smartTagFileName = @"C:\Program Files\Common Files\" +     @"Microsoft Shared\Smart Tag\SmartTagInstall.exe"; string systemFolder = @"\Windows\System32"; 


I'll leave it as an exercise for you to write a more enthusiastic version of this rule after we have covered writing FxCop rules.

"Do not pass literals as localized parameters"

Here's another great idea. This rule catches literal strings that should be localizable. Here's an example:

 MessageBox.Show("Insert the paper and press Send"); 


Clearly, this text has been hard-coded into the application and, therefore, is not localizable. The problem that this rule is trying to solve is quite a tricky one. It is trying to catch literal strings that should be localizable. In the previous example, it is easy to see that the string should be localizable. However, it is not just a simple case of mindlessly ploughing through an assembly identifying all literal strings. Assemblies are full of literal strings that are completely valid and should not be localizable. The rule has to take a more intelligent approach. The rule decides that a literal should be localized if:

  • It is used as a parameter where the name of the parameter is either "caption", "message", or "text".

  • It is used in an assignment to a property called either "Caption", "Message", or "Text".

  • It is used in an assignment to a property that has been marked as Localizable(true).

For example, the first parameter to MessageBox.Show() is called "text" and, therefore, meets these requirements. The DateTime.ToString() method also accepts a string as a parameter, but this string is not considered to be a target for localization.

 MessageBox.Show(DateTime.Now.ToString(     "HH:mm:ss", CultureInfo.CurrentUICulture)); 


You can "disable" this rule at the property level by marking a property with the Localizable(false) attribute.


This "smart" approach to detecting literal strings ensures that there are very few false positives. The rule's heuristic also means that the vast majority of localization cases will be caught. If you have literal text that is not being caught by this rule, the best solution is to use either parameter names of "caption", "message", and "text" or property names of "Caption", "Message" and "Text", or mark properties with the Localizable(true) attribute. If these solutions are not suitable, for a less accurate but more open solution, look at the "Do not use literal strings" rule, which I cover later in this chapter.

Another issue that you should consider when using this rule is that it considers Exception.Message to be localizable. You may or may not agree with this, and you should refer to "Exception Messages" in Chapter 8, "Best Practices," for more information. In summary, messages such as "Value does not fall within the expected range" are probably intended for the developer's benefit, whereas messages such as "Access denied" might be more useful to the user. Consequently, you need a policy on whether exception messages should be localizable. If you feel that they should not be localizable, this rule will give you many false positives.

"Set locale for data types"

This rule ensures that the DataTable.Locale property is set on all DataTable objects (either directly through DataTable.Locale or indirectly through DataSet.Locale). Data that is persisted or that crosses the application boundary should use the invariant culture or a culture that is uniform throughout all uses of the data. This rule serves to remind developers of this.

"Specify CultureInfo" and "Specify IFormatProvider"

These two rules are quite similar and attempt to check for unintended results from conversions and comparisons. "Specify CultureInfo" checks that when you call a method that has an overloaded version that accepts a CultureInfo parameter, you use that overloaded version and explicitly pass a CultureInfo parameter. An example is String.ToUpper(). This method has two overloaded versions: one that accepts a CultureInfo parameter and one that doesn't. If you call String.To Upper() without a CultureInfo parameter, FxCop will report an error. The same is true for the "Specify IFormatProvider" rule, which demands that if you call a method that has an overloaded version that accepts an IFormatProvider parameter, you pass a value for this parameter. An example of such a method is DateTime.ToString(). So the following code generates a "Specify CultureInfo" and a "Specify IFormatProvider" FxCop error:

 string greeting = "Hello"; DateTime dateTime = new DateTime(2005, 1, 31); greeting.ToUpper(); dateTime.ToString(); 


whereas the following code does not generate these errors:

 string greeting = "Hello"; DateTime dateTime = new DateTime(2005, 1, 31); greeting.ToUpper(CultureInfo.CurrentCulture); dateTime.ToString(CultureInfo.CurrentCulture); 


If you recall our discussion of CultureInfo.CurrentCulture in Chapter 6, "Globalization," you will notice that there is no functional difference between these two blocks of code. If the CultureInfo and IFormatProvider parameters are excluded, they will default to CultureInfo.CurrentCulture. Consequently, you might ask why, then, is there a rule to ensure that the default value cannot be used? The problem is one of ambiguity. It isn't possible for a static analysis engine to determine what the purpose of the conversion is. If the purpose is to display the result in the user interface, the CultureInfo.CurrentUICulture should be used. Of course, if you set the CultureInfo.CurrentCulture to be the same as CultureInfo.CurrentUICulture, we are back to the situation in which passing CultureInfo. CurrentUICulture has no functional difference from accepting the default. However, if the purpose of the conversion is to persist the result in a file or a database, there is a good argument that using either the CultureInfo.CurrentCulture or the CultureInfo.CurrentUICulture is incorrect. The argument would be that a persistent store should not be dependent upon a language or region so that the information is consistent across all languages and regions. In this scenario, a CultureInfo/IFormatProvider value must be passed. The problem that the rule faces is that it doesn't know when it is essential to explicitly pass a value, so it takes the approach that a value must always be passed so that the developer is forced to make a conscious decision. Unfortunately, I suspect that the majority of calls to such methods pass the default value for this parameter anyway, and the calls that use CultureInfo.InvariantCulture are the exception.

In the "Writing FxCop Globalization" rules section, I show you a new rule that checks for culture-specific DateTime format strings.

The "Specify CultureInfo" rule can be reported for code that Visual Studio itself generates in a form's InitializeComponent method. As you are not able to change the way this code is generated, and changing the code itself is both hazardous and pointless, you should "exclude" these errors. (FxCop allows errors to be excluded so that it does not report the specific excluded cases again.)


"Specify MessageBoxOptions"

This rule ensures that all calls to MessageBox.Show pass a parameter for the MessageBoxOptions. The purpose of this requirement is to ensure that developers have considered how message boxes will behave in a right-to-left application. If you set a form's RightToLeft property to true, all of the controls will inherit this setting by default and will look and behave appropriately on a right-to-left application. However, message boxes do not inherit such look and behavior from forms, so a simple call to MessageBox.Show("Hello") will result in a left-to-right dialog. To fix the code, the MessageBoxOptions parameter must be passed. The equivalent call to MessageBox.Show is now:

 MessageBox.Show("Hello", String.Empty, MessageBoxButtons.OK,     MessageBoxIcon.None, MessageBoxDefaultButton.Button1,     (MessageBoxOptions) 0); 


This prevents FxCop from raising the "Specify MessageBoxOptions" error, because a value for MessageBoxOptions is passed, but it doesn't solve the problem. The solution is to pass MessageBoxOptions.RightToLeft and MessageBox Options.RtlReading for this parameter on right-to-left systems or a 0 value on left-to-right systems. See the "MessageBox" section in Chapter 7, "Middle East and East Asian Cultures," for more information.




.NET Internationalization(c) The Developer's Guide to Building Global Windows and Web Applications
.NET Internationalization: The Developers Guide to Building Global Windows and Web Applications
ISBN: 0321341384
EAN: 2147483647
Year: 2006
Pages: 213

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net