Linguini is a C# implementation of Project Fluent, a localization system for natural-sounding translations with features like:
Natural-sounding translations with genders and grammatical cases only when necessary. Expressiveness is not limited by the grammar of the source language.
Translations are isolated; locale-specific logic doesn't leak to other locales. Authors can iteratively improve translations without impact on other languages.
Linguini is highly modular. You only can use the parts you need. Need just parsing? Get Linguni.Syntax. Need only Plural Rules data? Get PluralRules.Generator and connect to XML CLDR Plural rules data.
Linguini uses a zero-copy parser to parse the resources. While at the moment, there are no benchmarks, it is used by RobustToolbox as a localization framework.
To install the Fluent Bundle type in your console:
dotnet add package Linguini.Bundle
You can also follow other NuGet installation instructions. E.g. :
paket add Linguini.Bundle
Or copy this code to your PackageReference
<PackageReference Include="Linguini.Bundle" Version="0.8.2" />
For a 2-minute tour of Linguini, add this to your C# code:
var bundler = LinguiniBuilder.Builder()
.CultureInfo(new CultureInfo("en"))
.AddResource("hello-user = Hello, { $username }!")
.UncheckedBuild();
var message = bundler.GetAttrMessage("hello-user", ("username", (FluentString)"Test"));
Assert.AreEqual("Hello, Test!", message);
Let's go line by line and see how LinguiniBuilder
works.
-
Init - This creates a
LinguiniBuilder
using a type-safe builder pattern.var bundler = LinguiniBuilder.Builder()
-
Set the language - a translation bundle must have a language to translate to. In this case, we choose the English language.
.CultureInfo(new CultureInfo("en"))
-
Add a resource - a translation bundle without resources is pointless. We choose inline string for ease of the example.
.AddResource("hello-user = Hello, { $username }!")
If you need an example of passing files, here is a oneliner example assuming you defined
using var streamReader = new StreamReader(path_to_file);
somewhere (Hint: no need to useStreamReader
, anyTextReader
will do)..AddResource(streamReader)
-
Complete the
ResourceBundle
- We callUncheckedBuild()
to convert a builder to a bundle. The bundle will parse its resources and report errors. Since we don't care about errors, we are fine withResourceBundle
throwing errors..UncheckedBuild();
-
Get
hello-user
term whereusername
isTest
.bundler.GetAttrMessage("hello-user", ("username", (FluentString)"Test"));
To develop you need to install Git and .NET SDK first.
Installation of these tools is out of the scope of the document
git clone https://github.com/Ygg01/Linguini.git
cd Linguini
dotnet test
To build API documentation for Linguini
.
- Install
docfx
dotnet tool install -g docfx
- Build documentation
docfx build .\docfx_project\docfx.json --serve
Making it concurrent could add a performance penalty; otherwise, a concurrent bundle would be the default. To make it thread-safe, add UseConcurrent()
in builder:
var bundler = LinguiniBuilder.Builder()
.CultureInfo(new CultureInfo("en"))
.AddResource("hello-user = Hello, { $username }!")
.UseConcurrent()
.UncheckedBuild();
Or set UseConcurrent = true
in FluentBundleOption
passed to the factory method:
var x = new FluentBundleOption()
{
UseConcurrent = true,
};
var bundle = FluentBundle.MakeUnchecked(defaultBundleOpt);
No, it can also be Fluent, a localization system by Mozilla.
For more details, see Fluent syntax guide.
Linguini Bundle and associated projects are licensed under Apache and MIT licenses. Consult the LICENSE-MIT and LICENSE-APACHE for more detail.