diff --git a/src/Machine/src/Serval.Machine.Shared/Serval.Machine.Shared.csproj b/src/Machine/src/Serval.Machine.Shared/Serval.Machine.Shared.csproj index 4286a101..0d19202a 100644 --- a/src/Machine/src/Serval.Machine.Shared/Serval.Machine.Shared.csproj +++ b/src/Machine/src/Serval.Machine.Shared/Serval.Machine.Shared.csproj @@ -38,9 +38,9 @@ - - - + + + diff --git a/src/Serval/src/Serval.Shared/Serval.Shared.csproj b/src/Serval/src/Serval.Shared/Serval.Shared.csproj index d26b72b9..a159d88a 100644 --- a/src/Serval/src/Serval.Shared/Serval.Shared.csproj +++ b/src/Serval/src/Serval.Shared/Serval.Shared.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Serval/src/Serval.Translation/Services/PretranslationService.cs b/src/Serval/src/Serval.Translation/Services/PretranslationService.cs index 72a2c65e..aa4c3c79 100644 --- a/src/Serval/src/Serval.Translation/Services/PretranslationService.cs +++ b/src/Serval/src/Serval.Translation/Services/PretranslationService.cs @@ -320,26 +320,44 @@ private static string DenormalizeQuotationMarks(string usfm, ParallelCorpusAnaly QuotationMarkDenormalizationFirstPass quotationMarkDenormalizationFirstPass = new(targetQuoteConvention); UsfmParser.Parse(usfm, quotationMarkDenormalizationFirstPass); - List bestChapterStrategies = + List<(int ChapterNumber, QuotationMarkUpdateStrategy Strategy)> bestChapterStrategies = quotationMarkDenormalizationFirstPass.FindBestChapterStrategies(); QuotationMarkDenormalizationUsfmUpdateBlockHandler quotationMarkDenormalizer = - new(targetQuoteConvention, new QuotationMarkUpdateSettings(chapterStrategies: bestChapterStrategies)); + new( + targetQuoteConvention, + new QuotationMarkUpdateSettings( + chapterStrategies: bestChapterStrategies.Select(tuple => tuple.Strategy).ToList() + ) + ); + int denormalizableChapterCount = bestChapterStrategies.Count(tup => + tup.Strategy != QuotationMarkUpdateStrategy.Skip + ); List remarks = []; - if (bestChapterStrategies.Any(s => s != QuotationMarkUpdateStrategy.Skip)) + string quotationDenormalizationRemark; + if (denormalizableChapterCount == bestChapterStrategies.Count) { - string quotationDenormalizationRemark = + quotationDenormalizationRemark = + "The quote style in all chapters has been automatically adjusted to match the rest of the project."; + } + else if (denormalizableChapterCount > 0) + { + quotationDenormalizationRemark = "The quote style in the following chapters has been automatically adjusted to match the rest of the project: " - + string.Join( - ", ", + + GetChapterRangesString( bestChapterStrategies - .Select((strategy, index) => (strategy, index)) - .Where(tuple => tuple.strategy != QuotationMarkUpdateStrategy.Skip) - .Select(tuple => tuple.index + 1) + .Where(tuple => tuple.Strategy != QuotationMarkUpdateStrategy.Skip) + .Select(tuple => tuple.ChapterNumber) + .ToList() ) + "."; - remarks.Add(quotationDenormalizationRemark); } + else + { + quotationDenormalizationRemark = + "The quote style was not automatically adjusted to match the rest of your project in any chapters."; + } + remarks.Add(quotationDenormalizationRemark); var updater = new UpdateUsfmParserHandler(updateBlockHandlers: [quotationMarkDenormalizer], remarks: remarks); UsfmParser.Parse(usfm, updater); @@ -348,6 +366,43 @@ private static string DenormalizeQuotationMarks(string usfm, ParallelCorpusAnaly return usfm; } + public static string GetChapterRangesString(List chapterNumbers) + { + chapterNumbers = chapterNumbers.Order().ToList(); + int start = chapterNumbers[0]; + int end = chapterNumbers[0]; + List chapterRangeStrings = []; + foreach (int chapterNumber in chapterNumbers[1..]) + { + if (chapterNumber == end + 1) + { + end = chapterNumber; + } + else + { + if (start == end) + { + chapterRangeStrings.Add(start.ToString(CultureInfo.InvariantCulture)); + } + else + { + chapterRangeStrings.Add($"{start}-{end}"); + } + start = chapterNumber; + end = chapterNumber; + } + } + if (start == end) + { + chapterRangeStrings.Add(start.ToString(CultureInfo.InvariantCulture)); + } + else + { + chapterRangeStrings.Add($"{start}-{end}"); + } + return string.Join(", ", chapterRangeStrings); + } + /// /// Generate a natural sounding remark/comment describing marker placement. /// diff --git a/src/Serval/test/Serval.Translation.Tests/Services/PretranslationServiceTests.cs b/src/Serval/test/Serval.Translation.Tests/Services/PretranslationServiceTests.cs index f6f42bdc..d6f950f8 100644 --- a/src/Serval/test/Serval.Translation.Tests/Services/PretranslationServiceTests.cs +++ b/src/Serval/test/Serval.Translation.Tests/Services/PretranslationServiceTests.cs @@ -425,6 +425,18 @@ public void GetUsfmAsync_BadPretranslationVerseRef() }); } + [Test] + [TestCase(new int[] { 1, 2, 3 }, "1-3")] + [TestCase(new int[] { 1, 3, 4 }, "1, 3-4")] + [TestCase(new int[] { 2, 3, 4, 6, 8, 9 }, "2-4, 6, 8-9")] + [TestCase(new int[] { 1, 3, 2 }, "1-3")] + [TestCase(new int[] { 1 }, "1")] + public void GetChapterRanges(int[] chapterNumbers, string expectedRangeString) + { + string actualRangeString = PretranslationService.GetChapterRangesString(chapterNumbers.ToList()); + Assert.That(actualRangeString, Is.EqualTo(expectedRangeString)); + } + private class TestEnvironment : IDisposable { public TestEnvironment() diff --git a/src/ServiceToolkit/src/SIL.ServiceToolkit/SIL.ServiceToolkit.csproj b/src/ServiceToolkit/src/SIL.ServiceToolkit/SIL.ServiceToolkit.csproj index 13691c33..4054de0b 100644 --- a/src/ServiceToolkit/src/SIL.ServiceToolkit/SIL.ServiceToolkit.csproj +++ b/src/ServiceToolkit/src/SIL.ServiceToolkit/SIL.ServiceToolkit.csproj @@ -18,7 +18,7 @@ - +