Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
pomianowski committed May 19, 2024
1 parent fd3b131 commit 6fa5047
Show file tree
Hide file tree
Showing 35 changed files with 850 additions and 320 deletions.
13 changes: 13 additions & 0 deletions Lepo.i18n.sln
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{AA93DD64
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lepo.i18n.UnitTests", "tests\Lepo.i18n.UnitTests\Lepo.i18n.UnitTests.csproj", "{98789E33-F370-46FF-B4B6-CEAA81E9C2C3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lepo.i18n.DependencyInjection", "src\Lepo.i18n.DependencyInjection\Lepo.i18n.DependencyInjection.csproj", "{6297D5AB-EE2C-4DBB-BE29-B4813BB8803F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lepo.i18n.DependencyInjection.UnitTests", "tests\Lepo.i18n.DependencyInjection.UnitTests\Lepo.i18n.DependencyInjection.UnitTests.csproj", "{274021AA-F5A4-4A02-B8B7-224B254031A1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -52,12 +56,21 @@ Global
{98789E33-F370-46FF-B4B6-CEAA81E9C2C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98789E33-F370-46FF-B4B6-CEAA81E9C2C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98789E33-F370-46FF-B4B6-CEAA81E9C2C3}.Release|Any CPU.Build.0 = Release|Any CPU
{6297D5AB-EE2C-4DBB-BE29-B4813BB8803F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6297D5AB-EE2C-4DBB-BE29-B4813BB8803F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6297D5AB-EE2C-4DBB-BE29-B4813BB8803F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6297D5AB-EE2C-4DBB-BE29-B4813BB8803F}.Release|Any CPU.Build.0 = Release|Any CPU
{274021AA-F5A4-4A02-B8B7-224B254031A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{274021AA-F5A4-4A02-B8B7-224B254031A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{274021AA-F5A4-4A02-B8B7-224B254031A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{274021AA-F5A4-4A02-B8B7-224B254031A1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{98789E33-F370-46FF-B4B6-CEAA81E9C2C3} = {AA93DD64-B88F-46ED-9981-EABA0F3C3E95}
{274021AA-F5A4-4A02-B8B7-224B254031A1} = {AA93DD64-B88F-46ED-9981-EABA0F3C3E95}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF9C3C0B-D0EC-4FA3-A0D5-A8F70572737A}
Expand Down
10 changes: 10 additions & 0 deletions src/Lepo.i18n.DependencyInjection/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// 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 Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Localization;
global using System;
global using System.Collections.Generic;
global using System.Linq;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>Lepo.i18n.DependencyInjection</PackageId>
<TargetFrameworks>netstandard2.0;netstandard2.1;net462;net6.0;net8.0</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PublishAot>true</PublishAot>
<StripSymbols>true</StripSymbols>
<OptimizationPreference>Speed</OptimizationPreference>
</PropertyGroup>

<!-- Necessary polyfills -->
<PropertyGroup>
<PolySharpIncludeGeneratedTypes>
System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute;
System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute;
System.Diagnostics.CodeAnalysis.MemberNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullWhenAttribute;
System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute;
System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute;
System.Runtime.CompilerServices.CallerArgumentExpressionAttribute;
System.Runtime.CompilerServices.IsExternalInit;
System.Runtime.CompilerServices.SkipLocalsInitAttribute;
</PolySharpIncludeGeneratedTypes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lepo.i18n\Lepo.i18n.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,30 @@ public static class ServiceCollectionExtensions
/// Adds a string localizer to the specified services collection.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the string localizer to.</param>
/// <param name="configure">An action to configure the <see cref="StringLocalizerBuilder"/>.</param>
/// <param name="configure">An action to configure the <see cref="LocalizationBuilder"/>.</param>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
/// <remarks>
/// This method configures a <see cref="StringLocalizerBuilder"/>, creates a <see cref="StringLocalizer"/> from it,
/// This method configures a <see cref="LocalizationBuilder"/>, creates a <see cref="StringLocalizer"/> from it,
/// sets the <see cref="StringLocalizer"/> as the instance in the <see cref="StringLocalizerFactory"/>,

Check warning on line 21 in src/Lepo.i18n.DependencyInjection/ServiceCollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / deploy

XML comment has cref attribute 'StringLocalizerFactory' that could not be resolved

Check warning on line 21 in src/Lepo.i18n.DependencyInjection/ServiceCollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / deploy

XML comment has cref attribute 'StringLocalizerFactory' that could not be resolved

Check warning on line 21 in src/Lepo.i18n.DependencyInjection/ServiceCollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / deploy

XML comment has cref attribute 'StringLocalizerFactory' that could not be resolved

Check warning on line 21 in src/Lepo.i18n.DependencyInjection/ServiceCollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / deploy

XML comment has cref attribute 'StringLocalizerFactory' that could not be resolved

Check warning on line 21 in src/Lepo.i18n.DependencyInjection/ServiceCollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / deploy

XML comment has cref attribute 'StringLocalizerFactory' that could not be resolved
/// and then adds the <see cref="ILocalizationManager"/> and <see cref="IStringLocalizer"/> services to the services collection.
/// and then adds the <see cref="ILocalizationCultureManager"/> and <see cref="IStringLocalizer"/> services to the services collection.
/// </remarks>
public static IServiceCollection AddStringLocalizer(
this IServiceCollection services,
Action<StringLocalizerBuilder> configure
Action<LocalizationBuilder> configure
)
{
StringLocalizerBuilder builder = new();
LocalizationBuilder builder = new();

configure(builder);

StringLocalizer localizer = new(builder.GetLocalizations());
LocalizationProvider localizer = new(builder.GetLocalizations());
LocalizationProvider.SetInstance(localizer);

StringLocalizerFactory.SetInstance(localizer);

_ = services.AddSingleton<ILocalizationManager, LocalizationManager>();
_ = services.AddSingleton<IStringLocalizer>((_) => StringLocalizerFactory.GetInstance()!);
_ = services.AddSingleton<ILocalizationProvider>(
(_) => LocalizationProvider.GetInstance()!
);
_ = services.AddTransient<ILocalizationCultureManager, LocalizationCultureManager>();
_ = services.AddTransient<IStringLocalizer, StringLocalizer>();

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,11 @@

namespace Lepo.i18n;

/// <summary>
/// Provides localized strings for a specific culture.
/// </summary>
/// <remarks>
/// This class implements the <see cref="IStringLocalizer"/> interface and provides localized strings
/// based on the provided dictionary of localized strings and the current culture.
/// </remarks>
public class StringLocalizer(IDictionary<CultureInfo, IEnumerable<LocalizedString>> localizations)
: IStringLocalizer
public class StringLocalizer(
ILocalizationProvider localizations,
ILocalizationCultureManager cultureManager
) : IStringLocalizer
{
private CultureInfo culture = CultureInfo.CurrentCulture;

/// <summary>
/// Gets the localized string for the specified name.
/// </summary>
Expand All @@ -33,31 +26,17 @@ public class StringLocalizer(IDictionary<CultureInfo, IEnumerable<LocalizedStrin
public LocalizedString this[string name, params object[] arguments] =>
LocalizeString(name, arguments);

/// <summary>
/// Updates the culture used for localization.
/// </summary>
/// <param name="culture">The new culture to use for localization.</param>
/// <remarks>
/// This method updates the culture used for localization. It does not validate whether the culture is supported.
/// </remarks>
public void SetCulture(CultureInfo culture)
{
this.culture = culture;
}

/// <summary>
/// Gets all the localized strings for the current culture.
/// </summary>
/// <param name="_">A boolean parameter (not used).</param>
/// <returns>The localized strings.</returns>
public IEnumerable<LocalizedString> GetAllStrings(bool _)
{
if (localizations.TryGetValue(culture, out IEnumerable<LocalizedString>? translations))
{
return translations;
}

return [];
return localizations
.Get(cultureManager.GetCulture())
?.Strings.Select(x => new LocalizedString(x.Key, x.Value ?? x.Key))
?? Enumerable.Empty<LocalizedString>();
}

private LocalizedString LocalizeString(string name, object[] placeholders)
Expand Down
6 changes: 3 additions & 3 deletions src/Lepo.i18n.Json/StringLocalizerBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
namespace Lepo.i18n.Yaml;

/// <summary>
/// Provides extension methods for the <see cref="StringLocalizerBuilder"/> class.
/// Provides extension methods for the <see cref="LocalizationBuilder"/> class.
/// </summary>
public static class StringLocalizerBuilderExtensions
{
public static StringLocalizerBuilder FromJson(
this StringLocalizerBuilder builder,
public static LocalizationBuilder FromJson(
this LocalizationBuilder builder,
string path,
CultureInfo culture
)
Expand Down
3 changes: 2 additions & 1 deletion src/Lepo.i18n.Wpf/StringLocalizerExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public StringLocalizerExtension(string text)
return string.Empty;
}

return StringLocalizerFactory.GetInstance()?[EscapeText(Text)] ?? EscapeText(Text);
//return LocalizationProvider.GetInstance()?[EscapeText(Text)] ?? EscapeText(Text);
return string.Empty;
}

/// <summary>
Expand Down
9 changes: 9 additions & 0 deletions src/Lepo.i18n.Yaml/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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.Text;
8 changes: 3 additions & 5 deletions src/Lepo.i18n.Yaml/StringLocalizerBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors.
// All Rights Reserved.

using System.Globalization;

namespace Lepo.i18n.Yaml;

/// <summary>
/// Provides extension methods for the <see cref="StringLocalizerBuilder"/> class.
/// Provides extension methods for the <see cref="LocalizationBuilder"/> class.
/// </summary>
public static class StringLocalizerBuilderExtensions
{
public static StringLocalizerBuilder FromYaml(
this StringLocalizerBuilder builder,
public static LocalizationBuilder FromYaml(
this LocalizationBuilder builder,
string path,
CultureInfo culture
)
Expand Down
77 changes: 77 additions & 0 deletions src/Lepo.i18n.Yaml/YamlDecoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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 System.Security.Cryptography;

namespace Lepo.i18n.Yaml;

/// <summary>
/// Some weird YAML implementation. Don't ask me, it was supposed to be simple...
/// </summary>
internal class YamlDecoder
{
/// <summary>
/// Used to calculate a simple hash of a key in a dictionary to make searches faster.
/// </summary>
private static readonly MD5 Hasher = MD5.Create();

/// <summary>
/// Creates a hashed <see langword="int"/> representation of <see langword="string"/>.
/// </summary>
/// <param name="value">Value to be hashed.</param>
/// <returns></returns>
public static uint Map(string value)
{
return BitConverter.ToUInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(value)), 0);
}

/// <summary>
/// Creates new collection of mapped keys with translated values.
/// </summary>
/// <param name="rawYamlContent">String containing Yaml.</param>
public static IDictionary<uint, string> FromString(string rawYamlContent)
{
Dictionary<uint, string> keyValueCollection = new() { };

if (String.IsNullOrEmpty(rawYamlContent))
return keyValueCollection;

string[] splittedYamlLines = rawYamlContent.Split(
new[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);

// TODO: Recognize tab stops as subsections

if (splittedYamlLines.Length < 1)
return keyValueCollection;

foreach (string yamlLine in splittedYamlLines)
{
if (yamlLine.StartsWith("#") || String.IsNullOrEmpty(yamlLine))
continue;

string[] pair = yamlLine.Split(new[] { ':' }, 2);

if (pair.Length < 2)
continue;

uint mappedKey = Map(pair[0].Trim());

var translatedValue = pair[1].Trim();

if (
translatedValue.StartsWith("'") && translatedValue.EndsWith("'")
|| translatedValue.StartsWith("\"") && translatedValue.EndsWith("\"")
)
translatedValue = translatedValue.Substring(1, translatedValue.Length - 2);

if (!keyValueCollection.ContainsKey(mappedKey))
keyValueCollection.Add(mappedKey, translatedValue);
}

return keyValueCollection;
}
}
3 changes: 0 additions & 3 deletions src/Lepo.i18n/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@
// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors.
// All Rights Reserved.

global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Localization;
global using System;
global using System.Collections;
global using System.Collections.Generic;
global using System.Globalization;
global using System.Linq;
global using System.Reflection;
global using System.Resources;
global using System.Text;
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ namespace Lepo.i18n;
/// <summary>
/// Manages localization settings.
/// </summary>
public interface ILocalizationManager
public interface ILocalizationCultureManager
{
/// <summary>
/// Sets the culture to be used for localization.
/// </summary>
/// <param name="culture">The culture to be used for localization.</param>
/// <remarks>
/// This method sets the culture for the <see cref="StringLocalizerFactory"/> instance.
/// </remarks>
void SetCulture(CultureInfo culture);

CultureInfo GetCulture();
}
29 changes: 29 additions & 0 deletions src/Lepo.i18n/ILocalizationProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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;

/// <summary>
/// Provides functionality to retrieve localization sets for specific cultures.
/// </summary>
public interface ILocalizationProvider
{
/// <summary>
/// Retrieves the localization set for the specified culture.
/// </summary>
/// <param name="culture">The culture to get the localization set for.</param>
/// <returns>The localization set for the specified culture, or null if no localization set is found.</returns>

LocalizationSet? Get(CultureInfo culture);

/// <summary>
/// Retrieves the localization set with the specified name for the specified culture.
/// </summary>
/// <param name="name">The name of the localization set to get.</param>
/// <param name="culture">The culture to get the localization set for.</param>
/// <returns>The localization set with the specified name for the specified culture, or null if no localization set is found.</returns>

LocalizationSet? Get(string name, CultureInfo culture);
}
4 changes: 0 additions & 4 deletions src/Lepo.i18n/Lepo.i18n.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,5 @@
System.Runtime.CompilerServices.SkipLocalsInitAttribute;
</PolySharpIncludeGeneratedTypes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" />
</ItemGroup>

</Project>
Loading

0 comments on commit 6fa5047

Please sign in to comment.