Skip to content

Commit 508197f

Browse files
Add project files.
1 parent e67c3e0 commit 508197f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+4040
-0
lines changed

.editorconfig

Lines changed: 409 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# 🌏WinUI3Localizer
2+
The WinUI3Localizer is a NuGet package that helps you localize your WinUI 3 app.
3+
4+
- Switch languages **without restarting**
5+
- You/users can **edit** localized strings even after deployment
6+
- You/users can **add** new languages even after deployment
7+
- Use standard **Resources.resw**
8+
9+
## 🙌 Getting started
10+
11+
### Installing the WinUI3Localizer
12+
Install the WinUI3Localizer from the NuGet Package Manager or using the command below.
13+
14+
```powershell
15+
dotnet add package WinUI3Localizer
16+
```
17+
18+
### Prepare the "Strings" folder
19+
Create a "Strings" folder and populate it with your string resources files for the languages you need. For example, this is the basic structure of a "Strings" folder for English (en-US), es-ES (Spanish) and Japanese (ja).
20+
21+
- Strings
22+
- en-US
23+
- Resources.resw
24+
- es-ES
25+
- Resources.resw
26+
- ja
27+
- Resources.resw
28+
29+
The "Strings" folder can be anywhere as long the app can access it. Usually, aside the app executable for non-packaged apps, or in the LocalData folder for packaged-apps.

WinUI3Localizer.SampleApp/App.xaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Application
2+
x:Class="WinUI3Localizer.SampleApp.App"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:converters="using:WinUI3Localizer.SampleApp.Converters"
6+
xmlns:local="using:WinUI3Localizer.SampleApp">
7+
<Application.Resources>
8+
<ResourceDictionary>
9+
<ResourceDictionary.MergedDictionaries>
10+
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
11+
<!-- Other merged dictionaries here -->
12+
<!--<ResourceDictionary Source="Styles.xaml" />-->
13+
</ResourceDictionary.MergedDictionaries>
14+
<!-- Other app resources here -->
15+
<converters:NullableBooleanToBooleanConverter x:Key="NullableBooleanToBooleanConverter" />
16+
<Style TargetType="local:ExamplePresenter">
17+
<Setter Property="Margin" Value="5" />
18+
<Setter Property="CornerRadius" Value="5" />
19+
<Setter Property="FontSize" Value="12" />
20+
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
21+
<Setter Property="HeaderTextStyle" Value="{StaticResource SubtitleTextBlockStyle}" />
22+
<Setter Property="ExamplePresenterWidth" Value="290" />
23+
<Setter Property="HorizontalContentAlignment" Value="Left" />
24+
</Style>
25+
</ResourceDictionary>
26+
</Application.Resources>
27+
</Application>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Hosting;
3+
using Microsoft.Extensions.Logging;
4+
using Microsoft.UI.Xaml;
5+
using Microsoft.UI.Xaml.Documents;
6+
using Serilog;
7+
using System;
8+
using System.IO;
9+
using System.Threading.Tasks;
10+
using Windows.Storage;
11+
using WinUI3Localizer;
12+
13+
namespace WinUI3Localizer.SampleApp;
14+
15+
public partial class App : Application
16+
{
17+
private static IHost Host { get; } = BuildHost();
18+
19+
public static string StringsFolderPath { get; private set; } = string.Empty;
20+
21+
private Window? window;
22+
23+
private string[] DefaultStringsResources { get; } = { "en-US", "es-ES", "ja" };
24+
25+
public App()
26+
{
27+
InitializeComponent();
28+
RequestedTheme = ApplicationTheme.Dark;
29+
}
30+
31+
protected override async void OnLaunched(LaunchActivatedEventArgs args)
32+
{
33+
await InitializeLocalizer();
34+
35+
this.window = Host.Services.GetRequiredService<MainWindow>();
36+
this.window.Activate();
37+
}
38+
39+
private async Task PrepareDefaultStringsResourcesFolderForPackagedApps(StorageFolder stringsFolder)
40+
{
41+
foreach (string language in DefaultStringsResources)
42+
{
43+
StorageFolder languageFolder = await stringsFolder.CreateFolderAsync(
44+
language,
45+
CreationCollisionOption.OpenIfExists);
46+
47+
string resourcesFileName = "Resources.resw";
48+
49+
if (await languageFolder.TryGetItemAsync(resourcesFileName) is null)
50+
{
51+
Uri resourcesFileUri = new($"ms-appx:///Strings/{language}/{resourcesFileName}");
52+
StorageFile defaultResourceFile = await StorageFile.GetFileFromApplicationUriAsync(resourcesFileUri);
53+
_ = await defaultResourceFile.CopyAsync(languageFolder);
54+
}
55+
}
56+
}
57+
58+
/// <summary>
59+
/// Creates default Resources.resw files for the WinUI3Localizer.
60+
/// </summary>
61+
private async Task InitializeLocalizer()
62+
{
63+
#if IS_NON_PACKAGED
64+
// Initialize a "Strings" folder in the executables folder.
65+
StringsFolderPath = Path.Combine(Directory.GetCurrentDirectory(), "Strings");
66+
//StorageFolder localFolder = await StorageFolder.GetFolderFromPathAsync(Directory.GetCurrentDirectory());
67+
StorageFolder stringsFolder = await StorageFolder.GetFolderFromPathAsync(StringsFolderPath);
68+
#else
69+
// Initialize a "Strings" folder in the "LocalFolder" for the packaged app.
70+
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
71+
StorageFolder stringsFolder = await localFolder.CreateFolderAsync("Strings", CreationCollisionOption.OpenIfExists);
72+
StringsFolderPath = stringsFolder.Path;
73+
await PrepareDefaultStringsResourcesFolderForPackagedApps(stringsFolder);
74+
#endif
75+
76+
ILocalizer localizer = await new LocalizerBuilder()
77+
.AddStringResourcesFolderForLanguageDictionaries(StringsFolderPath)
78+
//.SetLogger(Host.Services
79+
// .GetRequiredService<ILoggerFactory>()
80+
// .CreateLogger<Localizer>())
81+
.SetOptions(options =>
82+
{
83+
options.DefaultLanguage = "en-US";
84+
options.UseUidWhenLocalizedStringNotFound = true;
85+
})
86+
//.AddLocalizationAction(new LocalizationActionItem(typeof(Hyperlink), arguments =>
87+
//{
88+
// if (arguments.DependencyObject is Hyperlink target && target.Inlines.Count is 0)
89+
// {
90+
// target.Inlines.Clear();
91+
// target.Inlines.Add(new Run() { Text = arguments.Value });
92+
// }
93+
//}))
94+
//.AddLocalizationAction(new LocalizationActionItem(typeof(Run), arguments =>
95+
//{
96+
// if (arguments.DependencyObject is Run target)
97+
// {
98+
// target.Text = arguments.Value;
99+
// }
100+
//}))
101+
.Build();
102+
}
103+
104+
private static IHost BuildHost()
105+
{
106+
return Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
107+
.UseSerilog((context, service, configuration) =>
108+
{
109+
_ = configuration
110+
.MinimumLevel.Verbose()
111+
.WriteTo.File(
112+
"WinUI3Localizer.log",
113+
restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Verbose,
114+
rollingInterval: RollingInterval.Month);
115+
})
116+
.ConfigureServices((context, services) =>
117+
{
118+
_ = services
119+
.AddLogging(configure =>
120+
{
121+
_ = configure
122+
.SetMinimumLevel(LogLevel.Trace)
123+
.AddSerilog()
124+
.AddDebug();
125+
})
126+
.AddSingleton<MainWindow>()
127+
//.AddSingleton<ILocalizer>(factory =>
128+
//{
129+
// return new LocalizerBuilder()
130+
// .AddStringResourcesFolderForLanguageDictionaries(StringsFolderPath)
131+
// .SetLogger(Host.Services
132+
// .GetRequiredService<ILoggerFactory>()
133+
// .CreateLogger<Localizer>())
134+
// .SetOptions(options =>
135+
// {
136+
// options.DefaultLanguage = "ja";
137+
// options.UseUidWhenLocalizedStringNotFound = true;
138+
// })
139+
// .Build()
140+
// .GetAwaiter()
141+
// .GetResult();
142+
//})
143+
;
144+
})
145+
.Build();
146+
}
147+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.Extensions.Configuration;
2+
3+
namespace WinUI3Localizer.SampleApp;
4+
5+
public class AppConfig
6+
{
7+
private readonly IConfigurationRoot configurationRoot;
8+
9+
public AppConfig(string basePath)
10+
{
11+
this.configurationRoot = new ConfigurationBuilder()
12+
.SetBasePath("")
13+
.AddJsonFile("appsettings.json", optional: false)
14+
.Build();
15+
}
16+
}
432 Bytes
Loading
5.25 KB
Loading
1.71 KB
Loading
637 Bytes
Loading
283 Bytes
Loading

0 commit comments

Comments
 (0)