Exemple #1
0
        internal static BamlLocalizableResourceKey StringToResourceKey(string value)
        {
            int nameEnd = value.LastIndexOf(':');

            if (nameEnd < 0)
            {
                throw new ArgumentException(StringLoader.Get("ResourceKeyFormatError"));
            }

            string name     = value.Substring(0, nameEnd);
            int    classEnd = value.LastIndexOf('.');

            if (classEnd < 0 || classEnd < nameEnd || classEnd == value.Length)
            {
                throw new ArgumentException(StringLoader.Get("ResourceKeyFormatError"));
            }

            string className    = value.Substring(nameEnd + 1, classEnd - nameEnd - 1);
            string propertyName = value.Substring(classEnd + 1);

            return(new BamlLocalizableResourceKey(
                       name,
                       className,
                       propertyName
                       ));
        }
        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);
            }
        }
        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);
                }
            }
        }
Exemple #5
0
        /// <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);
            }
        }
        /// <summary>
        /// return true if the operation succeeded.
        /// otherwise, return false
        /// </summary>
        internal string CheckAndSetDefault()
        {
            // we validate the options here and also set default
            // if we can

            // Rule #1: One and only one action at a time
            // i.e. Can't parse and generate at the same time
            //      Must do one of them
            if ((ToParse && ToGenerate) ||
                (!ToParse && !ToGenerate))
            {
                return(StringLoader.Get("MustChooseOneAction"));
            }

            // Rule #2: Must have an input
            if (string.IsNullOrEmpty(InputFile))
            {
                return(StringLoader.Get("InputFileRequired"));
            }
            else
            {
                if (!File.Exists(InputFile))
                {
                    return(StringLoader.Get("FileNotFound", InputFile));
                }

                string extension = Path.GetExtension(InputFile);

                // Get the input file type.
                if (string.Compare(extension, "." + FileType.BAML.ToString(), true, CultureInfo.InvariantCulture) == 0)
                {
                    InputType = FileType.BAML;
                }
                else if (string.Compare(extension, "." + FileType.RESOURCES.ToString(), true, CultureInfo.InvariantCulture) == 0)
                {
                    InputType = FileType.RESOURCES;
                }
                else if (string.Compare(extension, "." + FileType.DLL.ToString(), true, CultureInfo.InvariantCulture) == 0)
                {
                    InputType = FileType.DLL;
                }
                else if (string.Compare(extension, "." + FileType.EXE.ToString(), true, CultureInfo.InvariantCulture) == 0)
                {
                    InputType = FileType.EXE;
                }
                else
                {
                    return(StringLoader.Get("FileTypeNotSupported", extension));
                }
            }

            if (ToGenerate)
            {
                // Rule #3: before generation, we must have Culture string
                if (CultureInfo == null && InputType != FileType.BAML)
                {
                    // if we are not generating baml,
                    return(StringLoader.Get("CultureNameNeeded", InputType.ToString()));
                }

                // Rule #4: before generation, we must have translation file
                if (string.IsNullOrEmpty(TranslationsFile))
                {
                    return(StringLoader.Get("TranslationNeeded"));
                }
                else
                {
                    string extension = Path.GetExtension(TranslationsFile);

                    if (!File.Exists(TranslationsFile))
                    {
                        return(StringLoader.Get("TranslationNotFound", TranslationsFile));
                    }
                    else
                    {
                        if (string.Compare(extension, "." + FileType.CSV.ToString(), true, CultureInfo.InvariantCulture) == 0)
                        {
                            TranslationFileType = FileType.CSV;
                        }
                        else
                        {
                            TranslationFileType = FileType.TXT;
                        }
                    }
                }
            }



            // Rule #5: If the output file name is empty, we act accordingly
            if (string.IsNullOrEmpty(OutputFileOrDirectory))
            {
                // Rule #5.1: If it is parse, we default to [input file name].csv
                if (ToParse)
                {
                    string fileName = Path.GetFileNameWithoutExtension(InputFile);
                    OutputFileOrDirectory = fileName + "." + FileType.CSV.ToString();
                    TranslationFileType   = FileType.CSV;
                }
                else
                {
                    // Rule #5.2: If it is generating, and the output can't be empty
                    return(StringLoader.Get("OutputDirectoryNeeded"));
                }
            }
            else
            {
                // output isn't null, we will determind the Output file type
                // Rule #6: if it is parsing. It will be .csv or .txt.
                if (ToParse)
                {
                    string fileName;
                    string outputDir;

                    if (Directory.Exists(OutputFileOrDirectory))
                    {
                        // the output is actually a directory name
                        fileName  = string.Empty;
                        outputDir = OutputFileOrDirectory;
                    }
                    else
                    {
                        // get the extension
                        fileName  = Path.GetFileName(OutputFileOrDirectory);
                        outputDir = Path.GetDirectoryName(OutputFileOrDirectory);
                    }

                    // Rule #6.1: if it is just the output directory
                    // we append the input file name as the output + csv as default
                    if (string.IsNullOrEmpty(fileName))
                    {
                        TranslationFileType   = FileType.CSV;
                        OutputFileOrDirectory = outputDir
                                                + Path.DirectorySeparatorChar
                                                + Path.GetFileName(InputFile)
                                                + "."
                                                + TranslationFileType.ToString();
                    }
                    else
                    {
                        // Rule #6.2: if we have file name, check the extension.
                        string extension = Path.GetExtension(OutputFileOrDirectory);

                        // ignore case and invariant culture
                        if (string.Compare(extension, "." + FileType.CSV.ToString(), true, CultureInfo.InvariantCulture) == 0)
                        {
                            TranslationFileType = FileType.CSV;
                        }
                        else
                        {
                            // just consider the output as txt format if it doesn't have .csv extension
                            TranslationFileType = FileType.TXT;
                        }
                    }
                }
                else
                {
                    // it is to generate. And Output should point to the directory name.
                    if (!Directory.Exists(OutputFileOrDirectory))
                    {
                        return(StringLoader.Get("OutputDirectoryError", OutputFileOrDirectory));
                    }
                }
            }

            // Rule #7: if the input assembly path is not null
            if (AssemblyPaths != null && AssemblyPaths.Count > 0)
            {
                Assemblies = new Assembly[AssemblyPaths.Count];
                for (int i = 0; i < Assemblies.Length; i++)
                {
                    string errorMsg = null;
                    try
                    {
                        // load the assembly
                        Assemblies[i] = Assembly.LoadFrom((string)AssemblyPaths[i]);
                    }
                    catch (ArgumentException argumentError)
                    {
                        errorMsg = argumentError.Message;
                    }
                    catch (BadImageFormatException formatError)
                    {
                        errorMsg = formatError.Message;
                    }
                    catch (FileNotFoundException fileError)
                    {
                        errorMsg = fileError.Message;
                    }
                    catch (PathTooLongException pathError)
                    {
                        errorMsg = pathError.Message;
                    }
                    catch (SecurityException securityError)
                    {
                        errorMsg = securityError.Message;
                    }

                    if (errorMsg != null)
                    {
                        return(errorMsg); // return error message when loading this assembly
                    }
                }
            }

            // if we come to this point, we are all fine, return null error message
            return(null);
        }