public void AddDictionary(BamlLocalizationDictionary dictionary) { if (dictionary != null) { dictionariesList.Add(dictionary); } }
/// <summary> /// Constructor /// </summary> /// <param name="reader">resoure text reader that reads CSV or a tab-separated txt file</param> internal TranslationDictionariesReader(IBamlResourceReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } // hash key is case insensitive strings table = new Hashtable(); // we read each Row while (reader.MoveNext()) { // get the dictionary BamlLocalizationDictionary dictionary = this[reader.CurrentBamlName]; if (dictionary == null) { // we create one if it is not there yet. dictionary = new BamlLocalizationDictionary(); this[reader.CurrentBamlName] = dictionary; } // at this point, we are good. // add to the dictionary. dictionary.Add(reader.CurrentResourceKey, reader.CurrentResource); } }
/// <summary> /// Write the localizable key-value pairs /// </summary> /// <param name="options"></param> internal static void Write(LocBamlOptions options) { InputBamlStreamList bamlStreamList = new InputBamlStreamList(options); using (ITranslationWriter writer = options.GetTranslationWriter()) { options.WriteLine(StringLoader.Get("WriteBamlValues")); for (int i = 0; i < bamlStreamList.Count; i++) { options.Write(" "); options.Write(StringLoader.Get("ProcessingBaml", bamlStreamList[i].Name)); // Search for comment file in the same directory. The comment file has the extension to be // "loc". string commentFile = Path.ChangeExtension(bamlStreamList[i].Name, "loc"); TextReader commentStream = null; try { if (File.Exists(commentFile)) { commentStream = new StreamReader(commentFile); } // create the baml localizer BamlLocalizer mgr = new BamlLocalizer( bamlStreamList[i].Stream, new BamlLocalizabilityByReflection(options.Assemblies), commentStream ); // extract localizable resource from the baml stream BamlLocalizationDictionary dict = mgr.ExtractResources(); // write out each resource foreach (DictionaryEntry entry in dict) { BamlLocalizableResourceKey key = (BamlLocalizableResourceKey)entry.Key; BamlLocalizableResource resource = (BamlLocalizableResource)entry.Value; writer.WriteResource(bamlStreamList[i].Name, LocBamlConst.ResourceKeyToString(key), resource); } options.WriteLine(StringLoader.Get("Done")); } finally { if (commentStream != null) { commentStream.Close(); } } } // close all the baml input streams, output stream is closed by writer. bamlStreamList.Close(); } }
//----------------------------- // 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 ); } }
internal TranslationDictionariesReader(List <BamlString> bamlStrings) { // hash key is case insensitive strings _table = new Hashtable(); // we read each Row int rowNumber = 0; foreach (BamlString bamlString in bamlStrings) { rowNumber++; // field #1 is the baml name. string bamlName = bamlString.BamlFile; // it can't be null if (bamlName == null) { throw new ApplicationException(StringLoader.Get("EmptyRowEncountered")); } // field #2: key to the localizable resource string key = bamlString.ResourceKey; 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. resource = new BamlLocalizableResource(); resource.Category = bamlString.Category; resource.Readable = (bool)BoolTypeConverter.ConvertFrom(bamlString.Readability); resource.Modifiable = (bool)BoolTypeConverter.ConvertFrom(bamlString.Modifiable); resource.Comments = bamlString.Comments; // in case content being the last column, consider null as empty. resource.Content = bamlString.Content ?? string.Empty; // at this point, we are good. // add to the dictionary. dictionary.Add(resourceKey, resource); } }
private void GenerateBamlStream(Stream input, Stream output, Dictionaries curDictionaries) { 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 var localizabilityReflector = new BamlLocalizabilityByReflection(options.Assemblies); // create baml localizer var mgr = new BamlLocalizer( input, localizabilityReflector, commentStream ); // get the resources var source = mgr.ExtractResources(); var translations = new BamlLocalizationDictionary(); foreach (DictionaryEntry entry in source) { var key = (BamlLocalizableResourceKey)entry.Key; var translatedResource = curDictionaries.FindCorrespondence(key); if (translatedResource != null) { string translatedContent = translatedResource.Content; if (!String.IsNullOrEmpty(translatedContent)) { var curResource = (BamlLocalizableResource)entry.Value; if (curResource.Content != translatedContent) { translations.Add(key, translatedResource); } } } } // update baml mgr.UpdateBaml(output, translations); } finally { if (commentStream != null) { commentStream.Close(); } } }
internal static List <BamlString> ExtractBamlStrings(Assembly assembly) { InputBamlStreamList bamlStreamList = new InputBamlStreamList(assembly); List <BamlString> resultingList = new List <BamlString>(); for (int i = 0; i < bamlStreamList.Count; i++) { // Search for comment file in the same directory. The comment file has the extension to be // "loc". // string commentFile = Path.ChangeExtension(bamlStreamList[i].Name, "loc"); TextReader commentStream = null; try { //if (File.Exists(commentFile)) //{ // commentStream = new StreamReader(commentFile); //} // create the baml localizer BamlLocalizer mgr = new BamlLocalizer( bamlStreamList[i].Stream, new BamlLocalizabilityByReflection(new Assembly[] { assembly }), commentStream ); // extract localizable resource from the baml stream BamlLocalizationDictionary dict = mgr.ExtractResources(); // write out each resource foreach (DictionaryEntry entry in dict) { BamlLocalizableResourceKey key = (BamlLocalizableResourceKey)entry.Key; BamlLocalizableResource resource = (BamlLocalizableResource)entry.Value; resultingList.Add(new BamlString(bamlStreamList[i].Name, LocBamlConst.ResourceKeyToString(key), resource)); } } finally { if (commentStream != null) { commentStream.Close(); } } } // close all the baml input streams, output stream is closed by writer. bamlStreamList.Close(); // options.WriteLine(StringLoader.Get("Done")); return(resultingList); }
private static string 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); } catch (Exception ex) { return(ex.Message); } finally { if (commentStream != null) { commentStream.Close(); } } return(null); }
public static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("this.exe [resource.dll]"); return; } Assembly assembly = Assembly.LoadFrom(args[0]); foreach (string resourceName in assembly.GetManifestResourceNames()) { Stream resourceStream = assembly.GetManifestResourceStream(resourceName); using (ResourceReader reader = new ResourceReader(resourceStream)) { foreach (DictionaryEntry entry in reader) { string name = entry.Key as string; if (Path.GetExtension(name).ToUpperInvariant() == ".BAML") { Console.WriteLine("Processing baml {0}", name); // <Snippet1> // Obtain the BAML stream. Stream source = entry.Value as Stream; // Create a BamlLocalizer on the stream. BamlLocalizer localizer = new BamlLocalizer(source); BamlLocalizationDictionary resources = localizer.ExtractResources(); // Write out all the localizable resources in the BAML. foreach (DictionaryEntry resourceEntry in resources) { BamlLocalizableResourceKey key = resourceEntry.Key as BamlLocalizableResourceKey; BamlLocalizableResource value = resourceEntry.Value as BamlLocalizableResource; Console.WriteLine( " {0}.{1}.{2} = {3}", key.Uid, key.ClassName, key.PropertyName, value.Content ); } // </Snippet1> Console.WriteLine("Done"); } } } } }
internal TranslationDictionariesReader(XliffObject xliff) { // hash key is case insensitive strings _table = new Hashtable(); foreach (File file in xliff.Files) { string bamlName = file.Original; // 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; } Body body = file.Body; // There should only be one group, but go through any that exist for good measure foreach (Group group in body.Groups) { foreach (TranslationUnit transUnit in group.TranslationUnits) { string key = transUnit.Id; BamlLocalizableResourceKey resourceKey = LocBamlConst.StringToResourceKey(key); BamlLocalizableResource resource = new BamlLocalizableResource(); resource.Category = (LocalizationCategory)StringCatConverter.ConvertFrom(transUnit.ResourceType); /* * resource.Readable = (bool)BoolTypeConverter.ConvertFrom(reader.GetColumn(3)); * resource.Modifiable = (bool)BoolTypeConverter.ConvertFrom(reader.GetColumn(4)); */ Note comment = transUnit.Notes.FirstOrDefault(n => n.From == "MultilingualBuild"); if (comment != null) { resource.Comments = comment.Text; } resource.Content = transUnit.Target.Content ?? string.Empty; dictionary.Add(resourceKey, resource); } } } }
// Token: 0x06006EAB RID: 28331 RVA: 0x001FC55C File Offset: 0x001FA75C private static void CreateMissingBamlTreeNode(BamlLocalizationDictionary dictionary, BamlTreeUpdater.BamlTreeUpdateMap treeMap) { BamlLocalizationDictionaryEnumerator enumerator = dictionary.GetEnumerator(); while (enumerator.MoveNext()) { BamlLocalizableResourceKey key = enumerator.Key; BamlLocalizableResource value = enumerator.Value; if (treeMap.MapKeyToBamlTreeNode(key) == null) { if (key.PropertyName == "$Content") { if (treeMap.MapUidToBamlTreeElementNode(key.Uid) == null) { BamlStartElementNode bamlStartElementNode = new BamlStartElementNode(treeMap.Resolver.ResolveAssemblyFromClass(key.ClassName), key.ClassName, false, false); bamlStartElementNode.AddChild(new BamlDefAttributeNode("Uid", key.Uid)); BamlTreeUpdater.TryAddContentPropertyToNewElement(treeMap, bamlStartElementNode); bamlStartElementNode.AddChild(new BamlEndElementNode()); treeMap.AddBamlTreeNode(key.Uid, key, bamlStartElementNode); } } else { BamlTreeNode node; if (key.PropertyName == "$LiteralContent") { node = new BamlLiteralContentNode(value.Content); } else { node = new BamlPropertyNode(treeMap.Resolver.ResolveAssemblyFromClass(key.ClassName), key.ClassName, key.PropertyName, value.Content, BamlAttributeUsage.Default); } treeMap.AddBamlTreeNode(null, key, node); } } } }
// Token: 0x06006EAA RID: 28330 RVA: 0x001FC4B8 File Offset: 0x001FA6B8 internal static void UpdateTree(BamlTree tree, BamlTreeMap treeMap, BamlLocalizationDictionary dictionary) { if (dictionary.Count <= 0) { return; } BamlTreeUpdater.BamlTreeUpdateMap treeMap2 = new BamlTreeUpdater.BamlTreeUpdateMap(treeMap, tree); BamlTreeUpdater.CreateMissingBamlTreeNode(dictionary, treeMap2); BamlLocalizationDictionaryEnumerator enumerator = dictionary.GetEnumerator(); ArrayList arrayList = new ArrayList(); while (enumerator.MoveNext()) { if (!BamlTreeUpdater.ApplyChangeToBamlTree(enumerator.Key, enumerator.Value, treeMap2)) { arrayList.Add(enumerator.Entry); } } for (int i = 0; i < arrayList.Count; i++) { DictionaryEntry dictionaryEntry = (DictionaryEntry)arrayList[i]; BamlTreeUpdater.ApplyChangeToBamlTree((BamlLocalizableResourceKey)dictionaryEntry.Key, (BamlLocalizableResource)dictionaryEntry.Value, treeMap2); } }
public BamlLocalizableResourceKey FindCorrespondenceKey(BamlLocalizableResourceKey key, BamlLocalizationDictionary dictionary) { return(key); }
public BamlLocalizableResource FindCorrespondence(BamlLocalizableResourceKey key, BamlLocalizationDictionary dictionary) { if (dictionary.Contains(key)) { return(dictionary[key]); } 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 void GenerateAssembly(ResourceGenerationOptions options) { TranslationDictionariesReader dictionaries = new TranslationDictionariesReader(options.BamlStrings); string sourceAssemblyFullName = options.AssemblyFileName; // source assembly full path string outputAssemblyLocalName = System.IO.Path.GetFileName(options.OutputFileName); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName( options.CultureInfo, System.IO.Path.GetFileName(outputAssemblyLocalName)); // the module name within the assmbly // get the source assembly Assembly sourceAssembly = options.SourceAssembly; CultureInfo cultureInfo = options.CultureInfo; // obtain the assembly name AssemblyName targetAssemblyNameObj = sourceAssembly.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = cultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = options.AppDomain.DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights System.IO.Path.GetDirectoryName(options.OutputFileName) // storage dir ); // we create a module builder for embeded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); //options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in sourceAssembly.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = sourceAssembly.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assemlby, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, cultureInfo); // resource stream Stream resourceStream = sourceAssembly.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embeded assembly if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources GenerateResourceStream(options, resourceName, reader, writer, dictionaries); // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine( System.IO.Path.GetDirectoryName(options.AssemblyFileName), targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); }
private static void GenerateResourceStream( ResourceGenerationOptions options, // options from the command line string resourceName, // the name of the .resources file IResourceReader reader, // the reader for the .resources IResourceWriter writer, // the writer for the output .resources TranslationDictionariesReader dictionaries // the translations ) { //options.WriteLine(StringLoader.Get("GenerateResource", resourceName)); // enumerate through each resource and generate it foreach (DictionaryEntry entry in reader) { string name = entry.Key as string; object resourceValue = null; // See if it looks like a Baml resource if (BamlStream.IsResourceEntryBamlStream(name, entry.Value)) { Stream targetStream = null; // options.Write(" "); //options.Write(StringLoader.Get("GenerateBaml", name)); // grab the localizations available for this Baml string bamlName = BamlStream.CombineBamlStreamName(resourceName, name); BamlLocalizationDictionary localizations = dictionaries[bamlName]; if (localizations != null) { targetStream = new MemoryStream(); // generate into a new Baml stream GenerateBamlStream( (Stream)entry.Value, targetStream, localizations, options ); } options.WriteLine(StringLoader.Get("Done")); // sets the generated object to be the generated baml stream resourceValue = targetStream; } if (resourceValue == null) { // // The stream is not localized as Baml yet, so we will make a copy of this item into // the localized resources // // We will add the value as is if it is serializable. Otherwise, make a copy resourceValue = entry.Value; object[] serializableAttributes = resourceValue.GetType().GetCustomAttributes(typeof(SerializableAttribute), true); if (serializableAttributes.Length == 0) { // The item returned from resource reader is not serializable // If it is Stream, we can wrap all the values in a MemoryStream and // add to the resource. Otherwise, we had to skip this resource. Stream resourceStream = resourceValue as Stream; if (resourceStream != null) { Stream targetStream = new MemoryStream(); byte[] buffer = new byte[resourceStream.Length]; resourceStream.Read(buffer, 0, buffer.Length); targetStream = new MemoryStream(buffer); resourceValue = targetStream; } } } if (resourceValue != null) { writer.AddResource(name, resourceValue); } } }
//-------------------------------------------------- // The function follows Managed code parser // implementation. in the future, maybe they should // share the same code //-------------------------------------------------- private static void GenerateAssembly(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // there are many names to be used when generating an assembly string sourceAssemblyFullName = options.Input; // source assembly full path string outputAssemblyDir = options.Output; // output assembly directory string outputAssemblyLocalName = GetOutputFileName(options); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName(options, outputAssemblyLocalName); // the module name within the assmbly // get the source assembly Assembly srcAsm = Assembly.LoadFrom(sourceAssemblyFullName); // obtain the assembly name AssemblyName targetAssemblyNameObj = srcAsm.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = options.CultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights outputAssemblyDir // storage dir ); // Add assembly info, trying to preserver original values as close as possible Action <Type, string> AddCustomStringAttribute = (Type type, string content) => { if (string.IsNullOrEmpty(content)) { return; } ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(string) }); targetAssemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(ctor, new object[] { content })); }; bool hasInformationalVersionAttr = false; object[] attrs = srcAsm.GetCustomAttributes(false); foreach (var attr in attrs) { if (attr is AssemblyCompanyAttribute cmp) { AddCustomStringAttribute(attr.GetType(), cmp.Company); continue; } if (attr is AssemblyCopyrightAttribute copy) { AddCustomStringAttribute(attr.GetType(), copy.Copyright); continue; } if (attr is AssemblyDescriptionAttribute da) { AddCustomStringAttribute(attr.GetType(), da.Description); continue; } if (attr is AssemblyFileVersionAttribute fva) { AddCustomStringAttribute(attr.GetType(), fva.Version); if (!hasInformationalVersionAttr) { // Also set AssemblyInformationalVersionAttribute, if not set already. // The unmanaged ProductVersion is taken from that attribute. AddCustomStringAttribute(typeof(AssemblyInformationalVersionAttribute), fva.Version); } continue; } if (attr is AssemblyInformationalVersionAttribute iva) { AddCustomStringAttribute(attr.GetType(), iva.InformationalVersion); hasInformationalVersionAttr = true; continue; } if (attr is AssemblyProductAttribute pa) { AddCustomStringAttribute(attr.GetType(), pa.Product); continue; } if (attr is AssemblyTitleAttribute ta) { AddCustomStringAttribute(attr.GetType(), ta.Title); continue; } if (attr is AssemblyTrademarkAttribute tm) { AddCustomStringAttribute(attr.GetType(), tm.Trademark); continue; } if (attr is AssemblyVersionAttribute va) { AddCustomStringAttribute(attr.GetType(), va.Version); continue; } } targetAssemblyBuilder.DefineVersionInfoResource(); // we create a module builder for embeded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in srcAsm.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = srcAsm.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assemlby, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, options.CultureInfo); // resource stream Stream resourceStream = srcAsm.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embeded assembly if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources GenerateResourceStream(options, resourceName, reader, writer, dictionaries); // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine(outputAssemblyDir, targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); }
public BamlLocalizableResourceKey FindCorrespondenceKey(BamlLocalizableResourceKey key, BamlLocalizationDictionary dictionary) { foreach (var entry in dictionary) { var entryKey = (BamlLocalizableResourceKey)entry.Key; if (entryKey.Uid == key.Uid && entryKey.PropertyName == key.PropertyName) { return(entryKey); } } return(null); }
//-------------------------------------------------- // The function follows Managed code parser // implementation. in the future, maybe they should // share the same code //-------------------------------------------------- private static void GenerateAssembly(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // there are many names to be used when generating an assembly string sourceAssemblyFullName = options.Input; // source assembly full path string outputAssemblyDir = options.Output; // output assembly directory string outputAssemblyLocalName = GetOutputFileName(options); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName(options, outputAssemblyLocalName); // the module name within the assmbly // get the source assembly byte[] sourceContents = File.ReadAllBytes(sourceAssemblyFullName); Assembly srcAsm = Assembly.Load(sourceContents); // obtain the assembly name AssemblyName targetAssemblyNameObj = srcAsm.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = options.CultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights outputAssemblyDir // storage dir ); // we create a module builder for embeded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); Dictionary <string, IResourceWriter> resourceWriters = new Dictionary <string, IResourceWriter>(); // If the output assembly already exists, copy the embedded resources to the new assembly string existingAssemblyName = Path.Combine(Directory.GetCurrentDirectory(), options.CultureInfo.Name, outputAssemblyLocalName); if (File.Exists(existingAssemblyName)) { // Use ReadAllBytes() so we don't hold a file handle open, which would prevent // us from overwriting the file at the end. Assembly existingAssembly = Assembly.Load(File.ReadAllBytes(existingAssemblyName)); string[] existingResourceNames = existingAssembly.GetManifestResourceNames(); foreach (string resourceName in existingResourceNames) { ManifestResourceInfo info = existingAssembly.GetManifestResourceInfo(resourceName); if ((info.ResourceLocation & ResourceLocation.Embedded) != ResourceLocation.Embedded) { continue; } IResourceWriter writer; if (!resourceWriters.TryGetValue(resourceName, out writer)) { writer = moduleBuilder.DefineResource( resourceName, // resource name resourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); resourceWriters.Add(resourceName, writer); } Stream resourceStream = existingAssembly.GetManifestResourceStream(resourceName); using (ResourceReader reader = new ResourceReader(resourceStream)) { foreach (DictionaryEntry entry in reader) { string key = entry.Key.ToString(); object value = entry.Value; if (key.EndsWith(".baml")) { // Skip it, we're going to get this from the untranslated assembly continue; } writer.AddResource(key, value); } } } } // Add assembly info, trying to preserver original values as close as possible CopyAssemblyVersion(targetAssemblyBuilder, srcAsm); options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in srcAsm.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = srcAsm.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assemlby, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, options.CultureInfo); // resource stream Stream resourceStream = srcAsm.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embeded assembly if (!resourceWriters.TryGetValue(targetResourceName, out writer)) { if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } resourceWriters.Add(targetResourceName, writer); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources GenerateResourceStream(options, resourceName, reader, writer, dictionaries); // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine(outputAssemblyDir, targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); }
/// <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); } }
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); } } } }
/// <summary> /// Write the localizable key-value pairs /// </summary> /// <param name="options"></param> internal static void Write(LocBamlOptions options) { Stream output = new FileStream(options.Output, FileMode.Create); InputBamlStreamList bamlStreamList = new InputBamlStreamList(options); using (ResourceTextWriter writer = new ResourceTextWriter(options.TranslationFileType, output)) { options.WriteLine(StringLoader.Get("WriteBamlValues")); for (int i = 0; i < bamlStreamList.Count; i++) { options.Write(" "); options.Write(StringLoader.Get("ProcessingBaml", bamlStreamList[i].Name)); // Search for comment file in the same directory. The comment file has the extension to be // "loc". string commentFile = Path.ChangeExtension(bamlStreamList[i].Name, "loc"); TextReader commentStream = null; try { if (File.Exists(commentFile)) { commentStream = new StreamReader(commentFile); } // create the baml localizer BamlLocalizer mgr = new BamlLocalizer( bamlStreamList[i].Stream, new BamlLocalizabilityByReflection(options.Assemblies), commentStream ); // extract localizable resource from the baml stream BamlLocalizationDictionary dict = mgr.ExtractResources(); // write out each resource foreach (DictionaryEntry entry in dict) { // column 1: baml stream name writer.WriteColumn(bamlStreamList[i].Name); BamlLocalizableResourceKey key = (BamlLocalizableResourceKey)entry.Key; BamlLocalizableResource resource = (BamlLocalizableResource)entry.Value; // column 2: localizable resource key writer.WriteColumn(LocBamlConst.ResourceKeyToString(key)); // column 3: localizable resource's category writer.WriteColumn(resource.Category.ToString()); // column 4: localizable resource's readability writer.WriteColumn(resource.Readable.ToString()); // column 5: localizable resource's modifiability writer.WriteColumn(resource.Modifiable.ToString()); // column 6: localizable resource's localization comments writer.WriteColumn(resource.Comments); // column 7: localizable resource's content writer.WriteColumn(resource.Content); // Done. finishing the line writer.EndLine(); } options.WriteLine(StringLoader.Get("Done")); } finally { if (commentStream != null) { commentStream.Close(); } } } // close all the baml input streams, output stream is closed by writer. bamlStreamList.Close(); } }
/// <summary> /// Generates localized Baml from translations /// </summary> /// <param name="options">LocBaml options</param> /// <param name="dictionaries">the translation dictionaries</param> internal static string 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); // output 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(); } string status = GenerateBamlStream(input, output, dictionary, options); if (status != null) { return(status); } } } 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); string status = GenerateResourceStream( options, // options options.Input, // resources name reader, // resource reader writer, // resource writer dictionaries); // translations reader.Close(); if (status != null) { return(status); } // now generate and close writer.Generate(); writer.Close(); } } options.WriteLine(StringLoader.Get("DoneGeneratingResource", outputFileName)); break; } case FileType.EXE: case FileType.DLL: { string status = GenerateAssembly(options, dictionaries); if (status != null) { return(status); } break; } default: { Debug.Assert(false, "Can't generate to this type"); return("Can't generate to a resource of the type EXE"); break; } } return(null); }