How to start an internationalized WPF-Project in SharpDevelop 4.2? - c#

I want to create a Software, where the User can choose between several Languages.
As a start i want to learn how to handle Internationalization, since i have never done that before.
As IDE i use SharpDevelop or #develop, however you would spell it.
I want to use C# and WPF, since i'm also learning XAML/WPF at the moment.
So i create a new WPF-Project in ShardDevelop.
On the Main Window i create a ComboBox and a TextBlock.
The ComboBox get's two Entries: "German" and "English".
The textBlock should show "Hallo Welt!" or "Hello World!", depending on the Language which is selected.
Now comes the part where i get stuck.
I guess each language get's a separate file in XML/XAML-Style (Makes sense).
Where are these files and how are they and their Content loaded so that the Text of the selected Language is loaded?
I found several examples but all are something about creating Resource-DLL and using some weird program to decompile them back into a csv-file... i don't get it, isn't there an easier way?
I took the next Step.
The Text of the TextBlock is now loaded via "{StaticResource Strings.MainForm.hwText}". It looks like this now:
<TextBlock Text="{StaticResource Strings.MainForm.hwText}" />
Also I created one ResourceDictionary for German and one for English which both define the key i used in the TextBlock.
In the Application.Resources Part i load one of the ResourceDictionary's per default.
The Problem now is: How can i "unload" this Dictionary during Runtime and Replace it with the other?
Of course i use the SelectionChange-Event of the ComboBox, but what do i do there?
Problem solved!! Thanks to kmatyaszek
Although i changed the Code of the Event-Handler a bit to my needs:
Uri baseUri = new Uri(AppDomain.CurrentDomain.BaseDirectory);
Uri uri = new Uri(baseUri,"Languages\\lang."+((sender as ComboBox).SelectedItem as ComboBoxItem).Tag.ToString()+".xaml");
if(File.Exists(uri.LocalPath) || File.Exists((uri = new Uri(baseUri,"Languages\\lang.de-DE.xaml")).LocalPath)){
ResourceDictionary dict = new ResourceDictionary();
dict.Source = uri;
this.Resources.MergedDictionaries.Add(dict);
}

If you created two ResourceDictionary files you can binding by DynamicResource.
Example:
First resource file (Lang.en-US.xaml):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="Username">Username:</system:String>
<system:String x:Key="Password">Password:</system:String>
<system:String x:Key="close">Close</system:String>
<system:String x:Key="login">Login</system:String>
</ResourceDictionary>
Second resource file (Lang.pl-PL.xaml):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="Username">Login:</system:String>
<system:String x:Key="Password">Hasło:</system:String>
<system:String x:Key="close">Zamknij</system:String>
<system:String x:Key="login">Zaloguj</system:String>
</ResourceDictionary>
Set default language in Application resources:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Lang.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Let's say that we have ComboBox like below:
<ComboBox Name="cbLang" Margin="2" SelectionChanged="cbLang_SelectionChanged" >
<ComboBoxItem Content="English" Tag="en-US" />
<ComboBoxItem Content="Polish" Tag="pl-PL" />
</ComboBox>
Code-behind SelectionChanged:
private void cbLang_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ResourceDictionary dict = new ResourceDictionary();
switch (((sender as ComboBox).SelectedItem as ComboBoxItem).Tag.ToString())
{
case "en-US":
dict.Source = new Uri("Lang.en-US.xaml", UriKind.Relative);
break;
case "pl-PL":
dict.Source = new Uri("Lang.pl-PL.xaml", UriKind.Relative);
break;
default:
break;
}
this.Resources.MergedDictionaries.Add(dict);
}
And you can binding like this:
<TextBlock Text="{DynamicResource Username}" VerticalAlignment="Center" />

Related

How to load a specific language XAML file

I am building my language system using XAML files.
The code I have is as follows:
es.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyAppTest"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="Hello">Hola</system:String>
</ResourceDictionary>
en.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyAppTest"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="Hello">Hello</system:String>
</ResourceDictionary>
App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="en" Source="mylang/en.xaml"/>
<ResourceDictionary x:Name="es" Source="mylang/es.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Main.xaml
<TextBlock Text="{DynamicResource Hello}" />
<ComboBox>
<ComboBoxItem Content="English" />
<ComboBoxItem Content="Spanish" />
</ComboBox>
How can I read the language XAML file according to the language selected in the ComboBox?
What you are trying to do is possible by using DynamicResource like you did for TextBlock:
<TextBlock Text="{DynamicResource Hello}"/>
The DynamicResource markup extension will reslove a resource at runtime and update it if it was added, removed or replaced in a resource dictionary. You would create a resource dictionary for each language and you would put them into the application resource dictionary.
Since you cannot assign multiple objects to the same key in a resource dictionary, you should only have the resource dictionary for the currently applied language in your application resources. Applying and switching languages is done in code by exchanging the current language resource dictionary.
In order to set the initial language, you can load your language setting and add the corresponding language resource dictionary to the application resources in the App.xaml.cs class. Use a URI and set it as source of the resource dictionary. I assume it is english in this sample.
var languageResourceDictionaryUri = new Uri("mylang/en.xaml");
var languageResourceDictionary = new ResourceDictionary { Source = languageResourceDictionaryUri };
Application.Current.Resources.MergedDictionaries.Add(languageResourceDictionary);
You should store a reference to the current language resource dictionary, so you can remove it from the application resources, when the user changes the language using the ComboBox.
Application.Current.Resources.MergedDictionaries.Remove(languageResourceDictionary);
Then you would add the a new resource dictionary for the selected language as above. Depending on where you want to switch the language, you might want to create a service to hide the access to the global, static application instance that is needed to change the resources.

Apply ResourceDictionary to Pages in Frame in WPF

I have a Window in WPF which simply contains a Frame element. The Frame displays a Page; which Page is displayed changes based on user interaction.
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="720" Width="1280">
<Grid>
<Frame Source="{Binding Source={StaticResource MainPageIntent}, Path=Path}"/>
</Grid>
</Window>
I would like all Pages that appear in that Frame to share a common Resource Dictionary so that they may all be styled in a common way.
Right now I have something like this in every page that this Window loads:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/BaseControlStyles/MenuStyle.xaml"/>
I was hoping that I might just be able to set the resource dictionary on the Window, and they would "inherit" those resources, but that does not appear to be the case. I tried something like this, but the styles found in MenuStyle.xaml are not applied the the controls inside the Page loaded by the Frame:
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="720" Width="1280">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/BaseControlStyles/MenuStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Frame Source="{Binding Source={StaticResource MainPageIntent}, Path=Path}"/>
</Grid>
</Window>
Is there are way to define styles at the Window level such that all pages loaded in child Frames will use those styles?
Note: I do not want to apply these styles to ALL windows in my application, so putting this ResourceDictionary in my App.xaml does not appear to be a valid solution.
If you want to write it once to avoid code duplicates, you can write it in code behind. On frame ContentRendered you can write a code to add resource to the page which is being loaded.
<Frame Name="fr_View" ContentRendered="fr_View_ContentRendered"/>
private void fr_View_ContentRendered(object sender, System.EventArgs e)
{
ResourceDictionary myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source = new Uri("Dictionary1.xaml", UriKind.Relative);
(fr_View.Content as System.Windows.Controls.Page).Resources.MergedDictionaries.Add(myResourceDictionary);
}
Take a look at this link:
Set up application resources from code

How to apply different ResourceDictionary Styles asynchronously every 5 seconds?

Below is the Code , in which i want to change the theme color of the MahApps.Metro pakage.
it can be changed by changing the ResourceDictionary Source pack of MahApps.
[/MahApps.Metro;component/Styles/Accents/Blue.xaml ]
say example its /Blue.xaml now ... we can change colors of the window. to /Red.xaml , /Yellow.xaml etc
So how can i change the color of the window asynchronously in every 5 seconds? is this possible in wpf ?
i am new to wpf and clueless.
<controls:MetroWindow x:Class="NginX.Choose"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="NginX" Height="350" Width="350" ShowMaxRestoreButton="False">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
</Grid>
</controls:MetroWindow>
You can replace the Application's resource dictionary by doing:
Application.Current.Resources.Clear()
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml")
});
Put this in a timer and cycle through Red.xaml, Blue.xaml etc

Changing resource in the runtime

Let's suppose, that we've got the following dictionary:
<ResourceDictionary xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="Test">Ala ma kota</sys:String>
</ResourceDictionary>
This dictionary is merged somewhere in custom control:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
How can I completely change value of the resource "Test" during application runtime from the code behind?
You can change resource from code-behind but main thing is how you are binding to that resource i.e. via StaticResource or DynamicResource.
Modify like this -
Resources["Test"] = "Ala ma kota updated";
XAML (After resource update from code behind, text value will differ for two approaches) -
<TextBlock Text="{StaticResource Test}"/> // Will be Ala ma kota
<TextBlock Text="{DynamicResource Test}"/> // Will be Ala ma kota updated
If you are looking to change a resource from code behind then just access the resource like a dictionary and change desired value :)
Like this:
this.Resource["myThickness"] = new Thickness(2);
That would be it :)

multilingual wpf application

I have a WPF application (in English) and I would like to let users to select different languages. I have read some possibilities to change languages in runtime applications, but I only want to choose a language during installation time and never change it.
Do you think the fastest and easiest way to do it is developing different versions of the program (changing only text language) and let the user to select one of them during the installation?? Probably to repeat code only changing textbox or labels is not very elegant, but notice that I have the application finished in English and I don´t need to change language at runtime.
You can follow these steps:
Creating the resource files
Add this file StringResources.xaml to Resources directory. Here is an example:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="close">Close</system:String>
</ResourceDictionary>
You can create several files, one for each language.
Adding the resource (Call this when you start your application)
private void SetLanguageDictionary()
{
ResourceDictionary dict = new ResourceDictionary();
switch (Thread.CurrentThread.CurrentCulture.ToString())
{
case "en-US":
dict.Source = new Uri("..\\Resources\\StringResources.xaml", UriKind.Relative);
break;
case "fr-CA":
dict.Source = new Uri("..\\Resources\\StringResources.fr-CA.xaml", UriKind.Relative);
break;
default :
dict.Source = new Uri("..\\Resources\\StringResources.xaml",UriKind.Relative);
break;
}
this.Resources.MergedDictionaries.Add(dict);
}
Using the Resource, like this -
<Button
x:Name="btnLogin"
Click="btnLogin_Click"
Content="{DynamicResource close}"
Grid.Row="3"
Grid.Column="0"
Padding="10" />
Source: https://www.codeproject.com/Articles/123460/Simplest-Way-to-Implement-Multilingual-WPF-Applica
I think the solution proposed by Aghilas is good; but you can use StaticResource instead of using DynamicResource in step 3, DynamicResource is not required in your case as you are not going to chnage the language while application is running.
Also have a look at these articles having details about using Resx files for localization in WPF -
Localizing a WPF Application with ResX Files
WPF Localization
WPF Localization Guidance - Whitepaper
Just to improve #AghilasYakoub's correct answer, I think I need to point out that the following code should be added to the file App.xaml apart from what he had said:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/StringResources.xaml"/>
<ResourceDictionary Source="Resources/StringResources.fr-CA.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
If you want to use RESX files instead of resource dictionaries, you can do it easily with static references in XAML.
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:res="clr-namespace:MyApp.Resources">
<Button Text="{x:Static res:MainWindow.MyTestKey}">
</Window>
In the Resource folder is the MainWindow.resx, MainWindow.de.resx, etc. and every file contains a key MyTestKey with a translation.

Categories