Scrumboard.Tools.Localization
1.1.0
dotnet add package Scrumboard.Tools.Localization --version 1.1.0
NuGet\Install-Package Scrumboard.Tools.Localization -Version 1.1.0
<PackageReference Include="Scrumboard.Tools.Localization" Version="1.1.0" />
<PackageVersion Include="Scrumboard.Tools.Localization" Version="1.1.0" />
<PackageReference Include="Scrumboard.Tools.Localization" />
paket add Scrumboard.Tools.Localization --version 1.1.0
#r "nuget: Scrumboard.Tools.Localization, 1.1.0"
#:package Scrumboard.Tools.Localization@1.1.0
#addin nuget:?package=Scrumboard.Tools.Localization&version=1.1.0
#tool nuget:?package=Scrumboard.Tools.Localization&version=1.1.0
Description
This tool gives you easy and convenient access to localized text that makes adding localization in your products much easier.
How to download
Install a NuGet package using following command:
dotnet add package Scrumboard.Tools.Localization
Use examples
IMPORTANT Only json format for localizations is supported
First thing you have to do is go into your .csproj where you want to generate localization structure and add your template file in your project.
In our case the template file will be English.json:
<ItemGroup>
<AdditionalFiles Include="English.json" />
</ItemGroup>
Properties example 1.1
English.json:
{
"Hello": "Hello",
"Bye": "Bye"
}
French.json:
{
"Hello": "Bonjour",
"Bye": "Au revoir"
}
Lang.cs:
[ExtractFrom("English.json")]
partial class Lang {} // The class must be partial
IMPORTANT You cannot specify nested paths as a template file such as: Localizations/English.json. If you have to, then you need to change your template file including to this
<AdditionalFiles Include="Localizations/English.json" />.
Usage:
// Load english
Lang.Load(File.ReadAllText("English.json"));
Console.WriteLine(Lang.Hello);
Console.WriteLine(Lang.HelloKey);
Console.WriteLine("=======");
// Load french
Lang.Load(File.ReadAllText("French.json"));
Console.WriteLine(Lang.Hello);
Console.WriteLine(Lang.HelloKey);
Output:
Hello
Hello
=======
Bonjour
Hello
Properties example 1.2
There is also a style variation that you can change in attribute:
Lang.cs:
[ExtractFrom("English.json", IsAdditionalsPostfixStyle = false)] // The default value is true
partial class Lang {}
Usage:
Lang.Load(File.ReadAllText("English.json"));
Console.WriteLine(Lang.Hello);
Console.WriteLine(Lang.Keys.Hello); // Here's the difference
Console.WriteLine("=====================");
Lang.Load(File.ReadAllText("French.json"));
Console.WriteLine(Lang.Hello);
Console.WriteLine(Lang.Keys.Hello); // And here
Nested properties example 1.1
English.json:
{
"Colors": {
"Orange": "Orange",
"Yellow": "Yellow",
"Purple": "Purple"
}
}
Deutsch.json:
{
"Colors": {
"Orange": "Orange",
"Yellow": "Gelb",
"Purple": "Lila"
}
}
Lang.cs:
[ExtractFrom("English.json")]
partial class Lang {}
Usage:
Lang.Load(File.ReadAllText("English.json"));
Console.WriteLine(Lang.Colors.Orange);
Console.WriteLine(Lang.Colors.Yellow);
Console.WriteLine(Lang.Colors.Purple);
Console.WriteLine(Lang.Colors.OrangeKey);
Console.WriteLine(Lang.Colors.YellowKey);
Console.WriteLine(Lang.Colors.PurpleKey);
Console.WriteLine("=====================");
Lang.Load(File.ReadAllText("Deutsch.json"));
Console.WriteLine(Lang.Colors.Orange);
Console.WriteLine(Lang.Colors.Yellow);
Console.WriteLine(Lang.Colors.Purple);
Console.WriteLine(Lang.Colors.OrangeKey);
Console.WriteLine(Lang.Colors.YellowKey);
Console.WriteLine(Lang.Colors.PurpleKey);
Output:
Orange
Yellow
Purple
Colors.Orange
Colors.Yellow
Colors.Purple
=====================
Orange
Gelb
Lila
Colors.Orange
Colors.Yellow
Colors.Purple
Nested properties example 1.2
For nested properties different style would look like this: Lang.cs:
[ExtractFrom("English.json", IsAdditionalsPostfixStyle = false)]
partial class Lang {}
Usage:
Lang.Load(File.ReadAllText("English.json"));
Console.WriteLine(Lang.Colors.Orange);
Console.WriteLine(Lang.Colors.Yellow);
Console.WriteLine(Lang.Colors.Purple);
Console.WriteLine(Lang.Colors.Keys.Orange); //
Console.WriteLine(Lang.Colors.Keys.Yellow); // Here's the difference
Console.WriteLine(Lang.Colors.Keys.Purple); //
Console.WriteLine("=====================");
Lang.Load(File.ReadAllText("Deutsch.json"));
Console.WriteLine(Lang.Colors.Orange);
Console.WriteLine(Lang.Colors.Yellow);
Console.WriteLine(Lang.Colors.Purple);
Console.WriteLine(Lang.Colors.Keys.Orange); //
Console.WriteLine(Lang.Colors.Keys.Yellow); // And here
Console.WriteLine(Lang.Colors.Keys.Purple); //
Formatted strings example 1.1
Sometimes translating only words is not enough and inconvenient to use formating. So this tool also supports formatted strings:
English.json:
{
"Greeting": "Hello, {0}!"
}
Spanish.json:
{
"Greeting": "Hola, {0}!"
}
Lang.cs:
[ExtractFrom("English.json")]
partial class Lang {}
Usage:
Lang.Load(File.ReadAllText("English.json"));
Console.WriteLine(Lang.Greeting("John"));
Console.WriteLine("============");
Lang.Load(File.ReadAllText("Spanish.json"));
Console.WriteLine(Lang.Greeting("John"));
Output:
Hello, John!
============
Hola, John!
Formatted strings example 1.2
By default the generator would name arguments in the method as arg0, arg1, arg2, etc. But you can give a meaningful name for arguments:
English.json:
{
"Greeting": "Hello, {0:name}!"
}
Now generator would generate this:
public static string Greeting(string name) { ... }
instead of:
public static string Greeting(string arg0) { ... }
IMPORTANT The showed syntax above is not supported on not template files, if you add this to other localizations file it would throw an exception. Arguments names must be only be added in template file.
This would throw an exception during runtime:
{
"Greeting": "Hola, {0:name}!"
}
This wouldn't:
{
"Greeting": "Hola, {0}!"
}
IMPORTANT You do not have to specify the name every time when you use a specific argument, but the argument cannot have more than one unique name.
This usage is acceptable:
{
"Saying": "Hello, {0:name}. Bye {0}!"
}
This as well:
{
"Saying": "Hello, {0:name}. Bye {0:name}!"
}
Even this:
{
"Saying": "Hello, {0}. Bye {0:name}!"
}
But this one is not:
{
"Saying": "Hello, {0:name}. Bye {0:otherName}!"
}
IMPORTANT Two different arguments cannot have the same argument name
This usage is acceptable:
{
"Saying": "Hello, {0:name}. Bye {1:otherName}!"
}
This one is not:
{
"Saying": "Hello, {0:name}. Bye {1:name}!"
}
IMPORTANT If in some other localization file there is no enough arguments used it's okay it would ignore passed values, but if the formatted string uses more than in the template file it would throw an exception when you get the localized string.
Template file:
{
"Greeting": "Hello, {0:name}!"
}
This wouldn't throw an exception:
{
"Greeting": "Bonjour!"
}
But this one would:
{
"Greeting": "Hallo {0} und {1}!"
}
Not fully translated example
If some of localizations may not be fully translated you can use your template file translations as placeholders for missing ones:
English.json:
{
"Hello": "Hello",
"Bye": "Bye"
}
French.json:
{
"Hello": "Bonjour"
}
Lang.cs:
[ExtractFrom("English.json")]
partial class Lang {}
Usage:
Lang.Load(File.ReadAllText("English.json"));
Console.WriteLine(Lang.Hello);
Console.WriteLine(Lang.Bye);
Console.WriteLine("=======");
Lang.Load(File.ReadAllText("French.json"));
Lang.Load(File.ReadAllText("English.json"), clearBeforeLoad: false); // This argument tells not to clear previously loaded strings and add missing ones
Console.WriteLine(Lang.Hello);
Console.WriteLine(Lang.Bye);
Output:
Hello
Bye
=======
Bonjour
Bye
IMPORTANT If some key is not found a getter would return #Key#
IMPORTANT If some other localization has extra properties, they will be loaded, but you won't be able to access them through C# properties and this behaviour should be avoided
Thread-safe example
If you work with multiple threads you may need to access localized strings from them.
This behaviour is supported and you only need to specify it in the attribute:
Lang.cs:
[ExtractFrom("English.json", ThreadSafe = true)] // Default value is false
partial class Lang {}
IMPORTANT It may use slightly more resources.
Providers
There's also LocalizedStringProvider delegate that takes no arguments and returns string.
It was introduced as a ongoing provider to get current localized string value. See LocalizedStringProvider documentation for use examples.
There are few ways how to get provider.
- Use
CreateProvidermethod:
var provider = Lang.CreateProvider(Lang.HelloKey);
- Use property:
// if IsAdditionalsPostfixStyle == true
var provider = Lang.HelloProvider;
// if IsAdditionalsPostfixStyle == false
var provider = Lang.Providers.Hello;
- Or create it from lambda:
var provider = () => Lang.Get(Lang.HelloKey);
Generated documentation
The generator also adds documentation to the methods. If you don't want to add documentation to the generated class you can change it.
Lang.cs:
[ExtractFrom("English.json", GenerateDocumentation = false)] // Default value is true
partial class Lang {}
Generated methods
bool Add(string key, string value)bool Remove(string? key)bool Contains(string? key)string Get(string? key)string GetOr(string? key, string defaultValue)void Clear()LocalizedStringProvider CreateProvider(string? key)void Load(string jsonString, bool clearBeforeLoad = true)void Load(Func<string> jsonProvider, bool clearBeforeLoad = true)async Task LoadAsync(Func<Task<string>> jsonProvider, bool clearBeforeLoad = true)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
See https://github.com/ScrumboardCompany/Scrumboard.Tools.Localization/releases for release notes.