Slang.Net
9.7.0
dotnet add package Slang.Net --version 9.7.0
NuGet\Install-Package Slang.Net -Version 9.7.0
<PackageReference Include="Slang.Net" Version="9.7.0" />
<PackageVersion Include="Slang.Net" Version="9.7.0" />
<PackageReference Include="Slang.Net" />
paket add Slang.Net --version 9.7.0
#r "nuget: Slang.Net, 9.7.0"
#:package Slang.Net@9.7.0
#addin nuget:?package=Slang.Net&version=9.7.0
#tool nuget:?package=Slang.Net&version=9.7.0
Slang.NET
Type-safe i18n for .NET
About this library
Slang.NET is a .NET port of the slang from the Dart/Flutter community with new features (like string format).
You can view how the generated files general, en, and de look
Getting Started:
Install the library as a NuGet package:
Install-Package dotnet add package Slang.Net
Add JSON files:
Important file must end with ".i18n.json". This is necessary so that the SourceGenerator does not track changes to other AdditionalFiles.
i18n/strings_en.i18n.json
or i18n/strings_en-US.i18n.json
or i18n/strings.i18n.json
(for base culture)
{
"screen": {
"locale1": "Locale 1"
}
}
i18n/strings_ru.i18n.json
or i18n/strings_ru-RU.i18n.json
{
"screen": {
"locale1": "Локаль 1"
}
}
slang.json
{
"base_culture": "en" // or "en-EN"
}
Recommendation It is recommended to specify the country code, such as "en-US," for proper functionality when formatting strings, especially if you will be retrieving the list of cultures from SupportedCultures.
Include JSON files as AdditionalFiles:
<ItemGroup>
<AdditionalFiles Include="i18n\*.i18n.json" />
<AdditionalFiles Include="slang.json" />
</ItemGroup>
Add a partial class:
[Translations(InputFileName = "strings")]
public partial class Strings;
Done!
Strings.SetCulture(new CultureInfo("ru-RU"));
Console.WriteLine(Strings.Instance.Root.Screen.Locale1); // Локаль 1
Strings.SetCulture(new CultureInfo("en-US"));
Console.WriteLine(Strings.Instance.Root.Screen.Locale1); // Locale 1
or
<MenuItem Header="{Binding Root.Screen.Locale1, Source={x:Static localization:Strings.Instance}}" />
Features
- String Interpolation
- Typed Parameters
- Comments
- String Format
- Pluralization
- Linked Translations
- Lists
- Maps
String Interpolation
You can specify parameters passed at runtime..
{
"Hello": "Hello {name}"
}
The generated code will look like this:
/// In en, this message translates to:
/// **"Hello {name}"**
public virtual string Hello(object name) => $"Hello {name}";
Typed Parameters
Parameters are typed as object
by default. This is convenient because it offers maximum flexibility.
You can specify the type using two syntax options: 1 - Simple:
{
"greet": "Hello {name: string}, you are {age: int} years old"
}
2 - Using a placeholders, which allows you to specify a type or format string (see String Format).
{
"greet2": "Hello {name}, you are {age} years old",
"@greet2": {
"placeholders": {
"name": {
"type": "string"
},
"age": {
"type": "int"
}
}
}
}
The generated code will look like this:
/// In ru, this message translates to:
/// **"Hello {name}, you are {age} years old"**
public virtual string Greet(string name, int age) => $"Hello {name}, you are {age} years old";
Comments
You can add comments to your translation files.
{
"@@locale": "en", // fully ignored
"mainScreen": {
"button": "Submit",
// ignored as translation but rendered as a comment
"@button": "The submit button shown at the bottom",
// or use
"button2": "Submit",
"@button2": {
"description": "The submit button shown at the bottom"
}
}
}
The generated code will look like this:
/// The submit button shown at the bottom
///
/// In ru, this message translates to:
/// **"Submit"**
public virtual string Button => "Submit";
String Format
This library supports embedding format via ToString(format)
for the following types: int
, long
, double
,
decimal
, float
, DateTime
, DateOnly
, TimeOnly
, TimeSpan
. For other types, the format string is passed through
string.Format(format, locale)
.
{
"dateExample": "Date {date}",
"@dateExample": {
"placeholders": {
"date": {
"type": "DateTime",
"format": "dd MMMM HH:mm"
}
}
}
}
String s = Strings.Instance.Root.DateExample(DateTime.Now); // Date 17 October 22:25
The generated code will look like this:
/// In ru, this message translates to:
/// **"Date {date}"**
public virtual string DateExample(DateTime date)
{
string dateString = date.ToString("dd MMMM HH:mm");
return $"Date {dateString}";
}
Pluralization
This library uses the concept defined here.
Some languages have support out of the box. See here.
Plurals are detected by the following keywords: zero
, one
, two
, few
, many
, other
.
{
"someKey": {
"apple": {
"one": "I have {n} apple.",
"other": "I have {n} apples."
}
}
}
String a = Strings.Instance.Root.SomeKey.Apple(n: 1); // I have 1 apple.
String b = Strings.Instance.Root.SomeKey.Apple(n: 2); // I have 2 apples.
The generated code will look like this:
public virtual string Apple(int n) => PluralResolvers.Cardinal("en")(n,
one: $"I have {n} apple.",
other: $"I have {n} apples.");
The detected plurals are cardinals by default.
To specify ordinals, you need to add the (ordinal)
modifier.
{
"someKey": {
"apple(cardinal)": {
"one": "I have {n} apple.",
"other": "I have {n} apples."
},
"place(ordinal)": {
"one": "{n}st place.",
"two": "{n}nd place.",
"few": "{n}rd place.",
"other": "{n}th place."
}
}
}
By default, the parameter name is n
. You can change that by adding a modifier.
{
"someKey": {
"apple(param=appleCount)": {
"one": "I have one apple.",
"other": "I have multiple apples."
}
}
}
String a = Strings.Instance.Root.SomeKey.Apple(appleCount: 1); // notice 'appleCount' instead of 'n'
You can set the default parameter globally using PluralParameter
.
[Translations(
InputFileName = "strings",
PluralParameter = "count")]
internal partial class Strings;
Linked Translations
You can link one translation to another. Add the prefix @:
followed by the absolute path to the desired
translation.
{
"fields": {
"name": "my name is {firstName}",
"age": "I am {age} years old"
},
"introduce": "Hello, @:fields.name and @:fields.age"
}
String s = Strings.Instance.Root.Introduce(firstName: "Tom", age: 27); // Hello, my name is Tom and I am 27 years old.
The generated code will look like this:
/// In ru, this message translates to:
/// **"Hello, {_root.Fields.Name(firstName: firstName)} and {_root.Fields.Age(age: age)}"**
public virtual string Introduce(object firstName, object age) => $"Hello, {_root.Fields.Name(firstName: firstName)} and {_root.Fields.Age(age: age)}";
Optionally, you can escape linked translations by surrounding the path with {}
:
{
"fields": {
"name": "my name is {firstName}"
},
"introduce": "Hello, @:{fields.name}inator"
}
Lists
You can also place lists inside lists!
{
"niceList": [
"hello",
"nice",
[
"first item in nested list",
"second item in nested list"
],
{
"wow": "WOW!",
"ok": "OK!"
},
{
"aMapEntry": "access via key",
"anotherEntry": "access via second key"
}
]
}
String a = Strings.Instance.Root.NiceList[1]; // "nice"
String b = Strings.Instance.Root.NiceList[2][0]; // "first item in nested list"
String c = Strings.Instance.Root.NiceList[3].Ok; // "OK!"
String d = Strings.Instance.Root.NiceList[4].AMapEntry; // "access via key"
The generated code will look like this:
public virtual List<dynamic> NiceList => [
"hello",
"nice",
new[]{
"first item in nested list",
"second item in nested list",
},
new Feature1NiceList0i3Ru(_root),
new Feature1NiceList0i4Ru(_root),
];
Maps
You can access each translation using string keys.
Add the (map)
modifier.
{
"a(map)": {
"helloWorld": "hello"
},
"b": {
"b0": "hey",
"b1(map)": {
"hiThere": "hi"
}
}
}
Now you can access translations using keys:
String a = Strings.Instance.Root.A["helloWorld"]; // "hello"
String b = Strings.Instance.Root.B.B0; // "hey"
String c = Strings.Instance.Root.B.B1["hiThere"]; // "hi"
The generated code will look like this:
/// In ru, this message translates to:
/// **"hey"**
public virtual string B0 => "hey";
public virtual IReadOnlyDictionary<string, string> B1 => new Dictionary<string, string> {
{"hiThere", "hi"},
};
Slang CLI
Translate with GPT
Take advantage of GPT to internationalize your app with context-aware translations.
Install Slang CLI:
dotnet tool install --global Slang.CLI
Then add the following configuration in your slang.json:
{
"base_culture": "en",
"gpt": {
"base_culture": "ru",
"model": "gpt-4o-mini",
"description": "Showcase for Slang.Net.Gpt"
}
}
Then use slang-gpt:
slang gpt --target=en --api-key=<api-key>
See more: Documentation
Additional Materials
Articles
Videos
Learn more about Target Frameworks and .NET Standard.
This package has 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.