Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - General-Fault/Gu.Localization · GitHub
Skip to content

Latest commit

History

513 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Gu.Localization.

Join the chat at https://gitter.im/JohanLarsson/Gu.LocalizationLicenseBuild statusNuGetNuGet

Contents.

1. 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.CurrentCulturechanges enabling runtime selection of language.

The markupextension has ErrorHandling = ErrorHandling.ReturnErrorInfoPreserveNeutral as default, it encodes errors in the result, see ErrorFormats)

1.1. Basic usage

For each language, create a resource.xx.resx file. You can use ResXManager to do this for you.

<UserControl ...
xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization"xmlns:p="clr-namespace:AppNamespace.Properties"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<!-- Dropbownbox to select a language -->
<ComboBoxx:Name="LanguageComboBox"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture), Converter={x:Static l:CultureOrDefaultConverter.Default}}" />
<!-- Label that changes translation upon language selection -->
<LabelContent="{l:Static p:Resources.ResourceKeyName}" />

1.2. Bind a localized string.

<Window ...
xmlns:p="clr-namespace:Gu.Wpf.Localization.Demo.WithResources.Properties"xmlns:l="http://gu.se/Localization">
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

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

1.3. 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

<Grid l:ErrorHandling.Mode="ReturnErrorInfo"
... >
...
<TextBlockText="{l:Static p:Resources.SomeResource}" />
<TextBlockText="{l:Enum ResourceManager={x:Static p:Resources.ResourceManager}, Member={x:Static local:SomeEnum.SomeMember}}" />
...

1.4. CurrentCulture.

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

<Grid numeric:NumericBox.Culture="{l:CurrentCulture}"
... >
...
<StackPanelOrientation="Horizontal">
<TextBlockText="Effective culture: " />
<TextBlockText="{l:CurrentCulture}" />
</StackPanel>
...

1.5. Binding to Culture and Culture in XAML.

The static properties support binding. Use this XAML for a twoway binding:

<Window ...
xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
...
<TextBoxText="{Binding Path=(localization:Translator.Culture)}" />

2. 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
namespaceYourNamespace.Properties{usingGu.Localization;usingGu.Localization.Properties;publicstaticclassTranslate{/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticstringKey(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnTranslationFor(key,errorHandling).Translated;}/// <summary>Call like this: Translate.Key(nameof(Resources.Saved_file__0_)).</summary>/// <param name="key">A key in Properties.Resources</param>/// <param name="errorHandling">How to handle translation errors like missing key or culture.</param>/// <returns>A translation for the key.</returns>publicstaticITranslationTranslationFor(stringkey,ErrorHandlingerrorHandling=ErrorHandling.ReturnErrorInfoPreserveNeutral){returnGu.Localization.Translation.GetOrCreate(Resources.ResourceManager,key,errorHandling);}}}

2.1. Translator.

2.1.1. 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.

2.1.2. 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.

2.1.3. 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.

2.1.4. Cultures.

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

2.1.5. ErrorHandling.

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

2.1.6. Translate.

Translate a key in a ResourceManager.

Use global culture & error handling:

Translator.Culture=CultureInfo.GetCultureInfo("en");// no need to set this every time, just for illustration purposes here.stringinEnglish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource));

2.1.6.1. Translate to neutral culture:

stringneutral=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.InvariantCulture);

2.1.6.2. Translate to explicit culture:

stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),CultureInfo.GetCultureInfo("sv"));

2.1.6.3. Override global error handling (throw on error):

Translator.ErrorHandling=ErrorHandling.ReturnErrorInfo;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.Throw);

2.1.6.4. Override global error handling (return info about error):

Translator.ErrorHandling=ErrorHandling.Throw;// no need to set this every time, just for illustration purposes here.stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource),ErrorHandling.ReturnErrorInfo);

2.1.6.5. Translate with parameter:

Translator.Culture=CultureInfo.GetCultureInfo("en");stringinSwedish=Translator.Translate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource__0__),foo);

2.2. Translator<T>.

Same as translator but used like Translator<Properties.Resources>.Translate(...)

2.3. 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.

2.3.1 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.

Translationtranslation=Translation.GetOrCreate(Properties.Resources.ResourceManager,nameof(Properties.Resources.SomeResource))

2.4. StaticTranslation.

An implementation of ITranslation that never updates the Translatedproperty 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.

3. 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.

3.1. Global setting

By setting Translator.Errorhandling the global default is changed.

3.2. ErrorFormats

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

ErrorFormat
missing key!{key}!
missing culture~{key}~
missing translation_{key}_
missing resources?{key}?
invalid format{{"{format}" : {args}}}
unknown error#{key}#

4. Validate.

Conveience API for unit testing localization.

4.1. Translations.

Validate a ResourceManager like this:

TranslationErrorserrors=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

4.2. EnumTranslations<T>.

Validate an enum like this:

TranslationErrorserrors=Validate.EnumTranslations<DummyEnum>(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

4.3. 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}

4.4. Format

Validate a formatstring like this:

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

5. FormatString.

Conveience API for testing formatstrings.

5.1. IsFormatString

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

5.2. IsValidFormatString

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

6. 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

6.1. AutogenerateLanguages

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

<l:LanguageSelectorAutogenerateLanguages="True" />

6.2. Explicit languages.

<l:LanguageSelector>
<l:LanguageCulture="de-DE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/de.png" />
<l:LanguageCulture="en-GB"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/gb.png" />
<l:LanguageCulture="sv-SE"FlagSource="pack://application:,,,/Gu.Wpf.Localization;component/Flags/se.png" />
</l:LanguageSelector>

screenie

7. Examples

7.1. Simple ComboBox language select.

The below example binds the available cutures to a ComboBox.

 <ComboBoxItemsSource="{Binding Path=(localization:Translator.Cultures)}" DockPanel.Dock="Top"HorizontalAlignment="right"SelectedItem="{Binding Path=(localization:Translator.CurrentCulture)}"/>

7.2 ComboBox Language selector

<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib"xmlns:l="http://gu.se/Localization"xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization">
<Grid>
<ComboBoxMinWidth="100"HorizontalAlignment="Right"VerticalAlignment="Top"ItemsSource="{Binding Path=(localization:Translator.Cultures)}"SelectedItem="{Binding Path=(localization:Translator.Culture)}">
<ComboBox.ItemTemplate>
<DataTemplateDataType="{x:Type globalization:CultureInfo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="Auto" />
<ColumnDefinitionWidth="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"Height="12"VerticalAlignment="Center"Source="{Binding Converter={x:Static l:CultureToFlagPathConverter.Default}}"Stretch="Fill" />
<TextBlock Grid.Column="1"Margin="10,0,0,0"HorizontalAlignment="Left"VerticalAlignment="Center"Text="{Binding NativeName}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
...
</Grid>
</Window>

7.3 CultureToFlagPathConverter

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

8 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. We advice you to use Fody (for it is tested).

8.1 Weaving Setup

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

9 Analyzer

animation

Checks if keys exists and some code fixes for conveninence.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages