|
| 1 | +--- |
| 2 | +title: Localization |
| 3 | +page_title: Localization |
| 4 | +description: Localization texts in the Telerik UI for Blazor suite. |
| 5 | +slug: globalization-localization |
| 6 | +tags: telerik,blazor,localization |
| 7 | +published: True |
| 8 | +position: 1 |
| 9 | +--- |
| 10 | + |
| 11 | +# Localization |
| 12 | + |
| 13 | +Localization (L10N) is the process of customizing an app for a given language and region. The Telerik UI for Blazor suite lets you translate its UI elements into the desired language. This includes texts of buttons, filter operators, WAI-ARIA attributes and so on. This article will show you how to use this feature in your application: |
| 14 | + |
| 15 | +1. [How Localization Works in the Telerik Components](#how-localization-works-in-the-telerik-components) |
| 16 | +1. [How to Enable Localization in Your App](#how-to-enable-localization-in-your-app) |
| 17 | + |
| 18 | +## How Localization Works in the Telerik Components |
| 19 | + |
| 20 | +The Telerik UI for Blazor components use a set of keys that a localization service resolves to the strings that will be rendered in the UI. The format of the keys is `<ComponentName>_<MessageKey>`. Out of the box, the Telerik NuGet package carries a `.resx` file with the default (English) strings. It is used internally if no app-specific service is provided. |
| 21 | + |
| 22 | +You can find the list of keys (and their default values) by inspecting the `Resources/Messages.resx` file. You can find it in the NuGet package itself, and in the offline Demos installation (under a path like `C:\Program Files (x86)\Progress\Telerik UI for Blazor 2.4.0\demos\TelerikBlazorDemos\Resources`). Make sure to refer to the version you are currently using, because newer versions may have more keys than old versions as more components and features are added to the suite. |
| 23 | + |
| 24 | +Telerik provides and supports the default English texts. The offline demos carry a few resource files with translations in several languages that are provided as-is, and you can use them as base for implementing your own. |
| 25 | + |
| 26 | + |
| 27 | +## How to Enable Localization in Your App |
| 28 | + |
| 29 | +When localizing a Blazor app, make sure you are familiar with the way localization works in the framework. You can start from the following resources: |
| 30 | + |
| 31 | +* [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.0](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.0) |
| 32 | +* [https://github.com/aspnet/AspNetCore.Docs/issues/13436](https://github.com/aspnet/AspNetCore.Docs/issues/13436) |
| 33 | + |
| 34 | +The necessary steps are to: |
| 35 | + |
| 36 | +1. Enable the .NET Core localization services. |
| 37 | +1. Implement the UI culture storage (for example, a cookie). |
| 38 | +1. Optionally, add UI that will let the user change the culture so you can test how this works (for example, a dropdownlist that will redirect to the appropriate controller). Alternatively, you can hardcode the `options.DefaultRequestCulture` in the `ConfigureServices` method inside `Startup.cs` when generating the options for the framework localization service. |
| 39 | +1. Implement a service for localizing the Telerik components - it must return the desired string based on the current culture and the requested key (see the explanations above). |
| 40 | + |
| 41 | +>note The code snippets below will showcase a sample implementation for a server-side app. For a client-side app, some framework configurations my differ and you cannot use `.resx` files because the framework does not support them. |
| 42 | +
|
| 43 | +>tip You can find an example implementation in our offline demos project that you can find your Telerik UI for Blazor installation. |
| 44 | +
|
| 45 | +>caption Step 1 - Example for enabling localization in the app |
| 46 | +
|
| 47 | +````CS |
| 48 | +public class Startup |
| 49 | +{ |
| 50 | + // This method gets called by the runtime. Use this method to add services to the container. |
| 51 | + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 |
| 52 | + public void ConfigureServices(IServiceCollection services) |
| 53 | + { |
| 54 | + #region Localization |
| 55 | + |
| 56 | + services.AddControllers(); |
| 57 | + services.AddLocalization(options => options.ResourcesPath = "Resources"); |
| 58 | + services.Configure<RequestLocalizationOptions>(options => |
| 59 | + { |
| 60 | + // define the list of cultures your app will support |
| 61 | + var supportedCultures = new List<CultureInfo>() |
| 62 | + { |
| 63 | + new CultureInfo("en-US"), |
| 64 | + new CultureInfo("de-DE"), |
| 65 | + new CultureInfo("es-ES"), |
| 66 | + new CultureInfo("bg-BG"), |
| 67 | + }; |
| 68 | + |
| 69 | + // set the default culture |
| 70 | + options.DefaultRequestCulture = new RequestCulture("en-US"); |
| 71 | + |
| 72 | + options.SupportedCultures = supportedCultures; |
| 73 | + options.SupportedUICultures = supportedCultures; |
| 74 | + }); |
| 75 | + |
| 76 | + #endregion |
| 77 | + |
| 78 | + // there may be other services registered here, this is just an example |
| 79 | + services.AddRazorPages(); |
| 80 | + services.AddServerSideBlazor(); |
| 81 | + |
| 82 | + services.AddTelerikBlazor(); |
| 83 | + |
| 84 | + // register a custom localizer for the Telerik components |
| 85 | + services.AddSingleton(typeof(ITelerikStringLocalizer), typeof(SampleResxLocalizer)); |
| 86 | + } |
| 87 | + |
| 88 | + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. |
| 89 | + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) |
| 90 | + { |
| 91 | + #region Localization |
| 92 | + |
| 93 | + app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value); |
| 94 | + |
| 95 | + #endregion |
| 96 | + |
| 97 | + // the rest is just a sample app configuration |
| 98 | +
|
| 99 | + app.UseResponseCompression(); |
| 100 | + |
| 101 | + if (env.IsDevelopment()) |
| 102 | + { |
| 103 | + app.UseDeveloperExceptionPage(); |
| 104 | + } |
| 105 | + else |
| 106 | + { |
| 107 | + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. |
| 108 | + app.UseHsts(); |
| 109 | + } |
| 110 | + |
| 111 | + app.UseHttpsRedirection(); |
| 112 | + |
| 113 | + app.UseStaticFiles(); |
| 114 | + |
| 115 | + app.UseRouting(); |
| 116 | + |
| 117 | + app.UseEndpoints(endpoints => |
| 118 | + { |
| 119 | + // enable controllers for the culture controller |
| 120 | + endpoints.MapDefaultControllerRoute(); |
| 121 | + endpoints.MapControllers(); |
| 122 | + |
| 123 | + endpoints.MapBlazorHub(); |
| 124 | + endpoints.MapFallbackToPage("/_Host"); |
| 125 | + }); |
| 126 | + } |
| 127 | +} |
| 128 | +```` |
| 129 | + |
| 130 | +>caption Step 2 -Controller for changing the thread UI culture and redirecting the user (a redirect is required by the framework) |
| 131 | +
|
| 132 | +````CS |
| 133 | +[Route("[controller]/[action]")] |
| 134 | +public class CultureController : Controller |
| 135 | +{ |
| 136 | + public IActionResult SetCulture(string culture, string redirectUri) |
| 137 | + { |
| 138 | + if (culture != null) |
| 139 | + { |
| 140 | + HttpContext.Response.Cookies.Append( |
| 141 | + CookieRequestCultureProvider.DefaultCookieName, |
| 142 | + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("en-US", culture))); |
| 143 | + } |
| 144 | + |
| 145 | + return LocalRedirect(redirectUri); |
| 146 | + } |
| 147 | + |
| 148 | + public IActionResult ResetCulture(string redirectUri) |
| 149 | + { |
| 150 | + HttpContext.Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName); |
| 151 | + |
| 152 | + return LocalRedirect(redirectUri); |
| 153 | + } |
| 154 | +} |
| 155 | +```` |
| 156 | + |
| 157 | +>caption Use a cookie to store the culture choice of the user - in this example - in `~/Pages/_Host.cshtml` |
| 158 | +
|
| 159 | +````CSHTML |
| 160 | +@using Microsoft.AspNetCore.Localization |
| 161 | +@using System.Globalization |
| 162 | +
|
| 163 | +. . . . |
| 164 | +<body> |
| 165 | + @{ |
| 166 | + this.HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, |
| 167 | + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture)) |
| 168 | + ); |
| 169 | + } |
| 170 | + |
| 171 | + <app> |
| 172 | + <component type="typeof(App)" render-mode="ServerPrerendered" /> |
| 173 | + </app> |
| 174 | + |
| 175 | + . . . . |
| 176 | + |
| 177 | +</body> |
| 178 | +```` |
| 179 | + |
| 180 | +>caption Sample UI component for changing cultures |
| 181 | +
|
| 182 | +```` |
| 183 | +@using System.Threading |
| 184 | +
|
| 185 | +@inject NavigationManager NavigationManager |
| 186 | +
|
| 187 | +<div style="margin-bottom: 20px;"> |
| 188 | + Select your language: |
| 189 | + <TelerikDropDownList Data="@Cultures" |
| 190 | + Value="@SelectedCulture" |
| 191 | + ValueChanged="@((string value) => { OnValueChanged(value); })" |
| 192 | + PopupHeight="" |
| 193 | + TextField="@nameof(CultureData.Text)" |
| 194 | + ValueField="@nameof(CultureData.Value)"> |
| 195 | + </TelerikDropDownList> |
| 196 | +</div> |
| 197 | +
|
| 198 | +@code{ |
| 199 | + public class CultureData |
| 200 | + { |
| 201 | + public string Text { get; set; } |
| 202 | + public string Value { get; set; } |
| 203 | + } |
| 204 | +
|
| 205 | + public List<CultureData> Cultures { get; set; } = new List<CultureData>() |
| 206 | + { |
| 207 | + new CultureData() { Text = "English", Value = "en-US" }, |
| 208 | + new CultureData() { Text = "German", Value = "de-DE" }, |
| 209 | + new CultureData() { Text = "Spanish", Value = "es-ES" }, |
| 210 | + new CultureData() { Text = "Bulgarian", Value = "bg-BG" }, |
| 211 | + }; |
| 212 | +
|
| 213 | + public string SelectedCulture { get; set; } = Thread.CurrentThread.CurrentUICulture.Name; |
| 214 | +
|
| 215 | + public void OnValueChanged(string eventArgs) |
| 216 | + { |
| 217 | + SelectedCulture = eventArgs; |
| 218 | +
|
| 219 | + SetCulture(eventArgs); |
| 220 | + } |
| 221 | +
|
| 222 | + public void SetCulture(string culture) |
| 223 | + { |
| 224 | + var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); |
| 225 | + var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}"; |
| 226 | +
|
| 227 | + // use a path that matches your culture redirect controller from the previous steps |
| 228 | + NavigationManager.NavigateTo("/blazor-ui/Culture/SetCulture" + query, forceLoad: true); |
| 229 | + } |
| 230 | +} |
| 231 | +```` |
| 232 | + |
| 233 | +>caption Sample Telerik localization service implementation - this example relies on a `~/Resources` folder with the necessary `.resx` files. |
| 234 | +
|
| 235 | +>important You must implement the indexer only. You can obtain the needed strings from any source you prefer and that matches you application, such as database, `resx` files (not supported in client-side projects at the time of writing), `json` files, hash tables, and so on. |
| 236 | +
|
| 237 | +````CS |
| 238 | +public class SampleResxLocalizer : ITelerikStringLocalizer |
| 239 | +{ |
| 240 | + // this is the indexed you must implement |
| 241 | + public string this[string name] |
| 242 | + { |
| 243 | + get |
| 244 | + { |
| 245 | + return GetStringFromResource(name); |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + // sample implementation - uses .resx files in the ~/Resources folder names TelerikMessages.<culture-locale>.resx |
| 250 | + public string GetStringFromResource(string key) |
| 251 | + { |
| 252 | + return Resources.TelerikMessages.ResourceManager.GetString(key, Resources.TelerikMessages.Culture); ; |
| 253 | + } |
| 254 | +} |
| 255 | +```` |
| 256 | + |
| 257 | +>caption Add `.resx` files to the `~/Resources` folder |
| 258 | +
|
| 259 | +In this example the files must be named `~/Resources/TelerikMessages.<culture-locale>.resx`, for example `TelerikMessages.bg-BG.resx`. Make sure to |
| 260 | + |
| 261 | +* mark them as `Embedded Resource` |
| 262 | +* add this in your `ProjectName.csproj` file so they are built |
| 263 | + |
| 264 | +````XML |
| 265 | +<ItemGroup> |
| 266 | + <Compile Update="Resources\TelerikMessages.designer.cs"> |
| 267 | + <DesignTime>True</DesignTime> |
| 268 | + <AutoGen>True</AutoGen> |
| 269 | + <DependentUpon>TelerikMessages.resx</DependentUpon> |
| 270 | + </Compile> |
| 271 | +</ItemGroup> |
| 272 | + |
| 273 | +<ItemGroup> |
| 274 | + <EmbeddedResource Update="Resources\TelerikMessages.resx"> |
| 275 | + <Generator>PublicResXFileCodeGenerator</Generator> |
| 276 | + <LastGenOutput>TelerikMessages.Designer.cs</LastGenOutput> |
| 277 | + </EmbeddedResource> |
| 278 | +</ItemGroup> |
| 279 | +```` |
| 280 | + |
| 281 | +## See Also |
| 282 | + |
| 283 | + * [Globalization Overview]({%slug globalization-overview%}) |
0 commit comments