private void ExtractComments(POKey key, POSingularEntry entry) { foreach (var comment in entry.Comments) { if (!(comment is POTranslatorComment translatorComment)) { continue; } var commentText = translatorComment.Text; if (string.IsNullOrEmpty(commentText)) { continue; } commentText = commentText.Replace(PartialMatchComment, "").Trim(new char[] { ';', ' ' }); if (string.IsNullOrEmpty(commentText)) { continue; } if (Comments.ContainsKey(key.Id)) { Debug.WriteLine($"Duplicate translator comment: '{commentText}'"); continue; } Comments[key.Id] = commentText; } }
bool TryGetTranslationCore(POKey key, int pluralCount, out string value, POCatalog catalog = null) { if (catalog == null) { catalog = Catalog; } if (catalog != null) { var translation = catalog.GetTranslation(key, pluralCount); if (translation != null) { value = translation; return(true); } else { translation = ParentCultureCatalog?.GetTranslation(key, pluralCount); if (translation != null) { value = translation; return(true); } else if (Options.Value.FallBackNeutralCulture && catalog.GetCultureName() != Settings.NeutralCulture) { return(TryGetTranslationCore(key, pluralCount, out value, FallBackCatalog)); } } } value = null; return(false); }
void CheckItems(POCatalog catalog, bool expectComments) { var key1 = new POKey("{0} hour to midnight", "{0} hours to midnight", "Home"); var key2 = new POKey($"Here is an example of how one might continue a very long string{Environment.NewLine}" + $"for the common case the string represents multi-line output.{Environment.NewLine}"); Assert.Equal(2, catalog.Count); Assert.Contains(key1, catalog.Keys); Assert.Contains(key2, catalog.Keys); Assert.Equal(2, catalog[key1].Count); Assert.Equal("Translation of {0} hour to midnight", catalog.GetTranslation(key1, 1)); Assert.Equal("Translation of {0} hours to midnight", catalog[key1][1]); Assert.Equal("Translation of {0} hour to midnight", catalog.GetTranslation(key1, 1)); Assert.Equal("Translation of {0} hours to midnight", catalog.GetTranslation(key1, 2)); Assert.Equal(1, catalog[key2].Count); Assert.Equal("Some translation of long text", catalog[key2][0]); if (expectComments) { Assert.Equal(6, catalog[key1].Comments.Count); Assert.Equal(0, catalog[key2].Comments.Count); var comments = catalog[key1].Comments; Assert.Equal(POCommentKind.Translator, comments[0].Kind); Assert.Equal("some translator comment", ((POTranslatorComment)comments[0]).Text); Assert.Equal(POCommentKind.Extracted, comments[1].Kind); Assert.Equal("some extracted comment", ((POExtractedComment)comments[1]).Text); Assert.Equal(POCommentKind.Reference, comments[2].Kind); var references = ((POReferenceComment)comments[2]).References; Assert.Equal(1, references.Count); Assert.Equal("/Views/Home/Index.cshtml", references[0].FilePath); Assert.Equal(8, references[0].Line); Assert.Equal(POCommentKind.Flags, comments[3].Kind); var flags = ((POFlagsComment)comments[3]).Flags; Assert.Equal(2, flags.Count); Assert.Contains("fuzzy", flags); Assert.Contains("csharp-format", flags); Assert.Equal(POCommentKind.PreviousValue, comments[4].Kind); Assert.Equal(POIdKind.Id, ((POPreviousValueComment)comments[4]).IdKind); Assert.Equal("{0} hour to midnite", ((POPreviousValueComment)comments[4]).Value); Assert.Equal(POCommentKind.PreviousValue, comments[5].Kind); Assert.Equal(POIdKind.PluralId, ((POPreviousValueComment)comments[5]).IdKind); Assert.Equal("{0} hours to midnite", ((POPreviousValueComment)comments[5]).Value); } else { Assert.Null(catalog[key1].Comments); Assert.Null(catalog[key2].Comments); } }
public POPluralEntry(POKey key) { if (!key.IsValid) { throw new ArgumentException(null, nameof(key)); } Key = key; }
private POPluralEntry(POKey key, IList <string> translations) : base(translations) { if (!key.IsValid) { throw new ArgumentException(null, nameof(key)); } Key = key; }
private void AddToCatalog(POCatalog catalog, ExtractedText extractedEntry) { var catalogKey = new POKey(extractedEntry.Japanese); var catalogEntry = new POSingularEntry(catalogKey) { Comments = new List <POComment> { new POReferenceComment { References = new POSourceReference[] { new POSourceReference($"{extractedEntry.Source}", extractedEntry.SourceLine) } } }, }; if (!string.IsNullOrEmpty(extractedEntry.English)) { catalogEntry.Translation = extractedEntry.English.Trim(' '); } var comment = extractedEntry.Comment ?? ""; // If we have Korean text add it to the comment as well. This gives us multiple strings to throw at a // machine translator to hopefully get better context. if (!string.IsNullOrEmpty(extractedEntry.Korean) && extractedEntry.Korean != extractedEntry.Japanese && !comment.Contains("Korean Text: ", StringComparison.Ordinal)) { if (comment.Length > 0) { comment += "; "; } // The comment we save the Korean text in can't contain new lines, tabs are just for visual convenience comment += "Korean Text: '" + extractedEntry.Korean.Replace("\r", "\\r", StringComparison.Ordinal) .Replace("\n", "\\n", StringComparison.Ordinal) .Replace("\t", "\\t", StringComparison.Ordinal) + "'"; } if (!string.IsNullOrEmpty(comment)) { catalogEntry.Comments.Add(new POTranslatorComment() { Text = comment }); } catalog.Add(catalogEntry); }
public static string FormatKey(POKey key) { var result = string.Concat("'", key.Id, "'"); if (key.PluralId != null) { result = string.Concat(result, "-'", key.PluralId, "'"); } if (key.ContextId != null) { result = string.Concat(result, "@'", key.ContextId, "'"); } return(result); }
protected override bool TryGetTranslation(string name, Plural plural, TextContext context, out string value) { var key = new POKey(name, plural.Id, context.Id); if (!TryGetTranslationCore(key, plural.Count, out string translation)) { Logger.LogTrace("No translation for key {0}.", POStringLocalizer.FormatKey(key)); base.TryGetTranslation(name, plural, context, out value); return(false); } value = translation; return(true); }
bool TryGetTranslation(string name, Plural plural, TextContext context, out string value) { var key = new POKey(name, plural.Id, context.Id); if (!TryGetTranslation(key, plural.Count, out string translation)) { _logger.LogTrace("No translation for key {KEY}.", POStringLocalizer.FormatKey(key)); TryGetTranslationFallback(name, plural, context, out value); return(false); } value = translation; return(true); }
bool TryGetTranslation(POKey key, int pluralCount, out string value) { if (_catalog != null) { var translation = _catalog.GetTranslation(key, pluralCount); if (translation != null) { value = translation; return(true); } } value = null; return(false); }
public bool TryGetTranslation(string name, Plural plural, TextContext context, out string?searchedLocation, [MaybeNullWhen(false)] out string value) { var catalog = GetCatalog(); if (catalog != null) { var key = new POKey(name, plural.Id, context.Id); value = plural.Id == null?catalog.GetTranslation(key) : catalog.GetTranslation(key, plural.Count); if (value != null) { searchedLocation = _location; return(true); } } searchedLocation = _location; value = default; return(false); }
/// <summary> /// Creates a catalog for a translations dictionary for a given encoding and language /// </summary> /// <param name="fileEncoding">File encoding</param> /// <param name="htmlTextKeys">A list of translations</param> /// <param name="translationsLanguage">Translations language</param> /// <returns></returns> public POCatalog CreateCatalog(Encoding fileEncoding, IList <string> htmlTextKeys, string translationsLanguage) { var catalog = new POCatalog { // Setting Required Headers Encoding = fileEncoding.WebName, Language = translationsLanguage, // Setting Custom Headers Headers = CreateHeaders() }; foreach (var htmlTextKey in htmlTextKeys) { var poKey = new POKey(htmlTextKey); var poEntry = new POSingularEntry(poKey); catalog.Add(poEntry); } return(catalog); }
public static void LoadDataPOFile() { POFileData.Clear(); var pathPoFile = GetPathFilePo(DefaultLanguageValue); if (string.IsNullOrEmpty(pathPoFile) || !File.Exists(pathPoFile)) { return; } using (var reader = new StreamReader(pathPoFile, Encoding.UTF8)) { var parser = new POParser(); var result = parser.Parse(reader); if (!result.Success) { return; } var catalog = result.Catalog; //var languageName = catalog.Language.Replace('_', '-').Trim(); var languageName = DefaultLanguageValue.Replace('_', '-'); languageName = languageName.Replace(".po", "").Trim(); CultureInfo ci = new CultureInfo(languageName); CultureInfo.DefaultThreadCurrentCulture = ci; foreach (var item in catalog) { var keyLangue = item.Key.Id; var key = new POKey(keyLangue); var translation = catalog.GetTranslation(key); POFileData.Add(keyLangue, translation); } } }
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) { var translationResult = (TranslationResult)context.Object; var poCatalog = new POCatalog(); poCatalog.Language = translationResult.Language; poCatalog.Encoding = "UTF-8"; translationResult.Entries.ForEach(entry => { var poKey = new POKey(entry.Key, contextId: entry.Collection); var poEntry = new POSingularEntry(poKey); poEntry.Translation = entry.Value; poCatalog.Add(poEntry); }); var poGenerator = new POGenerator(); var memoryStream = new MemoryStream(); poGenerator.Generate(memoryStream, poCatalog, Encoding.UTF8); memoryStream.Position = 0; await memoryStream.CopyToAsync(context.HttpContext.Response.Body); }
/// <summary> /// Creates a catalog for a translations dictionary for a given encoding and language /// </summary> /// <param name="fileEncoding">File encoding</param> /// <param name="htmlTextTranslations">Translations dictionary</param> /// <param name="translationsLanguage">Translations language</param> /// <returns></returns> public POCatalog CreateCatalog(Encoding fileEncoding, IOrderedDictionary <string, string> htmlTextTranslations, string translationsLanguage) { var catalog = new POCatalog { // Setting Required Headers Encoding = fileEncoding.HeaderName, Language = translationsLanguage, // Setting Custom Headers Headers = CreateHeaders() }; foreach (var htmlTextTranslation in htmlTextTranslations) { var poKey = new POKey(htmlTextTranslation.Key); var poEntry = new POSingularEntry(poKey) { Translation = htmlTextTranslation.Value }; catalog.Add(poEntry); } return(catalog); }
public static POCatalog CreateCatalog() { var result = new POCatalog(); result.HeaderComments = new POComment[] { new POTranslatorComment { Text = "header comment" } }; result.Headers = new OrderedDictionary <string, string> { { "Language-Team", "" }, { "PO-Revision-Date", "" }, { "POT-Creation-Date", "2018-06-22 07:01+0200" }, { "Project-Id-Version", "" }, { "Report-Msgid-Bugs-To", "" }, { "MIME-Version", "1.0" }, { "X-Generator", "Poedit 2.0.8" }, { "Last-Translator", "" }, }; result.Encoding = "UTF-8"; result.PluralFormCount = 2; result.PluralFormSelector = "(n != 1)"; result.Language = "en_US"; var key = new POKey("{0} hour to midnight", "{0} hours to midnight", "Home"); IPOEntry entry = new POPluralEntry(key) { "Translation of {0} hour to midnight", "Translation of {0} hours to midnight", }; entry.Comments = new POComment[] { new POTranslatorComment { Text = "some translator comment" }, new POExtractedComment { Text = "some extracted comment" }, new POReferenceComment { References = new POSourceReference[] { new POSourceReference("/Views/Home/Index.cshtml", 8) } }, new POFlagsComment { Flags = new SortedSet <string> { "fuzzy", "csharp-format" } }, new POPreviousValueComment { IdKind = POIdKind.Id, Value = "{0} hour to midnite" }, new POPreviousValueComment { IdKind = POIdKind.PluralId, Value = "{0} hours to midnite" }, }; result.Add(entry); key = new POKey($"Here is an example of how one might continue a very long string{Environment.NewLine}" + $"for the common case the string represents multi-line output.{Environment.NewLine}"); entry = new POSingularEntry(key) { Translation = "Some translation of long text" }; result.Add(entry); return(result); }
public IEnumerable <string> SaveTo(string filename, DateTime versionDate, List <ExtractedText> entries) { var translationCatalog = CreateCatalog(); var sanityChecker = new ExtractedTextSanityChecker(); entries.Sort((x, y) => { if (x.Source == y.Source) { return(x.SourceLine.CompareTo(y.SourceLine)); } return(new NaturalStringComparer().Compare(x.Source, y.Source)); }); var warnings = new List <string>(); foreach (var entry in entries) { // There are a lot of this string in various unrelated parts of the structure, seems to be a generic // error string. We don't want it anywhere but the error string table. if (entry.Japanese == "2-エラーが発生しました。" && !entry.Source.StartsWith("ServerErrString")) { continue; } var key = new POKey(entry.Japanese); if (translationCatalog.Contains(key)) { continue; } // Since PO catalogs can't contain duplicate entries any after this will be skipped. We pull the Korean // text from the duplicate entries if they have it and we don't. // // This is needed for the PCStory PO file to contain both. The PCStory table only contains Japanese // while the PCStory_Client contains both (but doesn't have contextual key names so we prefer PCStory). // For example, for a string in PCStory_Client the path is PCStory_Client[1][0].DgStartTriggerString1, // in PCStory the path is PCStory[Story_3P_ConstantiaS2_1_3P_ConstantiaS2_1].DgStartTriggerString1. if (string.IsNullOrEmpty(entry.Korean)) { var otherEntryWithKorean = entries.Where(e => { return(e != entry && e.Japanese.Equals(entry.Japanese, StringComparison.Ordinal) && !string.IsNullOrEmpty(e.Korean)); }).FirstOrDefault(); if (otherEntryWithKorean != null) { entry.Korean = otherEntryWithKorean.Korean; } } warnings.AddRange(sanityChecker.GetWarnings(entry)); AddToCatalog(translationCatalog, entry); } WriteCatalog(translationCatalog, filename, versionDate); return(warnings); }
public POPluralEntry(POKey key, IEnumerable <string> translations) : this(key, (translations ?? throw new ArgumentNullException(nameof(translations))).ToList())
public async Task Visit(DataStructure dataStructure) { await Task.CompletedTask; var language = Thread.CurrentThread.CurrentCulture.Name; var projectName = dataStructure.Project.Name; var projectPath = dataStructure.ProjectDirectory; var localizerEntries = dataStructure.LocalizerEntries; var POFilePath = Path.Combine(projectPath, "Localization", language + ".po"); POCatalog catalog = null; if (File.Exists(POFilePath)) { using var sr = new StreamReader(POFilePath, Encoding.UTF8); var parser = new POParser(POParserSettings.Default); var result = parser.Parse(sr); if (result.Success) { catalog = result.Catalog; foreach (var r in catalog) { r.Comments.Clear(); } } else { var diagnostics = result.Diagnostics; // examine diagnostics, display an error, etc... foreach (var diagnostic in diagnostics) { if (diagnostic.Severity.Equals(Karambolo.PO.DiagnosticSeverity.Error)) { Console.WriteLine($"Error has occurred while Parse the PO file: {POFilePath}"); } } } } if (catalog == null) { catalog = new POCatalog { Encoding = Encoding.UTF8.BodyName, PluralFormCount = 1, PluralFormSelector = "0", Language = language }; var assembly = typeof(IVisitor).Assembly; catalog.Headers = new Dictionary <string, string> { { "PO-Revision-Date", DateTime.UtcNow.ToString() }, { "Project-Id-Version", projectName }, { "X-Crowdin-Generator", $"Generated by {assembly.GetName().Name} {assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion}" }, }; } HashSet <POKey> sets = new HashSet <POKey>(); foreach (var entry in localizerEntries) { var key = new POKey(entry.Id, null, entry.ContextId); sets.Add(key); if (catalog.TryGetValue(key, out var POEntry)) { if (!POEntry.Comments.OfType <POExtractedComment>().Any(c => c.Text.Equals(entry.SourceCode))) { POEntry.Comments.Add(new POExtractedComment { Text = entry.SourceCode }); } var referenceComment = POEntry.Comments.OfType <POReferenceComment>().FirstOrDefault(); if (referenceComment == null) { POEntry.Comments.Add(new POReferenceComment { References = new List <POSourceReference>() { POSourceReference.Parse(entry.SourceReference) } }); } else { var sourceReference = POSourceReference.Parse(entry.SourceReference); if (!referenceComment.References.Any(r => r.FilePath.Equals(sourceReference.FilePath) && r.Line.Equals(sourceReference.Line))) { referenceComment.References.Add(sourceReference); } } } else { POEntry = new POSingularEntry(key) { Comments = new List <POComment>() { new POReferenceComment { References = new List <POSourceReference>() { POSourceReference.Parse(entry.SourceReference) } }, new POExtractedComment { Text = entry.SourceCode }, } }; catalog.Add(POEntry); } } var keys = catalog.Keys.ToList(); keys.Where(k => !sets.Contains(k)).ToList().ForEach(k => catalog.Remove(k)); if (catalog.Headers.ContainsKey("PO-Revision-Date")) { catalog.Headers["PO-Revision-Date"] = DateTime.UtcNow.ToString(); } var generator = new POGenerator(POGeneratorSettings.Default); using var sw = new StreamWriter(POFilePath, false, Encoding.UTF8); generator.Generate(sw, catalog); }
public POPluralEntry(POKey key) : this(key, new List <string>()) { }