Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare supporting additional languages #1397

Merged
merged 16 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Scripts/Python/plasma/PlasmaConstants.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,11 @@ class PtLanguage:
kSpanish = 3
kItalian = 4
kJapanese = 5
kNumLanguages = 6
kDutch = 6
kRussian = 7
kPolish = 8
kCzech = 9
kNumLanguages = 10

class PtMarkerMsgType:
"""(none)"""
Expand Down
4 changes: 2 additions & 2 deletions Sources/Plasma/Apps/plClient/win32/res/plClient.rc
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ IDI_ICON_DIRT ICON "Dirt.ICO"
// Dialog
//

IDD_LOADING DIALOGEX 0, 0, 161, 26
IDD_LOADING DIALOGEX 0, 0, 180, 26
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
LTEXT "Starting URU. Please wait...",IDC_STARTING_TEXT,32,9,127,8
LTEXT "Starting URU. Please wait...",IDC_STARTING_TEXT,32,9,146,8
ICON IDI_ICON_DIRT,IDC_STATIC,5,3,20,20
END

Expand Down
56 changes: 39 additions & 17 deletions Sources/Plasma/Apps/plClient/win32/winmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,10 +790,18 @@ INT_PTR CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA
SendMessage(GetDlgItem(hwndDlg, IDC_PRODUCTSTRING), WM_SETTEXT, 0,
(LPARAM)plProduct::ProductString().c_str());

for (int i = 0; i < plLocalization::GetNumLocales(); i++)
{
ST::wchar_buffer languageNameBuf = plLocalization::GetLanguageName((plLocalization::Language)i).to_wchar();
SendMessageW(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_ADDSTRING, 0, (LPARAM)languageNameBuf.c_str());
for (auto lang : plLocalization::GetAllLanguages()) {
ST::string langName = plLocalization::GetLanguageName(lang);
if (!plLocalization::IsLanguageUsable(lang)) {
#if defined(PLASMA_EXTERNAL_RELEASE)
// External clients only allow selecting usable languages.
continue;
#else
// Internal clients allow choosing unsupported languages as well.
langName += ST_LITERAL(" (unsupported)");
#endif
}
SendMessageW(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_ADDSTRING, 0, (LPARAM)langName.to_wchar().c_str());
}
SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_SETCURSEL, (WPARAM)plLocalization::GetLanguage(), 0);

Expand Down Expand Up @@ -921,28 +929,30 @@ INT_PTR CALLBACK SplashDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
switch (uMsg)
{
case WM_INITDIALOG:
ST::string message;
switch (plLocalization::GetLanguage())
{
case plLocalization::kFrench:
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "D�marrage d'URU. Veuillez patienter...");
message = ST_LITERAL("Démarrage d'URU. Veuillez patienter...");
break;
case plLocalization::kGerman:
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Starte URU, bitte warten ...");
message = ST_LITERAL("Starte URU, bitte warten ...");
break;
case plLocalization::kSpanish:
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Iniciando URU, por favor espera...");
message = ST_LITERAL("Iniciando URU, por favor espera...");
break;
case plLocalization::kItalian:
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Avvio di URU, attendere...");
message = ST_LITERAL("Avvio di URU, attendere...");
break;
// default is English
case plLocalization::kJapanese:
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "...");
case plLocalization::kRussian:
message = ST_LITERAL("Запуск URU. Пожалуйста, подождите...");
break;
// default is English
default:
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Starting URU. Please wait...");
message = ST_LITERAL("Starting URU. Please wait...");
break;
}
SetDlgItemTextW(hwndDlg, IDC_STARTING_TEXT, message.to_wchar().c_str());
return true;

}
Expand Down Expand Up @@ -1136,25 +1146,37 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
HANDLE hOneInstance = CreateMutex(nullptr, FALSE, "UruExplorer");
if (WaitForSingleObject(hOneInstance,0) != WAIT_OBJECT_0)
{
ST::string caption;
ST::string message;
switch (plLocalization::GetLanguage())
{
case plLocalization::kFrench:
hsMessageBox("Une autre copie d'URU est d�j� en cours d'ex�cution", "Erreur", hsMessageBoxNormal);
caption = ST_LITERAL("Erreur");
message = ST_LITERAL("Une autre copie d'URU est déjà en cours d'exécution");
break;
case plLocalization::kGerman:
hsMessageBox("URU wird bereits in einer anderen Instanz ausgef�hrt", "Fehler", hsMessageBoxNormal);
caption = ST_LITERAL("Fehler");
message = ST_LITERAL("URU wird bereits in einer anderen Instanz ausgeführt");
break;
case plLocalization::kSpanish:
hsMessageBox("En estos momentos se est� ejecutando otra copia de URU", "Error", hsMessageBoxNormal);
caption = ST_LITERAL("Error");
message = ST_LITERAL("En estos momentos se está ejecutando otra copia de URU");
break;
case plLocalization::kItalian:
hsMessageBox("Un'altra copia di URU � gi� aperta", "Errore", hsMessageBoxNormal);
caption = ST_LITERAL("Errore");
message = ST_LITERAL("Un'altra copia di URU è già aperta");
break;
case plLocalization::kRussian:
caption = ST_LITERAL("Ошибка");
message = ST_LITERAL("Другая копия URU уже запущена");
break;
// default is English
default:
hsMessageBox("Another copy of URU is already running", "Error", hsMessageBoxNormal);
caption = ST_LITERAL("Error");
message = ST_LITERAL("Another copy of URU is already running");
break;
}
hsMessageBox(message.to_wchar().c_str(), caption.to_wchar().c_str(), hsMessageBoxNormal);
return PARABLE_NORMAL_EXIT;
}
#endif
Expand Down
21 changes: 7 additions & 14 deletions Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2431,27 +2431,20 @@ PF_CONSOLE_CMD(App,
PF_CONSOLE_CMD(App,
SetLanguage,
"string language",
"Set the language (English, French, German, Spanish, Italian, or Japanese)")
"Set the language")
{
if (pfConsole::GetPipeline())
{
PrintString("This command must be used in an .ini file");
return;
}

if (stricmp(params[0], "english") == 0)
plLocalization::SetLanguage(plLocalization::kEnglish);
else if (stricmp(params[0], "french") == 0)
plLocalization::SetLanguage(plLocalization::kFrench);
else if (stricmp(params[0], "german") == 0)
plLocalization::SetLanguage(plLocalization::kGerman);
else if (stricmp(params[0], "spanish") == 0)
plLocalization::SetLanguage(plLocalization::kSpanish);
else if (stricmp(params[0], "italian") == 0)
plLocalization::SetLanguage(plLocalization::kItalian);
else if (stricmp(params[0], "japanese") == 0)
plLocalization::SetLanguage(plLocalization::kJapanese);

for (const auto& lang : plLocalization::GetAllLanguages()) {
if (plLocalization::GetLanguageName(lang).compare_i(params[0]) == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would we feel about ISO language codes (i.e., en, fr, de, it, es, etc.) rather that names? That would open us to support region-specific localizations (such as spelling "Neighbourhood" properly in en-GB)

Although I guess that complicates the .loc files too, eh?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we would use standard language codes everywhere instead of custom names, yeah. Migrating the existing .loc files would be quite painful though - it would be a big incompatible change to all existing content, which would break open PRs and require changes to other tools like Korman.

plLocalization::SetLanguage(lang);
break;
}
}
}

PF_CONSOLE_CMD(App,
Expand Down
36 changes: 28 additions & 8 deletions Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ You can contact Cyan Worlds, Inc. by email [email protected]
#include "pfCamera/plVirtualCamNeu.h"

#include <algorithm>
#include <string_theory/string>

//#define MF_TOSSER

Expand Down Expand Up @@ -1849,17 +1850,36 @@ void plDXPipeline::ICreateDynamicBuffers()

void plDXPipeline::IPrintDeviceInitError()
{
char str[256];
char err[16];
ST::string caption;
ST::string message;
switch(plLocalization::GetLanguage())
{
case plLocalization::kFrench: strcpy(err, "Erreur"); strcpy(str, "Erreur d'initialisation de votre carte graphique. Les valeurs par d�faut de ses param�tres ont �t� r�tablis. "); break;
case plLocalization::kGerman: strcpy(err, "Fehler"); strcpy(str, "Bei der Initialisierung Ihrer Grafikkarte ist ein Fehler aufgetreten. Standardeinstellungen werden wiederhergestellt."); break;
case plLocalization::kSpanish: strcpy(err, "Error"); strcpy(str, "Ocurri� un error al inicializar tu tarjeta de v�deo. Hemos restaurado los ajustes por defecto. "); break;
case plLocalization::kItalian: strcpy(err, "Errore"); strcpy(str, "Errore di inizializzazione della scheda video. Sono state ripristinate le impostazioni predefinite."); break;
default: strcpy(err, "Error"); strcpy(str, "There was an error initializing your video card. We have reset it to its Default settings."); break;
case plLocalization::kFrench:
caption = ST_LITERAL("Erreur");
message = ST_LITERAL("Erreur d'initialisation de votre carte graphique. Les valeurs par défaut de ses paramètres ont été rétablis. ");
break;
case plLocalization::kGerman:
caption = ST_LITERAL("Fehler");
message = ST_LITERAL("Bei der Initialisierung Ihrer Grafikkarte ist ein Fehler aufgetreten. Standardeinstellungen werden wiederhergestellt.");
break;
case plLocalization::kSpanish:
caption = ST_LITERAL("Error");
message = ST_LITERAL("Ocurrió un error al inicializar tu tarjeta de vídeo. Hemos restaurado los ajustes por defecto. ");
break;
case plLocalization::kItalian:
caption = ST_LITERAL("Errore");
message = ST_LITERAL("Errore di inizializzazione della scheda video. Sono state ripristinate le impostazioni predefinite.");
break;
case plLocalization::kRussian:
caption = ST_LITERAL("Ошибка");
message = ST_LITERAL("Произошла ошибка инициализации вашей видеокарты. Мы сбросили настройки по умолчанию.");
break;
default:
caption = ST_LITERAL("Error");
message = ST_LITERAL("There was an error initializing your video card. We have reset it to its Default settings.");
break;
}
hsMessageBox(str, err, hsMessageBoxNormal, hsMessageBoxIconError);
hsMessageBox(message.to_wchar().c_str(), caption.to_wchar().c_str(), hsMessageBoxNormal, hsMessageBoxIconError);
}

// Reset device creation parameters to default and write to ini file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,8 @@ You can contact Cyan Worlds, Inc. by email [email protected]

#include <expat.h>

#include <algorithm>
#include <stack>
#include <unordered_set>


//////////////////////////////////////////////////////////////////////
//
Expand Down Expand Up @@ -518,15 +517,7 @@ void LocalizationDatabase::IMergeData()

void LocalizationDatabase::IVerifyElement(const ST::string &ageName, const ST::string &setName, LocalizationXMLFile::set::iterator& curElement)
{
std::unordered_set<ST::string> languageNames;
ST::string defaultLanguage = plLocalization::GetLanguageName((plLocalization::Language)0);

int numLocales = plLocalization::GetNumLocales();
for (int curLocale = 0; curLocale <= numLocales; curLocale++)
{
ST::string name = plLocalization::GetLanguageName((plLocalization::Language)curLocale);
languageNames.emplace(std::move(name));
}
auto languageNames = plLocalization::GetAllLanguageNames();

ST::string elementName = curElement->first;
LocalizationXMLFile::element& theElement = curElement->second;
Expand All @@ -535,7 +526,7 @@ void LocalizationDatabase::IVerifyElement(const ST::string &ageName, const ST::s
while (curTranslation != theElement.end())
{
// Make sure this language exists!
auto languageIt = languageNames.find(curTranslation->first);
auto languageIt = std::find(languageNames.begin(), languageNames.end(), curTranslation->first);

if (languageIt == languageNames.end())
{
Expand All @@ -547,12 +538,11 @@ void LocalizationDatabase::IVerifyElement(const ST::string &ageName, const ST::s
curTranslation++;
}

for (const auto& language : languageNames)
{
if (theElement.find(language) == theElement.end())
{
for (auto lang : plLocalization::GetAllLanguages()) {
ST::string langName = plLocalization::GetLanguageName(lang);
if (plLocalization::IsLanguageUsable(lang) && theElement.find(langName) == theElement.end()) {
pfLocalizationDataMgr::GetLog()->AddLineF("WARNING: Language {} is missing from the translations in element {}.{}.{}. You'll want to get translations for that!",
language, ageName, setName, elementName);
langName, ageName, setName, elementName);
}
}
}
Expand All @@ -564,7 +554,7 @@ void LocalizationDatabase::IVerifySet(const ST::string &ageName, const ST::strin
LocalizationXMLFile::set& theSet = fData[ageName][setName];
LocalizationXMLFile::set::iterator curElement = theSet.begin();

ST::string defaultLanguage = plLocalization::GetLanguageName((plLocalization::Language)0);
ST::string defaultLanguage = plLocalization::GetLanguageName(plLocalization::kEnglish);

while (curElement != theSet.end())
{
Expand Down Expand Up @@ -817,44 +807,13 @@ pfLocalizationDataMgr::~pfLocalizationDataMgr()
}
}

//// ICreateLocalizedElement /////////////////////////////////////////

pfLocalizationDataMgr::localizedElement pfLocalizationDataMgr::ICreateLocalizedElement()
{
int numLocales = plLocalization::GetNumLocales();
pfLocalizationDataMgr::localizedElement retVal;

for (int curLocale = 0; curLocale <= numLocales; curLocale++)
{
retVal[plLocalization::GetLanguageName((plLocalization::Language)curLocale)] = "";
}

return retVal;
}

//// IGetCurrentLanguageName /////////////////////////////////////////

ST::string pfLocalizationDataMgr::IGetCurrentLanguageName() const
{
return plLocalization::GetLanguageName(plLocalization::GetLanguage());
}

//// IGetAllLanguageNames ////////////////////////////////////////////

std::vector<ST::string> pfLocalizationDataMgr::IGetAllLanguageNames() const
{
int numLocales = plLocalization::GetNumLocales();
std::vector<ST::string> retVal;

for (int curLocale = 0; curLocale <= numLocales; curLocale++)
{
ST::string name = plLocalization::GetLanguageName((plLocalization::Language)curLocale);
retVal.push_back(name);
}

return retVal;
}

//// IConvertSubtitle ////////////////////////////////////////////////

void pfLocalizationDataMgr::IConvertElement(const pfLocalizationDataMgr::element& elementInfo, const ST::string & curPath)
Expand Down Expand Up @@ -1153,10 +1112,9 @@ bool pfLocalizationDataMgr::DeleteElement(const ST::string & name)
void pfLocalizationDataMgr::WriteDatabaseToDisk(const plFileName & path) const
{
std::vector<ST::string> ageNames = GetAgeList();
std::vector<ST::string> languageNames = IGetAllLanguageNames();
for (const auto& curAge : ageNames)
{
for (const auto& curLanguage : languageNames)
for (const auto& curLanguage : plLocalization::GetAllLanguageNames())
{
plFileName locPath = plFileName::Join(path, ST::format("{}{}.loc",
curAge, curLanguage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,7 @@ class pfLocalizationDataMgr

plFileName fDataPath;

localizedElement ICreateLocalizedElement(); // ease of use function that creates a basic localized element object

ST::string IGetCurrentLanguageName() const; // get the name of the current language
std::vector<ST::string> IGetAllLanguageNames() const;

void IConvertElement(const element& elementInfo, const ST::string & curPath);
void IConvertSet(const set& setInfo, const ST::string & curPath);
Expand Down
4 changes: 4 additions & 0 deletions Sources/Plasma/FeatureLib/pfPython/cyMiscGlue2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,10 @@ void cyMisc::AddPlasmaConstantsClasses(PyObject *m)
PYTHON_ENUM_ELEMENT(PtLanguage, kSpanish, plLocalization::kSpanish)
PYTHON_ENUM_ELEMENT(PtLanguage, kItalian, plLocalization::kItalian)
PYTHON_ENUM_ELEMENT(PtLanguage, kJapanese, plLocalization::kJapanese)
PYTHON_ENUM_ELEMENT(PtLanguage, kDutch, plLocalization::kDutch)
PYTHON_ENUM_ELEMENT(PtLanguage, kRussian, plLocalization::kRussian)
PYTHON_ENUM_ELEMENT(PtLanguage, kPolish, plLocalization::kPolish)
PYTHON_ENUM_ELEMENT(PtLanguage, kCzech, plLocalization::kCzech)
PYTHON_ENUM_ELEMENT(PtLanguage, kNumLanguages, plLocalization::kNumLanguages)
PYTHON_ENUM_END(m, PtLanguage)

Expand Down
Loading