Skip to content

2.5 Localization

Marjan Nikolovski edited this page Apr 9, 2021 · 1 revision

Purpose

Language localization is the process of adapting text with translation to a specific country or region. It is the second phase of a larger process of product translation and cultural adaptation (for specific countries, regions, cultures or groups) to account for differences in distinct markets, a process known as internationalization and localization.

Signals offers multiple implementations for the Communication channels aspect out of the box:

  • Signals.Aspects.Localization.File
  • Signals.Aspects.Localization.Database

Only one implementation can be active at a time.

How to use

First we must define a file or database with key-value pairs with translated messages for each culture we need. Files must have property "Copy to Output Directory" set to "Copy always".

File example in file example.en-US.app:

{
    "MySpecification": "My property is required",
    "MyKey": "My value",
}

When we implement any type of process a localization provider is automatically injected in the process context. Every time there is a falied specification the localization provider searches for a translation based on the failed specification class name and returns a user visible message with the translated value.

public class MyProcess : BusinessProcess<VoidResult>
{
    /// <summary>
    /// Authenticate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Auth()
    {
        return Ok();
    }

    /// <summary>
    /// Validate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Validate()
    {
        // if the specification fails
        // it will return failed result with error message "My property is required"
        // based on the file described above
        return BeginValidation()
            .Validate(new MySpecification())
            .ReturnResult();
    }

    /// <summary>
    /// Handle process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Handle()
    {
        var translation = Context.LocalizationProvider.Get("MyKey");

        return Ok();
    }
}

Other more manual way of using the localization aspect is through the ILocalizationProvider instance.

public string GetTranslation(string key)
{
    var localizationProvider = SystemBootstrapper.GetInstance<ILocalizationProvider>();
    var translation = localizationProvider.Get(key);

    return translation ?? $"Translation for {key} was not found";
}
public string GetTranslationFromFile(string key, string file)
{
    var localizationProvider = SystemBootstrapper.GetInstance<ILocalizationProvider>();
    var translation = localizationProvider.Get(key, file);

    return translation ?? $"Translation for {key} was not found";
}
public string GetTranslationFromFolderAndFile(string key, string file, string folder)
{
    var localizationProvider = SystemBootstrapper.GetInstance<ILocalizationProvider>();
    var translation = localizationProvider.Get(key, file, folder);

    return translation ?? $"Translation for {key} was not found";
}

Configuration

We configure the localization aspect by using an instance of Signals.Aspects.Localization.ILocalizationConfiguration which we pass in the ApplicationBootstrapConfiguration instance (web or background) at startup.

Properties explanation

JsonDataProviderConfiguration

  • DirectoryPath: Root directory of json files. Default AppDomain.CurrentDomain.BaseDirectory
  • FileExtension: File extension of localization files. Default “app”`
  • LocalizationSources: List of localization files
  • Name: Collection name
  • SourcePath: Subfolder name

DatabaseDataProviderConfiguration

  • ConnectionString: Connection string to database
  • LocalizationEntryTableName: Default "LocalizationEntry"
  • LocalizationCollectionTableName: Default "LocalizationCollection"
  • LocalizationCategoryTableName: Default "LocalizationCategory"
  • LocalizationKeyTableName: Default "LocalizationKey"
  • LocalizationLanguageTableName: Default "LocalizationLanguage"

Examples

Using Signals.Aspects.Localization.File

services
    .AddSignals(config =>
    {
        config.LocalizationConfiguration = new JsonDataProviderConfiguration
        {
            DirectoryPath = Path.Combine(AppContext.BaseDirectory, "system.resources"),
            FileExtension = "app",
            LocalizationSources = new List<LocalizationSource>
            {
                new LocalizationSource
                {
                    Name = "Mail messages",
                    SourcePath = "mailmessages"
                },
                new LocalizationSource
                {
                    Name = "Validation rules",
                    SourcePath = "validationrules"
                },
                new LocalizationSource
                {
                    Name = "Pages",
                    SourcePath = "pages"
                },
                new LocalizationSource
                {
                    Name = "Processes",
                    SourcePath = "processes"
                }
            }
        };
    });

Using Signals.Aspects.Localization.Database

services
    .AddSignals(config =>
    {
        config.LocalizationConfiguration = new DatabaseDataProviderConfiguration(myConnectionString)
        {
            ConnectionString = myConnectionString,
            LocalizationCategoryTableName = "LocalizationCategory",
            LocalizationCollectionTableName = "LocalizationCollection",
            LocalizationEntryTableName = "LocalizationEntry",
            LocalizationKeyTableName = "LocalizationKey",
            LocalizationLanguageTableName = "LocalizationLanguage"
        };
    });

Extending localization

  1. Install package Signals.Aspects.Localization
  2. Create class with implementation of Signals.Aspects.Localization.ILocalizationConfiguration
/// <summary>
/// Localization configuration contract
/// </summary>
public class MyLocalizationConfiguration : ILocalizationConfiguration
{
    public string MyProperty { get; set; }
}
  1. Create class with implementation of Signals.Aspects.Localization.ILocalizationDataProvider
/// <summary>
/// Localization data provider ontract
/// </summary>
public class MyLocalizationDataProvider : ILocalizationDataProvider
{
    private MyLocalizationConfiguration _configuraiton;

    /// <summary>
    /// CTOR
    /// </summary>
    /// <param name="configuraiton"></param>
    public MyLocalizationDataProvider(MyLocalizationConfiguration configuraiton)
    {
        _configuraiton = configuraiton;
    }

    //
    /// <summary>
    /// Inserts new localization entry
    /// </summary>
    /// <param name="entry"></param>
    void InsertLocalizationEntry(LocalizationEntry entry);

    /// <summary>
    /// Inserts new localization key
    /// </summary>
    /// <param name="localizationKey"></param>
    void InsertLocalizationKey(LocalizationKey localizationKey);

    /// <summary>
    /// Inserts new localization language
    /// </summary>
    /// <param name="localizationLanguage"></param>
    void InsertLocalizationLanguage(LocalizationLanguage localizationLanguage);

    /// <summary>
    /// Inserts new localization category
    /// </summary>
    /// <param name="localizationCategory"></param>
    void InsertOrUpdateLocalizationCategory(LocalizationCategory localizationCategory);

    /// <summary>
    /// Inserts new localization collection
    /// </summary>
    /// <param name="localizationCollection"></param>
    void InsertOrUpdateLocalizationCollection(LocalizationCollection localizationCollection);

    /// <summary>
    /// Inserts or updates list of localization entries
    /// </summary>
    /// <param name="entries"></param>
    void InsertOrUpdateLocalizationEnties(List<LocalizationEntry> entries);

    /// <summary>
    /// Loads the localization categories
    /// </summary>
    List<LocalizationCategory> LoadLocalizationCategories();

    /// <summary>
    /// Loads the localization collections
    /// </summary>
    List<LocalizationCollection> LoadLocalizationCollections();

    /// <summary>
    /// Loads the localization entries
    /// </summary>
    List<LocalizationEntry> LoadLocalizationEntries();

    /// <summary>
    /// Loads the localizaiton keys
    /// </summary>
    List<LocalizationKey> LoadLocalizationKeys();

    /// <summary>
    /// Loads the localization languages
    /// </summary>
    List<LocalizationLanguage> LoadLocalizationLanguages();

    /// <summary>
    /// Updates all localization entries
    /// </summary>
    /// <param name="entries"></param>
    void UpdateAll(List<LocalizationEntry> entries);

    /// <summary>
    /// Updates an existing localizaiton entry
    /// </summary>
    /// <param name="entry"></param>
    void UpdateLocalizationEntry(LocalizationEntry entry);
}
  1. Use our implementation of ILocalizationConfiguration when configuring our application
public static IServiceProvider AddSignals(this IServiceCollection services)
{
    services
        .AddSignals(config =>
        {
            config.LocalizationConfiguration = new MyLocalizationConfiguration
            {
                MyProperty = "my_value"
            };
        });
}
Clone this wiki locally