private static void GenerateResourceStream( LocBamlOptions 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); } } }
/// <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; } } }
//-------------------------------------------------- // 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 ); // 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")); }
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 static methods //--------------------------------------------- /// <summary> /// Parse the baml resources given in the command line /// </summary> private static void ParseBamlResources(LocBamlOptions options) { TranslationDictionariesWriter.Write(options); }
private static void GenerateResourceStream( LocBamlOptions 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); } } }
/// <summary> /// Genereate localized baml /// </summary> private static void GenerateBamlResources(LocBamlOptions options) { Stream input = File.OpenRead(options.Translations); using (ResourceTextReader reader = new ResourceTextReader(options.TranslationFileType, input)) { TranslationDictionariesReader dictionaries = new TranslationDictionariesReader(reader); ResourceGenerator.Generate(options, dictionaries); } }
public ResourceXliffWriter(LocBamlOptions options, System.IO.Stream output, XliffObject existingObject) { _OutputStream = output; _RootObject = existingObject; _TargetLanguage = options.CultureInfo.Name; }
/// <summary> /// get CommandLineOptions, return error message /// </summary> private static void GetCommandLineOptions(string[] args, out LocBamlOptions options, out string errorMessage) { CommandLine commandLine; try{ // "*" means the option must have a value. no "*" means the option can't have a value commandLine = new CommandLine(args, new string[] { "parse", // /parse for update "generate", // /generate for generate "*out", // /out for output .csv|.txt when parsing, for output directory when generating "*culture", // /culture for culture name "*translation", // /translation for translation file, .csv|.txt "*asmpath", // /asmpath, for assembly path to look for references (TODO: add asmpath support) "nologo", // /nologo for not to print logo "help", // /help for help "verbose" // /verbose for verbose output } ); } catch (ArgumentException e) { errorMessage = e.Message; options = null; return; } if (commandLine.NumArgs + commandLine.NumOpts < 1) { PrintLogo(null); PrintUsage(); errorMessage = null; options = null; return; } options = new LocBamlOptions(); options.Input = commandLine.GetNextArg(); Option commandLineOption; while ((commandLineOption = commandLine.GetNextOption()) != null) { if (commandLineOption.Name == "parse") { options.ToParse = true; } else if (commandLineOption.Name == "generate") { options.ToGenerate = true; } else if (commandLineOption.Name == "nologo") { options.HasNoLogo = true; } else if (commandLineOption.Name == "help") { // we print usage and stop processing PrintUsage(); errorMessage = null; options = null; return; } else if (commandLineOption.Name == "verbose") { options.IsVerbose = true; } // the following ones need value else if (commandLineOption.Name == "out") { options.Output = commandLineOption.Value; } else if (commandLineOption.Name == "translation") { options.Translations = commandLineOption.Value; } else if (commandLineOption.Name == "asmpath") { if (options.AssemblyPaths == null) { options.AssemblyPaths = new ArrayList(); } options.AssemblyPaths.Add(commandLineOption.Value); } else if (commandLineOption.Name == "culture") { try { options.CultureInfo = new CultureInfo(commandLineOption.Value); } catch (ArgumentException e) { // Error errorMessage = e.Message; return; } } else { // something that we don't recognize errorMessage = StringLoader.Get("Err_InvalidOption", commandLineOption.Name); return; } } // we passed all the test till here. Now check the combinations of the options errorMessage = options.CheckAndSetDefault(); }
/// <summary> /// Generate localized baml /// </summary> private static void GenerateBamlResources(LocBamlOptions options) { Stream input = File.OpenRead(options.Translations); GenerateBamlResourcesFromStream(options, input); }
/// <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; } } }
//-------------------------------------------------- // 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 ); // 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")); }
private static string GetAssemblyModuleLocalName(LocBamlOptions options, string targetAssemblyName) { string moduleName; if (targetAssemblyName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources.dll")) { // we create the satellite assembly name moduleName = string.Format( CultureInfo.InvariantCulture, "{0}.{1}.{2}", targetAssemblyName.Substring(0, targetAssemblyName.Length - ".resources.dll".Length), options.CultureInfo.Name, "resources.dll" ); } else { moduleName = targetAssemblyName; } return moduleName; }
/// <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(); } }
//----------------------------------------- // private function dealing with naming //----------------------------------------- // return the local output file name, i.e. without directory private static string GetOutputFileName(LocBamlOptions options) { string outputFileName; string inputFileName = Path.GetFileName(options.Input); switch(options.InputType) { case FileType.BAML: { return inputFileName; } case FileType.EXE: { inputFileName = inputFileName.Remove(inputFileName.LastIndexOf('.')) + ".resources.dll"; return inputFileName; } case FileType.DLL : { return inputFileName; } case FileType.RESOURCES : { // get the output file name outputFileName = inputFileName; // get to the last dot seperating filename and extension int lastDot = outputFileName.LastIndexOf('.'); int secondLastDot = outputFileName.LastIndexOf('.', lastDot - 1); if (secondLastDot > 0) { string cultureName = outputFileName.Substring(secondLastDot + 1, lastDot - secondLastDot - 1); if (LocBamlConst.IsValidCultureName(cultureName)) { string extension = outputFileName.Substring(lastDot); string frontPart = outputFileName.Substring(0, secondLastDot + 1); outputFileName = frontPart + options.CultureInfo.Name + extension; } } return outputFileName; } default : { throw new NotSupportedException(); } } }
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(); } } }
/// <summary> /// get CommandLineOptions, return error message /// </summary> private static void GetCommandLineOptions(string[] args, out LocBamlOptions options, out string errorMessage) { CommandLine commandLine; try{ // "*" means the option must have a value. no "*" means the option can't have a value commandLine = new CommandLine(args, new string[]{ "parse", // /parse for update "generate", // /generate for generate "*out", // /out for output .csv|.txt when parsing, for output directory when generating "*culture", // /culture for culture name "*translation", // /translation for translation file, .csv|.txt "*asmpath", // /asmpath, for assembly path to look for references (TODO: add asmpath support) "nologo", // /nologo for not to print logo "help", // /help for help "verbose" // /verbose for verbose output } ); } catch (ArgumentException e) { errorMessage = e.Message; options = null; return; } if (commandLine.NumArgs + commandLine.NumOpts < 1) { PrintLogo(null); PrintUsage(); errorMessage = null; options = null; return; } options = new LocBamlOptions(); options.Input = commandLine.GetNextArg(); Option commandLineOption; while ( (commandLineOption = commandLine.GetNextOption()) != null) { if (commandLineOption.Name == "parse") { options.ToParse = true; } else if (commandLineOption.Name == "generate") { options.ToGenerate = true; } else if (commandLineOption.Name == "nologo") { options.HasNoLogo = true; } else if (commandLineOption.Name == "help") { // we print usage and stop processing PrintUsage(); errorMessage = null; options = null; return; } else if (commandLineOption.Name == "verbose") { options.IsVerbose = true; } // the following ones need value else if (commandLineOption.Name == "out") { options.Output = commandLineOption.Value; } else if (commandLineOption.Name == "translation") { options.Translations = commandLineOption.Value; } else if (commandLineOption.Name == "asmpath") { if (options.AssemblyPaths == null) { options.AssemblyPaths = new ArrayList(); } options.AssemblyPaths.Add(commandLineOption.Value); } else if (commandLineOption.Name == "culture") { try { options.CultureInfo = new CultureInfo(commandLineOption.Value); } catch (ArgumentException e) { // Error errorMessage = e.Message; return; } } else { // something that we don't recognize errorMessage = StringLoader.Get("Err_InvalidOption", commandLineOption.Name); return; } } // we passed all the test till here. Now check the combinations of the options errorMessage = options.CheckAndSetDefault(); }
/// <summary> /// constructor /// </summary> internal InputBamlStreamList(LocBamlOptions options) { _bamlStreams = new ArrayList(); switch(options.InputType) { case FileType.BAML: { _bamlStreams.Add( new BamlStream( Path.GetFileName(options.Input), File.OpenRead(options.Input) ) ); break; } case FileType.RESOURCES: { using (ResourceReader resourceReader = new ResourceReader(options.Input)) { // enumerate all bamls in a resources EnumerateBamlInResources(resourceReader, options.Input); } break; } case FileType.EXE: case FileType.DLL: { // for a dll, it is the same idea Assembly assembly = Assembly.LoadFrom(options.Input); foreach (string resourceName in assembly.GetManifestResourceNames()) { ResourceLocation resourceLocation = assembly.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 } Stream resourceStream = assembly.GetManifestResourceStream(resourceName); using (ResourceReader reader = new ResourceReader(resourceStream)) { EnumerateBamlInResources(reader, resourceName); } } break; } default: { Debug.Assert(false, "Not supported type"); break; } } }
private static void PrintLogo(LocBamlOptions option) { if (option == null || !option.HasNoLogo) { Console.WriteLine(StringLoader.Get("Msg_Copyright", GetAssemblyVersion())); } }
/// <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) { BamlLocalizableResourceKey key = (BamlLocalizableResourceKey)entry.Key; BamlLocalizableResource resource = (BamlLocalizableResource)entry.Value; // Output XlmData if (key.Uid.Contains("XmlData") && resource.Category == LocalizationCategory.None) resource.Category = LocalizationCategory.XmlData; // Ignore Category None or no content if (resource.Category == LocalizationCategory.None) continue; if (string.IsNullOrEmpty(resource.Content)) continue; // column 1: baml stream name writer.WriteColumn(bamlStreamList[i].Name); // 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(); } }