Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/GuOrg/Gu.Localization


https://github.com/GuOrg/Gu.Localization

Last synced: 3 months ago
JSON representation

Awesome Lists containing this project

README

        

# Gu.Localization.

[![Join the chat at https://gitter.im/JohanLarsson/Gu.Localization](https://badges.gitter.im/JohanLarsson/Gu.Localization.svg)](https://gitter.im/JohanLarsson/Gu.Localization?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Build status](https://ci.appveyor.com/api/projects/status/ili1qk8amyjmd71t/branch/master?svg=true)](https://ci.appveyor.com/project/JohanLarsson/gu-localization/branch/master)
[![Build Status](https://dev.azure.com/guorg/Gu.Localization/_apis/build/status/GuOrg.Gu.Localization?branchName=master)](https://dev.azure.com/guorg/Gu.Localization/_build/latest?definitionId=17&branchName=master)
[![NuGet](https://img.shields.io/nuget/v/Gu.Localization.svg)](https://www.nuget.org/packages/Gu.Localization/)
[![NuGet](https://img.shields.io/nuget/v/Gu.Wpf.Localization.svg)](https://www.nuget.org/packages/Gu.Wpf.Localization/)

# Contents.
- [Quickstart](#quickstart)
- [Usage in XAML.](#usage-in-xaml)
- [Simple example](#simple-example)
- [With converter](#with-converter)
- [Bind a localized string.](#bind-a-localized-string)
- [Errorhandling.](#errorhandling)
- [CurrentCulture.](#currentculture)
- [Binding to Culture and Culture in XAML.](#binding-to-culture-and-culture-in-xaml)
- [Usage in code.](#usage-in-code)
- [Translator.](#translator)
- [Culture.](#culture)
- [Culture.](#culture)
- [CurrentCulture.](#currentculture)
- [Cultures.](#cultures)
- [ErrorHandling.](#errorhandling)
- [Translate.](#translate)
- [Translate to neutral culture:](#translate-to-neutral-culture)
- [Translate to explicit culture:](#translate-to-explicit-culture)
- [Override global error handling (throw on error):](#override-global-error-handling-throw-on-error)
- [Override global error handling (return info about error):](#override-global-error-handling-return-info-about-error)
- [Translate with parameter:](#translate-with-parameter)
- [Translator<T>.](#translatort)
- [Translation.](#translation)
- [GetOrCreate.](#getorcreate)
- [StaticTranslation.](#statictranslation)
- [ErrorHandling.](#errorhandling)
- [Global setting](#global-setting)
- [ErrorFormats](#errorformats)
- [Validate.](#validate)
- [Translations.](#translations)
- [EnumTranslations<T>.](#enumtranslationst)
- [TranslationErrors](#translationerrors)
- [Format](#format)
- [FormatString.](#formatstring)
- [IsFormatString](#isformatstring)
- [IsValidFormatString](#isvalidformatstring)
- [LanguageSelector](#languageselector)
- [AutogenerateLanguages](#autogeneratelanguages)
- [Explicit languages.](#explicit-languages)
- [Examples](#examples)
- [Simple ComboBox language select.](#simple-combobox-language-select)
- [ComboBox Language selector](#combobox-language-selector)
- [CultureToFlagPathConverter](#culturetoflagpathconverter)
- [Embedded resource files (weaving)](#embedded-resource-files-weaving)
- [Weaving Setup](#weaving-setup)
- [Analyzer](#analyzer)

# Quickstart
1. `PM> Install-Package Gu.Wpf.Localization` or search for `Gu.Wpf.Localization` in the `Manage NuGet Packages` tab.
2. Create a new resource from `Project > Properties > Resources` and name it `Resources..resx`.
Example: `Resources.ru-RU.resx`
To see all convention tags you can check them [here](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c)
3. Use the markup extension like this:

```xaml








```

Renders:

![Localize](https://user-images.githubusercontent.com/1640096/61053560-1288a600-a3ee-11e9-9939-930dfa4d911f.gif)

`Text="{localize:Static properties:Resources.Some_text}"` will be the translated text based on the current culture.

**Note**: If you get errors about missing `localize:Static` when adding this, `clean` and `rebuild` your solution from `Build > Clean Solution` and `Build > Rebuild Solution` respectively.

**Note**: To set the translation programmatically write: `Translator.Culture = CultureInfo.GetCultureInfo("ru-RU");`
To use a neutral language (aka Resources.resx), simply add `[assembly:NeutralResourcesLanguageAttribute("en")]` in your `AssemblyInfo.cs` file found in your project.

**Note**: Make sure to add `xmlns:properties="clr-namespace:YourApp.Properties"` and `xmlns:localize="http://gu.se/Localization"` in your xaml.

**Note**: Intsall `Gu.Wpf.Localization` in the application project. The library is split in `Gu.Wpf.Localization` and `Gu.Localization` so that usage in domain projects does not require adding WPF dependencies.

For working with resx in Visual Studio [ResXManager](https://marketplace.visualstudio.com/items?itemName=TomEnglert.ResXManager) is a nice extension.

# NeutralResourcesLanguage

Adding:
```cs
[assembly:NeutralResourcesLanguage("en")]
```

To `AsseblyInfo.cs` or anywhere else tells Gu.Localization what language to use for the neutral resource. It prevents some duplication.
See: [NeutralResourcesLanguageAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.resources.neutralresourceslanguageattribute?view=netframework-4.8)

# Usage in XAML.

The library has a `StaticExtension` markupextension that is used when translating.
The reason for naming it `StaticExtension` and not `TranslateExtension` is that Resharper provides intellisense when named `StaticExtension`
Binding the text like below updates the text when `Translator.CurrentCulture`changes enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see [ErrorFormats](#3-errorhandling))

## Simple example
For each language, create a resource.xx.resx file. You can use [ResXManager](https://marketplace.visualstudio.com/items?itemName=TomEnglert.ResXManager#overview) to do this for you.

```xaml

...



```

## With converter

When `StaticExctension` is used for setting `Binding.Source` it returns an `ITranslation`, this means it can be used with a converter like below.

```xaml

```

```c#
[ValueConversion(typeof(string), typeof(string))]
public sealed class StringToUpperConverter : IValueConverter
{
public static readonly StringToUpperConverter Default = new StringToUpperConverter();

public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value switch
{
string { } s => s.ToUpper(culture),
null => null,
_ => throw new ArgumentException($"Expected a string, was: {value.GetType()} with value: {value}"),
};
}

object IValueConverter.ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotSupportedException($"{nameof(StringToUpperConverter)} can only be used in OneWay bindings");
}
}
```

## Bind a localized string.

```xaml

...


...
```

The above will show SomeResource in the `Translator.CurrentCulture` and update when culture changes.

## Errorhandling.
By setting the attached property `ErrorHandling.Mode` we override how translation errors are handled by the `StaticExtension` for the child elements.
When null the `StaticExtension` uses ReturnErrorInfoPreserveNeutral
```xaml

...


...
```

## CurrentCulture.
A markupextension for accessing `Translator.CurrentCulture` from xaml. Retruns a binding that updates when CurrentCulture changes.

```xaml

...




...
```

## Binding to Culture and Culture in XAML.
The static properties support binding. Use this XAML for a twoway binding:
```xaml

...

```

# Usage in code.

The API is not super clean, introducing a helper like this can clean things up a bit.

Creating it like the above is pretty verbose. Introducing a helper like below can clean it up some.
The analyzer checks calls to this method but it assumes:
1. That the class is named `Translate`
2. That the namespace the class is in has a class named `Resources`
3. That the first argument is of type `string`.
4. That the return type is `string` or `ITranslation`

```c#
namespace YourNamespace.Properties
{
using Gu.Localization;
using Gu.Localization.Properties;

public static class Translate
{
/// Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).
/// A key in Properties.Resources
/// How to handle translation errors like missing key or culture.
/// A translation for the key.
public static string Key(string key, ErrorHandling errorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral)
{
return TranslationFor(key, errorHandling).Translated;
}

/// Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).
/// A key in Properties.Resources
/// How to handle translation errors like missing key or culture.
/// A translation for the key.
public static ITranslation TranslationFor(string key, ErrorHandling errorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral)
{
return Gu.Localization.Translation.GetOrCreate(Resources.ResourceManager, key, errorHandling);
}
}
}
```

## Translator.

### Culture.
Get or set the current culture. The default is `null`
Changing culture updates all translations. Setting culture to a culture for which there is no translation throws. Check ContainsCulture() first.

### Culture.
Get or set the current culture. The default is `null`
Changing culture updates all translations. Setting culture to a culture for which there is no translation throws. Check ContainsCulture() first.

### CurrentCulture.
Get the culture used in translations. By the following mechanism:
1) CurrentCulture if not null.
2) Any Culture in matching by name.
3) Any Culture in matching by name.
4) CultureInfo.InvariantCulture
When this value changes CurrentCultureChanged is raised and all translatins updates and notifies.

### Cultures.
Get a list with the available cultures. Cultures are found by looking in current directory and scanning for satellite assemblies.

### ErrorHandling.
Get or set how errors are handled. The default value is `ReturnErrorInfoPreserveNeutral`.

### Translate.
Translate a key in a ResourceManager.

Use global culture & error handling:
```c#
Translator.Culture = CultureInfo.GetCultureInfo("en"); // no need to set this every time, just for illustration purposes here.
string inEnglish = Translator.Translate(Properties.Resources.ResourceManager,
nameof(Properties.Resources.SomeResource));
```

#### Translate to neutral culture:
```c#
string neutral = Translator.Translate(Properties.Resources.ResourceManager,
nameof(Properties.Resources.SomeResource),
CultureInfo.InvariantCulture);
```

#### Translate to explicit culture:
```c#
string inSwedish = Translator.Translate(Properties.Resources.ResourceManager,
nameof(Properties.Resources.SomeResource),
CultureInfo.GetCultureInfo("sv"));
```

#### Override global error handling (throw on error):
```c#
Translator.ErrorHandling = ErrorHandling.ReturnErrorInfo; // no need to set this every time, just for illustration purposes here.
string inSwedish = Translator.Translate(Properties.Resources.ResourceManager,
nameof(Properties.Resources.SomeResource),
ErrorHandling.Throw);
```

#### Override global error handling (return info about error):
```c#
Translator.ErrorHandling = ErrorHandling.Throw; // no need to set this every time, just for illustration purposes here.
string inSwedish = Translator.Translate(Properties.Resources.ResourceManager,
nameof(Properties.Resources.SomeResource),
ErrorHandling.ReturnErrorInfo);
```

#### Translate with parameter:
```c#
Translator.Culture = CultureInfo.GetCultureInfo("en");
string inSwedish = Translator.Translate(Properties.Resources.ResourceManager,
nameof(Properties.Resources.SomeResource__0__),
foo);
```

### MissingTranslation.
An event that notifies when the key or culture is missing. Can be used for logging.

```cs
Translator.MissingTranslation += (sender, args) => Log($"Missing translation for {args.Key} when translating to {args.Language}.");
```

## Translator<T>.

Same as translator but used like `Translator.Translate(...)`

## Translation.
An object with a Translated property that is a string with the value in `Translator.CurrentCulture`
Implements `INotifyPropertyChanged` and notifies when for the property `Translated` if a change in `Translator.CurrentCulture` updates the translation.

## GetOrCreate.
Returns an `ITranslation` from cache or creates and caches a new instance.
If ErrorHandling is Throw it throws if the key is missing. If other than throw a `StaticTranslation` is returned.

```c#
Translation translation = Translation.GetOrCreate(Properties.Resources.ResourceManager, nameof(Properties.Resources.SomeResource))
```

## StaticTranslation.
An implementation of `ITranslation` that never updates the `Translated`property and returns the value of `Translated` when calling `Translate()`on it with any paramaters.
This is returned from `Translation.GetOrCreate(...)` if the key is missing.

# ErrorHandling.
When calling the translate methods an ErrorHandling argument can be provided.
If `ErrorHandling.ReturnErrorInfo` is passed in the method does not throw but returns information about the error in the string.
There is also a property `Translator.ErrorHandling` that sets default behaviour. If an explicit errorhandling is passed in to a method it overrides the global setting.

## Global setting
By setting `Translator.Errorhandling` the global default is changed.

## ErrorFormats
When `ReturnErrorInfo` or `ReturnErrorInfoPreserveNeutral` is used the following formats are used to encode errors.

| Error | Format |
|---------------------|:-----------------------:|
| missing key | `!{key}!` |
| missing culture | `~{key}~` |
| missing translation | `_{key}_` |
| missing resources | `?{key}?` |
| invalid format |`{{"{format}" : {args}}}`|
| unknown error | `#{key}#` |

# Validate.
Conveience API for unit testing localization.

## Translations.

Validate a `ResourceManager` like this:
```c#
TranslationErrors errors = Validate.Translations(Properties.Resources.ResourceManager);
Assert.IsTrue(errors.IsEmpty);
```

Checks:
- That all keys has a non null value for all cultures in `Translator.AllCultures`
- If the resource is a format string like `"First: {0}, second{1}"` it checks that.
- The number of format items are the same for all cultures.
- That all format strings has format items numbered 0..1..n

## EnumTranslations<T>.
Validate an `enum` like this:
```c#
TranslationErrors errors = Validate.EnumTranslations(Properties.Resources.ResourceManager);
Assert.IsTrue(errors.IsEmpty);
```
Checks:
- That all enum members has keys in the `ResourceManager`
- That all keys has non null value for all cultures in `Translator.AllCultures`

## TranslationErrors
`errors.ToString(" ", Environment.NewLine);`
Prints a formatted report with the errors found, sample:

```
Key: EnglishOnly
Missing for: { de, sv }
Key: Value___0_
Has format errors, the formats are:
Value: {0}
null
Värde: {0} {1}
```
## Format
Validate a formatstring like this:
```c#
Validate.Format("Value: {0}", 1);
```

```c#
Debug.Assert(Validate.IsValidFormat("Value: {0}", 1), "Invalid format...");
```

# FormatString.
Conveience API for testing formatstrings.

## IsFormatString
Returns true if the string contains placeholders like `"Value: {0}"` and is a valid format string.

## IsValidFormatString
Returns true if the string contains placeholders like `"Value: {0}"` that matches the number of parameters and is a valid format string.

# LanguageSelector
A simple control for changing current language.
A few flags are included in the library, many are probably missing.

***Note: LanguageSelector might be depricated in the future***

## AutogenerateLanguages
Default is false.
If true it popolates itself with `Translator.Cultures` in the running application and picks the default flag or null.

```xaml

```

## Explicit languages.

```xaml



```

![screenie](http://i.imgur.com/DKfx8WB.png)

# Examples

## Simple ComboBox language select.
The below example binds the available cutures to a ComboBox.
```xaml

```

## ComboBox Language selector
```xaml













...

```

## CultureToFlagPathConverter

For convenience a converter that converts from `CultureInfo` to a string with the pack uri of the flag resource is included.

# Embedded resource files (weaving)

_"Weaving refers to the process of injecting functionality into an existing program."_

You might want to publish your software as just one .exe file, without additional assemblies (dll files). Gu.Localization supports this, and a sample project is added [here](https://github.com/GuOrg/Gu.Localization/tree/master/Gu.Wpf.Localization.Demo.Fody). We advice you to use Fody (for it is tested).

## Weaving Setup

- Install https://www.nuget.org/packages/Fody/ (and add FodyWeavers.xml to your project, see [here](https://github.com/Fody/Fody#add-fodyweaversxml))
- Install https://www.nuget.org/packages/Costura.Fody/
- Install https://www.nuget.org/packages/Resource.Embedder/ to include the satelite assemblies _(in the folders /sv-SE/, /nl-NL/, etc)_

Your resource files are now embeded in your executable. Gu.Localization will use the embedded resource files.

# Analyzer
![animation](https://user-images.githubusercontent.com/1640096/39090329-8115bd4a-45dc-11e8-8cc5-a4af4a2f5812.gif)

Checks if keys exists and some code fixes for conveninence.