| File: System\ComponentModel\Design\Serialization\CodeDomLocalizationProvider.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; using System.Resources; namespace System.ComponentModel.Design.Serialization; /// <summary> /// This is a serialization provider that provides a localization feature. This provider /// adds two properties to the root component: Language and Localizable. If Localizable /// is set to true this provider will change the way that component properties are generated /// and will route their values to a resource file. Two localization models are /// supported. /// </summary> public sealed partial class CodeDomLocalizationProvider : IDisposable, IDesignerSerializationProvider { private IExtenderProviderService _providerService; private readonly CodeDomLocalizationModel _model; private LanguageExtenders _extender; private Dictionary<MemberCodeDomSerializer, ResourcePropertyMemberCodeDomSerializer>? _memberSerializers; private Dictionary<MemberCodeDomSerializer, ResourcePropertyMemberCodeDomSerializer>? _nopMemberSerializers; /// <summary> /// Creates a new adapter and attaches it to the serialization manager. This /// will add itself as a serializer for resources into the serialization manager, and, /// if not already added, will add itself as an extender provider to the roost component /// and provide the Language and Localizable properties. The latter piece is only /// supplied if CodeDomLocalizationModel is not �none�. /// </summary> public CodeDomLocalizationProvider(IServiceProvider provider, CodeDomLocalizationModel model) { ArgumentNullException.ThrowIfNull(provider); _model = model; Initialize(provider, null); } /// <summary> /// Creates a new adapter and attaches it to the serialization manager. This /// will add itself as a serializer for resources into the serialization manager, and, /// if not already added, will add itself as an extender provider to the roost component /// and provide the Language and Localizable properties. The latter piece is only /// supplied if CodeDomLocalizationModel is not �none�. /// </summary> public CodeDomLocalizationProvider(IServiceProvider provider, CodeDomLocalizationModel model, CultureInfo?[] supportedCultures) { ArgumentNullException.ThrowIfNull(provider); ArgumentNullException.ThrowIfNull(supportedCultures); _model = model; Initialize(provider, (CultureInfo[])supportedCultures.Clone()); } /// <summary> /// Disposes this object. /// </summary> public void Dispose() { if (_providerService is not null && _extender is not null) { _providerService.RemoveExtenderProvider(_extender); _providerService = null!; _extender = null!; } } /// <summary> /// Adds our extended properties. /// </summary> [MemberNotNull(nameof(_extender))] [MemberNotNull(nameof(_providerService))] private void Initialize(IServiceProvider provider, CultureInfo?[]? supportedCultures) { _providerService = provider.GetService<IExtenderProviderService>() ?? throw new NotSupportedException(string.Format(SR.LocalizationProviderMissingService, nameof(IExtenderProviderService))); _extender = new LanguageExtenders(provider, supportedCultures); _providerService.AddExtenderProvider(_extender); } #region IDesignerSerializationProvider Members /// <summary> /// Returns a code dom serializer /// </summary> private static LocalizationCodeDomSerializer? GetCodeDomSerializer(IDesignerSerializationManager manager, object? currentSerializer, Type? objectType) { if (currentSerializer is null) { return null; } // Always do default processing for the resource manager. if (typeof(ResourceManager).IsAssignableFrom(objectType)) { return null; } // Here's how this works. We have two different types of serializers to offer : a // serializer that writes out code like this: // // this.Button1.Text = rm.GetString("Button1_Text"); // // And one that writes out like this: // // rm.ApplyResources(Button1, "Button1"); // // The first serializer is used for serializable objects that have no serializer of their // own, and for localizable properties when the CodeDomLocalizationModel is set to PropertyAssignment. // The second serializer is used only for localizing properties when the CodeDomLocalizationModel // is set to PropertyReflection // Compute a localization model based on the property, localization mode, // and what (if any) serializer already exists if (!manager.TryGetContext(out CodeDomLocalizationModel model)) { model = CodeDomLocalizationModel.None; } // Nifty, but this causes everything to be loc'd because our provider // comes in before the default one // if (model == CodeDomLocalizationModel.None && currentSerializer is null) { // model = CodeDomLocalizationModel.PropertyAssignment; // } if (model != CodeDomLocalizationModel.None) { return new LocalizationCodeDomSerializer(model, currentSerializer); } return null; } /// <summary> /// Returns a code dom serializer for members. /// </summary> private ResourcePropertyMemberCodeDomSerializer? GetMemberCodeDomSerializer( IDesignerSerializationManager manager, MemberCodeDomSerializer? currentSerializer, Type? objectType) { CodeDomLocalizationModel model = _model; if (!typeof(PropertyDescriptor).IsAssignableFrom(objectType)) { return null; } // Ok, we got a property descriptor. If we're being localized // we provide a different type of serializer. But, we only // do this if we were given a current serializer. Otherwise // we don't know how to perform the serialization. // We can only provide a custom serializer if we have an existing one // to base off of. if (currentSerializer is null) { return null; } // If we've already provided this serializer, don't do it again if (currentSerializer is ResourcePropertyMemberCodeDomSerializer) { return null; } // We only care if we're localizable if (_extender is null || !_extender.GetLocalizable(null)) { return null; } // Fish the property out of the context to see if the property is localizable. if (!manager.TryGetContext(out PropertyDescriptor? serializingProperty) || !serializingProperty.IsLocalizable) { model = CodeDomLocalizationModel.None; } Dictionary<MemberCodeDomSerializer, ResourcePropertyMemberCodeDomSerializer> map = model is CodeDomLocalizationModel.None ? _nopMemberSerializers ??= [] : _memberSerializers ??= []; if (!map.TryGetValue(currentSerializer, out ResourcePropertyMemberCodeDomSerializer? newSerializer)) { newSerializer = new ResourcePropertyMemberCodeDomSerializer(currentSerializer, model); map[currentSerializer] = newSerializer; } return newSerializer; } /// <summary> /// Returns an appropriate serializer for the object. /// </summary> object? IDesignerSerializationProvider.GetSerializer(IDesignerSerializationManager manager, object? currentSerializer, Type? objectType, Type serializerType) { if (serializerType == typeof(CodeDomSerializer)) { return GetCodeDomSerializer(manager, currentSerializer, objectType); } else if (serializerType == typeof(MemberCodeDomSerializer)) { return GetMemberCodeDomSerializer(manager, (MemberCodeDomSerializer?)currentSerializer, objectType); } return null; // don't understand this type of serializer. } #endregion }