-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
using Lepo.i18n.Json.Models; | ||
|
||
namespace Lepo.i18n.Json.Converters; | ||
|
||
/// <summary> | ||
/// JSON converter for the ITranslationsContainer interface. | ||
/// </summary> | ||
internal class TranslationsContainerConverter : JsonConverter<ITranslationsContainer> | ||
{ | ||
public override ITranslationsContainer? Read( | ||
ref Utf8JsonReader reader, | ||
Type typeToConvert, | ||
JsonSerializerOptions options | ||
) | ||
{ | ||
JsonElement jsonObject = JsonDocument.ParseValue(ref reader).RootElement; | ||
|
||
string version = "1.0"; | ||
|
||
foreach (JsonProperty property in jsonObject.EnumerateObject()) | ||
{ | ||
if (string.Equals(property.Name, "Version", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
version = property.Value.GetString() ?? version; | ||
break; | ||
} | ||
} | ||
|
||
return new TranslationsContainer(new Version(version).ToString()); | ||
} | ||
|
||
public override void Write( | ||
Utf8JsonWriter writer, | ||
ITranslationsContainer? value, | ||
JsonSerializerOptions options | ||
) | ||
{ | ||
JsonSerializer.Serialize( | ||
Check warning on line 43 in src/Lepo.i18n.Json/Converters/TranslationsContainerConverter.cs
|
||
writer, | ||
new TranslationsContainer(value?.Version ?? "1.0"), | ||
options | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
global using System; | ||
global using System.Collections.Generic; | ||
global using System.Globalization; | ||
global using System.IO; | ||
global using System.Reflection; | ||
global using System.Text.Json; | ||
global using System.Text.Json.Serialization; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
using Lepo.i18n.IO; | ||
using Lepo.i18n.Json.Converters; | ||
using Lepo.i18n.Json.Models; | ||
using Lepo.i18n.Json.Models.v1; | ||
|
||
namespace Lepo.i18n.Json; | ||
|
||
/// <summary> | ||
/// Provides extension methods for the <see cref="LocalizationBuilder"/> class. | ||
/// </summary> | ||
public static class LocalizationBuilderExtensions | ||
{ | ||
private static readonly JsonSerializerOptions DefaultJsonSerializerOptions = | ||
new() | ||
{ | ||
PropertyNameCaseInsensitive = true, | ||
AllowTrailingCommas = true, | ||
Converters = { new TranslationsContainerConverter() } | ||
}; | ||
|
||
/// <summary> | ||
/// Loads localization data from a JSON file in the calling assembly. | ||
/// </summary> | ||
/// <param name="builder">The <see cref="LocalizationBuilder"/> to add the localization data to.</param> | ||
/// <param name="path">The path to the JSON file.</param> | ||
/// <param name="culture">The culture of the localization data.</param> | ||
/// <returns>The updated <see cref="LocalizationBuilder"/>.</returns> | ||
public static LocalizationBuilder FromJson( | ||
this LocalizationBuilder builder, | ||
string path, | ||
CultureInfo culture | ||
) | ||
{ | ||
return builder.FromJson(Assembly.GetCallingAssembly(), path, culture); | ||
} | ||
|
||
/// <summary> | ||
/// Loads localization data from a JSON file in the specified assembly. | ||
/// </summary> | ||
/// <param name="builder">The <see cref="LocalizationBuilder"/> to add the localization data to.</param> | ||
/// <param name="assembly">The assembly that contains the JSON file.</param> | ||
/// <param name="path">The path to the JSON file.</param> | ||
/// <param name="culture">The culture of the localization data.</param> | ||
/// <returns>The updated <see cref="LocalizationBuilder"/>.</returns> | ||
public static LocalizationBuilder FromJson( | ||
this LocalizationBuilder builder, | ||
Assembly assembly, | ||
string path, | ||
CultureInfo culture | ||
) | ||
{ | ||
if (!path.EndsWith(".json")) | ||
{ | ||
throw new ArgumentException( | ||
$"Parameter {nameof(path)} in {nameof(FromJson)} must be path to the JSON file." | ||
); | ||
} | ||
|
||
string? contents = EmbeddedResourceReader.ReadToEnd(path, assembly); | ||
|
||
if (contents is null) | ||
{ | ||
throw new LocalizationBuilderException( | ||
$"Resource {path} not found in assembly {assembly.FullName}." | ||
); | ||
} | ||
|
||
Version schemaVersion = | ||
new( | ||
JsonSerializer | ||
Check warning on line 75 in src/Lepo.i18n.Json/LocalizationBuilderExtensions.cs
|
||
.Deserialize<ITranslationsContainer>(contents, DefaultJsonSerializerOptions) | ||
?.Version ?? "1.0.0" | ||
); | ||
|
||
if (!schemaVersion.Major.Equals(1)) | ||
{ | ||
throw new LocalizationBuilderException( | ||
$"Localization file with schema version \"{schemaVersion.ToString() ?? "unknown"}\" is not supported." | ||
); | ||
} | ||
|
||
TranslationFile? translationFile = JsonSerializer.Deserialize<TranslationFile>( | ||
Check warning on line 87 in src/Lepo.i18n.Json/LocalizationBuilderExtensions.cs
|
||
contents, | ||
DefaultJsonSerializerOptions | ||
); | ||
|
||
if (translationFile is null) | ||
{ | ||
throw new LocalizationBuilderException("Unable to extract data from json file."); | ||
} | ||
|
||
Dictionary<string, string> localizedStrings = new(); | ||
|
||
foreach (TranslationEntity localizedString in translationFile.Strings) | ||
{ | ||
if (localizedStrings.ContainsKey(localizedString.Name)) | ||
{ | ||
throw new LocalizationBuilderException( | ||
$"The {path} file contains duplicate \"{localizedString.Name}\" keys." | ||
); | ||
} | ||
|
||
localizedStrings.Add(localizedString.Name, localizedString.Value); | ||
} | ||
|
||
builder.AddLocalization( | ||
new LocalizationSet( | ||
Path.GetFileNameWithoutExtension(path).Trim().ToLowerInvariant(), | ||
culture, | ||
localizedStrings! | ||
) | ||
); | ||
|
||
return builder; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
namespace Lepo.i18n.Json.Models; | ||
|
||
/// <summary> | ||
/// Defines a contract for a translations container with a schema version. | ||
/// </summary> | ||
internal interface ITranslationsContainer | ||
{ | ||
/// <summary> | ||
/// Gets the version of the translation container. | ||
/// </summary> | ||
string Version { get; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
namespace Lepo.i18n.Json.Models; | ||
|
||
internal record TranslationsContainer(string Version) : ITranslationsContainer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
namespace Lepo.i18n.Json.Models.v1; | ||
|
||
/// <summary> | ||
/// Represents a translation entity with a name and a value. | ||
/// </summary> | ||
/// <param name="Name">The name of the translation entity.</param> | ||
/// <param name="Value">The value of the translation entity.</param> | ||
[method: JsonConstructor] | ||
internal readonly record struct TranslationEntity(string Name, string Value); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. | ||
// All Rights Reserved. | ||
|
||
namespace Lepo.i18n.Json.Models.v1; | ||
|
||
/// <summary> | ||
/// Represents a translation file with a version and a collection of translation entities. | ||
/// </summary> | ||
/// <param name="Version">The version of the translation file.</param> | ||
/// <param name="Strings">The collection of translation entities in the file.</param> | ||
[method: JsonConstructor] | ||
internal sealed record TranslationFile(string Version, IEnumerable<TranslationEntity> Strings) | ||
: TranslationsContainer(Version); |