Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

C++ how to multilanguage?

12 Sep 2017, 17:50

I found this old topic:
viewtopic.php?f=3&t=54&hilit=multi+language
there is some example from sfernandez, it is still relevant for Noesis 2.0.2?

If yes, how can I load this language.xaml file and use it? I want dynamicaly change the language for my program.
 
User avatar
sfernandez
Site Admin
Posts: 3005
Joined: 22 Dec 2011, 19:20

Re: C++ how to multilanguage?

14 Sep 2017, 01:35

You can take a look at NGUI Examples from showcase section: viewtopic.php?f=12&t=485
Specifically at Example 10 - Localization.

It shows one way to organize your language dictionaries, how to expose them in your viewmodel, and how to bind text values from the UI.
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: C++ how to multilanguage?

14 Sep 2017, 14:01

Thanks, but I am not sure what is the best and safe way where to add dataContext.

Before you give me example I discover myself this:
MainGrid::MainGrid()
{
	m_ResourceDirctionary = *new Noesis::ResourceDictionary;
	m_ResourceDirctionary->SetSource("Lang/langSVK.xaml");
	this->SetResources(m_ResourceDirctionary.GetPtr()); 
}
And it is working when I binding some text from my lang.xaml
for change language, it will be safe to change m_ResourceDirctionary->SetSource("Lang/langENG.xaml") ? Or this->SetDataContext(someLangObject) for MainGrid is better?

The last question, where can I set sources or dataContext when I use multiple windows? I use allways MainGrid class as base for all windows (and it working), but I am not sure if it good idea.
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: C++ how to multilanguage?

16 Sep 2017, 23:53

I am not able to recreate example in to C++. But I did something similar and instead DataContext I use Resource. When I select another language, resource is changed. It is working but UI not refresh the text. Only in another windows (not in main) if is reopen.
If I use DataContext, then text is changed, but it is working only for main window. Inside another window, text is not shown. I think because DataContext is not set properly, but I use MainGrid for the all windows.

Here is xaml
MainGrid:
<Grid 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:sys="clr-namespace:System;assembly=mscorlib"
	x:Name="MainGrid" x:Class="MainGrid"  >
// .. code
	<Grid.Resources>
        <DataModel x:Name="dataModel" />
    </Grid.Resources>
	// .. code
	<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Margin="10 0 10 0" >
		<TextBlock Text="{Binding Language[rd_button_Nastavenia]}" />
	</StackPanel>
</Grid>
New View for Options Window
<Grid 
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
	xmlns:sys="clr-namespace:System;assembly=mscorlib" 
	x:Name="MainGrid" x:Class="MainGrid" UseLayoutRounding="True" >
	// .. code 
	<ContainerItemOtions Grid.Row="1" />
</Grid>
GridView for Options (ContainerItemOtions )
<Grid 
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
	xmlns:sys="clr-namespace:System;assembly=mscorlib"
	x:Name="containerItemOtions" x:Class="containerItemOtions" UseLayoutRounding="True" >
	 
	<Grid Grid.Row="1" > 
		<StackPanel Grid.Column="1" > 
			<GroupBox Header="Nastavenia" >
				<Grid > 
					<StackPanel Orientation="Vertical"  Grid.Row="0" >
						<RadioButton
							Content="{Binding Language[rd_button_Nastavenia]}"  // show nothing
							Focusable="False"  />
					</StackPanel>
				</Grid>
			</GroupBox>
		</StackPanel>
	</Grid>
</Grid>
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: C++ how to multilanguage?

17 Sep 2017, 16:47

Ok, I discover that DataContext is not inherited inside ListBox and other windows. But If I use this:
Content="{Binding ElementName=MainGrid, Path=DataContext.Language[rd_button_Nastavenia]}"
than I see this text everywhere (inside UserControl or another window) and text is change if I set different language.
 
User avatar
sfernandez
Site Admin
Posts: 3005
Joined: 22 Dec 2011, 19:20

Re: C++ how to multilanguage?

19 Sep 2017, 13:54

Hi,
Thanks, but I am not sure what is the best and safe way where to add dataContext.
DataContext is usually set on code-behind just after component is initialized:
    MainGrid()
    {
        InitializeComponent();

        Ptr<ViewModel> viewModel = *new ViewModel();
        //...
        SetDataContext(viewModel.GetPtr());
    }
I am not able to recreate example in to C++
Hope this helps to understand how to translate Localization sample to C++, we tried to be almost the same as in C#:
class Language: public BaseComponent
{
public:
    Language(const NsChar* n, ResourceDictionary* r): name(n), resources(r) { }

    const NsChar* GetName() const { return name.c_str(); }
    ResourceDictionary* GetResources() const { return resources.GetPtr(); }

private:
    NsString name;
    Ptr<ResourceDictionary> resources;

    NS_IMPLEMENT_INLINE_REFLECTION(Language, BaseComponent)
    {
        NsProp("Name", &Language::GetName);
        NsProp("Resources", &Language::GetResources);
    }
};
class ViewModel: public BaseComponent, public INotifyPropertyChanged
{
public:
    ViewModel(): languages(*new ObservableCollection<Language>())
    {
    }

    // read-only property, only has getter
    ObservableCollection<Language>* GetLanguages() const { return languages.GetPtr(); }

    // writable property has getter and setter were property changes are notified
    Language* GetSelectedLanguage() const { return selectedLanguage.GetPtr(); }
    void SetSelectedLanguage(Language* language)
    {
        if (selectedLanguage != language)
        {
            selectedLanguage.Reset(language);
            OnPropertyChanged("SelectedLanguage");
        }
    }

    // ... other properties follow the same pattern

    PropertyChangedEventHandler& PropertyChanged()
    {
        return propertyChanged;
    }

    NS_IMPLEMENT_INTERFACE_FIXUP

private:
    void OnPropertyChanged(const NsChar* propertyName)
    {
        if (!propertyChanged.Empty())
        {
            propertyChanged(this, PropertyChangedEventArgs(NsSymbol(propertyName)));
        }
    }

private:
    Ptr<ObservableCollection<Language>> languages;
    Ptr<Language> selectedLanguage;

    PropertyChangedEventHandler propertyChanged;

    NS_IMPLEMENT_INLINE_REFLECTION(ViewModel, BaseComponent)
    {
        NsImpl<INotifyPropertyChanged>();

        NsProp("Languages", &ViewModel::GetLanguages);
        NsProp("SelectedLanguage", &ViewModel::GetSelectedLanguage, &ViewModel::SetSelectedLanguage);
    }
};
class MainGrid: public Grid
{
public:
    MainGrid()
    {
        InitializeComponent();

        Ptr<ViewModel> viewModel = *new ViewModel();

        Ptr<ResourceDictionary> svk = GUI::LoadXaml<ResourceDictionary>("Lang/langSVK.xaml");
        Ptr<Language> langSVK = *new Language("Svenska", svk.GetPtr());
        viewModel->GetLanguages()->Add(langSVK.GetPtr());

        Ptr<ResourceDictionary> eng = GUI::LoadXaml<ResourceDictionary>("Lang/langENG.xaml");
        Ptr<Language> langENG = *new Language("English", eng.GetPtr());
        viewModel->GetLanguages()->Add(langENG.GetPtr());

        viewModel->SetSelectedLanguage(langENG.GetPtr());

        SetDataContext(viewModel.GetPtr());
    }

private:
    void InitializeComponent()
    {
        GUI::LoadComponent(this, "MainGrid.xaml");
    }

    NS_IMPLEMENT_INLINE_REFLECTION(MainGrid, Grid)
    {
        NsMeta<TypeId>("MainGrid");
    }
};
If I use DataContext, then text is changed, but it is working only for main window. Inside another window, text is not shown. I think because DataContext is not set properly, but I use MainGrid for the all windows.
Ok, I discover that DataContext is not inherited inside ListBox and other windows.
DataContext property is inherited down through the UI tree, but some controls change DataContext on their visual tree. For example, a ContentPresenter will set its Content as DataContext of the data template used to visualize it. All ItemsControl (as ListBox) will assign the item as DataContext of the item container and data template used to visualize the item, etc. So you have to take this into account when defining the bindings in your UI.
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: C++ how to multilanguage?

21 Sep 2017, 20:43

Thank you very much for the code, this is interesting.
I made different solution. Can you please take a look, and make critique about my solution? It is ok?
(My solution search for all files in directory and then add language / languages in to colection. This is for when user decide translate to different language.)
NS_DECLARE_SYMBOL(Language);
class LanguageModel :
	public Noesis::BaseComponent // BaseComponent ResourceDictionary
	, public Noesis::INotifyPropertyChanged
{
public:
	LanguageModel();
	~LanguageModel();
	void mf_SelectLang(unsigned int lang);
	Noesis::ResourceDictionary * mf_GetLang() const;
	void mf_SetLang(Noesis::ResourceDictionary * lang);
	size_t mf_GetSizeOfLang() const;
	NsString mf_GetLanguageNames(unsigned int &n) const;
	Noesis::PropertyChangedEventHandler& PropertyChanged();
	static const Noesis::Gui::DependencyProperty * m_ResourceProperty;
	NS_IMPLEMENT_INTERFACE_FIXUP;
private:
	fileSystem::path m_path;
	std::list<NsString> m_LanguageNameList;
	Noesis::Ptr<Noesis::ObservableCollection<Noesis::ResourceDictionary>> m_LangCollectionItems;
	Noesis::ResourceDictionary * m_RD;
	Noesis::PropertyChangedEventHandler changed;
	void Changed(NsSymbol prop);
	NS_IMPLEMENT_INLINE_REFLECTION(LanguageModel, Noesis::BaseComponent)
	{
		NsMeta<Noesis::TypeId>("languageModel");
		NsImpl<Noesis::Gui::INotifyPropertyChanged>();
		NsProp("Language"
			, &LanguageModel::m_RD
		);
	}
};
LanguageModel::LanguageModel()
{
	m_LangCollectionItems = *new Noesis::ObservableCollection<Noesis::ResourceDictionary>;
	fileSystem::path p;
	std::string pathString;
	m_path.assign("Resources/gui/Lang");
	for (fileSystem::directory_entry de : fileSystem::recursive_directory_iterator( m_path , fileSystem::directory_options::none ) )
	{
		if (!fileSystem::is_directory(de))
		{
			p = de;
			if (p.extension() == ".xaml")
			{
				pathString = "Lang/" + p.filename().string();
				Noesis::Ptr<Noesis::ResourceDictionary> lang = *new Noesis::ResourceDictionary;
				lang->SetSource(pathString.c_str()); 
				NsString str = Noesis::ToString(lang->FindName("languageName"));
				m_LanguageNameList.insert(m_LanguageNameList.end(), str.c_str()); // for language list inside GUI
				m_LangCollectionItems->Add(lang.GetPtr());
				pathString.clear();
			}
		}
	}
	m_RD = m_LangCollectionItems->Get(0);
}
/// -------------------------------------------------------------------------------------------------------------------
LanguageModel::~LanguageModel()
{
	m_LangCollectionItems->Clear();
	m_LangCollectionItems.Reset();
	m_LanguageNameList.clear();
	m_path.clear();
}
// ====================================================================================================================
// most of code here is not finished.
/// -------------------------------------------------------------------------------------------------------------------
void LanguageModel::mf_SelectLang(unsigned int lang)
{
	if (lang == 0 || lang == 1)
	{
		mf_SetLang(m_LangCollectionItems->Get(lang));
	}
}
/// -------------------------------------------------------------------------------------------------------------------
Noesis::ResourceDictionary * LanguageModel::mf_GetLang() const { return m_RD; }
/// -------------------------------------------------------------------------------------------------------------------
void LanguageModel::mf_SetLang(Noesis::ResourceDictionary * lang)
{
	m_RD = lang;
	Changed(NSS(Language)); // SelectedLanguage
}
/// -------------------------------------------------------------------------------------------------------------------
size_t LanguageModel::mf_GetSizeOfLang() const { return m_LangCollectionItems->Count(); }
/// -------------------------------------------------------------------------------------------------------------------
NsString LanguageModel::mf_GetLanguageNames(unsigned int &n) const { return "zatial nic"; /* DOROBIT*/ }
/// -------------------------------------------------------------------------------------------------------------------
Noesis::PropertyChangedEventHandler& LanguageModel::PropertyChanged() { return changed; }
/// -------------------------------------------------------------------------------------------------------------------
void LanguageModel::Changed(NsSymbol prop) { changed(this, Noesis::PropertyChangedEventArgs(prop)); }
MainGrid::MainGrid()
{
	this->SetDataContext(MyDelegate::m_LangModel);
}

Who is online

Users browsing this forum: Ahrefs [Bot] and 5 guests