Draft: localisation support

this is a draft as i can't fully test this right now because i'm currently 37000 feet in the air and a 75 MB data quota costs 10 bucks :(

this also may be the first documented instance of me using wpf 100% properly as bill gates himself intended
This commit is contained in:
pizzaboxer 2024-06-21 22:10:11 +01:00
parent 36d8d5fbf4
commit 81d7ffe3da
No known key found for this signature in database
GPG Key ID: 59D4A1DBAD0F2BA8
15 changed files with 310 additions and 11 deletions

View File

@ -29,7 +29,7 @@ namespace Bloxstrap
public static LaunchSettings LaunchSettings { get; private set; } = null!;
public static CultureInfo CurrentCulture { get; private set; } = CultureInfo.InvariantCulture;
public static CultureInfo CurrentCulture { get; set; } = CultureInfo.InvariantCulture;
public static BuildMetadataAttribute BuildMetadata = Assembly.GetExecutingAssembly().GetCustomAttribute<BuildMetadataAttribute>()!;
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
@ -113,8 +113,7 @@ namespace Bloxstrap
{
const string LOG_IDENT = "App::OnStartup";
CultureInfo.DefaultThreadCurrentUICulture = CurrentCulture;
Thread.CurrentThread.CurrentUICulture = CurrentCulture;
CurrentCulture = Thread.CurrentThread.CurrentUICulture;
base.OnStartup(e);
@ -147,6 +146,7 @@ namespace Bloxstrap
Settings.Load();
State.Load();
FastFlags.Load();
Locale.Set();
}
LaunchSettings.ParseRoblox();

View File

@ -302,6 +302,16 @@ namespace Bloxstrap
_launchCommandLine += "production";
else
_launchCommandLine += App.Settings.Prop.Channel.ToLowerInvariant();
if (App.Settings.Prop.ForceRobloxLanguage)
{
if (_launchCommandLine.StartsWith("roblox-player:1"))
_launchCommandLine += "+robloxLocale:";
else
_launchCommandLine += " -robloxLocale ";
_launchCommandLine += App.CurrentCulture.Name.Replace('-', '_');
}
}
// whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes

View File

@ -130,6 +130,7 @@ namespace Bloxstrap
App.IsSetupComplete = false;
App.FastFlags.Load();
Frontend.ShowLanguageSelection();
Frontend.ShowMenu();
// exit if we don't click the install button on installation

80
Bloxstrap/Locale.cs Normal file
View File

@ -0,0 +1,80 @@
using System;
using System.Windows;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Bloxstrap.Resources;
namespace Bloxstrap
{
internal static class Locale
{
// TODO: put translated names
public static readonly Dictionary<string, string> SupportedLocales = new()
{
{ "nil", Strings.Enums_Theme_Default }, // /shrug
{ "en", "English" },
{ "en-US", "English (United States)" },
{ "ar", "Arabic" },
{ "bn", "Bengali" },
{ "bs", "Bosnian" },
{ "bg", "Bulgarian" },
{ "zh-CN", "Chinese (Simplified)" },
{ "zh-TW", "Chinese (Traditional)" },
{ "cs", "Czech" },
{ "dk", "Danish" },
{ "nl", "Dutch" },
{ "fl", "Filipino" },
{ "fi", "Finnish" },
{ "fr", "French" },
{ "de", "German" },
{ "he", "Hebrew" },
{ "hi", "Hindi" },
{ "hu", "Hungarian" },
{ "id", "Indonesian" },
{ "it", "Italian" },
{ "ja", "Japanese" },
{ "ko", "Korean" },
{ "lt", "Lithuanian" },
{ "no", "Norwegian" },
{ "pl", "Polish" },
{ "pt-BR", "Portuguese" },
{ "ro", "Romanian" },
{ "ru", "Russian" },
{ "es", "Spanish" },
{ "sv-SE", "Swedish" },
{ "th", "Thai" },
{ "tr", "Turkish" },
{ "uk", "Ukrainian" },
{ "vi", "Vietnamese" }
};
public static string GetIdentifierFromName(string language) => Locale.SupportedLocales.Where(x => x.Value == language).First().Key;
public static void Set()
{
string identifier = App.Settings.Prop.Locale;
if (!SupportedLocales.ContainsKey(identifier))
identifier = "nil";
if (identifier == "nil")
return;
App.CurrentCulture = new CultureInfo(identifier);
CultureInfo.DefaultThreadCurrentUICulture = App.CurrentCulture;
Thread.CurrentThread.CurrentUICulture = App.CurrentCulture;
if (identifier == "ar" || identifier == "he")
{
// TODO: credit the SO post i took this from
EventManager.RegisterClassHandler(typeof(Window), FrameworkElement.LoadedEvent, new RoutedEventHandler((window, _) =>
{
((Window)window).FlowDirection = FlowDirection.RightToLeft;
}));
}
}
}
}

View File

@ -13,6 +13,8 @@ namespace Bloxstrap.Models
public bool CheckForUpdates { get; set; } = true;
public bool CreateDesktopIcon { get; set; } = true;
public bool ConfirmLaunches { get; set; } = false;
public string Locale { get; set; } = "nil";
public bool ForceRobloxLanguage { get; set; } = false;
// channel configuration
public string Channel { get; set; } = RobloxDeployment.DefaultChannel;

View File

@ -693,6 +693,25 @@ namespace Bloxstrap.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Choose preferred language.
/// </summary>
public static string Dialog_LanguageSelector_Header {
get {
return ResourceManager.GetString("Dialog.LanguageSelector.Header", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Choose a language before continuing with installation.
///Scroll for more languages..
/// </summary>
public static string Dialog_LanguageSelector_Subtext {
get {
return ResourceManager.GetString("Dialog.LanguageSelector.Subtext", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 2008.
/// </summary>
@ -1144,7 +1163,7 @@ namespace Bloxstrap.Resources {
}
/// <summary>
/// Looks up a localized string similar to System Default.
/// Looks up a localized string similar to System default.
/// </summary>
public static string Enums_Theme_Default {
get {
@ -1497,6 +1516,24 @@ namespace Bloxstrap.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Scroll to see more. A relaunch is required for changes to take effect..
/// </summary>
public static string Menu_Appearance_Language_Description {
get {
return ResourceManager.GetString("Menu.Appearance.Language.Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Language.
/// </summary>
public static string Menu_Appearance_Language_Title {
get {
return ResourceManager.GetString("Menu.Appearance.Language.Title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Preview.
/// </summary>
@ -1596,6 +1633,24 @@ namespace Bloxstrap.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Roblox will be forced to display the same language that Bloxstrap is presently using..
/// </summary>
public static string Menu_Behaviour_ForceRobloxLanguage_Description {
get {
return ResourceManager.GetString("Menu.Behaviour.ForceRobloxLanguage.Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Force Roblox language.
/// </summary>
public static string Menu_Behaviour_ForceRobloxLanguage_Title {
get {
return ResourceManager.GetString("Menu.Behaviour.ForceRobloxLanguage.Title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Roblox will be installed fresh on next launch..
/// </summary>

View File

@ -484,7 +484,7 @@ Click for more information</value>
<value>Dark</value>
</data>
<data name="Enums.Theme.Default" xml:space="preserve">
<value>System Default</value>
<value>System default</value>
</data>
<data name="Enums.Theme.Light" xml:space="preserve">
<value>Light</value>
@ -1023,4 +1023,23 @@ Selecting 'No' will ignore this warning and continue installation.</value>
<data name="Menu.Title" xml:space="preserve">
<value>Bloxstrap Menu</value>
</data>
<data name="Dialog.LanguageSelector.Header" xml:space="preserve">
<value>Choose preferred language</value>
</data>
<data name="Dialog.LanguageSelector.Subtext" xml:space="preserve">
<value>Choose a language before continuing with installation.
Scroll for more languages.</value>
</data>
<data name="Menu.Appearance.Language.Title" xml:space="preserve">
<value>Language</value>
</data>
<data name="Menu.Appearance.Language.Description" xml:space="preserve">
<value>Scroll to see more. A relaunch is required for changes to take effect.</value>
</data>
<data name="Menu.Behaviour.ForceRobloxLanguage.Title" xml:space="preserve">
<value>Force Roblox language</value>
</data>
<data name="Menu.Behaviour.ForceRobloxLanguage.Description" xml:space="preserve">
<value>Roblox will be forced to display the same language that Bloxstrap is presently using.</value>
</data>
</root>

View File

@ -0,0 +1,41 @@
<ui:UiWindow x:Class="Bloxstrap.UI.Elements.Dialogs.LanguageSelectorDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Dialogs"
xmlns:resources="clr-namespace:Bloxstrap.Resources"
mc:Ignorable="d"
Title="Bloxstrap"
MinWidth="0"
MinHeight="0"
Width="380"
SizeToContent="Height"
ResizeMode="NoResize"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" Title="Bloxstrap" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
<StackPanel Grid.Row="1" Margin="12">
<TextBlock Text="{x:Static resources:Strings.Dialog_LanguageSelector_Header}" FontSize="18" FontWeight="Medium" />
<TextBlock Text="{x:Static resources:Strings.Dialog_LanguageSelector_Subtext}" TextWrapping="Wrap" Margin="0,0,0,12" />
<ComboBox ItemsSource="{Binding Languages, Mode=OneTime}" Text="{Binding SelectedLanguage, Mode=TwoWay}" />
</StackPanel>
<Border Grid.Row="2" Margin="0,10,0,0" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
<Button MinWidth="100" Content="{x:Static resources:Strings.Common_OK}" Command="{Binding SetLocaleCommand}" />
<!--<Button MinWidth="100" Margin="12,0,0,0" Content="{x:Static resources:Strings.Common_Cancel}" IsCancel="True" />-->
</StackPanel>
</Border>
</Grid>
</ui:UiWindow>

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Bloxstrap.UI.ViewModels.Dialogs;
namespace Bloxstrap.UI.Elements.Dialogs
{
/// <summary>
/// Interaction logic for LanguageSelectorDialog.xaml
/// </summary>
public partial class LanguageSelectorDialog
{
public LanguageSelectorDialog()
{
var viewModel = new LanguageSelectorViewModel();
DataContext = viewModel;
InitializeComponent();
viewModel.CloseRequestEvent += (_, _) => Close();
}
}
}

View File

@ -24,6 +24,12 @@
</ComboBox>
</controls:OptionControl>
<controls:OptionControl
Header="{x:Static resources:Strings.Menu_Appearance_Language_Title}"
Description="{x:Static resources:Strings.Menu_Appearance_Language_Description}">
<ComboBox Width="200" Padding="10,5,10,5" ItemsSource="{Binding Languages, Mode=OneTime}" Text="{Binding SelectedLanguage, Mode=TwoWay}" />
</controls:OptionControl>
<Grid Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />

View File

@ -29,6 +29,18 @@
<ui:ToggleSwitch IsChecked="{Binding UpdateCheckingEnabled, Mode=TwoWay}" />
</controls:OptionControl>
<controls:OptionControl
Header="{x:Static resources:Strings.Menu_Behaviour_ConfirmLaunches_Title}"
Description="{x:Static resources:Strings.Menu_Behaviour_ConfirmLaunches_Description}">
<ui:ToggleSwitch IsChecked="{Binding ConfirmLaunches, Mode=TwoWay}" />
</controls:OptionControl>
<controls:OptionControl
Header="{x:Static resources:Strings.Menu_Behaviour_ForceRobloxLanguage_Title}"
Description="{x:Static resources:Strings.Menu_Behaviour_ForceRobloxLanguage_Description}">
<ui:ToggleSwitch IsChecked="{Binding ForceRobloxLanguage, Mode=TwoWay}" />
</controls:OptionControl>
<controls:OptionControl
Header="{x:Static resources:Strings.Menu_Behaviour_ForceRobloxReinstall_Title}"
Description="{x:Static resources:Strings.Menu_Behaviour_ForceRobloxReinstall_Description}">
@ -43,11 +55,5 @@
</controls:OptionControl.Style>
<ui:ToggleSwitch IsChecked="{Binding ForceRobloxReinstallation, Mode=TwoWay}" />
</controls:OptionControl>
<controls:OptionControl
Header="{x:Static resources:Strings.Menu_Behaviour_ConfirmLaunches_Title}"
Description="{x:Static resources:Strings.Menu_Behaviour_ConfirmLaunches_Description}">
<ui:ToggleSwitch IsChecked="{Binding ConfirmLaunches, Mode=TwoWay}" />
</controls:OptionControl>
</StackPanel>
</ui:UiPage>

View File

@ -8,6 +8,8 @@ namespace Bloxstrap.UI
{
static class Frontend
{
public static void ShowLanguageSelection() => new LanguageSelectorDialog().ShowDialog();
public static void ShowMenu(bool showAlreadyRunningWarning = false) => new MainWindow(showAlreadyRunningWarning).ShowDialog();
public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxResult defaultResult = MessageBoxResult.None)

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
namespace Bloxstrap.UI.ViewModels.Dialogs
{
internal class LanguageSelectorViewModel
{
public event EventHandler? CloseRequestEvent;
public ICommand SetLocaleCommand => new RelayCommand(SetLocale);
public static List<string> Languages => Locale.SupportedLocales.Values.ToList();
public string SelectedLanguage { get; set; } = Locale.SupportedLocales[App.Settings.Prop.Locale];
private void SetLocale()
{
App.Settings.Prop.Locale = Locale.GetIdentifierFromName(SelectedLanguage);
Locale.Set();
CloseRequestEvent?.Invoke(this, new());
}
}
}

View File

@ -65,6 +65,14 @@ namespace Bloxstrap.UI.ViewModels.Menu
}
}
public static List<string> Languages => Locale.SupportedLocales.Values.ToList();
public string SelectedLanguage
{
get => Locale.SupportedLocales[App.Settings.Prop.Locale];
set => App.Settings.Prop.Locale = Locale.GetIdentifierFromName(value);
}
public IEnumerable<BootstrapperStyle> Dialogs { get; } = BootstrapperStyleEx.Selections;
public BootstrapperStyle Dialog

View File

@ -23,6 +23,12 @@
set => App.Settings.Prop.ConfirmLaunches = value;
}
public bool ForceRobloxLanguage
{
get => App.Settings.Prop.ForceRobloxLanguage;
set => App.Settings.Prop.ForceRobloxLanguage = value;
}
public bool ForceRobloxReinstallation
{
// wouldnt it be better to check old version guids?