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.