Merge lp:~aacid/ubuntu-ui-toolkit/i18n-RelativeDateTime into lp:ubuntu-ui-toolkit/staging

Proposed by Albert Astals Cid
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1611
Merged at revision: 1604
Proposed branch: lp:~aacid/ubuntu-ui-toolkit/i18n-RelativeDateTime
Merge into: lp:ubuntu-ui-toolkit/staging
Prerequisite: lp:~aacid/ubuntu-ui-toolkit/LiveTimer
Diff against target: 679 lines (+512/-24)
12 files modified
components.api (+1/-0)
src/Ubuntu/Components/plugin/i18n.cpp (+74/-0)
src/Ubuntu/Components/plugin/i18n.h (+1/-0)
src/Ubuntu/Components/plugin/timeutils_p.h (+24/-0)
tests/unit/tst_i18n/tst_i18n.pro (+3/-18)
tests/unit/tst_i18n/tst_i18n_LocalizedApp/src/LocalizedApp.qml (+43/-1)
tests/unit/tst_i18n/tst_i18n_LocalizedApp/src/tst_i18n_LocalizedApp.cpp (+5/-5)
tests/unit/tst_i18n/tst_i18n_LocalizedApp/tst_i18n_LocalizedApp.pro (+17/-0)
tests/unit/tst_i18n/tst_i18n_RelativeTime/po/en_US.po (+54/-0)
tests/unit/tst_i18n/tst_i18n_RelativeTime/src/RelativeTime.qml (+71/-0)
tests/unit/tst_i18n/tst_i18n_RelativeTime/src/tst_i18n_RelativeTime.cpp (+202/-0)
tests/unit/tst_i18n/tst_i18n_RelativeTime/tst_i18n_RelativeTime.pro (+17/-0)
To merge this branch: bzr merge lp:~aacid/ubuntu-ui-toolkit/i18n-RelativeDateTime
Reviewer Review Type Date Requested Status
Lukáš Tinkl (community) code-review Needs Fixing
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Review via email: mp+267788@code.launchpad.net

Commit message

Added relative date time i18n

Description of the change

Added relative date time i18n

To post a comment you must log in.
1608. By Nick Dedekind

i18n.relativeDateTime

1609. By Nick Dedekind

review comments

1610. By Nick Dedekind

split relative time i18n

1611. By Nick Dedekind

split relative time i18n from localizedApp

Revision history for this message
Albert Astals Cid (aacid) wrote :
Revision history for this message
Zsombor Egri (zsombi) wrote :

This one too.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

One small optimization comment

review: Needs Fixing (code-review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2015-08-12 10:11:43 +0000
3+++ components.api 2015-08-12 10:11:44 +0000
4@@ -1405,3 +1405,4 @@
5 function string dctr(string domain, string context, string text)
6 function string tag(string text)
7 function string tag(string context, string text)
8+ function string relativeDateTime(QDateTime datetime)
9
10=== modified file 'src/Ubuntu/Components/plugin/i18n.cpp'
11--- src/Ubuntu/Components/plugin/i18n.cpp 2015-03-03 13:47:48 +0000
12+++ src/Ubuntu/Components/plugin/i18n.cpp 2015-08-12 10:11:44 +0000
13@@ -17,6 +17,7 @@
14 */
15
16 #include "i18n.h"
17+#include "timeutils_p.h"
18 #include <QtCore/QDir>
19
20 namespace C {
21@@ -252,3 +253,76 @@
22 Q_UNUSED(context);
23 return text;
24 }
25+/*!
26+ * \qmlmethod string i18n::relativeDateTime(datetime dateTime)
27+ * Translate a datetime based on proximity to current time.
28+ */
29+QString UbuntuI18n::relativeDateTime(const QDateTime& datetime)
30+{
31+ QDateTime relativeTo(QDateTime::currentDateTime());
32+ const date_proximity_t prox = getDateProximity(relativeTo, datetime);
33+
34+ switch (prox) {
35+ case DATE_PROXIMITY_NOW:
36+ /* TRANSLATORS: Time based "this is happening/happened now" */
37+ return dtr("ubuntu-ui-toolkit", "Now");
38+
39+ case DATE_PROXIMITY_HOUR:
40+ {
41+ qint64 diff = datetime.toMSecsSinceEpoch() - relativeTo.toMSecsSinceEpoch();
42+ qint64 minutes = qRound(float(diff) / 60000);
43+ if (minutes < 0) {
44+ return dtr("ubuntu-ui-toolkit", "%1 minute ago", "%1 minutes ago", qAbs(minutes)).arg(qAbs(minutes));
45+ }
46+ return dtr("ubuntu-ui-toolkit", "%1 minute", "%1 minutes", minutes).arg(minutes);
47+ }
48+
49+ case DATE_PROXIMITY_TODAY:
50+ /* en_US example: "1:00 PM" */
51+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
52+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
53+ return datetime.toString(isLocale12h() ? dtr("ubuntu-ui-toolkit", "h:mm ap"):
54+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
55+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
56+ dtr("ubuntu-ui-toolkit", "HH:mm"));
57+
58+ case DATE_PROXIMITY_YESTERDAY:
59+ /* en_US example: "Yesterday 13:00" */
60+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
61+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
62+ return datetime.toString(isLocale12h() ? dtr("ubuntu-ui-toolkit", "'Yesterday\u2003'h:mm ap") :
63+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
64+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
65+ dtr("ubuntu-ui-toolkit", "'Yesterday\u2003'HH:mm"));
66+
67+ case DATE_PROXIMITY_TOMORROW:
68+ /* en_US example: "Tomorrow 1:00 PM" */
69+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
70+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
71+ return datetime.toString(isLocale12h() ? dtr("ubuntu-ui-toolkit", "'Tomorrow\u2003'h:mm ap") :
72+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
73+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
74+ dtr("ubuntu-ui-toolkit", "'Tomorrow\u2003'HH:mm"));
75+
76+ case DATE_PROXIMITY_LAST_WEEK:
77+ case DATE_PROXIMITY_NEXT_WEEK:
78+ /* en_US example: "Fri 1:00 PM" */
79+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
80+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
81+ return datetime.toString(isLocale12h() ? dtr("ubuntu-ui-toolkit", "ddd'\u2003'h:mm ap") :
82+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
83+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
84+ dtr("ubuntu-ui-toolkit", "ddd'\u2003'HH:mm"));
85+
86+ case DATE_PROXIMITY_FAR_BACK:
87+ case DATE_PROXIMITY_FAR_FORWARD:
88+ default:
89+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
90+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
91+ return datetime.toString(isLocale12h() ? dtr("ubuntu-ui-toolkit", "ddd d MMM'\u2003'h:mm ap") :
92+ /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by
93+ https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */
94+ dtr("ubuntu-ui-toolkit", "ddd d MMM'\u2003'HH:mm"));
95+ }
96+ return datetime.toString(Qt::DefaultLocaleShortDate);
97+}
98
99=== modified file 'src/Ubuntu/Components/plugin/i18n.h'
100--- src/Ubuntu/Components/plugin/i18n.h 2015-02-03 18:11:32 +0000
101+++ src/Ubuntu/Components/plugin/i18n.h 2015-08-12 10:11:44 +0000
102@@ -50,6 +50,7 @@
103 Q_INVOKABLE QString dctr(const QString& domain, const QString& context, const QString& text);
104 Q_INVOKABLE QString tag(const QString& text);
105 Q_INVOKABLE QString tag(const QString& context, const QString& text);
106+ Q_INVOKABLE QString relativeDateTime(const QDateTime& datetime);
107
108 // getter
109 QString domain() const;
110
111=== modified file 'src/Ubuntu/Components/plugin/timeutils_p.h'
112--- src/Ubuntu/Components/plugin/timeutils_p.h 2015-08-12 10:11:43 +0000
113+++ src/Ubuntu/Components/plugin/timeutils_p.h 2015-08-12 10:11:44 +0000
114@@ -20,9 +20,33 @@
115 #include "livetimer.h"
116
117 #include <QDateTime>
118+#include <QLocale>
119 #include <QObject>
120 #include <QTimer>
121
122+/* Check the system locale setting to see if the format is 24-hour
123+ time or 12-hour time */
124+inline bool isLocale12h(void)
125+{
126+ QString strTimeFormat = QLocale::system().timeFormat();
127+ QStringList includes; includes << "AP"; includes << "ap";
128+ QStringList excludes; excludes << "H"; excludes << "HH";
129+
130+ Q_FOREACH(const QString& exclude, excludes) {
131+ if (strTimeFormat.contains(exclude)) {
132+ return false;
133+ }
134+ }
135+
136+ Q_FOREACH(const QString& include, includes) {
137+ if (strTimeFormat.contains(include)) {
138+ return true;
139+ }
140+ }
141+
142+ return false;
143+}
144+
145 typedef enum
146 {
147 DATE_PROXIMITY_NOW,
148
149=== modified file 'tests/unit/tst_i18n/tst_i18n.pro'
150--- tests/unit/tst_i18n/tst_i18n.pro 2015-05-18 09:53:55 +0000
151+++ tests/unit/tst_i18n/tst_i18n.pro 2015-08-12 10:11:44 +0000
152@@ -1,18 +1,3 @@
153-include(../test-include.pri)
154-QT += gui
155-DEFINES += SRCDIR=\\\"$$PWD/\\\"
156-
157-DOMAIN = localizedApp
158-mo.target = mo
159-mo.commands = set -e;
160-mo.commands += echo Generating localization for $$DOMAIN;
161-mo.commands += mkdir -p $${DOMAIN}/share/locale/en/LC_MESSAGES;
162-mo.commands += msgfmt $$PWD/po/en_US.po -o $${DOMAIN}/share/locale/en/LC_MESSAGES/$${DOMAIN}.mo;
163-QMAKE_EXTRA_TARGETS += mo
164-PRE_TARGETDEPS += mo
165-
166-SOURCES += \
167- src/tst_i18n.cpp
168-
169-OTHER_FILES += \
170- src/LocalizedApp.qml
171+TEMPLATE = subdirs
172+SUBDIRS += tst_i18n_LocalizedApp
173+SUBDIRS += tst_i18n_RelativeTime
174
175=== added directory 'tests/unit/tst_i18n/tst_i18n_LocalizedApp'
176=== added file 'tests/unit/tst_i18n/tst_i18n_LocalizedApp.o'
177Binary files tests/unit/tst_i18n/tst_i18n_LocalizedApp.o 1970-01-01 00:00:00 +0000 and tests/unit/tst_i18n/tst_i18n_LocalizedApp.o 2015-08-12 10:11:44 +0000 differ
178=== renamed directory 'tests/unit/tst_i18n/localizedApp' => 'tests/unit/tst_i18n/tst_i18n_LocalizedApp/localizedApp'
179=== renamed directory 'tests/unit/tst_i18n/po' => 'tests/unit/tst_i18n/tst_i18n_LocalizedApp/po'
180=== renamed directory 'tests/unit/tst_i18n/src' => 'tests/unit/tst_i18n/tst_i18n_LocalizedApp/src'
181=== modified file 'tests/unit/tst_i18n/tst_i18n_LocalizedApp/src/LocalizedApp.qml'
182--- tests/unit/tst_i18n/src/LocalizedApp.qml 2015-03-03 13:20:06 +0000
183+++ tests/unit/tst_i18n/tst_i18n_LocalizedApp/src/LocalizedApp.qml 2015-08-12 10:11:44 +0000
184@@ -28,7 +28,7 @@
185 Button {
186 id: button
187 objectName: 'button'
188- anchors.centerIn: parent
189+ anchors.horizontalCenter: parent.horizontalCenter
190 text: i18n.tr('Count the kilometres')
191 width: units.gu(15)
192 }
193@@ -60,5 +60,47 @@
194 anchors.horizontalCenter: all2.horizontalCenter
195 text: i18n.tag('All Cats', 'All')
196 }
197+ Label {
198+ id: timeNow
199+ objectName: 'timeNow'
200+ anchors.top: all3.bottom
201+ anchors.horizontalCenter: all3.horizontalCenter
202+ text: i18n.relativeDateTime(new Date())
203+ }
204+ Label {
205+ id: timeMinuteBefore
206+ objectName: 'timeMinuteBefore'
207+ anchors.top: timeNow.bottom
208+ anchors.horizontalCenter: timeNow.horizontalCenter
209+ text: i18n.relativeDateTime(new Date(new Date().getTime() - 60000))
210+ }
211+ Label {
212+ id: timeMinuteAfter
213+ objectName: 'timeMinuteAfter'
214+ anchors.top: timeMinuteBefore.bottom
215+ anchors.horizontalCenter: timeMinuteBefore.horizontalCenter
216+ text: i18n.relativeDateTime(new Date(new Date().getTime() + 60000))
217+ }
218+ Label {
219+ id: tenMinutesBefore
220+ objectName: 'tenMinutesBefore'
221+ anchors.top: timeMinuteAfter.bottom
222+ anchors.horizontalCenter: timeMinuteAfter.horizontalCenter
223+ text: i18n.relativeDateTime(new Date(new Date().getTime() - 600000))
224+ }
225+ Label {
226+ id: tenMinutesAfter
227+ objectName: 'tenMinutesAfter'
228+ anchors.top: tenMinutesBefore.bottom
229+ anchors.horizontalCenter: tenMinutesBefore.horizontalCenter
230+ text: i18n.relativeDateTime(new Date(new Date().getTime() + 600000))
231+ }
232+ Label {
233+ id: timeFarAway
234+ objectName: 'timeFarAway'
235+ anchors.top: tenMinutesAfter.bottom
236+ anchors.horizontalCenter: tenMinutesAfter.horizontalCenter
237+ text: i18n.relativeDateTime(new Date(2000, 0, 1, 0, 0, 0, 0))
238+ }
239 }
240 }
241
242=== renamed file 'tests/unit/tst_i18n/src/tst_i18n.cpp' => 'tests/unit/tst_i18n/tst_i18n_LocalizedApp/src/tst_i18n_LocalizedApp.cpp'
243--- tests/unit/tst_i18n/src/tst_i18n.cpp 2015-02-03 18:11:32 +0000
244+++ tests/unit/tst_i18n/tst_i18n_LocalizedApp/src/tst_i18n_LocalizedApp.cpp 2015-08-12 10:11:44 +0000
245@@ -39,7 +39,7 @@
246 #include "ucunits.h"
247 #include "i18n.h"
248
249-class tst_I18n : public QObject
250+class tst_I18n_LocalizedApp : public QObject
251 {
252 Q_OBJECT
253
254@@ -47,7 +47,7 @@
255 QQuickView *view;
256
257 public:
258- tst_I18n() :
259+ tst_I18n_LocalizedApp() :
260 view(0)
261 {
262 }
263@@ -191,7 +191,7 @@
264 }
265 };
266
267-// The C++ equivalent of QTEST_MAIN(tst_I18n) with added initialization
268+// The C++ equivalent of QTEST_MAIN(tst_I18n_LocalizedApp) with added initialization
269 int main(int argc, char *argv[])
270 {
271 // LC_ALL would fail the test case; it must be unset before execution
272@@ -199,8 +199,8 @@
273
274 QGuiApplication app(argc, argv);
275 app.setAttribute(Qt::AA_Use96Dpi, true);
276- tst_I18n* testObject = new tst_I18n();
277+ tst_I18n_LocalizedApp* testObject = new tst_I18n_LocalizedApp();
278 return QTest::qExec(static_cast<QObject*>(testObject), argc, argv);
279 }
280
281-#include "tst_i18n.moc"
282+#include "tst_i18n_LocalizedApp.moc"
283
284=== added file 'tests/unit/tst_i18n/tst_i18n_LocalizedApp/tst_i18n_LocalizedApp.pro'
285--- tests/unit/tst_i18n/tst_i18n_LocalizedApp/tst_i18n_LocalizedApp.pro 1970-01-01 00:00:00 +0000
286+++ tests/unit/tst_i18n/tst_i18n_LocalizedApp/tst_i18n_LocalizedApp.pro 2015-08-12 10:11:44 +0000
287@@ -0,0 +1,17 @@
288+include(../../test-include.pri)
289+QT += gui
290+DEFINES += SRCDIR=\\\"$$PWD/\\\"
291+
292+DOMAIN = localizedApp
293+mo.target = mo
294+mo.commands = set -e;
295+mo.commands += echo Generating localization;
296+mo.commands += msgfmt po/en_US.po -o $${DOMAIN}/share/locale/en/LC_MESSAGES/$${DOMAIN}.mo;
297+QMAKE_EXTRA_TARGETS += mo
298+PRE_TARGETDEPS += mo
299+
300+SOURCES += \
301+ src/tst_i18n_LocalizedApp.cpp
302+
303+OTHER_FILES += \
304+ src/LocalizedApp.qml
305
306=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime'
307=== added file 'tests/unit/tst_i18n/tst_i18n_RelativeTime.o'
308Binary files tests/unit/tst_i18n/tst_i18n_RelativeTime.o 1970-01-01 00:00:00 +0000 and tests/unit/tst_i18n/tst_i18n_RelativeTime.o 2015-08-12 10:11:44 +0000 differ
309=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/po'
310=== added file 'tests/unit/tst_i18n/tst_i18n_RelativeTime/po/en_US.po'
311--- tests/unit/tst_i18n/tst_i18n_RelativeTime/po/en_US.po 1970-01-01 00:00:00 +0000
312+++ tests/unit/tst_i18n/tst_i18n_RelativeTime/po/en_US.po 2015-08-12 10:11:44 +0000
313@@ -0,0 +1,54 @@
314+msgid ""
315+msgstr ""
316+"Project-Id-Version: \n"
317+"POT-Creation-Date: \n"
318+"PO-Revision-Date: \n"
319+"Last-Translator: Christian Dywan <christian.dywan@canonical.com>\n"
320+"Language-Team: \n"
321+"Language: \n"
322+"MIME-Version: 1.0\n"
323+"Content-Type: text/plain; charset=iso-8859-1\n"
324+"Content-Transfer-Encoding: 8bit\n"
325+
326+msgid "Now"
327+msgstr "tr:Now"
328+
329+msgid "%1 minute ago"
330+msgid_plural "%1 minutes ago"
331+msgstr[0] "tr:%1 minute ago"
332+msgstr[1] "tr:%1 minutes ago"
333+
334+msgid "%1 minute"
335+msgid_plural "%1 minutes"
336+msgstr[0] "tr:%1 minute"
337+msgstr[1] "tr:%1 minutes"
338+
339+msgid "h:mm ap"
340+msgstr "'tr:'h:mm ap"
341+
342+msgid "HH:mm"
343+msgstr "'tr:'HH:mm"
344+
345+msgid "'Yesterday 'h:mm ap"
346+msgstr "'tr:Yesterday 'h:mm ap"
347+
348+msgid "'Yesterday 'HH:mm"
349+msgstr "'tr:Yesterday 'HH:mm"
350+
351+msgid "'Tomorrow 'h:mm ap"
352+msgstr "'tr:Tomorrow 'h:mm ap"
353+
354+msgid "'Tomorrow 'HH:mm"
355+msgstr "'tr:Tomorrow 'HH:mm"
356+
357+msgid "ddd' 'h:mm ap"
358+msgstr "'tr:'ddd' 'h:mm ap"
359+
360+msgid "ddd' 'HH:mm"
361+msgstr "'tr:'ddd' 'HH:mm"
362+
363+msgid "ddd d MMM' 'h:mm ap"
364+msgstr "'tr:FarAway'"
365+
366+msgid "ddd d MMM' 'HH:mm"
367+msgstr "'tr:FarAway'"
368
369=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/src'
370=== added file 'tests/unit/tst_i18n/tst_i18n_RelativeTime/src/RelativeTime.qml'
371--- tests/unit/tst_i18n/tst_i18n_RelativeTime/src/RelativeTime.qml 1970-01-01 00:00:00 +0000
372+++ tests/unit/tst_i18n/tst_i18n_RelativeTime/src/RelativeTime.qml 2015-08-12 10:11:44 +0000
373@@ -0,0 +1,71 @@
374+/*
375+ * Copyright 2013 Canonical Ltd.
376+ *
377+ * This program is free software; you can redistribute it and/or modify
378+ * it under the terms of the GNU Lesser General Public License as published by
379+ * the Free Software Foundation; version 3.
380+ *
381+ * This program is distributed in the hope that it will be useful,
382+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
383+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
384+ * GNU Lesser General Public License for more details.
385+ *
386+ * You should have received a copy of the GNU Lesser General Public License
387+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
388+ */
389+
390+import QtQuick 2.0
391+import Ubuntu.Components 1.3
392+
393+MainView {
394+ width: units.gu(48)
395+ height: units.gu(60)
396+ applicationName: "ubuntu-ui-toolkit"
397+
398+ Page {
399+ objectName: 'page'
400+
401+ Label {
402+ id: timeNow
403+ objectName: 'timeNow'
404+ anchors.top: parent.top
405+ anchors.horizontalCenter: parent.horizontalCenter
406+ text: i18n.relativeDateTime(new Date())
407+ }
408+ Label {
409+ id: timeMinuteBefore
410+ objectName: 'timeMinuteBefore'
411+ anchors.top: timeNow.bottom
412+ anchors.horizontalCenter: timeNow.horizontalCenter
413+ text: i18n.relativeDateTime(new Date(new Date().getTime() - 60000))
414+ }
415+ Label {
416+ id: timeMinuteAfter
417+ objectName: 'timeMinuteAfter'
418+ anchors.top: timeMinuteBefore.bottom
419+ anchors.horizontalCenter: timeMinuteBefore.horizontalCenter
420+ text: i18n.relativeDateTime(new Date(new Date().getTime() + 60000))
421+ }
422+ Label {
423+ id: tenMinutesBefore
424+ objectName: 'tenMinutesBefore'
425+ anchors.top: timeMinuteAfter.bottom
426+ anchors.horizontalCenter: timeMinuteAfter.horizontalCenter
427+ text: i18n.relativeDateTime(new Date(new Date().getTime() - 600000))
428+ }
429+ Label {
430+ id: tenMinutesAfter
431+ objectName: 'tenMinutesAfter'
432+ anchors.top: tenMinutesBefore.bottom
433+ anchors.horizontalCenter: tenMinutesBefore.horizontalCenter
434+ text: i18n.relativeDateTime(new Date(new Date().getTime() + 600000))
435+ }
436+ Label {
437+ id: timeFarAway
438+ objectName: 'timeFarAway'
439+ anchors.top: tenMinutesAfter.bottom
440+ anchors.horizontalCenter: tenMinutesAfter.horizontalCenter
441+ text: i18n.relativeDateTime(new Date(2000, 0, 1, 0, 0, 0, 0))
442+ }
443+ }
444+}
445
446=== added file 'tests/unit/tst_i18n/tst_i18n_RelativeTime/src/tst_i18n_RelativeTime.cpp'
447--- tests/unit/tst_i18n/tst_i18n_RelativeTime/src/tst_i18n_RelativeTime.cpp 1970-01-01 00:00:00 +0000
448+++ tests/unit/tst_i18n/tst_i18n_RelativeTime/src/tst_i18n_RelativeTime.cpp 2015-08-12 10:11:44 +0000
449@@ -0,0 +1,202 @@
450+
451+/*
452+ * Copyright 2015 Canonical Ltd.
453+ *
454+ * This program is free software; you can redistribute it and/or modify
455+ * it under the terms of the GNU Lesser General Public License as published by
456+ * the Free Software Foundation; version 3.
457+ *
458+ * This program is distributed in the hope that it will be useful,
459+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
460+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
461+ * GNU Lesser General Public License for more details.
462+ *
463+ * You should have received a copy of the GNU Lesser General Public License
464+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
465+ *
466+ * Author: Nick Dedekind <nick.dedekind@gmail.com>
467+ */
468+
469+#include <QtCore/QString>
470+#include <QtCore/QTextCodec>
471+#include <QtCore/QStandardPaths>
472+#include <QtCore/QDir>
473+#include <QtCore/QProcessEnvironment>
474+#include <QtTest/QTest>
475+#include <QtTest/QSignalSpy>
476+#include <QtCore/QCoreApplication>
477+#include <QtQml/QQmlEngine>
478+#include <QtQuick/QQuickView>
479+#include <QtQuick/QQuickItem>
480+#include <QtCore/QThread>
481+#include <QtCore/QFileInfo>
482+#include <QtCore/QDir>
483+#include <QtTest/qtest_gui.h>
484+
485+namespace C {
486+#include <libintl.h>
487+}
488+
489+#include "ucunits.h"
490+#include "i18n.h"
491+
492+class tst_I18n_RelativeTime : public QObject
493+{
494+ Q_OBJECT
495+
496+private:
497+ QQuickView *view;
498+
499+public:
500+ tst_I18n_RelativeTime() :
501+ view(0)
502+ {
503+ }
504+
505+ QQuickItem *loadTest(const QString &document)
506+ {
507+ // load the document
508+ view->setSource(QUrl::fromLocalFile(document));
509+ QTest::waitForEvents();
510+
511+ return view->rootObject();
512+ }
513+
514+ QQuickItem *testItem(QQuickItem *that, const QString &identifier)
515+ {
516+ if (that->property(identifier.toLocal8Bit()).isValid())
517+ return that->property(identifier.toLocal8Bit()).value<QQuickItem*>();
518+
519+ QList<QQuickItem*> children = that->findChildren<QQuickItem*>(identifier);
520+ return (children.count() > 0) ? children[0] : 0;
521+ }
522+
523+private Q_SLOTS:
524+
525+ void initTestCase()
526+ {
527+ // Set test locale folder in the environment
528+ // Using setenv because QProcessEnvironment ignores changes
529+ QString testAppDir(QDir::currentPath() + "/ubuntu-ui-toolkit");
530+ setenv("APP_DIR", testAppDir.toUtf8(), 1);
531+
532+ // Verify that we set it correctly
533+ QVERIFY(QFileInfo(testAppDir + "/share/locale/en/LC_MESSAGES/ubuntu-ui-toolkit.mo").exists());
534+
535+ QString modules(UBUNTU_QML_IMPORT_PATH);
536+ QVERIFY(QDir(modules).exists());
537+
538+ view = new QQuickView;
539+ QQmlEngine *quickEngine = view->engine();
540+
541+ view->setGeometry(0,0, UCUnits::instance().gu(40), UCUnits::instance().gu(30));
542+ //add modules folder so we have access to the plugin from QML
543+ QStringList imports = quickEngine->importPathList();
544+ imports.prepend(QDir(modules).absolutePath());
545+ quickEngine->setImportPathList(imports);
546+ }
547+
548+ void cleanupTestCase()
549+ {
550+ delete view;
551+ }
552+
553+ void testCase_RelativeTime()
554+ {
555+ UbuntuI18n* i18n = &UbuntuI18n::instance();
556+ // By default no domain is set
557+ QCOMPARE(i18n->domain(), QString(""));
558+
559+ // Start out with no localization
560+ i18n->setLanguage("C");
561+ // Load the app which should pick up the locale we prepared
562+ QQuickItem *root = loadTest("src/RelativeTime.qml");
563+ QVERIFY(root);
564+ QQuickItem *mainView = root;
565+
566+ // There no translation happens
567+ QQuickItem* page(testItem(mainView, "page"));
568+ QVERIFY(page);
569+
570+ QQuickItem* timeFarAway(testItem(page, "timeFarAway"));
571+ QVERIFY(timeFarAway);
572+ QCOMPARE(timeFarAway->property("text").toString(),
573+ QDateTime(QDate(2000,1,1), QTime(0,0,0,0)).toString("ddd d MMM'\u2003'HH:mm"));
574+ QQuickItem* timeNow(testItem(page, "timeNow"));
575+ QVERIFY(timeNow);
576+ QCOMPARE(timeNow->property("text").toString(), QString("Now"));
577+ QQuickItem* timeMinuteBefore(testItem(page, "timeMinuteBefore"));
578+ QVERIFY(timeMinuteBefore);
579+ QCOMPARE(timeMinuteBefore->property("text").toString(), QString("1 minute ago"));
580+ QQuickItem* timeMinuteAfter(testItem(page, "timeMinuteAfter"));
581+ QVERIFY(timeMinuteAfter);
582+ QCOMPARE(timeMinuteAfter->property("text").toString(), QString("1 minute"));
583+ QQuickItem* tenMinutesBefore(testItem(page, "tenMinutesBefore"));
584+ QVERIFY(tenMinutesBefore);
585+ QCOMPARE(tenMinutesBefore->property("text").toString(), QString("10 minutes ago"));
586+ QQuickItem* tenMinutesAfter(testItem(page, "tenMinutesAfter"));
587+ QVERIFY(tenMinutesAfter);
588+ QCOMPARE(tenMinutesAfter->property("text").toString(), QString("10 minutes"));
589+
590+ // There no translation happens in C++ either
591+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime()), QString("Now"));
592+ QCOMPARE(i18n->relativeDateTime(QDateTime(QDate(2000,1,1), QTime(0,0,0,0))),
593+ QDateTime(QDate(2000,1,1), QTime(0,0,0,0)).toString("ddd d MMM'\u2003'HH:mm"));
594+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(-60)), QString("1 minute ago"));
595+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(60)), QString("1 minute"));
596+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(-600)), QString("10 minutes ago"));
597+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(600)), QString("10 minutes"));
598+
599+ // Was the locale folder detected and set?
600+ QString boundDomain(C::bindtextdomain(i18n->domain().toUtf8(), ((const char*)0)));
601+ QString testAppDir(QDir::currentPath() + "/ubuntu-ui-toolkit");
602+ QString expectedLocalePath(QDir(testAppDir).filePath("share/locale"));
603+ QCOMPARE(boundDomain, expectedLocalePath);
604+ // Is the domain gettext uses correct?
605+ QString gettextDomain(C::textdomain(((const char*)0)));
606+ QCOMPARE(gettextDomain, i18n->domain());
607+ // Is the compiled en_US message catalog in the right location?
608+ QString messageCatalog(boundDomain + "/en/LC_MESSAGES/ubuntu-ui-toolkit.mo");
609+ QVERIFY(QFileInfo(messageCatalog).exists());
610+
611+ // Check if system has en_US locale, otherwise gettext won't work
612+ QProcess localeA;
613+ localeA.start("locale -a");
614+ QVERIFY(localeA.waitForFinished());
615+ QVERIFY(QString(localeA.readAll()).split("\n").contains("en_US.utf8"));
616+
617+ i18n->setLanguage("en_US.utf8");
618+ QSignalSpy spy(i18n, SIGNAL(languageChanged()));
619+ spy.wait();
620+
621+ // Inspect translated strings in QML
622+ QCOMPARE(timeNow->property("text").toString(), QString("tr:Now"));
623+ QCOMPARE(timeMinuteBefore->property("text").toString(), QString("tr:1 minute ago"));
624+ QCOMPARE(timeMinuteAfter->property("text").toString(), QString("tr:1 minute"));
625+ QCOMPARE(tenMinutesBefore->property("text").toString(), QString("tr:10 minutes ago"));
626+ QCOMPARE(tenMinutesAfter->property("text").toString(), QString("tr:10 minutes"));
627+ QCOMPARE(timeFarAway->property("text").toString(), QString("tr:FarAway"));
628+
629+ // Translate in C++
630+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime()), QString("tr:Now"));
631+ QCOMPARE(i18n->relativeDateTime(QDateTime(QDate(2000,1,1), QTime(0,0,0,0))), QString("tr:FarAway"));
632+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(-60)), QString("tr:1 minute ago"));
633+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(60)), QString("tr:1 minute"));
634+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(-600)), QString("tr:10 minutes ago"));
635+ QCOMPARE(i18n->relativeDateTime(QDateTime::currentDateTime().addSecs(600)), QString("tr:10 minutes"));
636+ }
637+};
638+
639+// The C++ equivalent of QTEST_MAIN(tst_I18n_RelativeTime) with added initialization
640+int main(int argc, char *argv[])
641+{
642+ // LC_ALL would fail the test case; it must be unset before execution
643+ unsetenv("LC_ALL");
644+
645+ QGuiApplication app(argc, argv);
646+ app.setAttribute(Qt::AA_Use96Dpi, true);
647+ tst_I18n_RelativeTime* testObject = new tst_I18n_RelativeTime();
648+ return QTest::qExec(static_cast<QObject*>(testObject), argc, argv);
649+}
650+
651+#include "tst_i18n_RelativeTime.moc"
652
653=== added file 'tests/unit/tst_i18n/tst_i18n_RelativeTime/tst_i18n_RelativeTime.pro'
654--- tests/unit/tst_i18n/tst_i18n_RelativeTime/tst_i18n_RelativeTime.pro 1970-01-01 00:00:00 +0000
655+++ tests/unit/tst_i18n/tst_i18n_RelativeTime/tst_i18n_RelativeTime.pro 2015-08-12 10:11:44 +0000
656@@ -0,0 +1,17 @@
657+include(../../test-include.pri)
658+QT += gui
659+DEFINES += SRCDIR=\\\"$$PWD/\\\"
660+
661+DOMAIN = ubuntu-ui-toolkit
662+mo.target = mo
663+mo.commands = set -e;
664+mo.commands += echo Generating localization;
665+mo.commands += msgfmt po/en_US.po -o $${DOMAIN}/share/locale/en/LC_MESSAGES/$${DOMAIN}.mo;
666+QMAKE_EXTRA_TARGETS += mo
667+PRE_TARGETDEPS += mo
668+
669+SOURCES += \
670+ src/tst_i18n_RelativeTime.cpp
671+
672+OTHER_FILES += \
673+ src/RelativeTime.qml
674
675=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/ubuntu-ui-toolkit'
676=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/ubuntu-ui-toolkit/share'
677=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/ubuntu-ui-toolkit/share/locale'
678=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/ubuntu-ui-toolkit/share/locale/en'
679=== added directory 'tests/unit/tst_i18n/tst_i18n_RelativeTime/ubuntu-ui-toolkit/share/locale/en/LC_MESSAGES'

Subscribers

People subscribed via source and target branches