Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added: Localization Backend & Documentation (fixes #452) #563

Merged
merged 12 commits into from
Aug 21, 2023

Conversation

Sewer56
Copy link
Member

@Sewer56 Sewer56 commented Aug 17, 2023

Summary

Closes #452

No special merge text for this PR; for all the change details, refer to the newly added docs in this PR.

@Sewer56 Sewer56 self-assigned this Aug 17, 2023

private readonly LocalizedStringUpdater _nameUpdater;

public IconViewModel(Func<string> getName) => _nameUpdater = new LocalizedStringUpdater(() => Name = getName());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need a function here? Vs a constant string?

Copy link
Member Author

@Sewer56 Sewer56 Aug 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For contributors/developers, this is documented in LocalizationAndTranslation.md:

#### Updating Strings Dynamically
If you have a string in C# which is long lived, and will be live when the language is changed; it must be updated dynamically.
For this purpose, the `LocalizedStringUpdater` class is provided; it is used like this:
```csharp
_localizable = new LocalizedStringUpdater(() => ReactiveField = Language.MyGames);
```
To give an example:
```csharp
public class SomeViewModel : AViewModel<ISomeViewModel>, ISomeViewModel, IDisposable
{
[Reactive]
public string Name { get; set; } = "";
private readonly LocalizedStringUpdater _nameUpdater;
public SomeViewModel(Func<string> getName)
{
_nameUpdater = new LocalizedStringUpdater(() => Name = getName());
}
// Note: Multi-dispose guard not needed; LocalizedStringUpdater.Dispose by contract only unsubscribes from an event.
public void Dispose() => _nameUpdater.Dispose();
}
```
When you call `new LocalizedStringUpdater` and every time the language is changed
through the use [Localizer.Instance.LoadLanguage](#switching-a-language), the callback given in the `LocalizedStringUpdater`
will be executed.
As for the `[Reactive]` fields, the autogenerated `INotifyPropertyChanged` handlers will always
do a comparison on the string in the setter. So if a string remains unchanged, no UI redraw will occur
for the affected element as `PropertyChanged` will not fire.
!!! note "The API is specifically designed like this to ensure compile time safety."
!!! danger "`LocalizedStringUpdater` must be properly disposed when no longer in use. Due to nature of .NET events, lack of proper disposal will lead to memory leak as the class subscribes to `Localizer` which has singleton lifetime."
##### Use within Reactive Code
When possible, use the `WhenActivated` ReactiveUI method; alongside `DisposeWith`. This will ensure that `LocalizedStringUpdater(s)` and structures which use them will be disposed safely.
```csharp
this.WhenActivated(disposable =>
{
var items = new ILeftMenuItemViewModel[]
{
new IconViewModel(() => Language.Newsfeed) { ... }.DisposeWith(disposable),
new IconViewModel(() => Language.MyGames) { ... }.DisposeWith(disposable),
new IconViewModel(() => Language.BrowseGames) { ... }.DisposeWith(disposable)
};
});
```
### Reference from XAML

As for the technical reason; it's pretty simple.

Some parts of the UI are driven by code behind. When you change a language behind the .resx file, there is no 'magic trigger' to automatically replace all instances of a given string throughout the application, so this must be handled manually.

The LocalizedStringUpdater class automatically fires any callbacks given to it when the user changes the language in the UI. (In this case Name = getName())

2023-08-17.17-20-30.mp4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the need for live updating outweigh the added complexity and performance loss? Most applications will just prompt the user to restart the application if they change the language.

@halgari halgari merged commit 0b44541 into main Aug 21, 2023
3 of 5 checks passed
@halgari halgari deleted the add-localization-support branch August 21, 2023 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants