3

Is there a way to automate the set of this property ? we have hundreds of forms that needs to be localized and it will be a nightmare going through all of them setting this property to true.

is there a way to make visual studio set all forms in the solution / project to Localizable = true some how ?

Pacman
  • 2,183
  • 6
  • 39
  • 70

3 Answers3

5

When you create a new Windows Form, it does not have have *.resx file and the related code in the designer.cs file. When you set the Form's Localizable property to True, VS adds the following code to the designer.cs but it also then generates and adds the *.resx file.

        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form2));
        this.SuspendLayout();
        // 
        // Form2
        // 
        resources.ApplyResources(this, "$this");
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.Name = "Form2";
        this.ResumeLayout(false);

Since VS adds the *.resx file, there is no way to find and replace or cut and paste only code.

I tried to record a VS Macro to automate it however, it would not record changing the Localizable property to True (not sure why)

This temp macro maybe a start for you. You could write get the list of your form filenames and loop through them with the macro code below.

    DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
    DTE.ActiveWindow.Object.GetItem("WindowsFormsApplication1\WindowsFormsApplication1\Form3.cs").Select(vsUISelectionType.vsUISelectionTypeSelect)
    DTE.ActiveWindow.Object.DoDefaultAction()
    DTE.Windows.Item(Constants.vsWindowKindProperties).Activate()
Scott Wylie
  • 4,725
  • 2
  • 36
  • 48
2

It's represented by an entry like the following (adjusted for .NET Framework version) in the form's .resx file:

<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
</metadata>

The easiest way to automate toggling all the values to true would probably be to run through the Form subclass files, loading their .resx files as XML to test for the presence of the element, and add it if it isn't. Alternately, you could use a ResXResourceReader and ResXResourceWriter to read and write the file contents.

Nicole Calinoiu
  • 20,843
  • 2
  • 44
  • 49
  • What doesn't it do that you expected? If you open the form in the designer after adding the metadata element to the .resx file, do you see a true or false value for the Localizable property in the form's properties sheet? – Nicole Calinoiu Jan 26 '12 at 17:48
  • Which version of Visual Studio are you using? Which .NET Framework version are you targeting for runtime? – Nicole Calinoiu Jan 26 '12 at 18:16
  • Well, it works just fine for me under that pairing, so I'm not quite sure what else to suggest... Do the contents of the .resx file after your edit exactly match what the designer would have generated had you modified the property via the designer UI? – Nicole Calinoiu Jan 30 '12 at 19:55
  • After adding the code to the .resx file, Visual Studio shows Localizable=true when re-opening the form, but unfortunately it does not add the code for retrieving strings from the resources file. – Matthias Wuttke Jul 16 '13 at 15:16
  • @NicoleCalinoiu, this is spot on. The question is how to set the flag, this does it. Localization involves more work than just setting the flag, of course. ResX files must be included in the project before these changes take effect. – reckface Jan 19 '18 at 13:49
0

The custom Designer Attribute we set on the DummyUserControl is only used by more derived classes. Suppose you open the DummyUserControl in the designer. In that case, nothing changes cause it looks for the Designer attribute on the BaseType in this case on the UserControl and ignores the one we specified. It applies to Forms as well. So you need a dummy base class where you just set the Designer Attribute.

public class BaseUserControl : DummyUserControl
{

}

[Designer(typeof(MyCustomDesigner), typeof(IRootDesigner))]
public class DummyUserControl : UserControl
{
    
}

public class MyCustomDesigner : DocumentDesigner
{
    /// <inheritdoc />
    public override void Initialize(IComponent component)
    {
        base.Initialize(component);
    }

    protected override void PreFilterProperties(IDictionary properties)
    {
        base.PreFilterProperties(properties);

        // We set the Localizable property to true then we return a fake property descriptor to disable changing it in the designer.
        var localizableDescriptor = properties["Localizable"] as PropertyDescriptor;
        if (localizableDescriptor != null)
        {
            if (localizableDescriptor.GetValue(Component) as bool? == false)
            {
                localizableDescriptor.SetValue(Component, true);
            }
            properties["Localizable"] = new LocalizablePropertyDescriptor(localizableDescriptor);
        }
    }

    /// <summary>
    /// A simple wrapper where we disallow to change this property in the designer by marking it ReadOnly.
    /// </summary>
    public class LocalizablePropertyDescriptor : PropertyDescriptor
    {
        private readonly PropertyDescriptor _source;

        /// <inheritdoc />
        public LocalizablePropertyDescriptor(PropertyDescriptor source) : base(source) => _source = source;

        /// <inheritdoc />
        public override bool CanResetValue(object component) => _source.CanResetValue(component);

        /// <inheritdoc />
        public override object GetValue(object component) => _source.GetValue(component);

        /// <inheritdoc />
        public override void ResetValue(object component) { }

        /// <inheritdoc />
        public override void SetValue(object component, object value) => _source.SetValue(component, value);

        /// <inheritdoc />
        public override bool ShouldSerializeValue(object component) => true;

        /// <inheritdoc />
        public override Type ComponentType => _source.ComponentType;

        /// <inheritdoc />
        public override bool IsReadOnly => true;

        /// <inheritdoc />
        public override Type PropertyType => _source.PropertyType;
    }
}