Exemple #1
0
 /// <summary>
 /// Duplicate msgids encountered - Abort if the msgstr contains a reference, as
 /// duplicate msgids are now supported yet and will result in the msgstr not being expanded.
 /// </summary>
 void TestDuplicateEntry(MsgInfo duplicateEntry)
 {
     if (GetFirstReference(duplicateEntry.Msgstr_Value, 0) != null)
     {
         throw new LineException(duplicateEntry.Msgstr_Info, "Duplicate msgid \"" + duplicateEntry.Msgid_Value + "\" encountered - Aborting because this is not supported yet and the msgstr contains a reference which popp will fail to expand.");
     }
     else
     {
         ErrorEncountered(duplicateEntry.Msgstr_Info, "Duplicate msgid \"" + duplicateEntry.Msgid_Value + "\" encountered (non-fatal).");
     }
 }
Exemple #2
0
 /// <summary>
 /// Duplicate msgids encountered - Abort if the msgstr contains a reference, as
 /// duplicate msgids are now supported yet and will result in the msgstr not being expanded.
 /// </summary>
 void TestDuplicateEntry(MsgInfo duplicateEntry)
 {
     if (GetFirstReference(duplicateEntry.Msgstr_Value, 0) != null) {
         throw new LineException(duplicateEntry.Msgstr_Info, "Duplicate msgid \"" + duplicateEntry.Msgid_Value + "\" encountered - Aborting because this is not supported yet and the msgstr contains a reference which popp will fail to expand.");
     } else {
         ErrorEncountered(duplicateEntry.Msgstr_Info, "Duplicate msgid \"" + duplicateEntry.Msgid_Value + "\" encountered (non-fatal).");
     }
 }
Exemple #3
0
        /// <summary>
        /// Parse the PO formatted file into a dictionary of entries.
        /// </summary>
        Dictionary<string/*MsgInfo.UniqueID*/, MsgInfo> BuildMsgInfoDictionary(IEnumerable<LineInfo> lines)
        {
            Dictionary<string/*MsgInfo.UniqueID*/, MsgInfo> result = new Dictionary<string, MsgInfo>();

            // Add a whitespace entry to the end of the list, so our state machine can rely on
            // whitespace as an end-of-entry marker.
            IEnumerable<LineInfo> linesPlusWhitespace = lines.Concat(new LineInfo[]{new LineInfo(LineType.Whitespace, -1, "")});

            LineInfoState state = LineInfoState.FinishedEntry;
            MsgInfo newEntry = new MsgInfo();

            foreach (LineInfo line in linesPlusWhitespace) {

                // The state machine is small enough to do with a switch.
                //
                // The .PO formats is roughly like this:
                //
                //    Whitespace, followed by
                //    [Optional]# Comments, followed by
                //    [Optional]msgctxt, optionally followed by multi-line context string, followed by
                //    msgid, optionally followed by multi-line id string, followed by
                //    [Optional]msgid_plural - I'm not supporting plural forms, followed by
                //    msgstr, optionally followed by multi-line msg string, followed by
                //    [Optional]msgstr[x] - I'm not supporting plural forms, followed by
                //    EOF or Whitespace
                switch (state) {
                    case LineInfoState.FinishedEntry:
                        // We're looking for the start of the next entry

                        if (line.Type == LineType.Msgid) {
                            state = LineInfoState.AddingMsgid;
                            newEntry.Msgid_Value = ExtractString(line);

                        } else if (line.Type == LineType.Msgctxt) {
                            // msgctxt is optional, but if present it appears before the msgid
                            state = LineInfoState.AddingMsgctxt;
                            newEntry.Msgctxt_Value = ExtractString(line);

                        } else if (line.Type == LineType.Msgstr || line.Type == LineType.StrContinuation) {
                            // An entry can't start with a msgstr or string-continuation
                            ErrorEncountered(line, "Unexpected string or msgstr");
                        }
                        break;

                    case LineInfoState.AddingMsgctxt:

                        if (line.Type == LineType.StrContinuation) {
                            newEntry.Msgctxt_Value += ExtractString(line);

                        } else if (line.Type == LineType.Msgid) {
                            state = LineInfoState.AddingMsgid;
                            newEntry.Msgid_Value = ExtractString(line);

                        } else {
                            // msgctxt is optional, but if present it appears before the msgid
                            ErrorEncountered(line, "msgid not found after msgctxt");
                        }
                        break;

                    case LineInfoState.AddingMsgid:

                        if (line.Type == LineType.StrContinuation) {
                            newEntry.Msgid_Value += ExtractString(line);

                        } else if (line.Type == LineType.Msgstr) {
                            state = LineInfoState.AddingMsgstr;
                            newEntry.Msgstr_Value = ExtractString(line);
                            newEntry.Msgstr_Info = line;

                        } else if (line.Type == LineType.Msgid) {
                            // We can't have two msgids in a row!
                            if (line.Line.StartsWith("msgid_plural", true, CultureInfo.InvariantCulture)) {
                                ErrorEncountered(line, "Multiple msgids encountered, PO plural-forms are not currently supported :(");
                            } else {
                                ErrorEncountered(line, "Unexpected msgid");
                            }
                        }
                        break;

                    case LineInfoState.AddingMsgstr:

                        if (line.Type == LineType.StrContinuation) {
                            newEntry.Msgstr_Value += ExtractString(line);
                            newEntry.Msgstr_LineCount++;

                        } else if (line.Type == LineType.Whitespace) {
                            // We've found the end of the entry
                            state = LineInfoState.FinishedEntry;
                            if (newEntry.IsValid()) {
                                string uniqueID = newEntry.UniqueID(_options.CaseSensitiveIDs);
                                if (result.ContainsKey(uniqueID)) {
                                    // Duplicate msgids encountered - Abort if the msgstr contains a reference, as duplicate msgids are now supported yet and will result in the reference not expanding
                                    TestDuplicateEntry(newEntry);
                                } else {
                                    result.Add(newEntry.UniqueID(_options.CaseSensitiveIDs), newEntry);
                                }
                            } else {
                                ErrorEncountered(line, "[End found of] invalid entry");
                            }
                            newEntry = new MsgInfo();

                        } else if (line.Type == LineType.Msgstr) {
                            // Multiple msgstrs encountered, PO plural-forms are not currently supported :(
                            TestPluralForm(line);

                        } else {
                            ErrorEncountered(line, "Unexpected line encountered at end of entry \"" + newEntry.Msgid_Value + "\" (was expecting whitespace)");
                        }
                        break;
                }
            }

            return result;
        }
Exemple #4
0
        /// <summary>
        /// Run the preprocessor
        /// </summary>
        /// <param name="inputDirectory">Note - can be null</param>
        /// <returns>errorLevel, or 0 for success</returns>
        /// <param name="inputDirectory">The directory that contained the source file that was supplied to popp, or null (e.g. if stdin was the source)</param>
        public int Process(TextReader inputReader, string inputDirectory, TextWriter outputWriter)
        {
            int unexpandableReferenceCount = 0;

            _errorLevel = 0;

            try {
                // Build a list of information about each line, expanding any $include statements
                IEnumerable <LineInfo> lines = BuildListOfLines(inputReader, inputDirectory, true);

                // Todo:
                // This is where we'll apply the $if $else etc conditional directives
                // lines = ApplyConditionalDirectives(lines);

                // Build a dictionary of translation items
                Dictionary <string /*MsgInfo.UniqueID*/, MsgInfo> keyValues = BuildMsgInfoDictionary(lines);

                int expandedReferenceCount;
                unexpandableReferenceCount = ExpandMsgstrs(keyValues, out expandedReferenceCount);

                // Write out the file with any adjusted msgstr entries...

                // build a second dictionary of the msgstrs we are changing, indexed by the linenumber
                Dictionary <int /*msgstr_lineNumber*/, MsgInfo> alteredMsgstrLines = new Dictionary <int, MsgInfo>();
                foreach (MsgInfo msgInfo in keyValues.Values)
                {
                    if (msgInfo.Msgstr_ContainsChanges)
                    {
                        alteredMsgstrLines.Add(msgInfo.Msgstr_Info.LineNumber, msgInfo);
                    }
                }

                // Write the lines to the output file, with any adjusted msgstr entries
                int linesToSkip = 0;
                foreach (LineInfo lineInfo in lines)
                {
                    if (linesToSkip > 0)
                    {
                        // skip over the multiline source strings if we have already written out our own version
                        linesToSkip--;
                    }
                    else
                    {
                        bool    replaceLineWithAdjustedMsgstr = false;
                        MsgInfo msgInfo = null;
                        if (alteredMsgstrLines.TryGetValue(lineInfo.LineNumber, out msgInfo))
                        {
                            // We have our own version of this line
                            if (msgInfo.Msgstr_ContainsChanges)
                            {
                                replaceLineWithAdjustedMsgstr = true;
                            }
                        }

                        // Only change the lines in the file that we need to, so all whitespace and weird user
                        // formatting etc will be preserved.
                        if (replaceLineWithAdjustedMsgstr)
                        {
                            outputWriter.WriteLine("msgstr \"" + msgInfo.Msgstr_Value + "\"");
                            linesToSkip = msgInfo.Msgstr_LineCount;
                        }
                        else
                        {
                            outputWriter.WriteLine(lineInfo.Line);
                        }
                    }
                }
                outputWriter.Close();

                DisplayInfo("Done - Expanded " + expandedReferenceCount + " references");
                if (unexpandableReferenceCount > 0)
                {
                    DisplayInfo("       Failed to expand " + unexpandableReferenceCount + " references");
                }
            } catch (LineException ex) {
                ErrorEncountered(ex.LineInfo, ex.Message);
                _errorLevel = (int)ErrorLevel.FatalError_Internal;
            } catch (Exception ex) {
                ErrorEncountered("Unexpected internal error - " + ex);
                _errorLevel = (int)ErrorLevel.FatalError_Internal;
            }

            // If the preprocessing was successful, then return the number of references
            // we found which could not be expanded, as a negative number (to prevent
            // confusion with the error codes)
            if (_errorLevel == 0)
            {
                _errorLevel = -unexpandableReferenceCount;
            }

            return(_errorLevel);
        }
Exemple #5
0
        /// <summary>
        /// Parse the PO formatted file into a dictionary of entries.
        /// </summary>
        Dictionary <string /*MsgInfo.UniqueID*/, MsgInfo> BuildMsgInfoDictionary(IEnumerable <LineInfo> lines)
        {
            Dictionary <string /*MsgInfo.UniqueID*/, MsgInfo> result = new Dictionary <string, MsgInfo>();

            // Add a whitespace entry to the end of the list, so our state machine can rely on
            // whitespace as an end-of-entry marker.
            IEnumerable <LineInfo> linesPlusWhitespace = lines.Concat(new LineInfo[] { new LineInfo(LineType.Whitespace, -1, "") });

            LineInfoState state    = LineInfoState.FinishedEntry;
            MsgInfo       newEntry = new MsgInfo();

            foreach (LineInfo line in linesPlusWhitespace)
            {
                // The state machine is small enough to do with a switch.
                //
                // The .PO formats is roughly like this:
                //
                //    Whitespace, followed by
                //    [Optional]# Comments, followed by
                //    [Optional]msgctxt, optionally followed by multi-line context string, followed by
                //    msgid, optionally followed by multi-line id string, followed by
                //    [Optional]msgid_plural - I'm not supporting plural forms, followed by
                //    msgstr, optionally followed by multi-line msg string, followed by
                //    [Optional]msgstr[x] - I'm not supporting plural forms, followed by
                //    EOF or Whitespace
                switch (state)
                {
                case LineInfoState.FinishedEntry:
                    // We're looking for the start of the next entry

                    if (line.Type == LineType.Msgid)
                    {
                        state = LineInfoState.AddingMsgid;
                        newEntry.Msgid_Value = ExtractString(line);
                    }
                    else if (line.Type == LineType.Msgctxt)
                    {
                        // msgctxt is optional, but if present it appears before the msgid
                        state = LineInfoState.AddingMsgctxt;
                        newEntry.Msgctxt_Value = ExtractString(line);
                    }
                    else if (line.Type == LineType.Msgstr || line.Type == LineType.StrContinuation)
                    {
                        // An entry can't start with a msgstr or string-continuation
                        ErrorEncountered(line, "Unexpected string or msgstr");
                    }
                    break;

                case LineInfoState.AddingMsgctxt:

                    if (line.Type == LineType.StrContinuation)
                    {
                        newEntry.Msgctxt_Value += ExtractString(line);
                    }
                    else if (line.Type == LineType.Msgid)
                    {
                        state = LineInfoState.AddingMsgid;
                        newEntry.Msgid_Value = ExtractString(line);
                    }
                    else
                    {
                        // msgctxt is optional, but if present it appears before the msgid
                        ErrorEncountered(line, "msgid not found after msgctxt");
                    }
                    break;

                case LineInfoState.AddingMsgid:

                    if (line.Type == LineType.StrContinuation)
                    {
                        newEntry.Msgid_Value += ExtractString(line);
                    }
                    else if (line.Type == LineType.Msgstr)
                    {
                        state = LineInfoState.AddingMsgstr;
                        newEntry.Msgstr_Value = ExtractString(line);
                        newEntry.Msgstr_Info  = line;
                    }
                    else if (line.Type == LineType.Msgid)
                    {
                        // We can't have two msgids in a row!
                        if (line.Line.StartsWith("msgid_plural", true, CultureInfo.InvariantCulture))
                        {
                            ErrorEncountered(line, "Multiple msgids encountered, PO plural-forms are not currently supported :(");
                        }
                        else
                        {
                            ErrorEncountered(line, "Unexpected msgid");
                        }
                    }
                    break;

                case LineInfoState.AddingMsgstr:

                    if (line.Type == LineType.StrContinuation)
                    {
                        newEntry.Msgstr_Value += ExtractString(line);
                        newEntry.Msgstr_LineCount++;
                    }
                    else if (line.Type == LineType.Whitespace)
                    {
                        // We've found the end of the entry
                        state = LineInfoState.FinishedEntry;
                        if (newEntry.IsValid())
                        {
                            string uniqueID = newEntry.UniqueID(_options.CaseSensitiveIDs);
                            if (result.ContainsKey(uniqueID))
                            {
                                // Duplicate msgids encountered - Abort if the msgstr contains a reference, as duplicate msgids are now supported yet and will result in the reference not expanding
                                TestDuplicateEntry(newEntry);
                            }
                            else
                            {
                                result.Add(newEntry.UniqueID(_options.CaseSensitiveIDs), newEntry);
                            }
                        }
                        else
                        {
                            ErrorEncountered(line, "[End found of] invalid entry");
                        }
                        newEntry = new MsgInfo();
                    }
                    else if (line.Type == LineType.Msgstr)
                    {
                        // Multiple msgstrs encountered, PO plural-forms are not currently supported :(
                        TestPluralForm(line);
                    }
                    else
                    {
                        ErrorEncountered(line, "Unexpected line encountered at end of entry \"" + newEntry.Msgid_Value + "\" (was expecting whitespace)");
                    }
                    break;
                }
            }

            return(result);
        }