Class Library with Dependency Injection
This article describes recommended practice for writing a localized class library that uses Depedency Injection.
Localization Sources
The class library may want to provide builtin localizations. The recommended practice is to create a public class AssetSources which implements IAssetSources as a signal to indicate that this class provides localizations for this class library.
Internal localization files are typically embedded resources.
using System.Collections.Generic;
using Lexical.Localization;
using Lexical.Localization.Asset;
using Microsoft.Extensions.FileProviders;
namespace TutorialLibrary2
{
public class AssetSources : List<IAssetSource>, ILibraryAssetSources
{
/// <summary>
/// Localization source reference to embedded resource.
/// </summary>
public readonly LineEmbeddedSource LocalizationSource =
LineReaderMap.Default.EmbeddedAssetSource(typeof(AssetSources).Assembly, "docs.TutorialLibrary2-de.xml");
/// <summary>
/// (Optional) External file localization source.
/// </summary>
public readonly LineFileProviderSource ExternalLocalizationSource;
public AssetSources() : base()
{
// Add internal localization source
Add(LocalizationSource);
}
public AssetSources(IFileProvider fileProvider) : this()
{
// Use file provider from dependency injection and search for an optional external localization source
if (fileProvider != null)
{
ExternalLocalizationSource =
XmlLinesReader.Default.FileProviderAssetSource(fileProvider, "Resources/TutorialLibrary2.xml", throwIfNotFound: false);
Add(ExternalLocalizationSource);
}
}
}
}
The example localization file TutorialLibrary2-de.xml.
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Type="urn:lexical.fi:Type"
xmlns:Key="urn:lexical.fi:Key"
xmlns="urn:lexical.fi">
<!-- Example: Localization string for Culture "de" -->
<Type:TutorialLibrary2.MyClass Culture="de">
<Key:OK>Erfolgreich!</Key:OK>
</Type:TutorialLibrary2.MyClass>
</Localization>
Classes
Classes in the class library can use IStringLocalizer abstractions
using Microsoft.Extensions.Localization;
namespace TutorialLibrary2
{
public class MyClass
{
IStringLocalizer<MyClass> localizer;
public MyClass(IStringLocalizer<MyClass> localizer)
{
this.localizer = localizer;
}
public string Do()
{
return localizer["OK"];
}
}
}
... or alternatively Lexical.Localization.Abstractions.
using Lexical.Localization;
namespace TutorialLibrary2
{
public class MyClassB
{
ILine<MyClass> localizer;
public MyClassB(ILine<MyClass> localizer)
{
this.localizer = localizer;
}
public string Do()
{
return localizer.Key("OK").Format("Operation Successful").ToString();
}
}
}
Application
Application that deploys the localizer must include the internal localizations with IAssetBuilder.AddAssetSources(Assembly) which searches the IAssetSources from the library.
// Create localizer
IAssetBuilder builder = new AssetBuilder.OneBuildInstance();
IAsset asset = builder.Build();
StringLocalizerRoot localizer = new StringLocalizerRoot(asset, new CulturePolicy());
// Install TutorialLibrary's IAssetSources
Assembly library = typeof(MyClass).Assembly;
builder.AddLibraryAssetSources(library).Build();
// Create class
IStringLocalizer<MyClass> classLocalizer = localizer.Type<MyClass>().AsStringLocalizer<MyClass>();
MyClass myClass = new MyClass(classLocalizer);
// Use the culture that was provided with the class library (AssetSources)
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de");
Console.WriteLine(myClass.Do());
Supplying Localizations
The application can supply additional localization sources with IAssetBuilder.AddSource(IAssetSource)
// Install additional localization that was not available in the TutorialLibrary.
IAssetSource assetSource = XmlLinesReader.Default.FileAssetSource("TutorialLibrary2-fi.xml");
builder.AddSource(assetSource).Build();
The example localization file TutorialLibrary2-fi.xml.
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Type="urn:lexical.fi:Type"
xmlns:Key="urn:lexical.fi:Key"
xmlns="urn:lexical.fi">
<!-- Example: Localization string for Culture "fi" -->
<Type:TutorialLibrary2.MyClass Culture="fi">
<Key:OK>Toiminto onnistui!</Key:OK>
</Type:TutorialLibrary2.MyClass>
</Localization>
When class is initialized with IServiceProvider, additional localizations are added to IServiceCollection as IAssetSources. Extension method AddLexicalLocalization(this IServiceCollection) adds the default services for localization.
IServiceCollection services = new ServiceCollection();
// Install file provider service
services.AddSingleton<IFileProvider>(s=>new PhysicalFileProvider(Directory.GetCurrentDirectory()));
// Install default IStringLocalizerFactory
services.AddLexicalLocalization(
addStringLocalizerService: true,
addCulturePolicyService: true,
useGlobalInstance: false,
addCache: false);
// Install TutorialLibrary's IAssetSources.
Assembly library = typeof(MyClass).Assembly;
services.AddLibraryAssetSources(library);
// Install additional localization that was not available in the TutorialLibrary.
services.AddSingleton<IAssetSource>(XmlLinesReader.Default.FileAssetSource("TutorialLibrary2-fi.xml"));
// Service MyClass
services.AddTransient<MyClass, MyClass>();
// Create instance container
using (var provider = services.BuildServiceProvider())
{
// Create class
MyClass myClass = provider.GetService<MyClass>();
// Use the culture that was provided by with the class library (AssetSources)
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de");
Console.WriteLine(myClass.Do());
// Use the culture that we supplied above
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("fi");
Console.WriteLine(myClass.Do());
}