Skip to content

Commit

Permalink
First pass localisation where buttons can self-retranslate.
Browse files Browse the repository at this point in the history
  • Loading branch information
Keflon committed Feb 25, 2024
1 parent f848cc8 commit 7e24d8f
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 53 deletions.
18 changes: 0 additions & 18 deletions FunctionZero.Maui.Controls/MarkupExtensions/TranslationService.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using FunctionZero.Maui.MarkupExtensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
Expand All @@ -11,30 +12,31 @@ namespace FunctionZero.Maui.Services
/// <summary>
/// Goal. To be decoupled enough to allow downloading and selection of new or updated language packs on the fly.
/// </summary>
public class TranslationService : INotifyPropertyChanged
public abstract partial class BaseLanguageService<TEnum> : INotifyPropertyChanged where TEnum : Enum
{
private readonly string _resourceKey;
private ResourceDictionary _resourceHost;
private Dictionary<string, LanguageProvider> _languages;
public event EventHandler<LanguageChangedEventArgs> LanguageChanged;

// INPC raised by SetLanguage(..)
public string CurrentLanguageId => _resourceHost[_resourceKey] as string;
public string CurrentLanguageId { get; protected set; }


public event PropertyChangedEventHandler PropertyChanged;


// TODO: Expose an ObsColl of languages, so the app can e.g. download new language packs and the UI can bind to it all.
public TranslationService(string resourceKey = "LocalisedStrings")
public BaseLanguageService(string resourceKey = "languageResource")
{
_resourceKey = resourceKey;
_languages = new();
}

public void Init(ResourceDictionary resourceHost)
public void Init(ResourceDictionary resourceHost, string initialLanguage)
{
_resourceHost = resourceHost;
SetLanguage(initialLanguage);
}

public void RegisterLanguage(string id, LanguageProvider language)
Expand All @@ -51,27 +53,25 @@ public void RegisterLanguage(string id, LanguageProvider language)
public void SetLanguage(string id)
{
if (_resourceHost == null)
throw new InvalidOperationException("You must call Init on the TranslationService before you call SetLanguage(string id), e.g. Init(Application.Current.Resources);");
throw new InvalidOperationException("You must call Init on the LanguageService before you call SetLanguage(string id), e.g. Init(Application.Current.Resources);");

if (_languages.TryGetValue(id, out var languageService))
_resourceHost[_resourceKey] = languageService.GetLookup();
else
throw new Exception($"Register a language before trying to set it. Language: '{id}' ");

CurrentLanguageId = id;

LanguageChanged?.Invoke(this, new LanguageChangedEventArgs(id));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentLanguageId)));
}

public string[] CurrentLookup => _resourceHost[_resourceKey] as string[];
public class LanguageProvider

public string GetText(TEnum textId)
{
public LanguageProvider(Func<string[]> getLookup, string languageName)
{
GetLookup = getLookup;
LanguageName = languageName;
}
public Func<string[]> GetLookup { get; }
public string LanguageName { get; }
var retval = _languages[CurrentLanguageId].GetLookup()[(int)(object)textId];
return retval;
}
}
}
13 changes: 13 additions & 0 deletions FunctionZero.Maui.Controls/Services/LanguageProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace FunctionZero.Maui.Services
{
public class LanguageProvider
{
public LanguageProvider(Func<string[]> getLookup, string languageName)
{
GetLookup = getLookup;
LanguageName = languageName;
}
public Func<string[]> GetLookup { get; }
public string LanguageName { get; }
}
}
4 changes: 3 additions & 1 deletion SampleApp/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@
using FunctionZero.Maui.MvvmZero;
using Microsoft.Maui.Platform;
using SampleApp.Mvvm.PageViewModels;
using SampleApp.Translations;
using SampleApp.Widgets;
using System.Diagnostics;

namespace SampleApp
{
public partial class App : Application
{
public App(IPageServiceZero pageService)
public App(IPageServiceZero pageService, LangService langService)
{
var temp = new WidgetContainer("", "", "");
InitializeComponent();

pageService.Init(this);
langService.Init(this.Resources, "english");

// Uses AdaptedFlyoutPage because https://github.com/dotnet/maui/issues/13496
var flyoutPage = pageService.GetFlyoutPage<AppFlyoutPageVm>();
Expand Down
19 changes: 19 additions & 0 deletions SampleApp/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using FunctionZero.Maui.Controls;
using FunctionZero.Maui.MvvmZero;
using FunctionZero.Maui.Services;
using SampleApp.Mvvm.Pages;
using SampleApp.Mvvm.Pages.Expander;
using SampleApp.Mvvm.Pages.List;
Expand All @@ -14,6 +15,7 @@
using SampleApp.Mvvm.PageViewModels.MultiView;
using SampleApp.Mvvm.PageViewModels.Translations;
using SampleApp.Mvvm.PageViewModels.Tree;
using SampleApp.Translations;

namespace SampleApp
{
Expand Down Expand Up @@ -98,10 +100,27 @@ public static MauiApp CreateMauiApp()
.AddSingleton<TranslationHomePage>()
.AddSingleton<TranslationHomePageVm>()

.AddSingleton<LangService>(GetConfiguredLanguageService)

;

return builder.Build();
}

#region Language translation setup
private static LangService GetConfiguredLanguageService(IServiceProvider provider)
{
var translationService = new LangService();
translationService.RegisterLanguage("english", new LanguageProvider(GetEnglish, "English"));
translationService.RegisterLanguage("german", new LanguageProvider(GetGerman, "Deutsch"));

return translationService;
}

// Example
private static string[] GetEnglish() => new string[] { "Hello", "World", "Welcome to the Moasure Playground!" };
private static string[] GetGerman() => new string[] { "Hallo", "Welt", "Willkommen auf dem Moasure Spielplatz!" };

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using FunctionZero.Maui.MvvmZero;
using FunctionZero.Maui.Services;
using SampleApp.Mvvm.ViewModels;
using SampleApp.Translations;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Expand All @@ -13,19 +15,35 @@ namespace SampleApp.Mvvm.PageViewModels.Translations
{
public class TranslationHomePageVm : BasePageVm
{
private string _selectedLanguage;

public IList<KeyValuePair<string, string>> AvailableLanguages { get; }

public string SelectedLanguage { get => _selectedLanguage; set => SetProperty(ref _selectedLanguage, value); }
private readonly LangService _langService;

public ICommand SetLanguageCommand { get; }
public TranslationHomePageVm(TranslationService translationService)
public ICommand DoTheThingCommand { get; }
public TranslationHomePageVm(LangService langService)
{
AvailableLanguages = [new KeyValuePair<string, string>("English", "english"), new KeyValuePair<string, string>("Deutsch", "german")];
_langService = langService;

SetLanguageCommand = new CommandBuilder()
.SetText()=>translationService.
.AddGuard(this)
.SetExecute(SetLanguageCommandExecute)
.Build();

DoTheThingCommand = new CommandBuilder()
.AddGuard(this)
.SetExecute(DoTheThingCommandExecute)
.SetName(() => langService.GetText(LangStrings.E_World))
.AddObservedProperty(langService, nameof(LangService.CurrentLanguageId))
.Build();
}

private void DoTheThingCommandExecute()
{
Debug.WriteLine($"New language: {_langService.CurrentLanguageId}");
}

private void SetLanguageCommandExecute(object arg)
{
_langService.SetLanguage((string)arg);
}
}
}
15 changes: 8 additions & 7 deletions SampleApp/Mvvm/Pages/Translations/TranslationHomePage.xaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tz="clr-namespace:SampleApp.Translations"
x:Class="SampleApp.Mvvm.Pages.Translations.TranslationHomePage"
Title="TranslationHomePage">
<VerticalStackLayout>
<CollectionView ItemsSource="{Binding AvailableLanguages}" SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Key}"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<HorizontalStackLayout>
<Button Text="English" Command="{Binding SetLanguageCommand}" CommandParameter="english"/>
<Button Text="German" Command="{Binding SetLanguageCommand}" CommandParameter="german"/>
</HorizontalStackLayout>
<Label Text="{tz:Lang TextId=E_Welcome}"/>
<Button Text="{Binding DoTheThingCommand.Text}" Command="{Binding DoTheThingCommand}"/>

</VerticalStackLayout>
</ContentPage>
7 changes: 2 additions & 5 deletions SampleApp/Translations/LangExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@

namespace SampleApp.Translations
{
public class LanguageService<TEnum> where TEnum : Enum
public class LangExtension : BaseLanguageExtension<LangStrings>
{
public class LangExtension : BaseLanguageExtension<TEnum>
public LangExtension() : base("languageResource")
{
public LangExtension() : base("languageResource")
{

}
}
}
}
14 changes: 14 additions & 0 deletions SampleApp/Translations/LangService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using FunctionZero.Maui.MarkupExtensions;
using FunctionZero.Maui.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Translations
{
public class LangService : BaseLanguageService<LangStrings>
{
}
}

0 comments on commit 7e24d8f

Please sign in to comment.