/// <summary> /// Udpate the source baml into a target stream with all the resource udpates applied. /// </summary> /// <param name="target">target stream</param> /// <param name="updates">resource updates to be applied when generating the localized baml</param> public void UpdateBaml( Stream target, BamlLocalizationDictionary updates ) { if (target == null) { throw new ArgumentNullException("target"); } if (updates == null) { throw new ArgumentNullException("updates"); } // we duplicate the internal baml tree here because // we will need to modify the tree to do generation // UpdateBaml can be called multiple times BamlTree _duplicateTree = _tree.Copy(); _bamlTreeMap.EnsureMap(); // Udpate the tree BamlTreeUpdater.UpdateTree( _duplicateTree, _bamlTreeMap, updates ); // Serialize the tree into Baml BamlResourceSerializer.Serialize( this, _duplicateTree, target ); }
//----------------------------- // internal methods //----------------------------- internal static void UpdateTree( BamlTree tree, BamlTreeMap treeMap, BamlLocalizationDictionary dictionary ) { Debug.Assert(tree != null && tree.Root != null, "Empty Tree!"); Debug.Assert(treeMap != null, "Empty map!"); Debug.Assert(dictionary != null, "Empty dictionary"); // no changes to do to the tree. if (dictionary.Count <= 0) return; // create a tree map to be used for update BamlTreeUpdateMap updateMap = new BamlTreeUpdateMap(treeMap, tree); // // a) Create baml tree nodes for missing child place holders and properties. // Translations may require new nodes to be constructed. For example // translation contains new child place holders // CreateMissingBamlTreeNode(dictionary, updateMap); // // b) Look through each translation and make modification to the tree // At this step, new nodes are linked to the tree if applicable. // BamlLocalizationDictionaryEnumerator enumerator = dictionary.GetEnumerator(); ArrayList deferredResources = new ArrayList(); while (enumerator.MoveNext()) { if (!ApplyChangeToBamlTree(enumerator.Key, enumerator.Value, updateMap)) { deferredResources.Add(enumerator.Entry); } } // // c) Hook up the property nodes that aren't hooked up yet // Formatting tags inserted in the translation will only be created the // previous step. Hook up properties to those nodes now if applicable // for(int i = 0; i < deferredResources.Count; i++) { DictionaryEntry entry = (DictionaryEntry) deferredResources[i]; ApplyChangeToBamlTree( (BamlLocalizableResourceKey) entry.Key, (BamlLocalizableResource) entry.Value, updateMap ); } }
// Token: 0x06002507 RID: 9479 RVA: 0x000B2D74 File Offset: 0x000B0F74 internal BamlLocalizationDictionary Copy() { BamlLocalizationDictionary bamlLocalizationDictionary = new BamlLocalizationDictionary(); foreach (KeyValuePair <BamlLocalizableResourceKey, BamlLocalizableResource> keyValuePair in this._dictionary) { BamlLocalizableResource value = (keyValuePair.Value == null) ? null : new BamlLocalizableResource(keyValuePair.Value); bamlLocalizationDictionary.Add(keyValuePair.Key, value); } bamlLocalizationDictionary._rootElementKey = this._rootElementKey; return(bamlLocalizationDictionary); }
/// <summary>Applies resource updates to the BAML source and writes the updated version to a specified stream in order to create a localized version of the source BAML. </summary> /// <param name="target">The stream that will receive the updated BAML.</param> /// <param name="updates">The resource updates to be applied to the source BAML.</param> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="target" /> or <paramref name="updates" /> are <see langword="null" />.</exception> // Token: 0x0600250E RID: 9486 RVA: 0x000B2E68 File Offset: 0x000B1068 public void UpdateBaml(Stream target, BamlLocalizationDictionary updates) { if (target == null) { throw new ArgumentNullException("target"); } if (updates == null) { throw new ArgumentNullException("updates"); } BamlTree tree = this._tree.Copy(); this._bamlTreeMap.EnsureMap(); BamlTreeUpdater.UpdateTree(tree, this._bamlTreeMap, updates); BamlResourceSerializer.Serialize(this, tree, target); }
//------------------------------ // internal functions //------------------------------ internal BamlLocalizationDictionary Copy() { BamlLocalizationDictionary newDictionary = new BamlLocalizationDictionary(); foreach (KeyValuePair <BamlLocalizableResourceKey, BamlLocalizableResource> pair in _dictionary) { BamlLocalizableResource resourceCopy = pair.Value == null ? null : new BamlLocalizableResource(pair.Value); newDictionary.Add(pair.Key, resourceCopy); } newDictionary._rootElementKey = _rootElementKey; // return the new dictionary return(newDictionary); }
private static void CreateMissingBamlTreeNode( BamlLocalizationDictionary dictionary, BamlTreeUpdateMap treeMap ) { BamlLocalizationDictionaryEnumerator enumerator = dictionary.GetEnumerator(); while (enumerator.MoveNext()) { BamlLocalizableResourceKey key = enumerator.Key; BamlLocalizableResource resource = enumerator.Value; // get the baml tree node from the tree BamlTreeNode node = treeMap.MapKeyToBamlTreeNode(key); if (node == null) { if (key.PropertyName == BamlConst.ContentSuffix) { // see if there is already a Baml node with the Uid. If so // ignore this entry node = treeMap.MapUidToBamlTreeElementNode(key.Uid); if (node == null) { // create new Baml element node BamlStartElementNode newNode = new BamlStartElementNode( treeMap.Resolver.ResolveAssemblyFromClass(key.ClassName), key.ClassName, false, /*isInjected*/ false /*CreateUsingTypeConverter*/ ); // create new x:Uid node for this element node newNode.AddChild( new BamlDefAttributeNode( XamlReaderHelper.DefinitionUid, key.Uid ) ); TryAddContentPropertyToNewElement(treeMap, newNode); // terminate the node with EndElementNode newNode.AddChild(new BamlEndElementNode()); // store this new node into the map so that it can be found // when other translations reference it as a childplace holder, or property owner treeMap.AddBamlTreeNode(key.Uid, key, newNode); } } else { BamlTreeNode newNode; if (key.PropertyName == BamlConst.LiteralContentSuffix) { // create a LiterContent node newNode = new BamlLiteralContentNode(resource.Content); } else { newNode = new BamlPropertyNode( treeMap.Resolver.ResolveAssemblyFromClass(key.ClassName), key.ClassName, key.PropertyName, resource.Content, BamlAttributeUsage.Default ); } // add to the map treeMap.AddBamlTreeNode(null, key, newNode); } } } }
public void UpdateBaml(Stream target, BamlLocalizationDictionary updates) { Contract.Ensures(target.CanWrite == true); }
/// <summary> /// Generates localized Baml from translations /// </summary> /// <param name="options">LocBaml options</param> /// <param name="dictionaries">the translation dictionaries</param> internal static void Generate(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // base on the input, we generate differently switch(options.InputType) { case FileType.BAML : { // input file name string bamlName = Path.GetFileName(options.Input); // outpuf file name is Output dir + input file name string outputFileName = GetOutputFileName(options); // construct the full path string fullPathOutput = Path.Combine(options.Output, outputFileName); options.Write(StringLoader.Get("GenerateBaml", fullPathOutput)); using (Stream input = File.OpenRead(options.Input)) { using (Stream output = new FileStream(fullPathOutput, FileMode.Create)) { BamlLocalizationDictionary dictionary = dictionaries[bamlName]; // if it is null, just create an empty dictionary. if (dictionary == null) dictionary = new BamlLocalizationDictionary(); GenerateBamlStream(input, output, dictionary, options); } } options.WriteLine(StringLoader.Get("Done")); break; } case FileType.RESOURCES : { string outputFileName = GetOutputFileName(options); string fullPathOutput = Path.Combine(options.Output, outputFileName); using (Stream input = File.OpenRead(options.Input)) { using (Stream output = File.OpenWrite(fullPathOutput)) { // create a Resource reader on the input; IResourceReader reader = new ResourceReader(input); // create a writer on the output; IResourceWriter writer = new ResourceWriter(output); GenerateResourceStream( options, // options options.Input, // resources name reader, // resource reader writer, // resource writer dictionaries); // translations reader.Close(); // now generate and close writer.Generate(); writer.Close(); } } options.WriteLine(StringLoader.Get("DoneGeneratingResource", outputFileName)); break; } case FileType.EXE: case FileType.DLL: { GenerateAssembly(options, dictionaries); break; } default: { Debug.Assert(false, "Can't generate to this type"); break; } } }
private static void GenerateBamlStream(Stream input, Stream output, BamlLocalizationDictionary dictionary, LocBamlOptions options) { string commentFile = Path.ChangeExtension(options.Input, "loc"); TextReader commentStream = null; try { if (File.Exists(commentFile)) { commentStream = new StreamReader(commentFile); } // create a localizabilty resolver based on reflection BamlLocalizabilityByReflection localizabilityReflector = new BamlLocalizabilityByReflection(options.Assemblies); // create baml localizer BamlLocalizer mgr = new BamlLocalizer( input, localizabilityReflector, commentStream ); // get the resources BamlLocalizationDictionary source = mgr.ExtractResources(); BamlLocalizationDictionary translations = new BamlLocalizationDictionary(); foreach (DictionaryEntry entry in dictionary) { BamlLocalizableResourceKey key = (BamlLocalizableResourceKey) entry.Key; // filter out unchanged items if (!source.Contains(key) || entry.Value == null || source[key].Content != ((BamlLocalizableResource)entry.Value).Content) { translations.Add(key, (BamlLocalizableResource)entry.Value); } } // update baml mgr.UpdateBaml(output, translations); } finally { if (commentStream != null) { commentStream.Close(); } } }
//-------------------------------------- // 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 functions //------------------------------ internal BamlLocalizationDictionary Copy() { BamlLocalizationDictionary newDictionary = new BamlLocalizationDictionary(); foreach (KeyValuePair<BamlLocalizableResourceKey, BamlLocalizableResource> pair in _dictionary) { BamlLocalizableResource resourceCopy = pair.Value == null ? null : new BamlLocalizableResource(pair.Value); newDictionary.Add(pair.Key, resourceCopy); } newDictionary._rootElementKey = _rootElementKey; // return the new dictionary return newDictionary; }
/// <summary> /// Constructor /// </summary> /// <param name="reader">resoure text reader that reads CSV or a tab-separated txt file</param> internal TranslationDictionariesReader(ResourceTextReader reader) { if (reader == null) throw new ArgumentNullException("reader"); // hash key is case insensitive strings _table = new Hashtable(); // we read each Row int rowNumber = 0; while (reader.ReadRow()) { rowNumber ++; // field #1 is the baml name. string bamlName = reader.GetColumn(0); // it can't be null if (bamlName == null) throw new ApplicationException(StringLoader.Get("EmptyRowEncountered")); if (string.IsNullOrEmpty(bamlName)) { // allow for comment lines in csv file. // each comment line starts with ",". It will make the first entry as String.Empty. // and we will skip the whole line. continue; // if the first column is empty, take it as a comment line } // field #2: key to the localizable resource string key = reader.GetColumn(1); if (key == null) throw new ApplicationException(StringLoader.Get("NullBamlKeyNameInRow")); BamlLocalizableResourceKey resourceKey = LocBamlConst.StringToResourceKey(key); // get the dictionary BamlLocalizationDictionary dictionary = this[bamlName]; if (dictionary == null) { // we create one if it is not there yet. dictionary = new BamlLocalizationDictionary(); this[bamlName] = dictionary; } BamlLocalizableResource resource; // the rest of the fields are either all null, // or all non-null. If all null, it means the resource entry is deleted. // get the string category string categoryString = reader.GetColumn(2); if (categoryString == null) { // it means all the following fields are null starting from column #3. resource = null; } else { // the rest must all be non-null. // the last cell can be null if there is no content for (int i = 3; i < 6; i++) { if (reader.GetColumn(i) == null) throw new Exception(StringLoader.Get("InvalidRow")); } // now we know all are non-null. let's try to create a resource resource = new BamlLocalizableResource(); // field #3: Category resource.Category = (LocalizationCategory) StringCatConverter.ConvertFrom(categoryString); // field #4: Readable resource.Readable = (bool) BoolTypeConverter.ConvertFrom(reader.GetColumn(3)); // field #5: Modifiable resource.Modifiable = (bool) BoolTypeConverter.ConvertFrom(reader.GetColumn(4)); // field #6: Comments resource.Comments = reader.GetColumn(5); // field #7: Content resource.Content = reader.GetColumn(6); // in case content being the last column, consider null as empty. if (resource.Content == null) resource.Content = string.Empty; // field > #7: Ignored. } // at this point, we are good. // add to the dictionary. dictionary.Add(resourceKey, resource); } }