1 // Copyright (c) 2005, Rodrigo Braz Monteiro
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of the Aegisub Group nor the names of its contributors
13 //     may be used to endorse or promote products derived from this software
14 //     without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 //
28 // Aegisub Project http://www.aegisub.org/
29 
30 /// @file aegisublocale.cpp
31 /// @brief Enumerate available locales for picking translation on Windows
32 /// @ingroup utility
33 ///
34 
35 #include "aegisublocale.h"
36 
37 #include "compat.h"
38 #include "options.h"
39 #include "utils.h"
40 
41 #include <libaegisub/path.h>
42 
43 #include <algorithm>
44 #include <clocale>
45 #include <functional>
46 #include <wx/intl.h>
47 #include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set.
48 
49 #ifndef AEGISUB_CATALOG
50 #define AEGISUB_CATALOG "aegisub"
51 #endif
52 
GetTranslations()53 wxTranslations *AegisubLocale::GetTranslations() {
54 	wxTranslations *translations = wxTranslations::Get();
55 	if (!translations) {
56 		wxTranslations::Set(translations = new wxTranslations);
57 		wxFileTranslationsLoader::AddCatalogLookupPathPrefix(config::path->Decode("?data/locale/").wstring());
58 	}
59 	return translations;
60 }
61 
Init(std::string const & language)62 void AegisubLocale::Init(std::string const& language) {
63 	wxTranslations *translations = GetTranslations();
64 	translations->SetLanguage(to_wx(language));
65 	translations->AddCatalog(AEGISUB_CATALOG);
66 	translations->AddStdCatalog();
67 
68 	setlocale(LC_NUMERIC, "C");
69 	setlocale(LC_CTYPE, "C");
70 	active_language = language;
71 }
72 
HasLanguage(std::string const & language)73 bool AegisubLocale::HasLanguage(std::string const& language) {
74 	auto langs = GetTranslations()->GetAvailableTranslations(AEGISUB_CATALOG);
75 	return std::find(langs.begin(), langs.end(), to_wx(language)) != langs.end();
76 }
77 
PickLanguage()78 std::string AegisubLocale::PickLanguage() {
79 	if (active_language.empty()) {
80 		wxString os_ui_language = GetTranslations()->GetBestTranslation(AEGISUB_CATALOG);
81 		if (!os_ui_language.empty())
82 			return from_wx(os_ui_language);
83 	}
84 
85 	wxArrayString langs = GetTranslations()->GetAvailableTranslations(AEGISUB_CATALOG);
86 
87 	// No translations available, so don't bother asking the user
88 	if (langs.empty() && active_language.empty())
89 		return "en_US";
90 
91 	langs.insert(langs.begin(), "en_US");
92 
93 	// Check if user local language is available, if so, make it first
94 	const wxLanguageInfo *info = wxLocale::GetLanguageInfo(wxLocale::GetSystemLanguage());
95 	if (info) {
96 		auto it = std::find(langs.begin(), langs.end(), info->CanonicalName);
97 		if (it != langs.end())
98 			std::rotate(langs.begin(), it, it + 1);
99 	}
100 
101 	// Generate names
102 	wxArrayString langNames;
103 	for (auto const& lang : langs)
104 		langNames.push_back(LocalizedLanguageName(lang));
105 
106 	long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxOK | wxCENTRE;
107 	if (!active_language.empty())
108 		style |= wxCANCEL;
109 
110 	wxSingleChoiceDialog dialog(nullptr, "Please choose a language:", "Language", langNames,
111 			(void **)nullptr,
112 			style);
113 	if (dialog.ShowModal() == wxID_OK) {
114 		int picked = dialog.GetSelection();
115 		if (langs[picked] != active_language)
116 			return from_wx(langs[picked]);
117 	}
118 
119 	return "";
120 }
121