ASP.NET Boilerplate defines a strong UI localization system which is used both in server and client side. It allows to easily configure application languages and define localization texts (strings) in different sources (Resource files and XML files are two pre-defined source).
While it's good for most cases, we may want to define languages and texts dynamically on a database. Module-Zero allows us to dynamically manage application languages and texts per tenant.
It's strongly suggested to read localization documentation before this document.
If you create your project from startup templates, you can skip this section since the template comes with database based localization enabled by default. If you created your project before this feature, please read this to enable it for your application.
Database localization is designed to be backward-compatible with ASP.NET Boilerplate's existing localization system. It actually replaces all existing dictionary based localization sources with the MultiTenantLocalizationSource.
MultiTenantLocalizationSource wraps existing DictionaryBasedLocalizationSource based sources. So, we generally wrap XML based localization sources. It can not wrap Resource File sources since resource files are designed to work hard-coded and static files which is not proper for dynamic localization.
Since it's a wrapper, underlying XML files are used as fallback source if a text is not localized in the database. It may seems complicated, but easy to implement for your application. Let's see how to enable database based localization.
First, we are enabling it:
Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();
This should be done in the top level module's PreInitialize method (it's the web module for a web application. Import Abp.Zero.Configuration namespace (using Abp.Zero.Configuration) to see the Zero() extension method).
Actually, this configuration makes all the magic. But, we should make a bit more to make it properly work.
Since ABP will get list of languages from database anymore, we should insert default languages to database. If you're using EntityFramework, you can use seed code as like this one:
If you have static language configuration as shown below, you can delete these lines from your configuration code, since it will get languages from database anymore.
Configuration.Localization.Languages.Add(new LanguageInfo("en", "English", "famfamfam-flag-england", true));
Do not delete your XML localization files and source configuration code. Because, these files are used as fallback source and also all localization keys are obtained from this source.
So, when you need to a new localized text, define it into XML files as you do normally. You should at least define it in default language's XML file. Also thus, you don't need to add default values of localized texts to database migration code.
IApplicationLanguageManager interface is injected and used to manage languages. It has methods like GetLanguagesAsync, AddAsync, RemoveAsync, UpdateAsync... to manage languages for host and tenants.
List of languages are stored per tenant and for the host, and calculated as below:
ApplicationLanguage entity represents a language for a tenant or the host.
[Serializable]
[Table("AbpLanguages")]
public class ApplicationLanguage : FullAuditedEntity, IMayHaveTenant
{
//...
}
It's basic properties are:
Also, ApplicationLanguage inherits FullAuditedEntity as you see. That means, it's a soft-delete entity and automatically audited (see entity document for more).
ApplicationLanguage entities are stored in AbpLanguages table in the database.
IApplicationLanguageTextManager interface is injected and used to manage localization texts. It has needed methods to get/set a localization text for a tenant or the host.
Let's see what happens when you want to localize a text;
So, getting a localized text is a bit complicated. But it works fast since it uses cache.
ApplicationLanguageText is used to store localized values in the database.
[Serializable]
[Table("AbpLanguageTexts")]
public class ApplicationLanguageText : AuditedEntity<long>, IMayHaveTenant
{
//...
}
It's basic properties are;
ApplicationLanguageText entities are stored in AbpLanguageTexts table in the database.