Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / Globalization / BamlTreeMap.cs / 2 / BamlTreeMap.cs
//--------------------------------------------------------
// Class that implements BamlTreeMap.
//
// Created: Garyyang @ 12/1/2003
//
//-------------------------------------------------------
using System;
using System.IO;
using System.Xml;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Markup;
using System.Windows.Markup.Localizer;
using System.Diagnostics;
using System.Text;
using System.Windows;
using MS.Utility;
// Disabling 1634 and 1691:
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler,
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
namespace MS.Internal.Globalization
{
///
/// creates mappings for the baml tree node
/// this class in charges of creating mappings to the
/// loclaizable resources and tree nodes.
///
internal class BamlTreeMap
{
//----------------------------------
// internal Constructor
//----------------------------------
///
/// BamlTreeMap.
///
internal BamlTreeMap(
BamlLocalizer localizer,
BamlTree tree,
BamlLocalizabilityResolver resolver,
TextReader comments
)
{
Debug.Assert(tree!= null, "Baml Tree is empty");
Debug.Assert(localizer!= null, "BamlLocalizer is null");
_tree = tree;
// creates an internal resolver which willd delegate calls to client's resolver intelligently.
_resolver = new InternalBamlLocalizabilityResolver(localizer, resolver, comments);
// create a LocalizableResourceBuilder to build localizable resources
_localizableResourceBuilder = new LocalizableResourceBuilder(_resolver);
}
//----------------------------------
// internal properties
//----------------------------------
internal BamlLocalizationDictionary LocalizationDictionary
{
get
{
EnsureMap();
return _localizableResources;
}
}
internal InternalBamlLocalizabilityResolver Resolver
{
get
{
return _resolver;
}
}
///
/// Maps a key to a baml tree node in the given tree
///
internal BamlTreeNode MapKeyToBamlTreeNode(BamlLocalizableResourceKey key, BamlTree tree)
{
if (_keyToBamlNodeIndexMap.Contains(key))
{
return tree[(int)_keyToBamlNodeIndexMap[key]];
}
return null;
}
///
/// Maps a uid to a baml tree node in the given tree
///
internal BamlStartElementNode MapUidToBamlTreeElementNode(string uid, BamlTree tree)
{
if (_uidToBamlNodeIndexMap.Contains(uid))
{
return tree[(int)_uidToBamlNodeIndexMap[uid]] as BamlStartElementNode;
}
return null;
}
//--------------------------------------
// Private methods
//--------------------------------------
// construct the maps for enumeration
internal void EnsureMap()
{
if (_localizableResources != null)
return; // map is already created.
// create the table based on the treesize passed in
// the hashtable is for look-up during update
_resolver.InitLocalizabilityCache();
_keyToBamlNodeIndexMap = new Hashtable(_tree.Size);
_uidToBamlNodeIndexMap = new Hashtable(_tree.Size / 2);
_localizableResources = new BamlLocalizationDictionary();
for (int i = 0; i < _tree.Size; i++)
{
BamlTreeNode currentNode = _tree[i];
// a node may be marked as unidentifiable if it or its parent has a duplicate uid.
if (currentNode.Unidentifiable) continue; // skip unidentifiable nodes
if (currentNode.NodeType == BamlNodeType.StartElement)
{
// remember classes encountered in this baml
BamlStartElementNode elementNode = (BamlStartElementNode) currentNode;
_resolver.AddClassAndAssembly(elementNode.TypeFullName, elementNode.AssemblyName);
}
// find the Uid of the current node
BamlLocalizableResourceKey key = GetKey(currentNode);
if (key != null)
{
if (currentNode.NodeType == BamlNodeType.StartElement)
{
// store uid mapping to the corresponding element node
if (_uidToBamlNodeIndexMap.ContainsKey(key.Uid))
{
_resolver.RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
key,
BamlLocalizerError.DuplicateUid
)
);
// Mark this element and its properties unidentifiable.
currentNode.Unidentifiable = true;
if (currentNode.Children != null)
{
foreach (BamlTreeNode child in currentNode.Children)
{
if (child.NodeType != BamlNodeType.StartElement)
child.Unidentifiable = true;
}
}
continue; // skip the duplicate node
}
else
{
_uidToBamlNodeIndexMap.Add(key.Uid, i);
}
}
_keyToBamlNodeIndexMap.Add(key, i);
if (_localizableResources.RootElementKey == null
&& currentNode.NodeType == BamlNodeType.StartElement
&& currentNode.Parent != null
&& currentNode.Parent.NodeType == BamlNodeType.StartDocument)
{
// remember the key to the root element so that
// users can further add modifications to the root that would have a global impact.
// such as FlowDirection or CultureInfo
_localizableResources.SetRootElementKey(key);
}
// create the resource and add to the dictionary
BamlLocalizableResource resource = _localizableResourceBuilder.BuildFromNode(key, currentNode);
if (resource != null)
{
_localizableResources.Add(key, resource);
}
}
}
_resolver.ReleaseLocalizabilityCache();
}
//-------------------------------------------------
// Internal static
//-------------------------------------------------
///
/// Return the localizable resource key for this baml tree node.
/// If this node shouldn't be localized, the key returned will be null.
///
internal static BamlLocalizableResourceKey GetKey(BamlTreeNode node)
{
BamlLocalizableResourceKey key = null;
switch (node.NodeType)
{
case BamlNodeType.StartElement:
{
BamlStartElementNode elementNode = (BamlStartElementNode) node;
if (elementNode.Uid != null)
{
key = new BamlLocalizableResourceKey(
elementNode.Uid,
elementNode.TypeFullName,
BamlConst.ContentSuffix,
elementNode.AssemblyName
);
}
break;
}
case BamlNodeType.Property:
{
BamlPropertyNode propertyNode = (BamlPropertyNode) node;
BamlStartElementNode parent = (BamlStartElementNode) propertyNode.Parent;
if (parent.Uid != null)
{
string uid;
if (propertyNode.Index <= 0)
{
uid = parent.Uid;
}
else
{
// This node is auto-numbered. This has to do with the fact that
// the compiler may compile duplicated properties into Baml under the same element.
uid = string.Format(
System.Windows.Markup.TypeConverterHelper.EnglishUSCulture,
"{0}.{1}_{2}",
parent.Uid,
propertyNode.PropertyName,
propertyNode.Index
);
}
key = new BamlLocalizableResourceKey(
uid,
propertyNode.OwnerTypeFullName,
propertyNode.PropertyName,
propertyNode.AssemblyName
);
}
break;
}
case BamlNodeType.LiteralContent:
{
BamlLiteralContentNode literalNode = (BamlLiteralContentNode) node;
BamlStartElementNode parent = (BamlStartElementNode) node.Parent;
if (parent.Uid != null)
{
key = new BamlLocalizableResourceKey(
parent.Uid,
parent.TypeFullName,
BamlConst.LiteralContentSuffix,
parent.AssemblyName
);
}
break;
}
}
return key;
}
//---------------------------------
// private members
//---------------------------------
private Hashtable _keyToBamlNodeIndexMap; // _key to baml node. Key is integer. Not using Generic on value type for perf reason
private Hashtable _uidToBamlNodeIndexMap;
private LocalizableResourceBuilder _localizableResourceBuilder;
private BamlLocalizationDictionary _localizableResources;
private BamlTree _tree;
private InternalBamlLocalizabilityResolver _resolver;
}
internal class InternalBamlLocalizabilityResolver : BamlLocalizabilityResolver
{
BamlLocalizabilityResolver _externalResolver;
// a list of assemblies encounter in the baml
FrugalObjectList _assemblyNames;
// class name mapped to assembly index in the Frugal list
Hashtable _classNameToAssemblyIndex;
// cached localizablity values
private Dictionary _classAttributeTable;
private Dictionary _propertyAttributeTable;
//
// cached localization comments
// Normally, we only need to use comments of a single element at one time.
// In case of formatting inline tags we might be grabing comments of a few more elements.
// A small cached would be enough
//
private ElementComments[] _comments;
private int _commentsIndex;
// Localization comment document
private XmlDocument _commentsDocument;
private BamlLocalizer _localizer;
private TextReader _commentingText;
internal InternalBamlLocalizabilityResolver(
BamlLocalizer localizer,
BamlLocalizabilityResolver externalResolver,
TextReader comments
)
{
_localizer = localizer;
_externalResolver = externalResolver;
_commentingText = comments;
}
internal void AddClassAndAssembly(string className, string assemblyName)
{
if (assemblyName == null || _classNameToAssemblyIndex.Contains(className))
return;
int index = _assemblyNames.IndexOf(assemblyName);
if (index < 0)
{
// add the new assembly
_assemblyNames.Add(assemblyName);
index = _assemblyNames.Count - 1;
}
_classNameToAssemblyIndex.Add(className, index);
}
internal void InitLocalizabilityCache()
{
_assemblyNames = new FrugalObjectList();
_classNameToAssemblyIndex = new Hashtable(8);
_classAttributeTable = new Dictionary (8);
_propertyAttributeTable = new Dictionary (8);
// 8 cached values for comments. Slots are reused in round-robin fashion
_comments = new ElementComments[8];
_commentsIndex = 0;
XmlDocument doc = null;
if (_commentingText != null)
{
doc = new XmlDocument();
try {
doc.Load(_commentingText);
}catch (XmlException)
{
RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
new BamlLocalizableResourceKey(string.Empty, string.Empty, string.Empty),
BamlLocalizerError.InvalidCommentingXml
)
);
doc = null;
}
}
_commentsDocument = doc;
}
internal void ReleaseLocalizabilityCache()
{
// release cached that is not needed for baml genearation
_propertyAttributeTable = null;
_comments = null;
_commentsIndex = 0;
_commentsDocument = null;
}
// Grab the comments on a BamlTreeNode for the value.
internal LocalizabilityGroup GetLocalizabilityComment(
BamlStartElementNode node,
string localName
)
{
// get all the comments declares on this node
ElementComments comment = LookupCommentForElement(node);
for (int i = 0; i < comment.LocalizationAttributes.Length; i++)
{
if (comment.LocalizationAttributes[i].PropertyName == localName)
{
return (LocalizabilityGroup) comment.LocalizationAttributes[i].Value;
}
}
return null;
}
internal string GetStringComment(
BamlStartElementNode node,
string localName
)
{
// get all the comments declares on this node
ElementComments comment = LookupCommentForElement(node);
for (int i = 0; i < comment.LocalizationComments.Length; i++)
{
if (comment.LocalizationComments[i].PropertyName == localName)
{
return (string) comment.LocalizationComments[i].Value;
}
}
return null;
}
internal void RaiseErrorNotifyEvent(BamlLocalizerErrorNotifyEventArgs e)
{
_localizer.RaiseErrorNotifyEvent(e);
}
//--------------------------------------
// BamlLocalizabilityResolver interface
//--------------------------------------
public override ElementLocalizability GetElementLocalizability(string assembly, string className)
{
if ( _externalResolver == null
|| assembly == null || assembly.Length == 0
|| className == null || className.Length == 0)
{
// return the default value
return new ElementLocalizability(
null,
DefaultAttribute
);
}
if (_classAttributeTable.ContainsKey(className))
{
// return cached value
return _classAttributeTable[className];
}
else
{
ElementLocalizability loc = _externalResolver.GetElementLocalizability(assembly, className);
if (loc == null || loc.Attribute == null)
{
loc = new ElementLocalizability(
null,
DefaultAttribute
);
}
_classAttributeTable[className] = loc;
return loc;
}
}
public override LocalizabilityAttribute GetPropertyLocalizability(string assembly, string className, string property)
{
if ( _externalResolver == null
|| assembly == null || assembly.Length == 0
|| className == null || className.Length == 0
|| property == null || property.Length == 0)
{
return DefaultAttribute;
}
string fullName = className + ":" + property;
if (_propertyAttributeTable.ContainsKey(fullName))
{
// return cached value
return _propertyAttributeTable[fullName];
}
else
{
LocalizabilityAttribute loc = _externalResolver.GetPropertyLocalizability(assembly, className, property);
if (loc == null)
{
loc = DefaultAttribute;
}
_propertyAttributeTable[fullName] = loc;
return loc;
}
}
public override string ResolveFormattingTagToClass(string formattingTag)
{
// go through the cache to find the mapping
foreach (KeyValuePair pair in _classAttributeTable)
{
if (pair.Value.FormattingTag == formattingTag)
return pair.Key;
}
string className = null;
if (_externalResolver != null)
{
// it is a formatting tag not resolved before. need to ask for client's help
className = _externalResolver.ResolveFormattingTagToClass(formattingTag);
if (!string.IsNullOrEmpty(className))
{
// cache the result
if (_classAttributeTable.ContainsKey(className))
{
_classAttributeTable[className].FormattingTag = formattingTag;
}
else
{
_classAttributeTable[className] = new ElementLocalizability(formattingTag, null);
}
}
}
return className;
}
public override string ResolveAssemblyFromClass(string className)
{
if (className == null || className.Length == 0)
{
return string.Empty;
}
// go through class encountered in this baml first
// if we saw this class before, we return the corresponding assembly
if (_classNameToAssemblyIndex.Contains(className))
{
return _assemblyNames[(int)_classNameToAssemblyIndex[className]];
}
string assemblyName = null;
if (_externalResolver != null)
{
// it is a class not resolved before. need to ask for client's help
assemblyName = _externalResolver.ResolveAssemblyFromClass(className);
AddClassAndAssembly(className, assemblyName);
}
return assemblyName;
}
private LocalizabilityAttribute DefaultAttribute
{
get
{
// if the value has no localizability attribute set, we default to all inherit.
LocalizabilityAttribute attribute = new LocalizabilityAttribute(LocalizationCategory.Inherit);
attribute.Modifiability = Modifiability.Inherit;
attribute.Readability = Readability.Inherit;
return attribute;
}
}
private ElementComments LookupCommentForElement(BamlStartElementNode node)
{
Debug.Assert(node.NodeType == BamlNodeType.StartElement);
if (node.Uid == null)
{
return new ElementComments(); // return empty comments for null Uid
}
for (int i = 0; i < _comments.Length; i++)
{
if (_comments[i] != null && _comments[i].ElementId == node.Uid)
{
return _comments[i];
}
}
ElementComments comment = new ElementComments();
comment.ElementId = node.Uid;
if (_commentsDocument != null)
{
// select the xmlNode containing the comments
XmlElement element = FindElementByID(_commentsDocument, node.Uid);
if (element != null)
{
// parse the comments
string locAttribute = element.GetAttribute(LocComments.LocLocalizabilityAttribute);
SetLocalizationAttributes(node, comment, locAttribute);
locAttribute = element.GetAttribute(LocComments.LocCommentsAttribute);
SetLocalizationComments(node, comment, locAttribute);
}
}
if (node.Children != null)
{
//
// The baml itself might contain comments too
// Grab the missing comments from Baml if there is any.
//
for (int i = 0;
i < node.Children.Count && (comment.LocalizationComments.Length == 0 || comment.LocalizationAttributes.Length == 0);
i++)
{
BamlTreeNode child = (BamlTreeNode) node.Children[i];
if (child.NodeType == BamlNodeType.Property)
{
BamlPropertyNode propertyNode = (BamlPropertyNode) child;
if (LocComments.IsLocCommentsProperty(propertyNode.OwnerTypeFullName, propertyNode.PropertyName)
&& comment.LocalizationComments.Length == 0)
{
// grab comments from Baml
SetLocalizationComments(node, comment, propertyNode.Value);
}
else if (LocComments.IsLocLocalizabilityProperty(propertyNode.OwnerTypeFullName, propertyNode.PropertyName)
&& comment.LocalizationAttributes.Length == 0)
{
// grab comments from Baml
SetLocalizationAttributes(node, comment, propertyNode.Value);
}
}
}
}
// cached it
_comments[_commentsIndex] = comment;
_commentsIndex = (_commentsIndex + 1) % _comments.Length;
return comment;
}
private static XmlElement FindElementByID(XmlDocument doc, string uid)
{
// Have considered using XPATH. However, XPATH doesn't have a way to escape single quote within
// single quotes, here we iterate through the document by ourselves
if (doc != null && doc.DocumentElement != null)
{
foreach(XmlNode node in doc.DocumentElement.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element)
{
XmlElement element = (XmlElement) node;
if ( element.Name == LocComments.LocCommentsElement
&& element.GetAttribute(LocComments.LocCommentIDAttribute) == uid)
{
return element;
}
}
}
}
return null;
}
private void SetLocalizationAttributes(
BamlStartElementNode node,
ElementComments comments,
string attributes
)
{
if (!string.IsNullOrEmpty(attributes))
{
try {
comments.LocalizationAttributes = LocComments.ParsePropertyLocalizabilityAttributes(attributes);
}
catch (FormatException)
{
RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
BamlTreeMap.GetKey(node),
BamlLocalizerError.InvalidLocalizationAttributes
)
);
}
}
}
private void SetLocalizationComments(
BamlStartElementNode node,
ElementComments comments,
string stringComment
)
{
if (!string.IsNullOrEmpty(stringComment))
{
try {
comments.LocalizationComments = LocComments.ParsePropertyComments(stringComment);
}
catch (FormatException)
{
RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
BamlTreeMap.GetKey(node),
BamlLocalizerError.InvalidLocalizationComments
)
);
}
}
}
///
/// Data structure for all the comments declared on a particular element
///
private class ElementComments
{
internal string ElementId; // element's uid
internal PropertyComment[] LocalizationAttributes; // Localization.Attributes
internal PropertyComment[] LocalizationComments; // Localization.Comments
internal ElementComments()
{
ElementId = null;
LocalizationAttributes = new PropertyComment[0];
LocalizationComments = new PropertyComment[0];
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------
// Class that implements BamlTreeMap.
//
// Created: Garyyang @ 12/1/2003
//
//-------------------------------------------------------
using System;
using System.IO;
using System.Xml;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Markup;
using System.Windows.Markup.Localizer;
using System.Diagnostics;
using System.Text;
using System.Windows;
using MS.Utility;
// Disabling 1634 and 1691:
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler,
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
namespace MS.Internal.Globalization
{
///
/// creates mappings for the baml tree node
/// this class in charges of creating mappings to the
/// loclaizable resources and tree nodes.
///
internal class BamlTreeMap
{
//----------------------------------
// internal Constructor
//----------------------------------
///
/// BamlTreeMap.
///
internal BamlTreeMap(
BamlLocalizer localizer,
BamlTree tree,
BamlLocalizabilityResolver resolver,
TextReader comments
)
{
Debug.Assert(tree!= null, "Baml Tree is empty");
Debug.Assert(localizer!= null, "BamlLocalizer is null");
_tree = tree;
// creates an internal resolver which willd delegate calls to client's resolver intelligently.
_resolver = new InternalBamlLocalizabilityResolver(localizer, resolver, comments);
// create a LocalizableResourceBuilder to build localizable resources
_localizableResourceBuilder = new LocalizableResourceBuilder(_resolver);
}
//----------------------------------
// internal properties
//----------------------------------
internal BamlLocalizationDictionary LocalizationDictionary
{
get
{
EnsureMap();
return _localizableResources;
}
}
internal InternalBamlLocalizabilityResolver Resolver
{
get
{
return _resolver;
}
}
///
/// Maps a key to a baml tree node in the given tree
///
internal BamlTreeNode MapKeyToBamlTreeNode(BamlLocalizableResourceKey key, BamlTree tree)
{
if (_keyToBamlNodeIndexMap.Contains(key))
{
return tree[(int)_keyToBamlNodeIndexMap[key]];
}
return null;
}
///
/// Maps a uid to a baml tree node in the given tree
///
internal BamlStartElementNode MapUidToBamlTreeElementNode(string uid, BamlTree tree)
{
if (_uidToBamlNodeIndexMap.Contains(uid))
{
return tree[(int)_uidToBamlNodeIndexMap[uid]] as BamlStartElementNode;
}
return null;
}
//--------------------------------------
// Private methods
//--------------------------------------
// construct the maps for enumeration
internal void EnsureMap()
{
if (_localizableResources != null)
return; // map is already created.
// create the table based on the treesize passed in
// the hashtable is for look-up during update
_resolver.InitLocalizabilityCache();
_keyToBamlNodeIndexMap = new Hashtable(_tree.Size);
_uidToBamlNodeIndexMap = new Hashtable(_tree.Size / 2);
_localizableResources = new BamlLocalizationDictionary();
for (int i = 0; i < _tree.Size; i++)
{
BamlTreeNode currentNode = _tree[i];
// a node may be marked as unidentifiable if it or its parent has a duplicate uid.
if (currentNode.Unidentifiable) continue; // skip unidentifiable nodes
if (currentNode.NodeType == BamlNodeType.StartElement)
{
// remember classes encountered in this baml
BamlStartElementNode elementNode = (BamlStartElementNode) currentNode;
_resolver.AddClassAndAssembly(elementNode.TypeFullName, elementNode.AssemblyName);
}
// find the Uid of the current node
BamlLocalizableResourceKey key = GetKey(currentNode);
if (key != null)
{
if (currentNode.NodeType == BamlNodeType.StartElement)
{
// store uid mapping to the corresponding element node
if (_uidToBamlNodeIndexMap.ContainsKey(key.Uid))
{
_resolver.RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
key,
BamlLocalizerError.DuplicateUid
)
);
// Mark this element and its properties unidentifiable.
currentNode.Unidentifiable = true;
if (currentNode.Children != null)
{
foreach (BamlTreeNode child in currentNode.Children)
{
if (child.NodeType != BamlNodeType.StartElement)
child.Unidentifiable = true;
}
}
continue; // skip the duplicate node
}
else
{
_uidToBamlNodeIndexMap.Add(key.Uid, i);
}
}
_keyToBamlNodeIndexMap.Add(key, i);
if (_localizableResources.RootElementKey == null
&& currentNode.NodeType == BamlNodeType.StartElement
&& currentNode.Parent != null
&& currentNode.Parent.NodeType == BamlNodeType.StartDocument)
{
// remember the key to the root element so that
// users can further add modifications to the root that would have a global impact.
// such as FlowDirection or CultureInfo
_localizableResources.SetRootElementKey(key);
}
// create the resource and add to the dictionary
BamlLocalizableResource resource = _localizableResourceBuilder.BuildFromNode(key, currentNode);
if (resource != null)
{
_localizableResources.Add(key, resource);
}
}
}
_resolver.ReleaseLocalizabilityCache();
}
//-------------------------------------------------
// Internal static
//-------------------------------------------------
///
/// Return the localizable resource key for this baml tree node.
/// If this node shouldn't be localized, the key returned will be null.
///
internal static BamlLocalizableResourceKey GetKey(BamlTreeNode node)
{
BamlLocalizableResourceKey key = null;
switch (node.NodeType)
{
case BamlNodeType.StartElement:
{
BamlStartElementNode elementNode = (BamlStartElementNode) node;
if (elementNode.Uid != null)
{
key = new BamlLocalizableResourceKey(
elementNode.Uid,
elementNode.TypeFullName,
BamlConst.ContentSuffix,
elementNode.AssemblyName
);
}
break;
}
case BamlNodeType.Property:
{
BamlPropertyNode propertyNode = (BamlPropertyNode) node;
BamlStartElementNode parent = (BamlStartElementNode) propertyNode.Parent;
if (parent.Uid != null)
{
string uid;
if (propertyNode.Index <= 0)
{
uid = parent.Uid;
}
else
{
// This node is auto-numbered. This has to do with the fact that
// the compiler may compile duplicated properties into Baml under the same element.
uid = string.Format(
System.Windows.Markup.TypeConverterHelper.EnglishUSCulture,
"{0}.{1}_{2}",
parent.Uid,
propertyNode.PropertyName,
propertyNode.Index
);
}
key = new BamlLocalizableResourceKey(
uid,
propertyNode.OwnerTypeFullName,
propertyNode.PropertyName,
propertyNode.AssemblyName
);
}
break;
}
case BamlNodeType.LiteralContent:
{
BamlLiteralContentNode literalNode = (BamlLiteralContentNode) node;
BamlStartElementNode parent = (BamlStartElementNode) node.Parent;
if (parent.Uid != null)
{
key = new BamlLocalizableResourceKey(
parent.Uid,
parent.TypeFullName,
BamlConst.LiteralContentSuffix,
parent.AssemblyName
);
}
break;
}
}
return key;
}
//---------------------------------
// private members
//---------------------------------
private Hashtable _keyToBamlNodeIndexMap; // _key to baml node. Key is integer. Not using Generic on value type for perf reason
private Hashtable _uidToBamlNodeIndexMap;
private LocalizableResourceBuilder _localizableResourceBuilder;
private BamlLocalizationDictionary _localizableResources;
private BamlTree _tree;
private InternalBamlLocalizabilityResolver _resolver;
}
internal class InternalBamlLocalizabilityResolver : BamlLocalizabilityResolver
{
BamlLocalizabilityResolver _externalResolver;
// a list of assemblies encounter in the baml
FrugalObjectList _assemblyNames;
// class name mapped to assembly index in the Frugal list
Hashtable _classNameToAssemblyIndex;
// cached localizablity values
private Dictionary _classAttributeTable;
private Dictionary _propertyAttributeTable;
//
// cached localization comments
// Normally, we only need to use comments of a single element at one time.
// In case of formatting inline tags we might be grabing comments of a few more elements.
// A small cached would be enough
//
private ElementComments[] _comments;
private int _commentsIndex;
// Localization comment document
private XmlDocument _commentsDocument;
private BamlLocalizer _localizer;
private TextReader _commentingText;
internal InternalBamlLocalizabilityResolver(
BamlLocalizer localizer,
BamlLocalizabilityResolver externalResolver,
TextReader comments
)
{
_localizer = localizer;
_externalResolver = externalResolver;
_commentingText = comments;
}
internal void AddClassAndAssembly(string className, string assemblyName)
{
if (assemblyName == null || _classNameToAssemblyIndex.Contains(className))
return;
int index = _assemblyNames.IndexOf(assemblyName);
if (index < 0)
{
// add the new assembly
_assemblyNames.Add(assemblyName);
index = _assemblyNames.Count - 1;
}
_classNameToAssemblyIndex.Add(className, index);
}
internal void InitLocalizabilityCache()
{
_assemblyNames = new FrugalObjectList();
_classNameToAssemblyIndex = new Hashtable(8);
_classAttributeTable = new Dictionary (8);
_propertyAttributeTable = new Dictionary (8);
// 8 cached values for comments. Slots are reused in round-robin fashion
_comments = new ElementComments[8];
_commentsIndex = 0;
XmlDocument doc = null;
if (_commentingText != null)
{
doc = new XmlDocument();
try {
doc.Load(_commentingText);
}catch (XmlException)
{
RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
new BamlLocalizableResourceKey(string.Empty, string.Empty, string.Empty),
BamlLocalizerError.InvalidCommentingXml
)
);
doc = null;
}
}
_commentsDocument = doc;
}
internal void ReleaseLocalizabilityCache()
{
// release cached that is not needed for baml genearation
_propertyAttributeTable = null;
_comments = null;
_commentsIndex = 0;
_commentsDocument = null;
}
// Grab the comments on a BamlTreeNode for the value.
internal LocalizabilityGroup GetLocalizabilityComment(
BamlStartElementNode node,
string localName
)
{
// get all the comments declares on this node
ElementComments comment = LookupCommentForElement(node);
for (int i = 0; i < comment.LocalizationAttributes.Length; i++)
{
if (comment.LocalizationAttributes[i].PropertyName == localName)
{
return (LocalizabilityGroup) comment.LocalizationAttributes[i].Value;
}
}
return null;
}
internal string GetStringComment(
BamlStartElementNode node,
string localName
)
{
// get all the comments declares on this node
ElementComments comment = LookupCommentForElement(node);
for (int i = 0; i < comment.LocalizationComments.Length; i++)
{
if (comment.LocalizationComments[i].PropertyName == localName)
{
return (string) comment.LocalizationComments[i].Value;
}
}
return null;
}
internal void RaiseErrorNotifyEvent(BamlLocalizerErrorNotifyEventArgs e)
{
_localizer.RaiseErrorNotifyEvent(e);
}
//--------------------------------------
// BamlLocalizabilityResolver interface
//--------------------------------------
public override ElementLocalizability GetElementLocalizability(string assembly, string className)
{
if ( _externalResolver == null
|| assembly == null || assembly.Length == 0
|| className == null || className.Length == 0)
{
// return the default value
return new ElementLocalizability(
null,
DefaultAttribute
);
}
if (_classAttributeTable.ContainsKey(className))
{
// return cached value
return _classAttributeTable[className];
}
else
{
ElementLocalizability loc = _externalResolver.GetElementLocalizability(assembly, className);
if (loc == null || loc.Attribute == null)
{
loc = new ElementLocalizability(
null,
DefaultAttribute
);
}
_classAttributeTable[className] = loc;
return loc;
}
}
public override LocalizabilityAttribute GetPropertyLocalizability(string assembly, string className, string property)
{
if ( _externalResolver == null
|| assembly == null || assembly.Length == 0
|| className == null || className.Length == 0
|| property == null || property.Length == 0)
{
return DefaultAttribute;
}
string fullName = className + ":" + property;
if (_propertyAttributeTable.ContainsKey(fullName))
{
// return cached value
return _propertyAttributeTable[fullName];
}
else
{
LocalizabilityAttribute loc = _externalResolver.GetPropertyLocalizability(assembly, className, property);
if (loc == null)
{
loc = DefaultAttribute;
}
_propertyAttributeTable[fullName] = loc;
return loc;
}
}
public override string ResolveFormattingTagToClass(string formattingTag)
{
// go through the cache to find the mapping
foreach (KeyValuePair pair in _classAttributeTable)
{
if (pair.Value.FormattingTag == formattingTag)
return pair.Key;
}
string className = null;
if (_externalResolver != null)
{
// it is a formatting tag not resolved before. need to ask for client's help
className = _externalResolver.ResolveFormattingTagToClass(formattingTag);
if (!string.IsNullOrEmpty(className))
{
// cache the result
if (_classAttributeTable.ContainsKey(className))
{
_classAttributeTable[className].FormattingTag = formattingTag;
}
else
{
_classAttributeTable[className] = new ElementLocalizability(formattingTag, null);
}
}
}
return className;
}
public override string ResolveAssemblyFromClass(string className)
{
if (className == null || className.Length == 0)
{
return string.Empty;
}
// go through class encountered in this baml first
// if we saw this class before, we return the corresponding assembly
if (_classNameToAssemblyIndex.Contains(className))
{
return _assemblyNames[(int)_classNameToAssemblyIndex[className]];
}
string assemblyName = null;
if (_externalResolver != null)
{
// it is a class not resolved before. need to ask for client's help
assemblyName = _externalResolver.ResolveAssemblyFromClass(className);
AddClassAndAssembly(className, assemblyName);
}
return assemblyName;
}
private LocalizabilityAttribute DefaultAttribute
{
get
{
// if the value has no localizability attribute set, we default to all inherit.
LocalizabilityAttribute attribute = new LocalizabilityAttribute(LocalizationCategory.Inherit);
attribute.Modifiability = Modifiability.Inherit;
attribute.Readability = Readability.Inherit;
return attribute;
}
}
private ElementComments LookupCommentForElement(BamlStartElementNode node)
{
Debug.Assert(node.NodeType == BamlNodeType.StartElement);
if (node.Uid == null)
{
return new ElementComments(); // return empty comments for null Uid
}
for (int i = 0; i < _comments.Length; i++)
{
if (_comments[i] != null && _comments[i].ElementId == node.Uid)
{
return _comments[i];
}
}
ElementComments comment = new ElementComments();
comment.ElementId = node.Uid;
if (_commentsDocument != null)
{
// select the xmlNode containing the comments
XmlElement element = FindElementByID(_commentsDocument, node.Uid);
if (element != null)
{
// parse the comments
string locAttribute = element.GetAttribute(LocComments.LocLocalizabilityAttribute);
SetLocalizationAttributes(node, comment, locAttribute);
locAttribute = element.GetAttribute(LocComments.LocCommentsAttribute);
SetLocalizationComments(node, comment, locAttribute);
}
}
if (node.Children != null)
{
//
// The baml itself might contain comments too
// Grab the missing comments from Baml if there is any.
//
for (int i = 0;
i < node.Children.Count && (comment.LocalizationComments.Length == 0 || comment.LocalizationAttributes.Length == 0);
i++)
{
BamlTreeNode child = (BamlTreeNode) node.Children[i];
if (child.NodeType == BamlNodeType.Property)
{
BamlPropertyNode propertyNode = (BamlPropertyNode) child;
if (LocComments.IsLocCommentsProperty(propertyNode.OwnerTypeFullName, propertyNode.PropertyName)
&& comment.LocalizationComments.Length == 0)
{
// grab comments from Baml
SetLocalizationComments(node, comment, propertyNode.Value);
}
else if (LocComments.IsLocLocalizabilityProperty(propertyNode.OwnerTypeFullName, propertyNode.PropertyName)
&& comment.LocalizationAttributes.Length == 0)
{
// grab comments from Baml
SetLocalizationAttributes(node, comment, propertyNode.Value);
}
}
}
}
// cached it
_comments[_commentsIndex] = comment;
_commentsIndex = (_commentsIndex + 1) % _comments.Length;
return comment;
}
private static XmlElement FindElementByID(XmlDocument doc, string uid)
{
// Have considered using XPATH. However, XPATH doesn't have a way to escape single quote within
// single quotes, here we iterate through the document by ourselves
if (doc != null && doc.DocumentElement != null)
{
foreach(XmlNode node in doc.DocumentElement.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element)
{
XmlElement element = (XmlElement) node;
if ( element.Name == LocComments.LocCommentsElement
&& element.GetAttribute(LocComments.LocCommentIDAttribute) == uid)
{
return element;
}
}
}
}
return null;
}
private void SetLocalizationAttributes(
BamlStartElementNode node,
ElementComments comments,
string attributes
)
{
if (!string.IsNullOrEmpty(attributes))
{
try {
comments.LocalizationAttributes = LocComments.ParsePropertyLocalizabilityAttributes(attributes);
}
catch (FormatException)
{
RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
BamlTreeMap.GetKey(node),
BamlLocalizerError.InvalidLocalizationAttributes
)
);
}
}
}
private void SetLocalizationComments(
BamlStartElementNode node,
ElementComments comments,
string stringComment
)
{
if (!string.IsNullOrEmpty(stringComment))
{
try {
comments.LocalizationComments = LocComments.ParsePropertyComments(stringComment);
}
catch (FormatException)
{
RaiseErrorNotifyEvent(
new BamlLocalizerErrorNotifyEventArgs(
BamlTreeMap.GetKey(node),
BamlLocalizerError.InvalidLocalizationComments
)
);
}
}
}
///
/// Data structure for all the comments declared on a particular element
///
private class ElementComments
{
internal string ElementId; // element's uid
internal PropertyComment[] LocalizationAttributes; // Localization.Attributes
internal PropertyComment[] LocalizationComments; // Localization.Comments
internal ElementComments()
{
ElementId = null;
LocalizationAttributes = new PropertyComment[0];
LocalizationComments = new PropertyComment[0];
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UrlMappingsSection.cs
- LeftCellWrapper.cs
- XMLDiffLoader.cs
- Column.cs
- UnconditionalPolicy.cs
- SamlSerializer.cs
- ConfigLoader.cs
- ErrorHandler.cs
- XmlQualifiedName.cs
- ApplicationServiceHelper.cs
- MarkupCompiler.cs
- RootProfilePropertySettingsCollection.cs
- Validator.cs
- QuaternionConverter.cs
- WebException.cs
- Monitor.cs
- PixelFormat.cs
- SoapClientProtocol.cs
- ClosableStream.cs
- MultiPageTextView.cs
- AppSecurityManager.cs
- DataMemberFieldConverter.cs
- ZipIOLocalFileDataDescriptor.cs
- SerializationException.cs
- VisualStyleRenderer.cs
- SequenceFullException.cs
- SqlProfileProvider.cs
- IconHelper.cs
- MetabaseServerConfig.cs
- BasicExpressionVisitor.cs
- ITextView.cs
- SyncOperationState.cs
- XmlArrayItemAttribute.cs
- FilteredAttributeCollection.cs
- ToolStripSettings.cs
- COMException.cs
- RemoveStoryboard.cs
- PtsCache.cs
- LogEntrySerializationException.cs
- SHA384Cng.cs
- BindingsCollection.cs
- DesignBindingConverter.cs
- TextWriter.cs
- CqlBlock.cs
- CompiledQueryCacheEntry.cs
- GeneratedContractType.cs
- DesignerTransaction.cs
- FixedLineResult.cs
- ImportedPolicyConversionContext.cs
- MenuAutomationPeer.cs
- TextDecorationCollection.cs
- XmlSchemaCompilationSettings.cs
- RegexFCD.cs
- CustomErrorsSectionWrapper.cs
- ACE.cs
- CompositeCollectionView.cs
- DataGridHeaderBorder.cs
- ComponentCommands.cs
- DocumentReferenceCollection.cs
- DataKeyArray.cs
- ScriptControlManager.cs
- CalendarDesigner.cs
- SQLInt16Storage.cs
- UnionCqlBlock.cs
- DbProviderSpecificTypePropertyAttribute.cs
- ToolStripSystemRenderer.cs
- AspNetHostingPermission.cs
- MediaTimeline.cs
- DataSourceViewSchemaConverter.cs
- BitmapMetadataEnumerator.cs
- OutputScope.cs
- ILGenerator.cs
- System.Data_BID.cs
- OutputCacheProviderCollection.cs
- EncoderFallback.cs
- TypeNameParser.cs
- DBCSCodePageEncoding.cs
- StreamSecurityUpgradeProvider.cs
- TableParaClient.cs
- FixedBufferAttribute.cs
- Help.cs
- WebPartMovingEventArgs.cs
- GenericsInstances.cs
- ExpressionEditorSheet.cs
- LayoutTableCell.cs
- DetailsViewDeleteEventArgs.cs
- DataMemberFieldConverter.cs
- DateTimeValueSerializerContext.cs
- WorkflowCreationContext.cs
- WindowsFont.cs
- DataBindingExpressionBuilder.cs
- ExtendedPropertyDescriptor.cs
- OrthographicCamera.cs
- X509SecurityTokenProvider.cs
- CompositionAdorner.cs
- ClientTargetCollection.cs
- XmlnsDefinitionAttribute.cs
- Control.cs
- StylusSystemGestureEventArgs.cs
- ConfigurationStrings.cs