You can create a separate resources file for each language in managed C++ which contain all the strings used by the application.

In the solution explorer, right-click the Resource Files folder for the project > Add > New Item > Visual C++ > Resource > Assembly Resource File (.resx).

Give it the name AppLocalization.resx for example.

Add your strings to the file.

Important

Your project properties "Common Language Runtime Support" setting must not be set to "/clr:safe". If it is the non default resource files won't get used.  Setting it to "/clr:pure works fine.

Adding files for the other languages

Create the files with the same name and the localization characters added:

French: AppLocalization.fr.resx
French-France: AppLocalization.fr-FR.resx

Table of Language Culture Names, Codes, and ISO Values

Using On Forms

Don't set the form to 'Localizable' in its properties as that will create a resx file specifically for the form and let visual studio handle the multi languages (another way of doing all this, but not as simple as a single languages file when you want to be able to send it off and have others provide translations as this is more aimed at the localizations being carried out within visual studio).

Setting Strings Of Form Controls

It would be nice to be able to use the rm->GetString() in the auto generated form designer code but if you do you'll break the design time ability to design your form as the strings can only be found at run time.  So you need to set strings in say the form Load event instead.

Using The Strings

Locally accessing the resource file

	Resources::ResourceManager^ rm1 = gcnew Resources::ResourceManager(L"MyProjectsNamespace.AppLocalization", this->GetType()->Assembly);
	this->Text = rm1->GetString(L"My String Name");

"MyProjectsNamespace" is the project name / namespace

"AppLocalization" is the name of your .resx files before the extension.

Creating a global object

In stdafx.h


ref class GlobalObjects
{
	public: static System::Resources::ResourceManager ^rm1;
};

In the constructor of your main form


	GlobalObjects::rm1 = gcnew System::Resources::ResourceManager(L"MyProjectsNamespace.AppLocalization", this->GetType()->Assembly);

Then to use it


	this->Text = GlobalObjects::rm1->GetString(L"My String Name");

Language Identifiers

"fr" means french.  "fr-FR" means French in France, whereas "fr-BE" means French in Belgium. You can use both "fr" and "fr-##" files with territory specific strings in the latter and more generic strings in the former.  If it can't find a string in the specific teritory file it will drop down to the language file instead and look for it there.

So for general French translations use a file .fr.resx and if you need to add specific translations for a particular territory add the file for that territory also.

Testing Translations

Testing Individually

	this->Text = GlobalObjects::rm1->GetString(L"My String Name", gcnew System::Globalization::CultureInfo("fr-FR"));
Testing Globally

Just add these 2 CultureInfo settings before creating the ResourceManager:


	System::Threading::Thread::CurrentThread->CurrentCulture = gcnew System::Globalization::CultureInfo("fr");
	System::Threading::Thread::CurrentThread->CurrentUICulture = gcnew System::Globalization::CultureInfo("fr");
						
	GlobalObjects::rm1 = gcnew System::Resources::ResourceManager(L"MyProjectsNamespace.AppLocalization", Assembly::GetExecutingAssembly());

This will also cause region specific number formats to be used too.

USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.