Skip to content

Commit

Permalink
Add ability to use IStringLocalizerFactory/IStringLocalizer implement…
Browse files Browse the repository at this point in the history
…ation (#37)

* Add ability to use IStringLocalizerFactory/IStrinLocilizer implemntations

* Update README.md

* fix typo
  • Loading branch information
npavlyk82 committed Jun 27, 2024
1 parent db41f91 commit 60583a0
Show file tree
Hide file tree
Showing 15 changed files with 660 additions and 87 deletions.
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@ The last step is to implement and register an IResourcesProvider. This provider
services.AddSingleton<IResourcesProvider, MyResourcesProvider>();
```

The alternative way is to implement both the IStringLocalizerFactory and IStringLocalizer interfaces.
Additionally, we can use resource type marker classes.
This approach overrides all logic related to the usage of the IResourcesProvider interface.
```csharp
namespace Namespace.Namespace1.Namespace2;

[ResourceTypeAlias("SomePath")]
public class CustomResource
{
}

new ServiceCollection()
.AddGraphQLServer()
.SetSchema<MySchema>()
.AddTranslation(
/* add all translatable types explicitely, except String, which is already added implicitely. */
c => c.AddTranslatableType<Country>()
.AddTranslatableType<MyEnum2>()
)
.AddStringLocalizerFactory()
.AddStringLocalizer<CustomLocalizer>(ServiceLifetime.Singleton, typeof(CustomResource))
.AddStringLocalizer<OtherCustomLocalizer>(ServiceLifetime.Scoped, [ typeof(OtherCustomResource) /* additional resources can share the same localizer logic */ ]);
```

If the resource type is not decorated with the ResourceTypeAlias attribute,
the default alias is generated from the namespace and name of the resource class.
For the case described above, it would generate the alias "Namespace::Namespace1::Namespace2::CustomResource".


With this we have registered the necessary objects to support translation on our fields. Now we can start adding translation support to our fields.

### Translating fields
Expand All @@ -63,23 +92,43 @@ We can also rewrite our string/enum/other field to make it a `{ key label }` fie
This can be useful if we also use Array Translations, which use the same typing (see next chapter).

```csharp
[ResourceTypeAlias("Ref/Aex/Countries"))]
public class CountryResource
{
}

public class AddressType : ObjectType<Query>
{
protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
{
descriptor
.Field(c => c.Country) // The Country property is a Country enum
.Translate("Ref/Aex/Countries");

// OR
// descriptor
// .Field(c => c.Country)
// .Translate(typeof(CountryResource));
}
}
```

Alternatively it is possible to translate the field via an attribute directly on the property:
```csharp
[ResourceTypeAlias("Ref/Aex/Countries"))]
public class CountryResource
{
}

public class Address
{
[Translate("Ref/Aex/Countries")]
public Country Country { get; }


// OR
// [Translate(typeof(CountryResource)]
// public Country Country { get; }
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using HotChocolate.Extensions.Translation.Resources;

namespace HotChocolate.Extensions.Translation.Tests;

[ResourceTypeAlias(Path)]
public class TestResourceType
{
public const string Path = "myNodePath";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using HotChocolate.Extensions.Translation.Resources;
using HotChocolate.Extensions.Translation.Tests.Mock;
using Microsoft.Extensions.Localization;

namespace HotChocolate.Extensions.Translation.Tests;

public class TestStringLocalizer : IStringLocalizer
{
private readonly DictionaryResourcesProviderAdapter _dictionaryResourcesProviderAdapter;

public TestStringLocalizer(
Func<IDictionary<Mock.Language, Dictionary<string, Resource>>> func)
{
_dictionaryResourcesProviderAdapter =
new DictionaryResourcesProviderAdapter(func());
}

public LocalizedString this[string name]
{
get
{
CultureInfo culture = Thread.CurrentThread.CurrentCulture;

string notFound = "*** NOT FOUND ***";

var translatedValue =
_dictionaryResourcesProviderAdapter.TryGetTranslationAsStringAsync(
$"{TestResourceType.Path}/{name}", culture, notFound, CancellationToken.None)
.GetAwaiter().GetResult();

return new LocalizedString(
name,
translatedValue == notFound ? name : translatedValue,
resourceNotFound: translatedValue == notFound);
}
}

public LocalizedString this[string name, params object[] arguments] =>
new LocalizedString(name, string.Format(this[name].Value, arguments));


public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
{
throw new NotImplementedException();
}
}
Loading

0 comments on commit 60583a0

Please sign in to comment.