[Mono-dev] gendarme: request for globalization

Christian Birkl christian.birkl at gmail.com
Wed Aug 30 15:33:46 EDT 2006


Hi all,

after talking to Sebastien about another issue I'd like to see changed the
topic "globalization" came up. I think I found a solution which may bring
globalization to gendarme with just a few changes and also fixing the other
issue I had :-).

The attached patch is an example translation which supports rule information
for "Gendarme.Rules.Portability" in english and german.  The design follows
using System.ResourceManager and the commonly used "MyType.CULTURE.resx"
resources. Each rule will get it's own resx file which stores its localized
strings in this format:

Key: Value
----------------
Rule.Name: <Name>
Rule.Problem: <Problem>
Rule.Solution: <Solution>
Rule.Uri: <Uri>
Msg.MyFirstKey: MyFirstTest
Msg.MySecondKey: MySecondKey

In order to fit this into the gendarme framework I've extended IRule with a
property named "ResourceManager ResourceManager { get; }" which every rule
needs to implement. This returns the resource manager for this rule.

Since my knowledge about globalization is very limited I googled a bit
around to find out what other applications do. It seems using "resx" files
is a "best practice" (according to MS). But I'd like to here how other mono
projects handle this issue and what might fit best into gendarme's
framework.

Christian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-devel-list/attachments/20060830/194300d1/attachment.html 
-------------- next part --------------
Index: framework/IRule.cs
===================================================================
--- framework/IRule.cs	(revision 64515)
+++ framework/IRule.cs	(working copy)
@@ -28,11 +28,14 @@
 
 using System;
 using System.Collections;
+using System.Resources;
+
 using Mono.Cecil;
 
 namespace Gendarme.Framework {
 
 	public interface IRule {
+		ResourceManager ResourceManager { get; }
 	}
 
 	public interface IAssemblyRule : IRule {
Index: framework/RuleInformationManager.cs
===================================================================
--- framework/RuleInformationManager.cs	(revision 64515)
+++ framework/RuleInformationManager.cs	(working copy)
@@ -30,13 +30,15 @@
 using System.IO;
 using System.Collections;
 using System.Xml;
+using System.Resources;
+using System.Reflection;
 
 namespace Gendarme.Framework {
 
 	public class RuleInformationManager {
 
-		private static Hashtable rules;
-		private static Hashtable infos;
+		private static Hashtable rules = new Hashtable();
+		private static Hashtable infos = new Hashtable();
 
 		static RuleInformationManager ()
 		{
@@ -46,99 +48,40 @@
 		{
 		}
 
-		static private XmlDocument LoadAssemblyRulesInformations (string filename)
+		static public RuleInformation GetRuleInformation (IRule rule)
 		{
-			XmlDocument doc = null;
-			if (rules == null) {
-				rules = new Hashtable ();
-			} else {
-				doc = (XmlDocument) rules[filename];
-			}
+			if (rule == null)
+				throw new ArgumentNullException("rule");
 
-			if (doc == null) {
-				doc = new XmlDocument ();
-				if (File.Exists (filename)) {
-					doc.Load (filename);
-				}
-				rules[filename] = doc;
-			}
-			return doc;
-		}
+			Type type = rule.GetType();
 
-		static private string GetAttribute (XmlElement xel, string name)
-		{
-			XmlAttribute xa = xel.Attributes[name];
-			if (xa == null)
-				return String.Empty;
-			return xa.Value;
-		}
+			RuleInformation ri = (infos[type.FullName] as RuleInformation);
+			if (ri != null)
+				return ri;
 
-		static private string GetSubElement (XmlElement xel, string name)
-		{
-			if (xel.ChildNodes.Count > 0) {
-				foreach (XmlElement child in xel.ChildNodes) {
-					if (child.Name == name)
-						return child.InnerText;
-				}
+			ResourceManager rm = rule.ResourceManager;
+			if (rm == null) {
+				throw new NullReferenceException (string.Format 
+					("The rule {0} doesn't supply a resource manager.", type.FullName));
 			}
-			return String.Empty;
-		}
 
-		static private RuleInformation LoadRuleInformations (XmlDocument doc, string name)
-		{
-			RuleInformation ri = null;
-			if (doc.DocumentElement != null) {
-				foreach (XmlElement xel in doc.DocumentElement) {
-					if ((xel.Name == "rule") && (GetAttribute (xel, "Type") == name)) {
-						ri = new RuleInformation ();
-						ri.Name = GetAttribute (xel, "Name");
-						ri.Uri = GetAttribute (xel, "Uri");
-						ri.Problem = GetSubElement (xel, "problem");
-						ri.Solution = GetSubElement (xel, "solution");
-						ri.ReadOnly = true;
-					}
-				}
-			}
+			ri = new RuleInformation ();
+			ri.Name = GetResourceString (rm, "Rule.Name");		
+			ri.Problem = GetResourceString (rm, "Rule.Problem");
+			ri.Solution = GetResourceString (rm, "Rule.Solution");
+			ri.Uri = GetResourceString (rm, "Rule.Uri");						
+			infos[type.FullName] = ri;
 
-			return (ri == null) ? RuleInformation.Empty : ri;
-		}
-
-		static public RuleInformation GetRuleInformation (Type type)
-		{
-			if (type == null)
-				throw new ArgumentNullException ("rule");
-
-			object o = null;
-			if (infos == null) {
-				infos = new Hashtable ();
-			} else {
-				o = infos[type.AssemblyQualifiedName];
-			}
-
-			if (o != null)
-				return (o as RuleInformation);
-
-			string fname = Path.ChangeExtension (type.Assembly.Location, ".xml");
-			if (rules == null) {
-				rules = new Hashtable ();
-			}
-
-			XmlDocument doc = (XmlDocument) rules[fname];
-			if (doc == null) {
-				doc = LoadAssemblyRulesInformations (fname);
-			}
-
-			RuleInformation ri = LoadRuleInformations (doc, type.AssemblyQualifiedName);
-			infos[type.AssemblyQualifiedName] = ri;
 			return ri;
 		}
 
-		static public RuleInformation GetRuleInformation (IRule rule)
-		{
-			if (rule == null)
-				throw new ArgumentNullException ("rule");
-
-			return GetRuleInformation (rule.GetType ());
+		private static string GetResourceString (ResourceManager rm, string key) {
+			string value = rm.GetString (key);
+			if (value == null)
+				throw new ArgumentNullException ("value", string.Format (
+						"Missing resource key: {0}", key));
+			return value;
 		}
+
 	}
 }
Index: rules/Gendarme.Rules.Portability/NewLineLiteralRule.cs
===================================================================
--- rules/Gendarme.Rules.Portability/NewLineLiteralRule.cs	(revision 64515)
+++ rules/Gendarme.Rules.Portability/NewLineLiteralRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Resources;
 using System.Collections;
 
 using Mono.Cecil;
@@ -37,6 +38,20 @@
 
 	public class NewLineLiteralRule: IMethodRule {
 
+		#region ResourceManager
+
+		private ResourceManager resourceManager = null;
+
+		public ResourceManager ResourceManager { 
+			get {
+				if (resourceManager == null)
+					resourceManager = new ResourceManager(GetType());
+				return resourceManager;
+			}
+		}
+
+		#endregion
+
 		private static char[] InvalidChar = { '\r', '\n' };
 
 		private ArrayList results;
@@ -54,7 +69,8 @@
 			s = s.Replace ("\n", "\\n");
 			s = s.Replace ("\r", "\\r");
 			// add the "problematic" string for easier validation
-			results.Add (String.Format ("Found string: \"{0}\"", s));
+			results.Add (String.Format (
+				ResourceManager.GetString ("Msg.FoundString"), s));
 		}
 
 		public IList CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method, Runner runner)
Index: rules/Gendarme.Rules.Portability/NewLineLiteralRule.de-DE.resx
===================================================================
--- rules/Gendarme.Rules.Portability/NewLineLiteralRule.de-DE.resx	(revision 0)
+++ rules/Gendarme.Rules.Portability/NewLineLiteralRule.de-DE.resx	(revision 0)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+    <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+        <xsd:element name="root" msdata:IsDataSet="true">
+            <xsd:complexType>
+                <xsd:choice maxOccurs="unbounded">
+                    <xsd:element name="data">
+                        <xsd:complexType>
+                            <xsd:sequence>
+                                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+                            </xsd:sequence>
+                            <xsd:attribute name="name" type="xsd:string" />
+                            <xsd:attribute name="type" type="xsd:string" />
+                            <xsd:attribute name="mimetype" type="xsd:string" />
+                        </xsd:complexType>
+                    </xsd:element>
+                    <xsd:element name="resheader">
+                        <xsd:complexType>
+                            <xsd:sequence>
+                                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                            </xsd:sequence>
+                            <xsd:attribute name="name" type="xsd:string" use="required" />
+                        </xsd:complexType>
+                    </xsd:element>
+                </xsd:choice>
+            </xsd:complexType>
+        </xsd:element>
+    </xsd:schema>
+    <resheader name="ResMimeType">
+        <value>text/microsoft-resx</value>
+    </resheader>
+    <resheader name="Version">
+        <value>1.0.0.0</value>
+    </resheader>
+    <resheader name="Reader">
+        <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    </resheader>
+    <resheader name="Writer">
+        <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    </resheader>
+    <data name="Rule.Name">
+        <value>NewLineLiteral</value>
+    </data>
+    <data name="Rule.Uri">
+        <value>http://www.mono-project.com/Gendarme</value>
+    </data>
+    <data name="Rule.Problem">
+        <value>Die Methode '{0}' benutzt nicht portierbare Zeichenumbr??che (Beispiel '\r\n').</value>
+    </data>
+    <data name="Rule.Solution">
+        <value>Zeilenumbr??che (Beispiel '\r\n') sollten durch 'Environment.NewLine' ersetzt werden.</value>
+    </data>
+    <data name="Msg.FoundString">
+        <value>String: {0}</value>
+    </data>
+</root>
\ No newline at end of file
Index: rules/Gendarme.Rules.Portability/NewLineLiteralRule.resx
===================================================================
--- rules/Gendarme.Rules.Portability/NewLineLiteralRule.resx	(revision 0)
+++ rules/Gendarme.Rules.Portability/NewLineLiteralRule.resx	(revision 0)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+    <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+        <xsd:element name="root" msdata:IsDataSet="true">
+            <xsd:complexType>
+                <xsd:choice maxOccurs="unbounded">
+                    <xsd:element name="data">
+                        <xsd:complexType>
+                            <xsd:sequence>
+                                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+                            </xsd:sequence>
+                            <xsd:attribute name="name" type="xsd:string" />
+                            <xsd:attribute name="type" type="xsd:string" />
+                            <xsd:attribute name="mimetype" type="xsd:string" />
+                        </xsd:complexType>
+                    </xsd:element>
+                    <xsd:element name="resheader">
+                        <xsd:complexType>
+                            <xsd:sequence>
+                                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                            </xsd:sequence>
+                            <xsd:attribute name="name" type="xsd:string" use="required" />
+                        </xsd:complexType>
+                    </xsd:element>
+                </xsd:choice>
+            </xsd:complexType>
+        </xsd:element>
+    </xsd:schema>
+    <resheader name="ResMimeType">
+        <value>text/microsoft-resx</value>
+    </resheader>
+    <resheader name="Version">
+        <value>1.0.0.0</value>
+    </resheader>
+    <resheader name="Reader">
+        <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    </resheader>
+    <resheader name="Writer">
+        <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    </resheader>
+    <data name="Rule.Name">
+        <value>NewLineLiteral</value>
+    </data>
+    <data name="Rule.Uri">
+        <value>http://www.mono-project.com/Gendarme</value>
+    </data>
+    <data name="Rule.Problem">
+        <value>The method '{0}' use some literal values for new lines (e.g. \r\n) which aren't portable across operating systems.</value>
+    </data>
+    <data name="Rule.Solution">
+        <value>Replace literals with Environment.NewLine.</value>
+    </data>
+    <data name="Msg.FoundString">
+        <value>Found string: {0}</value>
+    </data>
+</root>
\ No newline at end of file


More information about the Mono-devel-list mailing list