1 /*
2 * Stellarium
3 * Copyright (C) 2006 Fabien Chereau
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20 #include "StelLocaleMgr.hpp"
21 #include "StelApp.hpp"
22 #include "StelUtils.hpp"
23 #include "StelFileMgr.hpp"
24
25 #include <QLocale>
26 #include <QDebug>
27 #include <QSettings>
28 #include <QString>
29 #include <QTextStream>
30 #include <QFile>
31
32 #include <ctime>
33
StelLocaleMgr()34 StelLocaleMgr::StelLocaleMgr()
35 : skyTranslator(Q_NULLPTR)
36 , planetaryFeaturesTranslator(Q_NULLPTR)
37 , scriptsTranslator(Q_NULLPTR)
38 , timeFormat()
39 , dateFormat()
40 {
41 core = StelApp::getInstance().getCore();
42 createNameLists();
43 }
44
45
~StelLocaleMgr()46 StelLocaleMgr::~StelLocaleMgr()
47 {
48 delete skyTranslator;
49 skyTranslator = Q_NULLPTR;
50 delete planetaryFeaturesTranslator;
51 planetaryFeaturesTranslator = Q_NULLPTR;
52 delete scriptsTranslator;
53 scriptsTranslator = Q_NULLPTR;
54 }
55
init()56 void StelLocaleMgr::init()
57 {
58 QSettings* conf = StelApp::getInstance().getSettings();
59 Q_ASSERT(conf);
60
61 setSkyLanguage(conf->value("localization/sky_locale", "system").toString(), false);
62 setAppLanguage(conf->value("localization/app_locale", "system").toString(), false);
63
64 timeFormat = stringToSTimeFormat(conf->value("localization/time_display_format", "system_default").toString());
65 dateFormat = stringToSDateFormat(conf->value("localization/date_display_format", "system_default").toString());
66 }
67
68 /*************************************************************************
69 Set the application locale. This apply to GUI, console messages etc..
70 *************************************************************************/
setAppLanguage(const QString & newAppLanguageName,bool refreshAll)71 void StelLocaleMgr::setAppLanguage(const QString& newAppLanguageName, bool refreshAll)
72 {
73 // Update the translator with new locale name
74 Q_ASSERT(StelTranslator::globalTranslator);
75 delete StelTranslator::globalTranslator;
76 StelTranslator::globalTranslator = new StelTranslator("stellarium", newAppLanguageName);
77 qDebug() << "Application language is " << StelTranslator::globalTranslator->getTrueLocaleName();
78
79 delete scriptsTranslator;
80 // Update the translator with new locale name
81 scriptsTranslator = new StelTranslator("stellarium-scripts", newAppLanguageName);
82 qDebug() << "Scripts language is " << scriptsTranslator->getTrueLocaleName();
83
84 createNameLists();
85 if (refreshAll)
86 StelApp::getInstance().updateI18n();
87 }
88
isAppRTL() const89 bool StelLocaleMgr::isAppRTL() const
90 {
91 return QString("ar fa ckb ug ur he yi").contains(getAppLanguage());
92 }
93
94 /*************************************************************************
95 Set the sky language.
96 *************************************************************************/
setSkyLanguage(const QString & newSkyLanguageName,bool refreshAll)97 void StelLocaleMgr::setSkyLanguage(const QString& newSkyLanguageName, bool refreshAll)
98 {
99 delete skyTranslator;
100 // Update the translator with new locale name
101 skyTranslator = new StelTranslator("stellarium-skycultures", newSkyLanguageName);
102 qDebug() << "Sky language is " << skyTranslator->getTrueLocaleName();
103
104 delete planetaryFeaturesTranslator;
105 // Update the translator with new locale name
106 planetaryFeaturesTranslator = new StelTranslator("stellarium-planetary-features", newSkyLanguageName);
107 qDebug() << "Planetary features language is " << planetaryFeaturesTranslator->getTrueLocaleName();
108
109 if (refreshAll)
110 StelApp::getInstance().updateI18n();
111 }
112
113 /*************************************************************************
114 Get the language currently used for sky objects..
115 *************************************************************************/
getSkyLanguage() const116 QString StelLocaleMgr::getSkyLanguage() const
117 {
118 return skyTranslator->getTrueLocaleName();
119 }
120
isSkyRTL() const121 bool StelLocaleMgr::isSkyRTL() const
122 {
123 return QString("ar fa ckb ug ur he yi").contains(getSkyLanguage());
124 }
125
126 // Get the StelTranslator currently used for sky objects.
getSkyTranslator() const127 const StelTranslator& StelLocaleMgr::getSkyTranslator() const
128 {
129 return *skyTranslator;
130 }
131
getPlanetaryFeaturesTranslator() const132 const StelTranslator& StelLocaleMgr::getPlanetaryFeaturesTranslator() const
133 {
134 return *planetaryFeaturesTranslator;
135 }
136
getAppStelTranslator() const137 const StelTranslator &StelLocaleMgr::getAppStelTranslator() const
138 {
139 return *StelTranslator::globalTranslator;
140 }
141
getScriptsTranslator() const142 const StelTranslator& StelLocaleMgr::getScriptsTranslator() const
143 {
144 return *scriptsTranslator;
145 }
146
147 // Return the time in ISO 8601 format that is : %Y-%m-%d %H:%M:%S
getISO8601TimeLocal(double JD) const148 QString StelLocaleMgr::getISO8601TimeLocal(double JD) const
149 {
150 return StelUtils::julianDayToISO8601String(JD + core->getUTCOffset(JD)*0.041666666666);
151 }
152
153 //! get the six ints from an ISO8601 date time, understood to be local time, make a jdate out
154 //! of them.
getJdFromISO8601TimeLocal(const QString & t,bool * ok) const155 double StelLocaleMgr::getJdFromISO8601TimeLocal(const QString& t, bool* ok) const
156 {
157 double jd = StelUtils::getJulianDayFromISO8601String(t, ok);
158 if (!*ok)
159 {
160 qWarning() << "StelLocaleMgr::getJdFromISO8601TimeLocal: invalid ISO8601 date. Returning JD=0";
161 return 0.0;
162 }
163
164 jd -= core->getUTCOffset(jd)*0.041666666666;
165 return jd;
166 }
167
168
169 // Return a string with the local date formated according to the dateFormat variable
getPrintableDateLocal(double JD) const170 QString StelLocaleMgr::getPrintableDateLocal(double JD) const
171 {
172 int year, month, day, dayOfWeek;
173 const double shift = core->getUTCOffset(JD)*0.041666666666;
174 StelUtils::getDateFromJulianDay(JD+shift, &year, &month, &day);
175 dayOfWeek = StelUtils::getDayOfWeek(year, month, day);
176 QString str;
177 switch (dateFormat)
178 {
179 case SDateMMDDYYYY:
180 str = QString("%1-%2-%3").arg(month,2,10,QLatin1Char('0')).arg(day,2,10,QLatin1Char('0')).arg(year,4,10);
181 break;
182 case SDateDDMMYYYY:
183 str = QString("%1-%2-%3").arg(day,2,10,QLatin1Char('0')).arg(month,2,10,QLatin1Char('0')).arg(year,4,10);
184 break;
185 case SDateYYYYMMDD:
186 str = QString("%1-%2-%3").arg(year,4,10).arg(month,2,10,QLatin1Char('0')).arg(day,2,10,QLatin1Char('0'));
187 break;
188 case SDateWWMMDDYYYY:
189 str = QString("%1, %2-%3-%4").arg(shortDayName(dayOfWeek)).arg(month,2,10,QLatin1Char('0')).arg(day,2,10,QLatin1Char('0')).arg(year,4,10);
190 break;
191 case SDateWWDDMMYYYY:
192 str = QString("%1, %2-%3-%4").arg(shortDayName(dayOfWeek)).arg(day,2,10,QLatin1Char('0')).arg(month,2,10,QLatin1Char('0')).arg(year,4,10);
193 break;
194 case SDateWWYYYYMMDD:
195 str = QString("%1, %2-%3-%4").arg(shortDayName(dayOfWeek)).arg(year,4,10).arg(month,2,10,QLatin1Char('0')).arg(day,2,10,QLatin1Char('0'));
196 break;
197 case SDateSystemDefault:
198 str = StelUtils::localeDateString(year, month, day, dayOfWeek);
199 break;
200 default:
201 qWarning() << "WARNING: unknown date format fallback to system default";
202 str = StelUtils::localeDateString(year, month, day, dayOfWeek);
203 }
204 return str;
205 }
206
207 // Return a string with the local time (according to timeZoneMode variable) formated
208 // according to the timeFormat variable
getPrintableTimeLocal(double JD) const209 QString StelLocaleMgr::getPrintableTimeLocal(double JD) const
210 {
211 int hour, minute, second, millsec;
212 const double shift = core->getUTCOffset(JD)*0.041666666666;
213 StelUtils::getTimeFromJulianDay(JD+shift, &hour, &minute, &second, &millsec);
214 QTime t(hour, minute, second, millsec);
215 switch (timeFormat)
216 {
217 case STimeSystemDefault:
218 return t.toString();
219 case STime24h:
220 return t.toString("hh:mm:ss");
221 case STime12h:
222 return t.toString("hh:mm:ss AP");
223 default:
224 qWarning() << "WARNING: unknown time format, fallback to system default";
225 return t.toString(Qt::DefaultLocaleShortDate);
226 }
227 }
228
getPrintableTimeZoneLocal(double JD) const229 QString StelLocaleMgr::getPrintableTimeZoneLocal(double JD) const
230 {
231 QString timeZone = "";
232 QString timeZoneST = "";
233 if (core->getCurrentLocation().planetName=="Earth")
234 {
235 QString currTZ = core->getCurrentTimeZone();
236
237 if (JD<=StelCore::TZ_ERA_BEGINNING || currTZ.contains("auto") || currTZ.contains("LMST"))
238 {
239 // TRANSLATORS: Local Mean Solar Time. Please use abbreviation.
240 timeZoneST = qc_("LMST", "solar time");
241 }
242
243 if (currTZ.contains("LTST"))
244 {
245 // TRANSLATORS: Local True Solar Time. Please use abbreviation.
246 timeZoneST = qc_("LTST", "solar time");
247 }
248
249 const double shift = core->getUTCOffset(JD);
250 QTime tz = QTime(0, 0, 0).addSecs(static_cast<int>(3600*qAbs(shift)));
251 if(shift<0.0)
252 timeZone = QString("UTC-%1").arg(tz.toString("hh:mm"));
253 else
254 timeZone = QString("UTC+%1").arg(tz.toString("hh:mm"));
255
256 if (!timeZoneST.isEmpty() && !core->getUseCustomTimeZone())
257 timeZone = QString("%1 (%2)").arg(timeZone, timeZoneST);
258 }
259 else
260 {
261 // TODO: Make sure LMST/LTST would make sense on other planet, or inhibit it?
262 const double shift = core->getUTCOffset(JD);
263 QTime tz = QTime(0, 0, 0).addSecs(static_cast<int>(3600*qAbs(shift)));
264 if(shift<0.0)
265 timeZone = QString("UTC-%1").arg(tz.toString("hh:mm"));
266 else
267 timeZone = QString("UTC+%1").arg(tz.toString("hh:mm"));
268
269 //if (!timeZoneST.isEmpty() && !core->getUseCustomTimeZone())
270 // timeZone = QString("%1 (%2)").arg(timeZone, timeZoneST);
271 }
272 return timeZone;
273 }
274
275 // Convert the time format enum to its associated string and reverse
stringToSTimeFormat(const QString & tf)276 StelLocaleMgr::STimeFormat StelLocaleMgr::stringToSTimeFormat(const QString& tf)
277 {
278 static const QMap<QString, StelLocaleMgr::STimeFormat> map = {
279 {"system_default", STimeSystemDefault},
280 {"24h", STime24h},
281 {"12h", STime12h}};
282 if (!map.contains(tf))
283 qWarning() << "WARNING: unrecognized time_display_format : " << tf << " system_default used.";
284 return map.value(tf, STimeSystemDefault);
285 }
286
sTimeFormatToString(STimeFormat tf)287 QString StelLocaleMgr::sTimeFormatToString(STimeFormat tf)
288 {
289 static const QStringList tfmt={"system_default", "24h", "12h"};
290 return tfmt[tf];
291 }
292
293 // Convert the date format enum to its associated string and reverse
stringToSDateFormat(const QString & df)294 StelLocaleMgr::SDateFormat StelLocaleMgr::stringToSDateFormat(const QString& df)
295 {
296 static const QMap<QString, StelLocaleMgr::SDateFormat> map = {
297 {"system_default", SDateSystemDefault},
298 {"mmddyyyy", SDateMMDDYYYY},
299 {"ddmmyyyy", SDateDDMMYYYY},
300 {"yyyymmdd", SDateYYYYMMDD}, // iso8601
301 {"wwmmddyyyy", SDateWWMMDDYYYY},
302 {"wwddmmyyyy", SDateWWDDMMYYYY},
303 {"wwyyyymmdd", SDateWWYYYYMMDD}};
304 if (!map.contains(df))
305 qWarning() << "WARNING: unrecognized date_display_format : " << df << " system_default used.";
306 return map.value(df, SDateSystemDefault);
307 }
308
sDateFormatToString(SDateFormat df)309 QString StelLocaleMgr::sDateFormatToString(SDateFormat df)
310 {
311 QStringList dfmt = {
312 "system_default",
313 "mmddyyyy",
314 "ddmmyyyy",
315 "yyyymmdd",
316 "wwddmmyyyy",
317 "wwddmmyyyy",
318 "wwyyyymmdd"};
319 return dfmt[df];
320 }
321
getQtDateFormatStr() const322 QString StelLocaleMgr::getQtDateFormatStr() const
323 {
324 QStringList dfmt = {
325 "yyyy.MM.dd",
326 "MM.dd.yyyy",
327 "dd.MM.yyyy",
328 "yyyy.MM.dd",
329 "ddd, MM.dd.yyyy",
330 "ddd, dd.MM.yyyy",
331 "ddd, yyyy.MM.dd"};
332 return dfmt[dateFormat];
333 }
334
shortDayName(int weekday)335 QString StelLocaleMgr::shortDayName(int weekday)
336 {
337 Q_ASSERT(weekday>=0);
338 Q_ASSERT(shortWeekDays.length()==7);
339 return shortWeekDays[weekday % 7];
340 }
341
longDayName(int weekday)342 QString StelLocaleMgr::longDayName(int weekday)
343 {
344 Q_ASSERT(weekday>=0);
345 Q_ASSERT(longWeekDays.length()==7);
346 return longWeekDays[weekday % 7];
347 }
348
shortMonthName(int month)349 QString StelLocaleMgr::shortMonthName(int month)
350 {
351 Q_ASSERT(month >= 0);
352 Q_ASSERT(shortMonthNames.length()==12);
353 return shortMonthNames[month % 12];
354 }
355
longMonthName(int month)356 QString StelLocaleMgr::longMonthName(int month)
357 {
358 Q_ASSERT(month >= 0);
359 Q_ASSERT(longMonthNames.length()==12);
360 return longMonthNames[month % 12];
361 }
362
longGenitiveMonthName(int month)363 QString StelLocaleMgr::longGenitiveMonthName(int month)
364 {
365 Q_ASSERT(month >= 0);
366 Q_ASSERT(longGenitiveMonthNames.length()==12);
367 return longGenitiveMonthNames[month % 12];
368 }
369
romanMonthName(int month)370 QString StelLocaleMgr::romanMonthName(int month)
371 {
372 Q_ASSERT(month >= 0);
373 static const QStringList romanMonths = { "XII", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI"};
374 return romanMonths[month % 12];
375 }
376
377
createNameLists()378 void StelLocaleMgr::createNameLists()
379 {
380 shortWeekDays.clear();
381 shortWeekDays
382 << qc_("Sun", "short day name")
383 << qc_("Mon", "short day name")
384 << qc_("Tue", "short day name")
385 << qc_("Wed", "short day name")
386 << qc_("Thu", "short day name")
387 << qc_("Fri", "short day name")
388 << qc_("Sat", "short day name");
389 longWeekDays.clear();
390 longWeekDays
391 << qc_("Sunday", "long day name")
392 << qc_("Monday", "long day name")
393 << qc_("Tuesday", "long day name")
394 << qc_("Wednesday", "long day name")
395 << qc_("Thursday", "long day name")
396 << qc_("Friday", "long day name")
397 << qc_("Saturday", "long day name");
398
399 shortMonthNames.clear();
400 shortMonthNames
401 << qc_("Dec", "short month name")
402 << qc_("Jan", "short month name")
403 << qc_("Feb", "short month name")
404 << qc_("Mar", "short month name")
405 << qc_("Apr", "short month name")
406 << qc_("May", "short month name")
407 << qc_("Jun", "short month name")
408 << qc_("Jul", "short month name")
409 << qc_("Aug", "short month name")
410 << qc_("Sep", "short month name")
411 << qc_("Oct", "short month name")
412 << qc_("Nov", "short month name");
413
414 longMonthNames.clear();
415 longMonthNames
416 << qc_("December", "long month name")
417 << qc_("January", "long month name")
418 << qc_("February", "long month name")
419 << qc_("March", "long month name")
420 << qc_("April", "long month name")
421 << qc_("May", "long month name")
422 << qc_("June", "long month name")
423 << qc_("July", "long month name")
424 << qc_("August", "long month name")
425 << qc_("September", "long month name")
426 << qc_("October", "long month name")
427 << qc_("November", "long month name");
428 longGenitiveMonthNames.clear();
429 longGenitiveMonthNames
430 << qc_("December", "genitive")
431 << qc_("January", "genitive")
432 << qc_("February", "genitive")
433 << qc_("March", "genitive")
434 << qc_("April", "genitive")
435 << qc_("May", "genitive")
436 << qc_("June", "genitive")
437 << qc_("July", "genitive")
438 << qc_("August", "genitive")
439 << qc_("September", "genitive")
440 << qc_("October", "genitive")
441 << qc_("November", "genitive");
442 }
443
444 QStringList StelLocaleMgr::shortWeekDays;
445 QStringList StelLocaleMgr::longWeekDays;
446 QStringList StelLocaleMgr::shortMonthNames;
447 QStringList StelLocaleMgr::longMonthNames;
448 QStringList StelLocaleMgr::longGenitiveMonthNames;
449