Ava UI: RTL Language Support (#5619)
* Add Hebrew locale files to ItemGroups * Align all windows RTL for testing This should be controlled with a binding that selects the appropriate layout based on current language * Update FlowDirection as Locale changes * Fix Settings NavigationViewItem FlowDirection * Fix remaining text * Fix input menu directionality * Fix RTL not rendering * Fix rebase errors
This commit is contained in:
parent
f037fcba9a
commit
1a45dc8df8
14 changed files with 60 additions and 29 deletions
|
@ -16,8 +16,10 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
private readonly Dictionary<LocaleKeys, string> _localeStrings;
|
private readonly Dictionary<LocaleKeys, string> _localeStrings;
|
||||||
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
||||||
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
||||||
|
private string _localeLanguageCode;
|
||||||
|
|
||||||
public static LocaleManager Instance { get; } = new();
|
public static LocaleManager Instance { get; } = new();
|
||||||
|
public event Action LocaleChanged;
|
||||||
|
|
||||||
public LocaleManager()
|
public LocaleManager()
|
||||||
{
|
{
|
||||||
|
@ -104,6 +106,15 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsRTL()
|
||||||
|
{
|
||||||
|
return _localeLanguageCode switch
|
||||||
|
{
|
||||||
|
"he_IL" => true,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
|
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
|
||||||
{
|
{
|
||||||
_dynamicValues[key] = values;
|
_dynamicValues[key] = values;
|
||||||
|
@ -124,6 +135,9 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
{
|
{
|
||||||
this[item.Key] = item.Value;
|
this[item.Key] = item.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_localeLanguageCode = languageCode;
|
||||||
|
LocaleChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
|
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
|
||||||
|
|
|
@ -119,6 +119,7 @@
|
||||||
<None Remove="Assets\Locales\en_US.json" />
|
<None Remove="Assets\Locales\en_US.json" />
|
||||||
<None Remove="Assets\Locales\es_ES.json" />
|
<None Remove="Assets\Locales\es_ES.json" />
|
||||||
<None Remove="Assets\Locales\fr_FR.json" />
|
<None Remove="Assets\Locales\fr_FR.json" />
|
||||||
|
<None Remove="Assets\Locales\he_IL.json" />
|
||||||
<None Remove="Assets\Locales\de_DE.json" />
|
<None Remove="Assets\Locales\de_DE.json" />
|
||||||
<None Remove="Assets\Locales\it_IT.json" />
|
<None Remove="Assets\Locales\it_IT.json" />
|
||||||
<None Remove="Assets\Locales\ja_JP.json" />
|
<None Remove="Assets\Locales\ja_JP.json" />
|
||||||
|
@ -143,6 +144,7 @@
|
||||||
<EmbeddedResource Include="Assets\Locales\en_US.json" />
|
<EmbeddedResource Include="Assets\Locales\en_US.json" />
|
||||||
<EmbeddedResource Include="Assets\Locales\es_ES.json" />
|
<EmbeddedResource Include="Assets\Locales\es_ES.json" />
|
||||||
<EmbeddedResource Include="Assets\Locales\fr_FR.json" />
|
<EmbeddedResource Include="Assets\Locales\fr_FR.json" />
|
||||||
|
<EmbeddedResource Include="Assets\Locales\he_IL.json" />
|
||||||
<EmbeddedResource Include="Assets\Locales\de_DE.json" />
|
<EmbeddedResource Include="Assets\Locales\de_DE.json" />
|
||||||
<EmbeddedResource Include="Assets\Locales\it_IT.json" />
|
<EmbeddedResource Include="Assets\Locales\it_IT.json" />
|
||||||
<EmbeddedResource Include="Assets\Locales\ja_JP.json" />
|
<EmbeddedResource Include="Assets\Locales\ja_JP.json" />
|
||||||
|
|
|
@ -86,17 +86,17 @@
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
Text="{Binding TitleName}"
|
Text="{Binding TitleName}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding Developer}"
|
Text="{Binding Developer}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding Version}"
|
Text="{Binding Version}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -110,12 +110,12 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding TitleId}"
|
Text="{Binding TitleId}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding FileExtension}"
|
Text="{Binding FileExtension}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
@ -127,17 +127,17 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding TimePlayedString}"
|
Text="{Binding TimePlayedString}"
|
||||||
TextAlignment="Right"
|
TextAlignment="End"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding LastPlayedString, Converter={helpers:LocalizedNeverConverter}}"
|
Text="{Binding LastPlayedString, Converter={helpers:LocalizedNeverConverter}}"
|
||||||
TextAlignment="Right"
|
TextAlignment="End"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding FileSizeString}"
|
Text="{Binding FileSizeString}"
|
||||||
TextAlignment="Right"
|
TextAlignment="End"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ui:SymbolIcon
|
<ui:SymbolIcon
|
||||||
|
|
|
@ -7,5 +7,6 @@
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.UI.Renderer.RendererHost"
|
x:Class="Ryujinx.Ava.UI.Renderer.RendererHost"
|
||||||
|
FlowDirection="LeftToRight"
|
||||||
Focusable="True">
|
Focusable="True">
|
||||||
</UserControl>
|
</UserControl>
|
|
@ -218,6 +218,7 @@
|
||||||
<Grid
|
<Grid
|
||||||
Name="SettingButtons"
|
Name="SettingButtons"
|
||||||
MinHeight="450"
|
MinHeight="450"
|
||||||
|
FlowDirection="LeftToRight"
|
||||||
IsVisible="{Binding ShowSettings}">
|
IsVisible="{Binding ShowSettings}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
PointerReleased="VsyncStatus_PointerReleased"
|
PointerReleased="VsyncStatus_PointerReleased"
|
||||||
Text="VSync"
|
Text="VSync"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Start" />
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
PointerReleased="DockedStatus_PointerReleased"
|
PointerReleased="DockedStatus_PointerReleased"
|
||||||
Text="{Binding DockedStatusText}"
|
Text="{Binding DockedStatusText}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Start" />
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
|
@ -225,7 +225,7 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
Text="{Binding GameStatusText}"
|
Text="{Binding GameStatusText}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Start" />
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
|
@ -240,7 +240,7 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
Text="{Binding FifoStatusText}"
|
Text="{Binding FifoStatusText}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Start" />
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
|
@ -255,7 +255,7 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
Text="{Binding BackendText}"
|
Text="{Binding BackendText}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Start" />
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
|
@ -270,7 +270,7 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
Text="{Binding GpuNameText}"
|
Text="{Binding GpuNameText}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Start" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
Text="{locale:Locale ProfileImageSelectionNote}" />
|
Text="{locale:Locale ProfileImageSelectionNote}" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding UserId}"
|
Text="{Binding UserId}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
|
|
@ -238,7 +238,7 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
FontSize="10"
|
FontSize="10"
|
||||||
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
|
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
|
||||||
TextAlignment="Right"
|
TextAlignment="End"
|
||||||
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
|
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
@ -158,7 +158,7 @@
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
IsVisible="{Binding ShowLoadProgress}"
|
IsVisible="{Binding ShowLoadProgress}"
|
||||||
Text="{Binding LoadHeading}"
|
Text="{Binding LoadHeading}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
MaxWidth="500" />
|
MaxWidth="500" />
|
||||||
<Border
|
<Border
|
||||||
|
@ -192,7 +192,7 @@
|
||||||
FontSize="18"
|
FontSize="18"
|
||||||
IsVisible="{Binding ShowLoadProgress}"
|
IsVisible="{Binding ShowLoadProgress}"
|
||||||
Text="{Binding CacheLoadStatus}"
|
Text="{Binding CacheLoadStatus}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Start"
|
||||||
MaxWidth="500" />
|
MaxWidth="500" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -101,6 +101,9 @@
|
||||||
<Style Selector="Grid#PlaceholderGrid">
|
<Style Selector="Grid#PlaceholderGrid">
|
||||||
<Setter Property="Height" Value="40" />
|
<Setter Property="Height" Value="40" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ui|NavigationViewItem ui|SymbolIcon">
|
||||||
|
<Setter Property="FlowDirection" Value="LeftToRight" />
|
||||||
|
</Style>
|
||||||
</ui:NavigationView.Styles>
|
</ui:NavigationView.Styles>
|
||||||
</ui:NavigationView>
|
</ui:NavigationView>
|
||||||
<ReversibleStackPanel
|
<ReversibleStackPanel
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Media;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
@ -22,6 +24,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
Icon = new WindowIcon(stream);
|
Icon = new WindowIcon(stream);
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
IconImage = new Bitmap(stream);
|
IconImage = new Bitmap(stream);
|
||||||
|
|
||||||
|
LocaleManager.Instance.LocaleChanged += LocaleChanged;
|
||||||
|
LocaleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LocaleChanged()
|
||||||
|
{
|
||||||
|
FlowDirection = LocaleManager.Instance.IsRTL() ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
|
|
Reference in a new issue