private static Dictionary<object, LocalizabilityAttribute> DefinedAttributes; // stores pre-defined attribute for types #endregion Fields #region Constructors static DefaultAttributes() { // predefined localizability attributes DefinedAttributes = new Dictionary<object, LocalizabilityAttribute>(32); // nonlocalizable attribute LocalizabilityAttribute notReadable = new LocalizabilityAttribute(LocalizationCategory.None); notReadable.Readability = Readability.Unreadable; LocalizabilityAttribute notModifiable = new LocalizabilityAttribute(LocalizationCategory.None); notModifiable.Modifiability = Modifiability.Unmodifiable; // not localizable CLR types DefinedAttributes.Add(typeof(Boolean), notReadable); DefinedAttributes.Add(typeof(Byte), notReadable); DefinedAttributes.Add(typeof(SByte), notReadable); DefinedAttributes.Add(typeof(Char), notReadable); DefinedAttributes.Add(typeof(Decimal), notReadable); DefinedAttributes.Add(typeof(Double), notReadable); DefinedAttributes.Add(typeof(Single), notReadable); DefinedAttributes.Add(typeof(Int32), notReadable); DefinedAttributes.Add(typeof(UInt32), notReadable); DefinedAttributes.Add(typeof(Int64), notReadable); DefinedAttributes.Add(typeof(UInt64), notReadable); DefinedAttributes.Add(typeof(Int16), notReadable); DefinedAttributes.Add(typeof(UInt16), notReadable); DefinedAttributes.Add(typeof(Uri), notModifiable); }
/// <summary> /// It combines the min values of two localizability attributes. /// </summary> /// <param name="first">first </param> /// <param name="second">second</param> /// <returns>LocalizabilityAttribute</returns> private LocalizabilityAttribute CombineMinimumLocalizability( LocalizabilityAttribute first, LocalizabilityAttribute second ) { if (first == null || second == null) { return (first == null) ? second : first; } // min of two readability enum. The less the more restrictive. Readability readability = (Readability) Math.Min( (int) first.Readability, (int) second.Readability ); // min of two Modifiability enum. The less the more restrictive. Modifiability modifiability = (Modifiability) Math.Min( (int) first.Modifiability, (int) second.Modifiability ); // for category, NeverLocalize < Ignore < { all others } < None // If both categories belong to { all others }, first.Category wins LocalizationCategory category = LocalizationCategory.None; if ( first.Category == LocalizationCategory.NeverLocalize || second.Category == LocalizationCategory.NeverLocalize) { category = LocalizationCategory.NeverLocalize; } else if ( first.Category == LocalizationCategory.Ignore || second.Category == LocalizationCategory.Ignore) { category = LocalizationCategory.Ignore; } else { category = ( first.Category != LocalizationCategory.None) ? first.Category : second.Category; } LocalizabilityAttribute result = new LocalizabilityAttribute(category); result.Readability = readability; result.Modifiability = modifiability; return result; }
/// <summary> /// Create the inherited localizability attribute /// </summary> /// <param name="source">localizability attribute defined in source</param> /// <param name="inheritable">localizability attribute inheritable from above</param> /// <returns>LocalizabilityAttribute</returns> private LocalizabilityAttribute CreateInheritedLocalizability( LocalizabilityAttribute source, LocalizabilityAttribute inheritable ) { LocalizationCategory category = (source.Category == LocalizationCategory.Inherit) ? inheritable.Category : source.Category; Readability readability = (source.Readability == Readability.Inherit) ? inheritable.Readability : source.Readability; Modifiability modifiability = (source.Modifiability == Modifiability.Inherit) ? inheritable.Modifiability : source.Modifiability; LocalizabilityAttribute attribute = new LocalizabilityAttribute(category); attribute.Readability = readability; attribute.Modifiability = modifiability; return attribute; }
/// <summary> /// Combine inheritable attributes, and propegate it down the tree. /// </summary> /// <param name="node">current node</param> /// <param name="localizabilityFromSource">localizability defined in source code</param> /// <returns> /// The LocalizabilityAttribute to used for this node. It is not the same as the /// inheritable attributes of the node when the node is set to Ignore. /// </returns> /// <remarks>We always walk the baml tree in depth-first order</remarks> private LocalizabilityAttribute CombineAndPropagateInheritanceValues( ILocalizabilityInheritable node, LocalizabilityAttribute localizabilityFromSource ) { if (node == null ) { return localizabilityFromSource; } // If this node's inheritable localizability has been constructed, we can skip it // This can happen when recursively format the content if (node.InheritableAttribute != null) { return (!node.IsIgnored) ? node.InheritableAttribute : LocalizabilityIgnore; } // To test wether the current node needs to inherit values from parents. // It inherits values if: // o This node is set to Ignore, in which case it propagates parent values. // o Some of its attributes set to Inherit. if ( localizabilityFromSource.Category != LocalizationCategory.Ignore && localizabilityFromSource.Category != LocalizationCategory.Inherit && localizabilityFromSource.Readability != Readability.Inherit && localizabilityFromSource.Modifiability != Modifiability.Inherit) { // just return the same one because no value is inherited node.InheritableAttribute = localizabilityFromSource; return node.InheritableAttribute; } // find the ancestor to inherit values now. ILocalizabilityInheritable ancestor = node.LocalizabilityAncestor; // find out the attribute that is inheritable from above LocalizabilityAttribute inheritableAttribute = ancestor.InheritableAttribute; if (inheritableAttribute == null) { // if ancestor's inheritable value isn't resolved yet, we recursively // resolve it here. BamlStartElementNode elementNode = ancestor as BamlStartElementNode; if (elementNode != null) { string formattingTag; GetLocalizabilityForElementNode(elementNode, out inheritableAttribute, out formattingTag); } else { BamlStartComplexPropertyNode propertyNode = ancestor as BamlStartComplexPropertyNode; GetLocalizabilityForPropertyNode(propertyNode, out inheritableAttribute); } CombineAndPropagateInheritanceValues(ancestor, inheritableAttribute); inheritableAttribute = ancestor.InheritableAttribute; Debug.Assert(inheritableAttribute != null); } // if this item is set to ignore if ( localizabilityFromSource.Category == LocalizationCategory.Ignore) { // It propagates ancestor's inheritable localizability, but it will use // its own value declared in source. // We also mark this node as being "Ignored" in the inheritance tree to signal that // this node is not using the inheritance value. node.InheritableAttribute = inheritableAttribute; node.IsIgnored = true; return LocalizabilityIgnore; } // the item is not set to ignore, so we process the inheritable values BamlTreeNode treeNode = (BamlTreeNode) node; switch (treeNode.NodeType) { case BamlNodeType.StartElement : case BamlNodeType.LiteralContent : { // if everything set to inherit, we just return the inheritable localizability if (localizabilityFromSource.Category == LocalizationCategory.Inherit && localizabilityFromSource.Readability == Readability.Inherit && localizabilityFromSource.Modifiability == Modifiability.Inherit) { // just propagate the ancestor's localizability. node.InheritableAttribute = inheritableAttribute; } else { // set new inherited values node.InheritableAttribute = CreateInheritedLocalizability( localizabilityFromSource, inheritableAttribute ); } break; } case BamlNodeType.Property : case BamlNodeType.StartComplexProperty : { ILocalizabilityInheritable parent = (ILocalizabilityInheritable) treeNode.Parent; // Find the mininum localizability of the containing class and // parent property. Parent property means the proeprty from parent node that // has the same name. LocalizabilityAttribute inheritedAttribute = CombineMinimumLocalizability( inheritableAttribute, parent.InheritableAttribute ); node.InheritableAttribute = CreateInheritedLocalizability( localizabilityFromSource, inheritedAttribute ); if (parent.IsIgnored && localizabilityFromSource.Category == LocalizationCategory.Inherit) { // If the parent node is Ignore and this property is set to inherit, then // this property node is to be ignore as well. We set the the "Ignore" flag so that // the node will always be ignored without looking at the source localizability again. node.IsIgnored = true; return LocalizabilityIgnore; } break; } default: { Debug.Assert(false, "Can't process localizability attribute on nodes other than Element, Property and LiteralContent."); break; } } return node.InheritableAttribute; }
private void GetLocalizabilityForPropertyNode( BamlStartComplexPropertyNode node, out LocalizabilityAttribute localizability ) { localizability = null; string assemblyName = node.AssemblyName; string className = node.OwnerTypeFullName; string propertyLocalName = node.PropertyName; if (className == null || className.Length == 0) { // class name can be empty or null. For example, <Set PropertyPath="..."> // We will use the parent node's value. string formattingTag; GetLocalizabilityForElementNode((BamlStartElementNode)node.Parent, out localizability, out formattingTag); return; } LocalizabilityGroup comment = _resolver.GetLocalizabilityComment( (BamlStartElementNode) node.Parent, node.PropertyName ); localizability = _resolver.GetPropertyLocalizability( assemblyName, className, propertyLocalName ); if (comment != null) { localizability = comment.Override(localizability); } }
private void GetLocalizabilityForElementNode( BamlStartElementNode node, out LocalizabilityAttribute localizability, out string formattingTag ) { localizability = null; formattingTag = null; // get the names we need string assemblyName = node.AssemblyName; string className = node.TypeFullName; // query the resolver ElementLocalizability result = _resolver.GetElementLocalizability( assemblyName, className ); LocalizabilityGroup comment = null; comment = _resolver.GetLocalizabilityComment(node, BamlConst.ContentSuffix); if (comment != null) { localizability = comment.Override(result.Attribute); } else { localizability = result.Attribute; } formattingTag = result.FormattingTag; }
// Helper to override a localizability attribute. Not needed for compiler internal LocalizabilityAttribute Override(LocalizabilityAttribute attribute) { Modifiability modifiability = attribute.Modifiability; Readability readability = attribute.Readability; LocalizationCategory category = attribute.Category; bool overridden = false; if (((int) Modifiability)!= InvalidValue) { modifiability = Modifiability; overridden = true; } if (((int) Readability) != InvalidValue) { readability = Readability; overridden = true; } if (((int) Category) != InvalidValue) { category = Category; overridden = true; } if (overridden) { attribute = new LocalizabilityAttribute(category); attribute.Modifiability = modifiability; attribute.Readability = readability; } return attribute; }
/// <summary> /// Get the localizability of a CLR property /// </summary> private void GetLocalizabilityForClrProperty( string propertyName, Type owner, out LocalizabilityAttribute localizability, out Type propertyType ) { localizability = null; propertyType = null; PropertyInfo info = owner.GetProperty(propertyName); if (info == null) { return; // couldn't find the Clr property } // we found the CLR property, set the type of the property propertyType = info.PropertyType; object[] locAttributes = info.GetCustomAttributes( TypeOfLocalizabilityAttribute, // type of the attribute true // search in base class ); if (locAttributes.Length == 0) { return; } else { Debug.Assert(locAttributes.Length == 1, "Should have only 1 localizability attribute"); // we found the attribute defined on the property localizability = (LocalizabilityAttribute) locAttributes[0]; } }
/// <summary> /// Get localizability for attached property /// </summary> /// <param name="propertyName">property name</param> /// <param name="owner">owner type</param> /// <param name="localizability">out: localizability attribute</param> /// <param name="propertyType">out: type of the property</param> private void GetLocalizabilityForAttachedProperty( string propertyName, Type owner, out LocalizabilityAttribute localizability, out Type propertyType ) { localizability = null; propertyType = null; // if it is an attached property, it should have a dependency property with the name // <attached proeprty's name> + "Property" DependencyProperty attachedDp = DependencyPropertyFromName( propertyName, // property name owner ); // owner type if (attachedDp == null) return; // couldn't find the dp. // we found the Dp, set the type of the property propertyType = attachedDp.PropertyType; FieldInfo fieldInfo = attachedDp.OwnerType.GetField( attachedDp.Name + "Property", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Debug.Assert(fieldInfo != null); object[] attributes = fieldInfo.GetCustomAttributes( TypeOfLocalizabilityAttribute, // type of localizability true ); // inherit if (attributes.Length == 0) { // didn't find it. return; } else { Debug.Assert(attributes.Length == 1, "Should have only 1 localizability attribute"); localizability = (LocalizabilityAttribute) attributes[0]; } }
/// <summary> /// Get the localizability attribute for a type /// </summary> internal static LocalizabilityAttribute GetDefaultAttribute(object type) { if (DefinedAttributes.ContainsKey(type)) { LocalizabilityAttribute predefinedAttribute = DefinedAttributes[type]; // create a copy of the predefined attribute and return the copy LocalizabilityAttribute result = new LocalizabilityAttribute(predefinedAttribute.Category); result.Readability = predefinedAttribute.Readability; result.Modifiability = predefinedAttribute.Modifiability; return result; } else { Type targetType = type as Type; if ( targetType != null && targetType.IsValueType) { // It is looking for the default value of a value type (i.e. struct and enum) // we use this default. LocalizabilityAttribute attribute = new LocalizabilityAttribute(LocalizationCategory.Inherit); attribute.Modifiability = Modifiability.Unmodifiable; return attribute; } else { return DefaultAttribute; } } }