CodingSebLocalization.Fody
1.3.1
dotnet add package CodingSebLocalization.Fody --version 1.3.1
NuGet\Install-Package CodingSebLocalization.Fody -Version 1.3.1
<PackageReference Include="CodingSebLocalization.Fody" Version="1.3.1" />
paket add CodingSebLocalization.Fody --version 1.3.1
#r "nuget: CodingSebLocalization.Fody, 1.3.1"
// Install CodingSebLocalization.Fody as a Cake Addin #addin nuget:?package=CodingSebLocalization.Fody&version=1.3.1 // Install CodingSebLocalization.Fody as a Cake Tool #tool nuget:?package=CodingSebLocalization.Fody&version=1.3.1
Localization
A suit of libs to localize C# and WPF projects easily based on file format you choose.
Replace the archived TranslateMe lib
Nuget | Version |
---|---|
CodingSeb.Localization | |
CodingSeb.Localization.JsonFileLoader | |
CodingSeb.Localization.YamlFileLoader | |
CodingSeb.Localization.WPF | |
CodingSebLocalization.Fody |
The differents parts of the project
The library is composed of 4 parts :
The part "Core" : Nuget "CodingSeb.Localization" Contains the dictionnary of all translations for a "TextId" in C#.
A part "FileLoader" : Allow to open a type of file that contains translations to load in the dictionnary of the "Core" part.
The part to translate (localize) XAML (WPF) "CodingSeb.Localization.WPF". Provide
Tr
andMultiTr
markups and some converters to use in Bindings. It use the "Core" in backend.The part to translate ViewModel (
INotifyPropertyChanged
). ProvideLocalize
attribute to put on ViewModel properties that are localized
Installation
With Nuget
For Simple C# projects
PM> Install-Package CodingSeb.Localization.JsonFileLoader
or
PM> Install-Package CodingSeb.Localization.YamlFileLoader
or
PM> Install-Package CodingSeb.Localization
and implement your own FileLoader.
For WPF projects
Add this :
PM> Install-Package CodingSeb.Localization.WPF
and
PM> Install-Package CodingSebLocalization.Fody
Use it in C# :
To localize a text
using CodingSeb.Localization
/// ...
// To translate a text in the current language
// Loc.Tr("TextId");
Loc.Tr("SayHello");
// To show a default text if the text is not localized in the current language
// Loc.Tr("TextId", "DefaultText")
Loc.Tr("SayHello", "Not localized");
// To Translate a text in fixed language
// Loc.Tr("TextId","DefaultText" "LanguageId");
Loc.Tr("SayHello", null, "fr");
To Change the current language
Loc.Instance.CurrentLanguage = "en";
Loc.Instance.CurrentLanguage = "fr";
Loc.Instance.CurrentLanguage = "es";
// ...
// To get availables languages
Collection<string> languages = Loc.AvailableLanguages;
Use it In XAML (WPF) :
(no xmlns needed Tr Markup is available as soon as CodingSeb.Localization.WPF is in project's references)
Simple localization with the Markup Tr
<TextBlock Text="{Tr 'SayHello'}"/>
<TextBlock Text="{Tr 'SayHello', DefaultText='Not localized'}"/>
<TextBlock Text="{Tr 'SayHello', LanguageId='fr'}"/>
In general use XML escape to escape special characters. For single quote use [apos]
to escape. XML escape does'nt work in this case for inline Tr markup. Or use the following format :
<Label x:Name="lbMyLabel" >
<Label.Content>
<Tr DefaultText="Text with a ' here" />
</Label.Content>
</Label>
To Translate with Bindings
<TextBlock Text="{Tr {Binding MyPropertyAsTextId}, DefaultText='Not localized'}"/>
<TextBlock Text="{Tr TextIdBinding={Binding MyPropertyAsTextId}, DefaultText='Not localized'}"/>
<TextBlock Text="{Binding MyPropertyAsTextId, Converter={TrTextIdConverter DefaultText='Not localized'}"/>
<TextBlock Text="{Tr {Binding MyPropertyAsPartOfTextId}, TextIdStringFormat='MyEnum{0}'}"/>
<TextBlock Text="{Tr TextIdBinding={Binding MyPropertyAsPartOfTextId}, TextIdStringFormat='MyEnum{0}'}"/>
<TextBlock Text="{Binding MyPropertyAsPartOfTextId, Converter={TrTextIdConverter TextIdStringFormat='MyEnum{0}'}"/>
<TextBlock Text="{Binding MyPropertyAsLanguageId, Converter={TrLanguageIdConverter TextId='SayHello'}" />
<TextBlock Text="{Tr SayHello, {Binding FirstName}}" />
<TextBlock Text="{Tr SayHello, StringFormatArgBinding={Binding FirstName}}" />
<TextBlock Text="{Binding FirstName, Converter={TrStringFormatConverter TextId='SayHello'}" />
<TextBlock Text="{Tr SayHello, {Binding FirstName}, {Binding LastName}}" />
<TextBlock>
<TextBlock.Text>
<Tr TextId="SayHello">
<Tr.StringFormatArgsBindings>
<Binding Path="FirstName" />
<Binding Path="LastName" />
</Tr.StringFormatArgBinding>
</Tr>
</TextBlock.Text>
</TextBlock>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{TrStringFormatMultiValuesConverter TextId='SayHello'}">
<Binding Path="FirstName" />
<Binding Path="LastName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
To concatenate some translations
<TextBlock>
<TextBlock.Text>
<MultiTr>
<Tr TextId=TextId1 />
<Tr TextId=TextId2 />
</MultiTr>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{MultiTr {Tr TextId1}, {Tr TextId2}}" />
<TextBlock Text="{MultiTr TextId1, TextId2}" />
<TextBlock Text="{MultiTr TextId1, TextId2, Separator=' - '}" />
<TextBlock Text="{MultiTr TextId1, TextId2, StringFormat='{0}, {1}.'}" />
Remark : By default the translation made in the XAML are automatically updated when current language changed.
In templates (DataTemplate
, ControlTemplate
) Bindings with TrConverters do not update when language change. Prefer to use Tr
Markup with bindings in templates
To Change the current language from the xaml
<ComboBox ItemsSource="{Binding Source={x:Static loc:Loc.AvailableLanguages}}"
SelectedItem="{Binding CurrentLanguage, Source={x:Static loc:Loc.Instance}}"/>
Use it In ViewModel (Fody) :
You can use the Property attibute Localize
to automatically generate the PropertyChanged event for the property when CurrentLanguageChanged.
public class LocalizedWithFodyClass : INotifyPropertyChanged
{
[Localize]
public string TestProperty => Loc.Tr("TestLabel");
[Localize(nameof(TextIdInAttribute))]
public string TextIdInAttribute { get; set; }
// ...
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The specific code is injected at compile time thanks to Fody.
It is compatible with PropertyChanged.Fody or other similar fody addins like ReactiveUI.Fody. Just ensure that CodingSebLocalization is defined after in the FodyWeavers.xml
file.
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
<ReactiveUI />
<CodingSebLocalization />
</Weavers>
OK But... ...How I define my translations ?
JsonFileLoader
With the default JsonFileLoader, Translations are defined in JSON files with the extension "*.loc.json".
Here an example :
{
"LanguageName": {
"en": "English",
"es": "Español",
"fr": "Français"
},
"[Localization.Examples.MainWindow].lblCurrentLanguage[Label].Content": {
"en": "Current language",
"es": "Lenguaje actual",
"fr": "Langue courrante"
},
"[Localization.Examples.MainWindow].lblHelloInCurrentLanguage[Label].Content": {
"en": "Hello",
"es": "Hola",
"fr": "Bonjour"
},
"HelloInCurrentLanguage": {
"en": "Hello in the current language",
"es": "Hola en la lengua actual",
"fr": "Bonjour dans la langue actuelle"
},
"[Localization.Examples.MainWindow].lblHelloInCurrentLanguage[Label].ToolTip": {
"en": "In english",
"es": "En español",
"fr": "En français"
}
}
It's also possible to create a hierarchy :
{
"AppName": {
"MainMenu": {
"FileMenuItem": {
"Header": {
"en": "_File",
"fr": "_Fichier"
},
"NewMenuItem": {
"Header": {
"en": "_New",
"fr": "_Nouveau"
}
},
"OpenMenuItem": {
"Header": {
"en": "_Open",
"fr": "_Ouvrir"
}
},
"..."
}
}
}
To use like this :
Loc.Tr("AppName.MainMenu.FileMenuItem.Header");
Loc.Tr("AppName.MainMenu.FileMenuItem.NewMenuItem.Header");
Loc.Tr("AppName.MainMenu.FileMenuItem.OpenMenuItem.Header");
or like this in XAML :
<Menu>
<MenuItem Header="{Tr 'AppName.MainMenu.FileMenuItem.Header', DefaultText='_File'}">
<MenuItem Header="{Tr 'AppName.MainMenu.FileMenuItem.NewMenuItem.Header', DefaultText='_New'}"
Command="ApplicationCommands.New" />
<MenuItem Header="{Tr 'AppName.MainMenu.FileMenuItem.OpenMenuItem.Header', DefaultText='_Open'}"
Command="ApplicationCommands.Open" />
And to load these files :
using CodingSeb.Localization.Loaders;
// You need first to add the specific fileLoader
LocalizationLoader.Instance.FileLanguageLoaders.Add(new JsonFileLoader());
// ...
// And then you can add your localization file
LocalizationLoader.Instance.AddFile(@"PathToTheFile\Example1.loc.json");
// or load directly a directory with multiple "*.loc.json" files.
LocalizationLoader.Instance.AddDirectory(@"PathToTheDirectory");
So you can change the text of your app or translate it in a new language without recompile all your application.
// or you can also load a translation by code (textId, languageId, value)
LocalizationLoader.Instance.AddTranslation("SayHello", "en", "Hello" );
LocalizationLoader.Instance.AddTranslation("SayHello", "es", "Hola" );
LocalizationLoader.Instance.AddTranslation("SayHello", "fr", "Bonjour" );
YamlFileLoader
For Yaml format of localization files "*.loc.yaml" it's working the same way as the Json
Implement your own file format
If you want to support an other format than json or yaml, you can create your custom FileLanguageLoader. Simply create a class that implement the ILocalizationFileLoader interface and add an instance of your class in the LocalizationLoader :
LocalizationLoader.Instance.FileLanguageLoaders.Add(new YouCustomClassImplementingILocalizationFileLoader());
Find Missing Translations
You can activate an option to be notify when a translation is missing.
// with all TextId and LanguageId that are missing when you trying to translate them.
Loc.LogOutMissingTranslations = true;
Loc.MissingTranslationFound += Loc_MissingTranslationFound;
If you want to log it automatically in a json file you can also use the class JsonMissingTranslationsLogger
in the "CodingSeb.Localization.JsonFileLoader" package.
JsonMissingTranslationsLogger.EnableLog();
Tr and WPF Styles
The Tr
markup is usable in Styles. but if a Trigger is used the Tr
markup only works if used in static mode : <Tr IsDynamic=False ...
.
In dynamic mode the Tr
markup create in backend a Binding and do not allow to be modified by a Datatrigger.
To do a localization in a same manner, prefer to use a binding with a TrTextIdConverter
in place of a trigger.
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. |
.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
- CodingSeb.Localization (>= 1.3.1)
- Fody (>= 6.8.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.3.1 | 269 | 6/27/2024 |
1.3.0 | 1,678 | 6/20/2023 |
1.2.0 | 738 | 1/20/2022 |
1.2.0-alpha003 | 173 | 1/20/2022 |
1.2.0-alpha002 | 165 | 1/19/2022 |
1.2.0-alpha001 | 172 | 1/19/2022 |
1.0.0 | 682 | 12/21/2020 |
* Update links for package