Exemplo n.º 1
0
        void ParseFile(string projectDirectory, string filePath, ConcurrentDictionary <string, TemplateItem> templateItems)
        {
            var referencePath = PathNormalizer.MakeRelativePath(projectDirectory, filePath);

            DebugHelpers.WriteLine("FileNuggetFinder.ParseFile -- {0}", filePath);
            // Lookup any/all nuggets in the file and for each add a new template item.
            using var fs           = I18NUtility.Retry(() => File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read), 3);
            using var streamReader = new StreamReader(fs);

            _nuggetParser.ParseString(streamReader.ReadToEnd(), delegate(string nuggetString, int pos, Nugget nugget, string iEntity)
            {
                var referenceContext = _localizationOptions.DisableReferences
                    ? ReferenceContext.Create("Disabled references", iEntity, 0)
                    : ReferenceContext.Create(referencePath, iEntity, pos);
                var fileName = Path.GetFileNameWithoutExtension(filePath);
                // If we have a file like "myfile.aspx.vb" then the fileName will be "myfile.aspx" resulting in split
                // .pot files. So remove all extensions, so that we just have the actual name to deal with.
                fileName = fileName.IndexOf('.') > -1 ? fileName.Split('.')[0] : fileName;

                AddNewTemplateItem(
                    fileName,
                    referenceContext,
                    nugget,
                    templateItems);
                // Done.
                return(null); // null means we are not modifying the entity.
            });
        }
Exemplo n.º 2
0
        /// <summary>
        /// Parses a PO file into a Language object
        /// </summary>
        /// <param name="langTag">The language (tag) you wish to load into Translation object</param>
        /// <param name="fileNames"></param>
        /// <param name="loadingCache"></param>
        /// <returns>A complete translation object with all all translations and language values set.</returns>
        Translation ParseTranslationFile(string langTag, List <string> fileNames, bool loadingCache)
        {
            //todo: consider that lines we don't understand like headers from poedit and #| should be preserved and outputted again.

            var translation = new Translation();
            var language    = new Language
            {
                LanguageShortTag = langTag
            };

            translation.LanguageInformation = language;
            var items = new ConcurrentDictionary <string, TranslationItem>();

            var paths = new List <string>();

            if (!_localizationOptions.GenerateTemplatePerFile || loadingCache)
            {
                paths.Add(GetPathForLanguage(langTag));
            }

            paths.AddRange(_localizationOptions.LocaleOtherFiles.Where(file => file.IsSet()).Select(file => GetPathForLanguage(langTag, file)));

            if (_localizationOptions.GenerateTemplatePerFile && !loadingCache)
            {
                if (fileNames != null && fileNames.Count > 0)
                {
                    paths.AddRange(fileNames.Select(fileName => GetPathForLanguage(langTag, fileName)));
                }
            }

            foreach (var path in paths.Where(File.Exists))
            {
                DebugHelpers.WriteLine("Reading file: {0}", path);

                using var fs           = I18NUtility.Retry(() => File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read), 3);
                using var streamReader = new StreamReader(fs);

                // http://www.gnu.org/s/hello/manual/gettext/PO-Files.html

                string line;
                var    itemStarted = false;
                while ((line = streamReader.ReadLine()) != null)
                {
                    var extractedComments  = new HashSet <string>();
                    var translatorComments = new HashSet <string>();
                    var flags      = new HashSet <string>();
                    var references = new List <ReferenceContext>();

                    //read all comments, flags and other descriptive items for this string
                    //if we have #~ its a historical/log entry but it is the messageID/message so we skip this do/while
                    if (line.StartsWith("#") && !line.StartsWith("#~"))
                    {
                        do
                        {
                            itemStarted = true;
                            switch (line[1])
                            {
                            case '.':     //Extracted comments
                                extractedComments.Add(line.Substring(2).Trim());
                                break;

                            case ':':     //references
                                references.Add(ReferenceContext.Parse(line.Substring(2).Trim()));
                                break;

                            case ',':     //flags
                                flags.Add(line.Substring(2).Trim());
                                break;

                            case '|':     //msgid previous-untranslated-string - NOT used by us
                                break;

                            default:     //translator comments
                                translatorComments.Add(line.Substring(1).Trim());
                                break;
                            }
                        } while ((line = streamReader.ReadLine()) != null && line.StartsWith("#"));
                    }

                    if (line != null && (itemStarted || line.StartsWith("#~")))
                    {
                        var item = ParseBody(streamReader, line);
                        if (item != null)
                        {
                            //
                            item.TranslatorComments = translatorComments;
                            item.ExtractedComments  = extractedComments;
                            item.Flags      = flags;
                            item.References = references;
                            //
                            items.AddOrUpdate(
                                item.MsgKey,
                                // Add routine.
                                k => item,
                                // Update routine.
                                (k, v) =>
                            {
                                v.References             = v.References.Append(item.References);
                                var referencesAsComments =
                                    item.References.Select(r => r.ToComment()).ToList();
                                v.ExtractedComments  = v.ExtractedComments.Append(referencesAsComments);
                                v.TranslatorComments = v.TranslatorComments.Append(referencesAsComments);
                                v.Flags = v.Flags.Append(referencesAsComments);
                                return(v);
                            });
                        }
                    }

                    itemStarted = false;
                }
            }
            translation.Items = items;
            return(translation);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Saves a translation into file with standard pattern locale/langtag/message.po
        /// Also saves a backup of previous version
        /// </summary>
        /// <param name="translation">The translation you wish to save. Must have Language shortag filled out.</param>
        public void SaveTranslation(Translation translation)
        {
            var templateFilePath = Path.Combine(GetAbsoluteLocaleDir(), _localizationOptions.LocaleFilename + ".pot");
            var potDate          = DateTime.Now;

            if (File.Exists(templateFilePath))
            {
                potDate = File.GetLastWriteTime(templateFilePath);
            }

            var filePath = GetPathForLanguage(translation.LanguageInformation.LanguageShortTag);

            using var fs     = I18NUtility.Retry(() => File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.Write), 3);
            using var stream = new StreamWriter(fs);
            DebugHelpers.WriteLine("Writing file: {0}", filePath);

            // Establish ordering of items in PO file.
            var orderedItems = translation.Items.Values
                               .OrderBy(x => x.References == null || !x.References.Any())
                               // Non-orphan items before orphan items.
                               .ThenBy(x => x.MsgKey);

            // Then order alphanumerically.

            //This is required for poedit to read the files correctly if they contains for instance swedish characters
            stream.WriteLine("msgid \"\"");
            stream.WriteLine("msgstr \"\"");
            stream.WriteLine("\"Project-Id-Version: \\n\"");
            stream.WriteLine("\"POT-Creation-Date: " + potDate.ToString("yyyy-MM-dd HH:mmzzz") + "\\n\"");
            stream.WriteLine("\"PO-Revision-Date: " + DateTime.Now.ToString("yyyy-MM-dd HH:mmzzz") + "\\n\"");
            stream.WriteLine("\"MIME-Version: 1.0\\n\"");
            stream.WriteLine("\"Content-Type: text/plain; charset=utf-8\\n\"");
            stream.WriteLine("\"Content-Transfer-Encoding: 8bit\\n\"");
            stream.WriteLine($"\"X-Generator: pot ({_assemblyVersion})\\n\"");
            stream.WriteLine();

            foreach (var item in orderedItems)
            {
                var hasReferences = false;

                if (item.TranslatorComments != null)
                {
                    foreach (var translatorComment in item.TranslatorComments.Distinct())
                    {
                        stream.WriteLine("# " + translatorComment);
                    }
                }

                if (item.ExtractedComments != null)
                {
                    foreach (var extractedComment in item.ExtractedComments.Distinct())
                    {
                        stream.WriteLine("#. " + extractedComment);
                    }
                }

                if (item.References != null)
                {
                    foreach (var reference in item.References.Distinct())
                    {
                        hasReferences = true;
                        stream.WriteLine("#: " + reference.ToComment());
                    }
                }

                if (item.Flags != null)
                {
                    foreach (var flag in item.Flags.Distinct())
                    {
                        stream.WriteLine("#, " + flag);
                    }
                }

                if (_localizationOptions.MessageContextEnabledFromComment &&
                    item.ExtractedComments != null &&
                    item.ExtractedComments.Count() != 0)
                {
                    WriteString(stream, hasReferences, "msgctxt", item.ExtractedComments.First());
                }

                WriteString(stream, hasReferences, "msgid", Escape(item.MsgId));
                WriteString(stream, hasReferences, "msgstr", Escape(item.Message));

                stream.WriteLine("");
            }
        }