Holds a complete translation in any one language. The template (TemplateItems) will have told the language which id's/strings that needs translation.
示例#1
0
 public void MergeTranslation(IDictionary<string, TemplateItem> src, Translation dst)
 {
     // Our purpose here is to merge newly parsed message items (src) with those already stored in a translation repo (dst).
     // 1. Where an orphan msgid is found (present in the dst but not the src) we update it in the dst to remove all references.
     // 2. Where a src msgid is missing from dst, we simply ADD it to dst.
     // 3. Where a src msgid is present in dst, we update the item in the dst to match the src (references, comments, etc.).
     //
        // 1.
        // Simply remove all references from dst items, for now.
     foreach (TranslationItem dstItem in dst.Items.Values) {
         dstItem.References = null; }
        // 2. and 3.
     foreach (TemplateItem srcItem in src.Values) {
         TranslationItem dstItem = dst.Items.GetOrAdd(srcItem.MsgKey, k => new TranslationItem { MsgKey = srcItem.MsgKey });
         dstItem.MsgId = srcItem.MsgId;
         dstItem.References = srcItem.References;
         dstItem.ExtractedComments = srcItem.Comments;
      }
        // Persist changes.
     _repository.SaveTranslation(dst);
 }
示例#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>
        /// <returns>A complete translation object with all all translations and language values set.</returns>
        private Translation ParseTranslationFile(string langtag)
        {
            //todo: consider that lines we don't understand like headers from poedit and #| should be preserved and outputted again.

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

            string path = GetPathForLanguage(langtag);

            if (File.Exists(path)) {
                Console.WriteLine("Reading file: {0}", path);

                using (var fs = File.OpenText(path))
                {
                    // http://www.gnu.org/s/hello/manual/gettext/PO-Files.html

                    string line;
                    bool itemStarted = false;
                    while ((line = fs.ReadLine()) != null)
                    {
                        List<string> extractedComments = new List<string>();
                        List<string> translatorComments = new List<string>();
                        List<string> flags = new List<string>();
                        List<string> references = new List<string>();

                        //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(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 = fs.ReadLine()) != null && line.StartsWith("#"));
                        }

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

                        itemStarted = false;
                    }
                }
            }
            translation.Items = items;
            return translation;
        }
示例#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 = GetAbsoluteLocaleDir() + "/messages.pot";
            var POTDate = DateTime.Now;
            if (File.Exists(templateFilePath)) {
                POTDate = File.GetLastWriteTime(templateFilePath); }

            string filePath = GetPathForLanguage(translation.LanguageInformation.LanguageShortTag);
            string backupPath = GetPathForLanguage(translation.LanguageInformation.LanguageShortTag) + ".backup";
            if (File.Exists(filePath)) //we backup one version. more advanced backup solutions could be added here.
            {
                if (File.Exists(backupPath))
                {
                    File.Delete(backupPath);
                }
                System.IO.File.Move(filePath, backupPath);
            }

            if (File.Exists(filePath)) //we make sure the old file is removed first
            {
                File.Delete(filePath);
            }

            bool hasReferences = false;

            if (!File.Exists(filePath))
            {
                var fileInfo = new FileInfo(filePath);
                var dirInfo = new DirectoryInfo(Path.GetDirectoryName(filePath));
                if (!dirInfo.Exists)
                {
                    dirInfo.Create();
                }
                fileInfo.Create().Close();
            }

            using (StreamWriter stream = new StreamWriter(filePath))
            {
                Console.WriteLine("Writing file: {0}", filePath);
               // Establish ordering of items in PO file.
                var orderedItems = translation.Items.Values
                    .OrderBy(x => x.References == null || x.References.Count() == 0)
                        // 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: i18n.POTGenerator\\n\"");
                stream.WriteLine();

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

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

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

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

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

                    string prefix = hasReferences ? "" : prefix = "#~ ";

                    if (_settings.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("");
                }
            }
        }