diff --git a/Claunia.Localization.Parsers/Claunia.Localization.Parsers.csproj b/Claunia.Localization.Parsers/Claunia.Localization.Parsers.csproj new file mode 100644 index 0000000..5576201 --- /dev/null +++ b/Claunia.Localization.Parsers/Claunia.Localization.Parsers.csproj @@ -0,0 +1,11 @@ + + + + netstandard1.6 + + + + + + + diff --git a/Claunia.Localization.Parsers/GetText.cs b/Claunia.Localization.Parsers/GetText.cs new file mode 100644 index 0000000..f81cc29 --- /dev/null +++ b/Claunia.Localization.Parsers/GetText.cs @@ -0,0 +1,287 @@ +using System; +using System.IO; +using System.Text; +using Claunia.Localization.Core; + +namespace Claunia.Localization.Parsers +{ + public static class GetText + { + public static Core.Localization Parse(string catalog) + { + using(StringReader sr = new StringReader(catalog)) return Parse(sr); + } + + public static Core.Localization Parse(string path, Encoding encoding) + { + using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + using(StreamReader sr = new StreamReader(fs, encoding)) return Parse(sr); + } + } + + public static Core.Localization Parse(Stream catalog) + { + using(StreamReader sr = new StreamReader(catalog)) return Parse(sr); + } + + public static Core.Localization Parse(TextReader catalog) + { + Core.Localization localization = new Core.Localization(); + + string line = ""; + string currentMsgId = ""; + string currentMsgString = ""; + Translator currentTranslator = null; + string currentLocale = null; + bool firstEmptyMessageId = true; + string currentComment = ""; + string extractedComment = ""; + string currentReference = ""; + string currentContext = ""; + var currentLanguage = Language.None; + + while(line != null) + { + line = catalog.ReadLine(); + + if(line is null) break; + + if(line == string.Empty) + { + if(!firstEmptyMessageId) + { + var message = localization.NewMessage(); + + message.Comments = extractedComment; + message.Context = currentContext; + message.Reference = currentReference; + message.Source.Singular = currentMsgId; + message.Id = currentMsgId; + var localizedString = message.NewLocalizedString(); + + localizedString.Comments = currentComment; + localizedString.Locale = currentLocale; + localizedString.Singular = currentMsgString; + localizedString.Translator = currentTranslator?.Id; + } + + firstEmptyMessageId = false; + currentMsgId = ""; + currentMsgString = ""; + currentComment = ""; + extractedComment = ""; + currentReference = ""; + currentContext = ""; + continue; // TODO + } + + if(line[0] == '#') + { + if(line.Length == 1) + { + if(!firstEmptyMessageId) + currentComment += "\n"; + continue; + } + + switch(line[1]) + { + case ' ': + if(firstEmptyMessageId) break; + + currentComment += line.Substring(2) + "\n"; + continue; + case '.': + extractedComment += line.Substring(2) + "\n"; + continue; + case ':': + currentReference += line.Substring(2) + "\n"; + continue; + case ',': + var flags = line.Substring(2); + + if(flags.StartsWith("no-")) + { + currentLanguage = Language.None; + continue; + } + + switch(flags) + { + case "fuzzy": continue; + case "c-format": + currentLanguage = Language.C; + continue; + case "objc-format": + currentLanguage = Language.ObjectiveC; + continue; + case "sh-format": + currentLanguage = Language.Shell; + continue; + case "python-format": + currentLanguage = Language.Python; + continue; + case "python-brace-format": + currentLanguage = Language.PythonBraced; + continue; + case "lisp-format": + currentLanguage = Language.Lisp; + continue; + case "elisp-format": + currentLanguage = Language.EmacsLisp; + continue; + case "librep-format": + currentLanguage = Language.Librep; + continue; + case "scheme-format": + currentLanguage = Language.Scheme; + continue; + case "smalltalk-format": + currentLanguage = Language.Smalltalk; + continue; + case "java-format": + currentLanguage = Language.Java; + continue; + case "csharp-format": + currentLanguage = Language.CSharp; + continue; + case "awk-format": + currentLanguage = Language.Awk; + continue; + case "object-pascal-format": + currentLanguage = Language.ObjectPascal; + continue; + case "ycp-format": + currentLanguage = Language.Ycp; + continue; + case "tcl-format": + currentLanguage = Language.Tcl; + continue; + case "perl-format": + currentLanguage = Language.Perl; + continue; + case "perl-brace-format": + currentLanguage = Language.PerlBraced; + continue; + case "php-format": + currentLanguage = Language.Php; + continue; + case "gcc-internal-format": + currentLanguage = Language.GccInternal; + continue; + case "gfc-internal-format": + currentLanguage = Language.GfcInternal; + continue; + case "qt-format": + currentLanguage = Language.Qt; + continue; + case "qt-plural-format": + currentLanguage = Language.QtPlural; + continue; + case "kde-format": + currentLanguage = Language.Kde; + continue; + case "boost-format": + currentLanguage = Language.Boost; + continue; + case "lua-format": + currentLanguage = Language.Lua; + continue; + case "javascript-format": + currentLanguage = Language.JavaScript; + continue; + default: + currentLanguage = Language.None; + continue; + } + case '|': break; + } + } + + if(line.StartsWith("msgid ", StringComparison.Ordinal)) + { + currentMsgId += line.Substring(7, line.Length - 8); + continue; + } + + if(line.StartsWith("msgstr ", StringComparison.Ordinal)) + { + currentMsgString = line.Substring(7, line.Length - 8); + continue; + } + + if(line[0] == '"') + { + if(currentMsgId != string.Empty) + { + currentMsgString += line.Substring(1, line.Length - 2); + continue; + } + + var projectString = line.Substring(1, line.Length - 2); + + if(projectString.StartsWith("Project-Id-Version", StringComparison.Ordinal)) + { + var projectIdVersion = projectString.Substring(20, projectString.Length - 20); + if(projectIdVersion.EndsWith("\\n", StringComparison.Ordinal)) + { + projectIdVersion = projectIdVersion.Substring(0, projectIdVersion.Length - 2); + } + + localization.Project.Name = projectIdVersion; + continue; + } + + if(projectString.StartsWith("Report-Msgid-Bugs-To", StringComparison.Ordinal)) + { + var projectReportTo = projectString.Substring(22, projectString.Length - 22); + if(projectReportTo.EndsWith("\\n", StringComparison.Ordinal)) + { + projectReportTo = projectReportTo.Substring(0, projectReportTo.Length - 2); + } + + localization.Project.Url = projectReportTo; + continue; + } + + if(projectString.StartsWith("Last-Translator", StringComparison.Ordinal)) + { + var lastTranslator = projectString.Substring(17, projectString.Length - 17); + if(lastTranslator.EndsWith("\\n", StringComparison.Ordinal)) + { + lastTranslator = lastTranslator.Substring(0, lastTranslator.Length - 2); + } + + if(lastTranslator[lastTranslator.Length - 1] == '>') + { + var emailStart = lastTranslator.LastIndexOf('<'); + var name = lastTranslator.Substring(0, emailStart - 1); + var email = lastTranslator.Substring(emailStart + 1, + lastTranslator.Length - emailStart - 2); + + currentTranslator = localization.NewTranslator(name, email); + } + else + currentTranslator = localization.NewTranslator(lastTranslator, null); + + continue; + } + + if(projectString.StartsWith("Language", StringComparison.Ordinal)) + { + currentLocale = projectString.Substring(10, projectString.Length - 10); + if(currentLocale.EndsWith("\\n", StringComparison.Ordinal)) + { + currentLocale = currentLocale.Substring(0, currentLocale.Length - 2); + } + + continue; + } + } + } + + return localization; + } + } +} \ No newline at end of file