Introduction: What's "Blazor" (client-side)?
"Blazor" (client-side) is a Single Page Web Application (a.k.a "SPA") framework.
Client-side Blazor allows you to run C# code and .NET Standard 2.0 native assembly (.dll) on a top of modern web browser's WebAssembly engine, without any .NET server processes.
If you are new to Blazor, I recommend watching this YouTube video.
NDC Oslo 2017 - "Web Apps canβt really do that, can they? - Steve Sanderson"
The video was about prototype of Blazor, and the current version when I wrote this post was v.0.9.0, which had some breaking changes. But that video is useful to understanding the concept and pros/cons of "Blazor".
Localization of client-side Blazor WebAssembly App
Scope of this article
This article will only discuss text localization scenarios.
Date, time, and currency formats are outside the scope of this article.
And also, server-side Blazor is out of this article, too.
[2019/11/09] "Blazor I18n Text" Library ver.7 started support Server-Side Blazor! π
Are there already any solutions for text localization?
Yes, we can find great solutions and articles about it on the internet.
For example:
- "Localization In Blazor App Using Microsoft.JSInterop"
- "Internationalizing a Blazor App with ASPNET Core as backend service"
However, I couldn't be satisfied with the above solutions, because those solutions have consideration points below.
The 4 reasons why I wasn't satisfied with the above solutions
1. It requires Server-Side implementation.
Blazor is a client-side solution, therefore, a Blazor app can deploy on static contents only HTTP server, like GitHub pages.
However, the above localization solutions require a server side ASP.NET Core implementation, and of course it requires Web server which can run ASP.NET Core.
2. It requires .resx editor.
.resx file is a just an XML format file, and it is popular to be used in localization scenario in general C# programming.
However, to edit .resx file, you will need Visual Studio. It's hard work that editing .resx file with a text editor, I think.
3. It requires key access by "string".
A common text localization solution works as getting localized text from a "key".
In the above solutions, you must describe key by string in C#/Razor source code.
Writing a key as string often can be causing miss typing, and that miss can't detect at compile time.
It also can't get the help of the code completion feature of an editor. (ex. "IntelliSense")
I really want to get static typing solutions rather than late binding solutions such as key accessing by string
4. It doesn't consider Blazor components libraries.
Blazor support creating and reusing component library as NuGet package.
However, the above solutions couldn't resolve the localization texts in Blazor component library package.
I decided to make a new solution.
As mentioned above, I couldn't be satisfied any solutions which I found on the internet, therefore, I decided to make a new solution.
My approach is...
The most important point of my approach is, not only writing library code but writing build script for processing some tasks (such as generate static typing files, generate localized text files as static contents) at build time.
- Use the simple JSON/CSV format instead of the .resx file format to writing the key-localized text corresponds table (I call it "localized text source file").
- Generate static typed C# class (I call it as "text table class") source code files from "localized text source files" on build automatically.
- "text table class" has fields associated with each key in "localized test source file".
- And also generate JSON format files (I call it as "localized text resource JSON file") in under the "wwwroot" content folder from "localized text source files" on build automatically.
- "localized text resource JSON files" are deployed as static content files on a Web server, and those are fetched from Blazor client process at run time.
- Include an "msbuild" script that makes "localized text resource JSON files" to be contained in a NuGet package of Blazor component library.
... and, I did it!
The result of my work is here:
- Blazor Internationalization(I18n) Text - "Toolbelt.Blazor.I18nText" NuGet package
No .resx, simple JSON format, and also CSV format is available!
It works on GitHub pages. (static contents only HTTP server)
IntelliSense works well.
How to use it?
Step.1 - Add "Toolbelt.Blazor.I18nText" Package
Add Toolbelt.Blazor.I18nText
NuGet package to your Blazor app project.
If you are using dotnet CLI, you can do it by command line bellow.
$ dotnet add package Toolbelt.Blazor.I18nText
You can also do it in Package Manager Console of Visual Studio, if you are using Visual Studio in Windows OS.
PM> Install-Package Toolbelt.Blazor.I18nText
Step.2 - Create localized text source files as JSON or CSV
Add localized text source files for each language in a i18ntext
folder under your Blazor app project folder.
The localized text source files must be simple key-value only JSON file like a bellow example,
{
"Key1": "Localized text 1",
"Key2": "Localized text 2",
...
}
or, 2 column only CSV file without header row like a bellow example.
Key1,Localized text 1
Key2,Localized text 2
NOTICE - The encoding of CSV file must be UTF-8.
And, the naming rule of localized text source files must be bellow.
<Text Table Name>.<Language Code>.{json|csv}
Step.3 - Build the project always when localized text source files are created or updated.
After creating or updating those localized text source files, you have to build your Blazor app project.
After building the project, "Typed Text Table class" C# files will be generated in the i18ntext/@types
folder, by the building process.
And also, "Localized Text Resource JSON" files will be generated at the wwwroot/content/i18ntext
folder, too.
NOTE - If you want to do this automatically whenever those localized text source files (.json or .csv) are changed, you can use dotnet watch
command with following arguments.
$ dotnet watch msbuild -t:CompileI18nText
After entry this dotnet CLI command, the dotnet CLI process keep running and watch the changing of localized text source files.
When the dotnet CLI which keep running detect the changing of localized text source files, the dotnet CLI re-compile localized text source files into "Typed Text Table class" files and "Localized Text Resource JSON" files.
Step.4 - Configure your app to use I18nText service
Open the C# source file of the "Startup" class of your Blazor app in your editor, and add using
clause for opening Toolbelt.Blazor.Extensions.DependencyInjection
namespace, and add following code in ConfigureServices()
method of the startup class.
services.AddI18nText<Startup>();
Step.5 - Get the "Text Table" object in your Blazor component
Open your Blazor component file (.cshtml) in your editor, and do this:
- Inject
Toolbelt.Blazor.I18nText.I18nText
service into the component.
@inject Toolbelt.Blazor.I18nText.I18nText I18nText
- Add a filed of the Text Table class generated from localized text source files, and assign the default instance.
@functions {
I18nText.MyText MyText = new I18nText.MyText();
NOTE - The namespace of the Text Table class is <default namespace of your Blazor project>
+ "I18nText"
.
- Override
OnInitAsync()
method of the Blazor component, and assign a Text Table object that's a return value ofGetTextTableAsync<T>()
method ofI18nText
service instance to the Text Table field.
protected override async Task OnInitAsync()
{
MyText = await I18nText.GetTextTableAsync<I18nText.MyText>(this);
Step.6 - Use the Text Table
After doing the these steps, you can reference a field of the Text Table object to get localized text.
If you are using Visual Studio in Windows OS and Blazor extensions is installed in that Visual Studio, you can get "IntelliSense" and "Document comment" support.
Note: Text Table object allows you to get localized text by key string dynamically, with indexer syntax, like this.
<h1>@MyText["HelloWorld"]</h1>
This way is sometimes called "late binding".
This feature is very useful in some cases.
However, if you make some mistakes that typo of key string, these mistakes will not be found at compile time.
In this case, it will just return the key string as is without any runtime exceptions.
Step.7 - Run it!
Build and run your Blazor app.
The I18nText service detects the language settings of the Web browser, and reads the localized text resource JSON which is most suitable for the language detected.
Learn more
You can find more detail of this my work on GitHub.
Happy coding with Blazor :)
Top comments (29)
Hi, thanks for the article. Just to add that
resx
could also do code generation for static access point, if you prefer the resource file way. The resource file could be compiled to local dll sent to the client side and then you useResourceManager
or the static generated code to access them.Thank you for your comment!
Yes, that's right,
.resx
file could be generated C# class as you said.I know this feature, and I often use this feature for ASP.NET MVC server programming.
However,
.resx
editor strongly depends on Visual Studio, and.resx
solution is hard to use for static contents only HTTP server scenario, I think.Anyway, your comment very important for the readers of this article.
Thanks!
In past few days I have been trying to make
.resx
localization works client side, because I love its generated class but unfortunately the generated class keeps falling back to the neutral language and not any other localized ones even withCultureInfo
override specified.I found that the main problem is that Blazor would include only main
dll
which contains your main localizationresx
. Other languages were separated by Visual Studio to a different satellite assembly and wouldn't be sent to client side, so it only works from server where all thosedll
are available.What I did is to avoid naming the
resx
asAAA.resx
,AAA.ja.resx
but instead useAAA_ja.resx
so Visual Studio don't see it as localized version and put them together in the maindll
and ensure client get all languages on loading the SPA web app. Then I have to make a modified version ofResourceManager
that knows how to look for_
separated resource according to incomingCultureInfo
. It was very hacky but somehow I could get it to work. I have summarized the steps here if anyone interested in following : gametorrahod.com/workaround-for-cl...The dependency of Visual Studio to edit
.resx
file still exists, but my website wouldn't be that large for now so I could put up with the difficulties :P Still I like that.resx
could pack images into a binary which reads asbyte[]
from the generated static class, so I could make localized images bytes instead of localized image paths.Thank you sooooo much for your solution
it is really helped me and works great with me
but when i use arabic character in the localization (I am using Json) the characters displayed as οΏ½οΏ½οΏ½ οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½.
Could you please help me in this.
I am sorry for asking too much but i am windows developer and completely new to Core 3 and Blazor Server-Side.
Did you save the json file with utf-8 encoding?
If you upload the json file that can reproduce your problem to somewhere public cloud storage, then I can investigate it.
Dear jsakamoto
Thank you very much for your reply.
I just opened the json file in notepad and saved it as text with utf-8 encoding
then i renamed it in the solution to .json and it works fine and shows the arabic character.
Thank you very much for your effort, and sorry for troubling you.
P.S. Do I have to do that with every json file or there is a better way.
How about using Visual Studio Code for?
Thank you very much.
The Visual Studio Code did the job well, it shows the right characters.
jsakamoto, thank you so much. it is so easy to localize for blazor.
I want to add a little. If language suggests right-to-left. For example Hebrew. To Blazar-Clien need
1) copy site.css => site-rtl.css
2) in site-rtl.css add in app 2 line
app {
...
text-align: right;
direction: rtl;
}
3) MainLayout.razor start so
@inherits LayoutComponentBase
@inject Toolbelt.Blazor.I18nText.I18nText I18nText
@if (CurrentLang == "he")
{
<link href="css/site-rtl.css"rel="stylesheet"/>
}
else
{
<link href="css/site.css" rel="stylesheet"/>
}
4) in index.html - delete
<link href="css/site.css" rel="stylesheet" />
5) "he" - in my case Hebrew -language suggests right-to-left GUI
Thank you very much for your this addition
Can you please post or send a small example showing how to change the language on at run time from within a Blazer server-side component, because i could not understand how to wire it with the API.
Thank you very much.
"Build" doesn't generate anything at all, is this compatible with preview 8?
If you use "Toolbelt.Blazor.I18nText" ver.5.0.0 (nuget.org/packages/Toolbelt.Blazor...), it should be compatible with Client-Side Blazor Wasm App v.3.0.0-preview8.
Please see also: github.com/jsakamoto/Toolbelt.Blaz...
If it looks like bug of "Toolbelt.Blazor.I18nText", could you provide your source code & project files to me?
Was my mistake I hadn't seen it was client side only, looking for a server side solution now, I assume basically anything that is MVC core compatible will work, thanks for the library, I've bookmarked it for future client side only work.
Thank you for your reply!
"Toolbelt.Blazor.I18nText" doesn't work on server side at this time, however, make "Toolbelt.Blazor.I18nText" to be available on server side is my important concern.
Because, I think, if "Toolbelt.Blazor.I18next" become working on server-side fine, it will have some advantages bellow.
I'll try to improve it.
Thanks!
P.S. "Toolbelt.Blazor.I18next" ver.7 started support for Server-side Blazor.
github.com/jsakamoto/Toolbelt.Blaz...
Dear sir,
Thank you very much for this great solution.
If you please post a small example on how to use the api's with this solution will be very appreciated.
Again thank you very much for that.
Is the sample code bellow helpful for you?
github.com/jsakamoto/Toolbelt.Blaz...
The sample code above describes how to retrieve the current language, and how to change the current language.
Thank you sooooo much for your reply
it is really helped me and works great with me
but when i use arabic character in the localization (I am using Json) the characters displayed as οΏ½οΏ½οΏ½ οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½.
Could you please help me in this.
I am sorry for asking too much but i am windows developer and completely new to Core 3 and Blazor Server-Side.
Hi @j_sakamoto ,
Thanks for the package and the article.
It will be great if you could give your valued inputs on the following issues I faced while trying the package as below:
I am using Visual Studio Community 2019 and ASP.Net Core 3.1 with Blazor templates. As suggested this package would work with the Blazor WASM app, but where do you register your service as there is no startup class in WASM(without ASP.Net Core hosted)
Also when I followed all the steps ditto (Blazor Server Project with Startup class), the project did not generate "Localized Text Resource JSON" files at the wwwroot/content/i18ntext folder.
In fact, no content folder was generated under wwwroot. Do you have any idea?
Anyway, when I went ahead despite the above issues and completed the rest of the steps and ran the application, it went to the fall-back "English" language.
It may be due to the absence of local text resource json files, but that's another point.
Can you help please?
Just a question about step 4. in a Blazor WebAssembly project there is no startup class how can I add your i18nText service ?
I'm sorry too late.
You can add i18ntext service in your
Program.cs
.Please see also "(If) Your project is Blazor WebAssembly v.3.2+, you should edit
Program
class to do this" section in Setp.4, the README document on the GitHub repository.Nevermind, how is written in your GitHub project page github.com/jsakamoto/Toolbelt.Blaz...
Mr.jsakamoto
Thank you very much for this excellent project.
are you planning to Localize Data Annotation and validation message in the near future?
Thank you in advance for your effort.
Yes, I am.
Please see: github.com/jsakamoto/Toolbelt.Blaz...
Thank you So much.
Great utility, but please update the generated code to use the following comment line so it plays nicely with code analysis.
// <auto-generated />
Hey Jsakamoto, great work !
What about translation of ValidationAttribute.ErrorMessage ?
Best regards,
Fabianus
Sorry too late!
Yes, you can do it with combinations NuGet packages below.
Unfortunately, there are no good documents at this time.
Could you try to figure out the sample program below?
github.com/jsakamoto/Toolbelt.Blaz...
P.S.
Blazor WebAssembly looks like it will be started to official support for localization.
See also: youtu.be/RsPXkgOL2gI?t=3010
Please keep watching it too!