From ed57f629391152029134ad826935b82354d20c44 Mon Sep 17 00:00:00 2001
From: Luca <106596790+RealLHI@users.noreply.github.com>
Date: Wed, 18 Sep 2024 10:56:08 +0200
Subject: [PATCH] feat: add new IFormatBuilderOptions and FormatWriteOptions,
add PoBuilderOptions to configure pipe splitting behaviour (#90)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: add new IFormatBuilderOptions and FormatWriteOptions, add PoBuilderOptions to configure pipe splitting behaviour
* tests(po): add new test case to test po files that dont have a msgctxt
* cleanup
---------
Co-authored-by: Tjorven Kämpfer <62958434+tjorvenK@users.noreply.github.com>
---
.../src/FormatReadOptions.cs | 2 +-
.../src/IFormatBuilder.cs | 2 +-
.../src/IFormatBuilderOptions.cs | 6 ++
.../tests/FormatTest.cs | 67 ++++++++++++++++++-
.../tests/_TestFiles_/test.po | 9 +++
.../src/AshLang/AshLangFormatBuilder.cs | 2 +-
.../src/CSV/CsvFormatBuilder.cs | 2 +-
.../src/DependencyInjection.cs | 4 +-
.../src/Gengo/GengoFormatBuilder.cs | 2 +-
.../JavaPropertiesFormatBuilder.cs | 2 +-
.../src/Json/JsonFormat.cs | 4 +-
.../src/Json/JsonFormatBuilder.cs | 2 +-
.../src/NLang/NLangFormatBuilder.cs | 2 +-
.../src/PO/MessageString.cs | 10 ++-
.../src/PO/POFormatBuilder.cs | 5 +-
.../src/PO/PoBuilderOptions.cs | 14 ++++
.../src/QT/QTFormatBuilder.cs | 2 +-
.../src/ResX/ResXFormatBuilder.cs | 2 +-
.../src/TsProj/TsProjFormatBuilder.cs | 2 +-
19 files changed, 120 insertions(+), 21 deletions(-)
create mode 100644 src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilderOptions.cs
create mode 100644 src/Ashampoo.Translation.Systems.Formats.PO/tests/_TestFiles_/test.po
create mode 100644 src/Ashampoo.Translation.Systems.Formats/src/PO/PoBuilderOptions.cs
diff --git a/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/FormatReadOptions.cs b/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/FormatReadOptions.cs
index 2928b06..cb52564 100644
--- a/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/FormatReadOptions.cs
+++ b/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/FormatReadOptions.cs
@@ -5,7 +5,7 @@ namespace Ashampoo.Translation.Systems.Formats.Abstractions;
///
/// This class is used to provide options for reading a from a file.
///
-public class FormatReadOptions
+public record FormatReadOptions
{
///
/// The target language of the format.
diff --git a/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilder.cs
index f575c11..3cda0fe 100644
--- a/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilder.cs
@@ -13,7 +13,7 @@ public interface IFormatBuilder where T : class, IFormat
///
/// The instance of .
///
- T Build();
+ T Build(IFormatBuilderOptions? options = null);
///
/// Set the header information. All information will be added to the header and will overwrite
diff --git a/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilderOptions.cs b/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilderOptions.cs
new file mode 100644
index 0000000..5177b78
--- /dev/null
+++ b/src/Ashampoo.Translation.Systems.Formats.Abstractions/src/IFormatBuilderOptions.cs
@@ -0,0 +1,6 @@
+namespace Ashampoo.Translation.Systems.Formats.Abstractions;
+
+///
+/// An interface to add optional options to a format builder to manipulate its behaviour.
+///
+public interface IFormatBuilderOptions;
\ No newline at end of file
diff --git a/src/Ashampoo.Translation.Systems.Formats.PO/tests/FormatTest.cs b/src/Ashampoo.Translation.Systems.Formats.PO/tests/FormatTest.cs
index 3af11d7..cff14ea 100644
--- a/src/Ashampoo.Translation.Systems.Formats.PO/tests/FormatTest.cs
+++ b/src/Ashampoo.Translation.Systems.Formats.PO/tests/FormatTest.cs
@@ -40,6 +40,69 @@ public void ReadFromFile()
.Be("Vielen Dank, dass Sie die Umfrage abgeschlossen haben!");
}
+ [Fact]
+ public void CreateBuilderWithDisabledPipeSplittingTest()
+ {
+ var format = CreateAndReadFromFile("translation_de.po",
+ new FormatReadOptions { SourceLanguage = new Language("en-US") });
+
+
+ var poHeader = format.Header as POHeader;
+ poHeader.Should().NotBeNull();
+
+ var poBuilder = new POFormatBuilder();
+ foreach (var unit in format.TranslationUnits)
+ {
+ foreach (var translation in unit.Translations)
+ {
+ poBuilder.Add(unit.Id, translation.Value);
+ }
+ }
+ poBuilder.SetTargetLanguage(format.Header.TargetLanguage);
+ var newFormat = poBuilder.Build(new PoBuilderOptions { SplitContextAndId = false });
+ var memoryStream = new MemoryStream();
+ newFormat.Write(memoryStream);
+ memoryStream.Seek(0, SeekOrigin.Begin);
+ var streamReader = new StreamReader(memoryStream);
+ var result = streamReader.ReadToEnd();
+ result.Should().NotContain("msgctxt ");
+ }
+
+ [Fact]
+ public void ReadWithoutMsgCtxtText()
+ {
+ var format = CreateAndReadFromFile("test.po",
+ new FormatReadOptions { SourceLanguage = new Language("en-US") });
+
+ var poHeader = format.Header as POHeader;
+ poHeader.Should().NotBeNull();
+
+ format.TranslationUnits.Count.Should().Be(2);
+ format.Header.TargetLanguage.Should().Be(new Language("de-DE"));
+
+ const string id = "testid2";
+
+ format.TranslationUnits.GetTranslationUnit(id).Translations.GetTranslation(new Language("de-DE")).Value.Should()
+ .Be("deutscher testid2 Text");
+ }
+
+ [Fact]
+ public async Task ReadAndWriteWithoutMsgCtxtText()
+ {
+ var format = await CreateAndReadFromFileAsync("test.po",
+ new FormatReadOptions { SourceLanguage = new Language("en-US") });
+
+ var outStream = new MemoryStream();
+ await format.WriteAsync(outStream);
+ await outStream.FlushAsync();
+ outStream.Seek(0, SeekOrigin.Begin);
+
+ var reader = new StreamReader(outStream);
+ var result = await reader.ReadToEndAsync();
+ result.Should().NotBeEmpty();
+ result.Should().NotContain("msgctxt ");
+ }
+
[Fact]
public async Task ReadAndWriteAsync()
{
@@ -66,7 +129,7 @@ public async Task ReadAndWriteAsync()
//fs.MustBeEqualTo(ms);
File.Delete($"{temp}normalized_translation_de.po");
}
-
+
[Fact]
public void ReadAndWrite()
{
@@ -105,7 +168,7 @@ public void WriteFormatLeavesStreamOpen()
memoryStream.CanRead.Should().BeTrue();
memoryStream.CanWrite.Should().BeTrue();
}
-
+
[Fact]
public async Task WriteFormatLeavesStreamOpenAsync()
{
diff --git a/src/Ashampoo.Translation.Systems.Formats.PO/tests/_TestFiles_/test.po b/src/Ashampoo.Translation.Systems.Formats.PO/tests/_TestFiles_/test.po
new file mode 100644
index 0000000..869900a
--- /dev/null
+++ b/src/Ashampoo.Translation.Systems.Formats.PO/tests/_TestFiles_/test.po
@@ -0,0 +1,9 @@
+msgid ""
+msgstr ""
+"Language: de-DE\n"
+
+msgid "testid1"
+msgstr "deutscher testid1 Text"
+
+msgid "testid2"
+msgstr "deutscher testid2 Text"
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/AshLang/AshLangFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/AshLang/AshLangFormatBuilder.cs
index 59add0d..7667350 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/AshLang/AshLangFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/AshLang/AshLangFormatBuilder.cs
@@ -17,7 +17,7 @@ public class AshLangFormatBuilder : IFormatBuilderWithSourceAndTarget _information = new();
///
- public AshLangFormat Build()
+ public AshLangFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage.Value, nameof(_targetLanguage));
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/CSV/CsvFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/CSV/CsvFormatBuilder.cs
index 670cdd4..45bd43e 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/CSV/CsvFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/CSV/CsvFormatBuilder.cs
@@ -17,7 +17,7 @@ public sealed class CsvFormatBuilder : IFormatBuilderWithSourceAndTarget CustomHeaderInformation { get; set; } = new();
///
- public CsvFormat Build()
+ public CsvFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage.Value);
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/DependencyInjection.cs b/src/Ashampoo.Translation.Systems.Formats/src/DependencyInjection.cs
index 69e3556..6cc5ce9 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/DependencyInjection.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/DependencyInjection.cs
@@ -6,6 +6,7 @@
using Ashampoo.Translation.Systems.Formats.Json;
using Ashampoo.Translation.Systems.Formats.NLang;
using Ashampoo.Translation.Systems.Formats.PO;
+using Ashampoo.Translation.Systems.Formats.QT;
using Ashampoo.Translation.Systems.Formats.ResX;
using Ashampoo.Translation.Systems.Formats.TsProj;
using Microsoft.Extensions.DependencyInjection;
@@ -34,13 +35,14 @@ public static IServiceCollection RegisterFormats(this IServiceCollection service
services.AddSingleton();
services
.AddAshLangFormatFeatures()
+ .AddCsvFormat()
.AddGengoFormatFeatures()
.AddJavaPropertiesFormatFeatures()
.AddJsonFormatFeatures()
.AddNLangFormatFeatures()
.AddPOFormatFeatures()
+ .AddQtFormat()
.AddResXFormatFeatures()
- .AddCsvFormat()
.AddTsProjFormatFeatures();
return services;
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/Gengo/GengoFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/Gengo/GengoFormatBuilder.cs
index b4553df..fd2013b 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/Gengo/GengoFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/Gengo/GengoFormatBuilder.cs
@@ -21,7 +21,7 @@ public void Add(string id, string source, string target)
}
///
- public GengoFormat Build()
+ public GengoFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_sourceLanguage?.Value, nameof(_sourceLanguage));
Guard.IsNotNullOrWhiteSpace(_targetLanguage?.Value, nameof(_targetLanguage));
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/JavaProperties/JavaPropertiesFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/JavaProperties/JavaPropertiesFormatBuilder.cs
index 1f5d9c3..2e849aa 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/JavaProperties/JavaPropertiesFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/JavaProperties/JavaPropertiesFormatBuilder.cs
@@ -14,7 +14,7 @@ public class JavaPropertiesFormatBuilder : IFormatBuilderWithTarget _translations = new();
///
- public JavaPropertiesFormat Build()
+ public JavaPropertiesFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage.Value);
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormat.cs b/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormat.cs
index 2983b56..9cd2743 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormat.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormat.cs
@@ -181,13 +181,13 @@ public async Task WriteAsync(Stream stream)
var root = new JsonObject();
CreateJsonObjects(root); // Create JSON objects from TranslationUnits
- var options = new JsonSerializerOptions // Create JSON serializer options
+ var serializerOptions = new JsonSerializerOptions // Create JSON serializer options
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
- await JsonSerializer.SerializeAsync(stream, root, options);
+ await JsonSerializer.SerializeAsync(stream, root, serializerOptions);
await stream.FlushAsync();
}
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormatBuilder.cs
index b6e4e85..1fc652f 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/Json/JsonFormatBuilder.cs
@@ -20,7 +20,7 @@ public void Add(string id, string target)
}
///
- public JsonFormat Build()
+ public JsonFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage?.Value, nameof(_targetLanguage));
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/NLang/NLangFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/NLang/NLangFormatBuilder.cs
index 35a176f..2fef4ed 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/NLang/NLangFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/NLang/NLangFormatBuilder.cs
@@ -19,7 +19,7 @@ public void Add(string id, string target)
}
///
- public NLangFormat Build()
+ public NLangFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage?.Value, nameof(_targetLanguage));
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/PO/MessageString.cs b/src/Ashampoo.Translation.Systems.Formats/src/PO/MessageString.cs
index a2e9346..7ab9177 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/PO/MessageString.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/PO/MessageString.cs
@@ -21,8 +21,10 @@ public class MessageString : ITranslation
///
/// Provides the id for the ITranslation interface.
///
- public string Id => !string.IsNullOrWhiteSpace(MsgCtxt) ? $"{MsgCtxt}{POConstants.Divider}{MsgId}" : MsgId;
-
+ public string Id => !string.IsNullOrWhiteSpace(MsgCtxt)
+ ? $"{MsgCtxt}{POConstants.Divider}{MsgId}"
+ : MsgId;
+
///
/// Provides the comment for the ITranslation interface.
///
@@ -30,7 +32,7 @@ public class MessageString : ITranslation
///
public Language Language { get; set; }
-
+
///
/// Message string of the po format.
///
@@ -53,6 +55,7 @@ public string Value
///
///
///
+ ///
public MessageString(string id, string value, Language language, IList comments, string msgCtxt = "")
{
MsgId = id;
@@ -88,6 +91,7 @@ public virtual async Task WriteAsync(TextWriter writer)
await writer.WriteLineAsync($"{Escape(comment)}");
}
}
+
if (!string.IsNullOrWhiteSpace(MsgCtxt))
await writer.WriteLineAsync($"{POConstants.TypeMsgCtxt}\"{Escape(MsgCtxt)}\"");
await writer.WriteLineAsync($"{POConstants.TypeMsgId}\"{Escape(MsgId)}\"");
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/PO/POFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/PO/POFormatBuilder.cs
index 61a6df1..b0f6d63 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/PO/POFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/PO/POFormatBuilder.cs
@@ -19,7 +19,7 @@ public void Add(string id, string target)
}
///
- public POFormat Build()
+ public POFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage?.Value, nameof(_targetLanguage));
@@ -32,11 +32,12 @@ public POFormat Build()
}
};
+ var builderOptions = options as PoBuilderOptions ?? new PoBuilderOptions();
foreach (var translation in _translations)
{
var translationUnit = new TranslationUnit(translation.Key);
var index = translation.Key.IndexOf(POConstants.Divider, StringComparison.InvariantCulture);
- if (index > 0) // if divider exists, then a message context is used
+ if (builderOptions.SplitContextAndId && index > 0) // if divider exists, then a message context is used
{
var ctxt = translation.Key[..index];
var msgId = translation.Key[(index + POConstants.Divider.Length)..];
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/PO/PoBuilderOptions.cs b/src/Ashampoo.Translation.Systems.Formats/src/PO/PoBuilderOptions.cs
new file mode 100644
index 0000000..f75a2c1
--- /dev/null
+++ b/src/Ashampoo.Translation.Systems.Formats/src/PO/PoBuilderOptions.cs
@@ -0,0 +1,14 @@
+using Ashampoo.Translation.Systems.Formats.Abstractions;
+
+namespace Ashampoo.Translation.Systems.Formats.PO;
+
+///
+/// IFormatBuilderOptions for POFormat
+///
+public sealed record PoBuilderOptions : IFormatBuilderOptions
+{
+ ///
+ /// Disables splitting of the id into msgctxt and msgid if a pipe separator is detected.
+ ///
+ public bool SplitContextAndId { get; init; } = true;
+};
\ No newline at end of file
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/QT/QTFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/QT/QTFormatBuilder.cs
index 4fbcb3f..f702228 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/QT/QTFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/QT/QTFormatBuilder.cs
@@ -14,7 +14,7 @@ public class QtFormatBuilder : IFormatBuilderWithTarget
private readonly Dictionary _translations = new();
///
- public QtFormat Build()
+ public QtFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage.Value);
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/ResX/ResXFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/ResX/ResXFormatBuilder.cs
index 343fd7a..a498b2d 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/ResX/ResXFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/ResX/ResXFormatBuilder.cs
@@ -15,7 +15,7 @@ public class ResXFormatBuilder : IFormatBuilderWithTarget
private readonly Dictionary _translations = new();
///
- public ResXFormat Build()
+ public ResXFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_targetLanguage?.Value, nameof(_targetLanguage));
diff --git a/src/Ashampoo.Translation.Systems.Formats/src/TsProj/TsProjFormatBuilder.cs b/src/Ashampoo.Translation.Systems.Formats/src/TsProj/TsProjFormatBuilder.cs
index c8ee2f6..8cc0664 100644
--- a/src/Ashampoo.Translation.Systems.Formats/src/TsProj/TsProjFormatBuilder.cs
+++ b/src/Ashampoo.Translation.Systems.Formats/src/TsProj/TsProjFormatBuilder.cs
@@ -23,7 +23,7 @@ public void Add(string id, string source, string target)
}
///
- public TsProjFormat Build()
+ public TsProjFormat Build(IFormatBuilderOptions? options = null)
{
Guard.IsNotNullOrWhiteSpace(_sourceLanguage?.Value, nameof(_sourceLanguage)); // sourceLanguage is required
Guard.IsNotNullOrWhiteSpace(_targetLanguage?.Value, nameof(_targetLanguage)); // targetLanguage is required