If you are building a reusable web part that you would like to sell or give away you should look into localizing your web part. The localization support is great with .NET 2.0, using resource files, and there are tons of built-in functionality for this. If you are creating an Editor Part for you web part, then your life is pretty easy, just use the standard techniques. But if you are using the approach by tagging the properties of your web part with the Personalizable attributes, then you are out of luck. Take a look at this property for example:

  1: [WebBrowsable]
  2: [Category("Look and feel")]
  3: [WebDisplayName("Use custom palette")]
  4: [WebDescription("Check this to use a custom palette")]
  5: [Personalizable(PersonalizationScope.Shared)]
  6: public bool UseCustomPalette {
  7:     get;
  8:     set;
  9: }

All these attribute values are hardcoded into you assembly, and you have to build different assemblies for different languages.

Fortunately the .NET framework is extensible so you can extend these attributes (Category, WebDisplayName and WebDescription) so they take advantage of the localization features.

All we have to do is to implement three classes: LocalizedCategoryAttribute, LocalizedWebDisplayNameAttribute and LocalizedWebDescriptionAttribute.

They basically look the same and here is the code for LocalizedWebDisplayNameAttribute:

  1: [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  2: public sealed class LocalizedWebDisplayNameAttribute
  3:     : WebDisplayNameAttribute {
  5:     bool m_isLocalized ;
  7:     public LocalizedWebDisplayNameAttribute(string displayName)
  8:         : base(displayName) {
  9:     }
 11:     public override string DisplayName {
 12:         get {
 13:             if (!m_isLocalized) {
 14:                 this.DisplayNameValue = 
 15:                     Resources.ResourceManager.GetString(
 16:                         base.DisplayName, Resources.Culture);
 17:                 m_isLocalized = true;
 18:             }
 19:             return base.DisplayName;
 20:         }
 21:     }
 22: }

What we do here is to override the DisplayName property and instead of just returning the value, we use the ResourceManager object and retrieve the value from our localized resources.

After this we can change our original property code to something like this:

  1: [WebBrowsable]
  2: [LocalizedCategory("LookAndFeel")]
  3: [LocalizedWebDisplayName("UseCustomPalette")]
  4: [LocalizedWebDescription("UseCustomPaletteDesc")]
  5: [Personalizable(PersonalizationScope.Shared)]
  6: public bool UseCustomPalette {
  7:     get;
  8:     set;
  9: }

To get this to work just add the three attribute values (LookAndFeel, UseCustomPalette, UseCustomPaletteDesc in the sample) to our resource file and you are set and done.