How to load a specific language XAML file - c#

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.

Related

XAML Designer error: "IOException: Cannot locate resource" - How to provide a Pack URI that works with dynamic assembly name?

We have a ResourceDictionary being referenced as follows
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Theming/AppTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
This works great at runtime. However, the Designer in Visual Studio gives an error in views that reference this UserControl:
IOException: Cannot locate resource 'theming/apptheme.xaml'.
Other SO answers have suggested referencing the ResourceDictionary by specifying the assembly name:
<ResourceDictionary Source="pack://application:,,,/MyDomain.MyApp.Wpf;component/Theming/AppTheme.xaml" />
This makes the Designer happy, but our assembly name is different in staging vs. production, so it would be nice if we didn't have to specify the assembly name. My question is: How can we provide a ResourceDictionary Source URI that makes the Designer happy and does not require specifying the assembly name?
If this is not possible, we might make the URI a static value that is different per build configuration using preprocessor directives.
You can define the UI or resources for your app using XAML.
Resources are typically definitions of some object that you expect to use more than once. To refer to a XAML resource later, you specify a key for a resource that acts like its name.
You can reference a resource throughout an app or from any XAML page within it.
You can define your resources using a ResourceDictionary element from the Windows Runtime XAML.
Then, you can reference your resources by using a StaticResource markup extension or ThemeResource markup extension.
Resources don't have to be strings.
they can be any shareable object, such as styles, templates, brushes, and colors. However, controls, shapes, and other FrameworkElements are not shareable, so they can't be declared as reusable resources.
Example:
<Page.Resources>
<x:String x:Key="key1">Hey</x:String>
<x:String x:Key="key2">Nice</x:String>
</Page.Resources>
you can use those resoures by addressing the keys in their proper location i.e.:
<Label Text="{StaticResource key1}" FontSize="Large" VerticalAlignment="Center"/>
Well, In order to make your project more organized you need to make a ResourceDictionary a seperate file and call it like this (ContentPage part is depending on the page):
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
// in this example Styles is in the same folder has the page you can make dynamic resource to access it from all areas or make a path in a proper manner like:
xmlns:themes = "clr-namespace:AppName.Themes;assembly=AppName"
How can we provide a ResourceDictionary Source URI that makes the Designer happy and does not require specifying the assembly name?
you make a dynamic one.
like this:
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
x:Class="App.Themes.Theme"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Color x:Key="PrimaryColor">#ffffff</Color>
<Color x:Key="PrimaryDarkColor">#0f0f0f</Color>
</ResourceDictionary>
and in app.xaml you do this (if Theme is in folder Themes in main project):
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:themes = "clr-namespace:YourProjectName.Themes;assembly=YourProjectName"
x:Class="YourProjectName.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<themes:Theme />
</ResourceDictionary.MergedDictionaries >
</ResourceDictionary>
</Application.Resources>
then you can do stuff like this anywhere:
BackgroundColor="{DynamicResource PrimaryColor}"
Good Luck!

What kind of "Key" do I need to supply when loading Resource Dictionaries?

In trying to set a default ResourceDictionary I receive the following warning:
The designer does not support loading dictionaries that mix
'ResourceDictionary' items without a key and other items in the same
collection. Please ensure that the 'Resources' property does not
contain 'ResourceDictionary' items without a key, or that the
'ResourceDictionary' item is the only element in the collection.
This is the code that I am using in my App.xaml file, that received the above warning:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Lang.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
This is the exact same code that I've used to set a ResourceDictionary in Visual Studio 2008. I am now using VS 2010. What Key do I need to provide this ResourceDictionary for it to work correctly?
This is the line in my MainWindow.xaml that I am currently testing along with this code:
<MenuItem Header="{DynamicResource new_test}" />
Since you haven't posted your complete XAML file, i suspect there are other resources apart from merged dictionary in your resources section.
As per MSDN -
It is legal to define resources within a ResourceDictionary that is
specified as a merged dictionary, either as an alternative to
specifying Source, or in addition to whatever resources are included
from the specified source. However, this is not a common scenario; the
main scenario for merged dictionaries is to merge resources from
external file locations. If you want to specify resources within the
markup for a page, you should typically define these in the main
ResourceDictionary and not in the merged dictionaries.
Try moving other resources in separate resource dictionary and make sure all other resources have x:Key set on them -
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Lang.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<ContextMenu x:Key="MyContextMenu"/>
</ResourceDictionary>
</ResourceDictionary>
</Application.Resources>
Use resource file for translations. Its better than resource dictionary.
Here is an example:
Set prefix like this for usage in xaml.
xmlns:const="clr-namespace:FileExplorer.Properties"
Resources are located in properties.
To use them in XAML you will need following:
<TextBox Text="{x:Static const:Resources.Window_Title_String}"/>
If you have different languages then create for each language own resource file following naming convention.
For example:
Resources.resx (this will be default)
Resources.de-DE.resx (this is for german)
Now you just have to set current culture to german for your app to be on german and the proper resource file will be used automatically.
Like this in Main method:
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");

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

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" />

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.

In WPF how do I reference a static resource that is defined in a different XAML file?

In WPF how do I reference a static resource that is defined in a different XAML file? It's in the same project.
The other XAML file will need to be a resource dictionary. You merge it into the current file using the MergedDictionaries property of the current ResourceDictionary. See Merged Resource Dictionaries on MSDN. Their example:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="myresourcedictionary.xaml"/>
<ResourceDictionary Source="myresourcedictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
Then within that Page object you can reference static resources defined in myresourcedictionary.xaml or in myresourcedictionary2.xaml.
"different XAML file" could mean a few different things:
App.xaml: Resources are automatically included in the resource tree of anything that's opened so you don't need to do anything extra.
Window or Page .xaml: Resources can be accessed by any child of an instance of the object like a UserControl that is used in a Window.
ResourceDictionary: Needs to be explicitly merged into the resource tree somewhere above where it is used. This can be App.xaml, Windowxx.xaml, or some lower level element. Use ResourceDictionary.MergedDictionaries to do this.
There are also lots of alternate ways to specify the path but this is the simplest:
<Window>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/MyResourceDict.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

Categories