Merge lp:~bzoltan/ubuntu-ui-toolkit/restructure_i18n into lp:ubuntu-ui-toolkit/staging
- restructure_i18n
- Merge into staging
Status: | Work in progress |
---|---|
Proposed branch: | lp:~bzoltan/ubuntu-ui-toolkit/restructure_i18n |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Diff against target: |
1154 lines (+1114/-2) 4 files modified
src/UbuntuToolkit/UbuntuToolkit.pro (+19/-2) src/UbuntuToolkit/i18n-android.cpp (+365/-0) src/UbuntuToolkit/i18n-macx.cpp (+365/-0) src/UbuntuToolkit/i18n-windows.cpp (+365/-0) |
To merge this branch: | bzr merge lp:~bzoltan/ubuntu-ui-toolkit/restructure_i18n |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
ubuntu-sdk-build-bot | continuous-integration | Needs Fixing | |
Ubuntu SDK team | Pending | ||
Review via email: mp+306424@code.launchpad.net |
Commit message
Restructure i18n API implementation for non Ubuntu platforms
Description of the change
Restructure i18n API implementation for non Ubuntu platforms
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2121
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2121
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2121
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2121
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2121
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
- 2122. By Zoltan Balogh
-
Missed backslash
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
PASSED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
PASSED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote : | # |
FAILED: Continuous integration, rev:2122
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Cris Dywan (kalikiana) wrote : | # |
Just to clear up the review queue: this needs a rationale as to what the split is trying to achieve. From the current code I barely see a difference in the implementations and no platform-specific code.
Unmerged revisions
- 2122. By Zoltan Balogh
-
Missed backslash
- 2121. By Zoltan Balogh
-
Restructure i18n API implementation for non Ubuntu platforms
Preview Diff
1 | === modified file 'src/UbuntuToolkit/UbuntuToolkit.pro' |
2 | --- src/UbuntuToolkit/UbuntuToolkit.pro 2016-09-12 14:56:56 +0000 |
3 | +++ src/UbuntuToolkit/UbuntuToolkit.pro 2016-09-22 08:32:15 +0000 |
4 | @@ -2,7 +2,7 @@ |
5 | QT = core-private gui-private qml-private quick-private testlib dbus svg organizer \ |
6 | UbuntuGestures-private UbuntuMetrics |
7 | |
8 | -unix { |
9 | +linux { |
10 | CONFIG += link_pkgconfig |
11 | PKGCONFIG += gio-2.0 dbus-1 libnih libnih-dbus |
12 | } |
13 | @@ -142,7 +142,6 @@ |
14 | $$PWD/colorutils.cpp \ |
15 | $$PWD/exclusivegroup.cpp \ |
16 | $$PWD/filterbehavior.cpp \ |
17 | - $$PWD/i18n.cpp \ |
18 | $$PWD/inversemouseareatype.cpp \ |
19 | $$PWD/listener.cpp \ |
20 | $$PWD/livetimer.cpp \ |
21 | @@ -237,4 +236,22 @@ |
22 | $$PWD/privates/shaders/frame.vert \ |
23 | $$PWD/privates/shaders/frame.frag |
24 | |
25 | +macx { |
26 | + # OSX and iOS specific |
27 | + SOURCES += \ |
28 | + $$PWD/i18n-osx.cpp |
29 | +} else:android { |
30 | + # Android specific |
31 | + SOURCES += \ |
32 | + $$PWD/i18n-android.cpp |
33 | +} else:windows { |
34 | + # Windows specific |
35 | + SOURCES += \ |
36 | + $$PWD/i18n-windows.cpp |
37 | +} else { |
38 | + # Ubuntu specific |
39 | + SOURCES += \ |
40 | + $$PWD/i18n-ubuntu.cpp |
41 | +} |
42 | + |
43 | load(ubuntu_qt_module) |
44 | |
45 | === added file 'src/UbuntuToolkit/i18n-android.cpp' |
46 | --- src/UbuntuToolkit/i18n-android.cpp 1970-01-01 00:00:00 +0000 |
47 | +++ src/UbuntuToolkit/i18n-android.cpp 2016-09-22 08:32:15 +0000 |
48 | @@ -0,0 +1,365 @@ |
49 | +/* |
50 | + * Copyright 2012-2015 Canonical Ltd. |
51 | + * |
52 | + * This program is free software; you can redistribute it and/or modify |
53 | + * it under the terms of the GNU Lesser General Public License as published by |
54 | + * the Free Software Foundation; version 3. |
55 | + * |
56 | + * This program is distributed in the hope that it will be useful, |
57 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
58 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
59 | + * GNU Lesser General Public License for more details. |
60 | + * |
61 | + * You should have received a copy of the GNU Lesser General Public License |
62 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
63 | + * |
64 | + * Author: Tim Peeters <tim.peeters@canonical.om> |
65 | + */ |
66 | + |
67 | +#include "i18n_p.h" |
68 | + |
69 | +namespace C { |
70 | +#include <libintl.h> |
71 | +#include <glib.h> |
72 | +#include <glib/gi18n.h> |
73 | +} |
74 | +#include <stdlib.h> |
75 | +#include <locale.h> |
76 | + |
77 | +#include <QtCore/QDir> |
78 | + |
79 | +#include "timeutils_p.h" |
80 | + |
81 | +UT_NAMESPACE_BEGIN |
82 | +/*! |
83 | + * \qmltype i18n |
84 | + * \inqmlmodule Ubuntu.Components |
85 | + * \ingroup ubuntu |
86 | + * \brief i18n is a context property that provides internationalization support. |
87 | + * |
88 | + * i18n cannot be instantiated, and is already available as a context property. |
89 | + * It is based on \l {https://www.gnu.org/software/gettext/} {gettext}, and thus the standard gettext tools can be used for translating |
90 | + * a project. Example: |
91 | + * \qml |
92 | + * import QtQuick 2.4 |
93 | + * import Ubuntu.Components 0.1 |
94 | + * |
95 | + * Item { |
96 | + * width: units.gu(40) |
97 | + * height: units.gu(50) |
98 | + * |
99 | + * Button { |
100 | + * anchors.centerIn: parent |
101 | + * text: i18n.tr("Press me") |
102 | + * } |
103 | + * } |
104 | + * \endqml |
105 | + */ |
106 | +UbuntuI18n *UbuntuI18n::m_i18 = nullptr; |
107 | + |
108 | +UbuntuI18n::UbuntuI18n(QObject* parent) : QObject(parent) |
109 | +{ |
110 | + /* |
111 | + * setlocale |
112 | + * category = LC_ALL: All types of i18n: LC_MESSAGES, LC_NUMERIC, LC_TIME |
113 | + * locale = "": Lookup the environment for $LC_ALL, $LC_* and $LANG in that order |
114 | + * Returns: for example en_US.utf8, da_DK or POSIX |
115 | + * |
116 | + * Note: $LANGUAGE is implicitly respected by gettext() calls and |
117 | + * defines the order of multiple locales |
118 | + */ |
119 | + m_language = QString::fromLocal8Bit(setlocale(LC_ALL, "")); |
120 | +} |
121 | + |
122 | +UbuntuI18n::~UbuntuI18n() |
123 | +{ |
124 | + m_i18 = nullptr; |
125 | +} |
126 | + |
127 | +/*! |
128 | + * \qmlproperty string i18n::domain |
129 | + * The gettext domain to be used for the translation. The default domain |
130 | + * is the applicationName specified in the application's \l MainView, or the empty string "" if |
131 | + * no applicationName was given or no \l MainView is used. |
132 | + * Use dtr() functions instead of tr() to use a different domain for a single translation |
133 | + * that ignores i18n.domain. |
134 | + */ |
135 | +QString UbuntuI18n::domain() const { |
136 | + return m_domain; |
137 | +} |
138 | + |
139 | +/*! |
140 | + * \qmlproperty string i18n::language |
141 | + * The language that is used for the translation. The default value is |
142 | + * the user's locale dending on $LC_ALL, $LC_MESSAGES and $LANG at the time |
143 | + * of running the application. See the gettext manual for details. |
144 | + */ |
145 | +QString UbuntuI18n::language() const { |
146 | + return m_language; |
147 | +} |
148 | + |
149 | +/** |
150 | + * \qmlmethod void i18n::bindtextdomain(string domain_name, string dir_name) |
151 | + * Specify that the domain_name message catalog can be found |
152 | + * in dir_name rather than in the system locale data base. |
153 | + */ |
154 | +void UbuntuI18n::bindtextdomain(const QString& domain_name, const QString& dir_name) { |
155 | + C::bindtextdomain(domain_name.toUtf8(), dir_name.toUtf8()); |
156 | + Q_EMIT domainChanged(); |
157 | +} |
158 | + |
159 | +void UbuntuI18n::setDomain(const QString &domain) { |
160 | + if (m_domain == domain) |
161 | + return; |
162 | + |
163 | + m_domain = domain; |
164 | + C::textdomain(domain.toUtf8()); |
165 | + /* |
166 | + The default is /usr/share/locale if we don't set a folder |
167 | + For click we use APP_DIR/share/locale |
168 | + e.g. /usr/share/click/preinstalled/com.example.foo/current/share/locale |
169 | + */ |
170 | + QString appDir = QString::fromLocal8Bit(getenv("APP_DIR")); |
171 | + if (!QDir::isAbsolutePath (appDir)) { |
172 | + appDir = QStringLiteral("/usr"); |
173 | + } |
174 | + QString localePath(QDir(appDir).filePath(QStringLiteral("share/locale"))); |
175 | + C::bindtextdomain(domain.toUtf8(), localePath.toUtf8()); |
176 | + Q_EMIT domainChanged(); |
177 | +} |
178 | + |
179 | +void UbuntuI18n::setLanguage(const QString &lang) { |
180 | + if (m_language == lang) |
181 | + return; |
182 | + |
183 | + m_language = lang; |
184 | + |
185 | + /* |
186 | + This is needed for LP: #1263163. |
187 | + |
188 | + LANGUAGE may be set to one or more languages for example "fi" or |
189 | + "sv:de". gettext prioritizes LANGUAGE over LC_ALL, LC_*, and |
190 | + LANG, so if the session has already set LANGUAGE, calls to |
191 | + gettext will only use that. We must override it here so that |
192 | + future calls to gettext are done in the new language. |
193 | + |
194 | + This only affects the current process. It does not override the |
195 | + user's session LANGUAGE. |
196 | + */ |
197 | + setenv("LANGUAGE", lang.toUtf8().constData(), 1); |
198 | + |
199 | + /* |
200 | + The inverse form of setlocale as used in the constructor, passing |
201 | + a valid locale string updates all category type defaults. |
202 | + */ |
203 | + setlocale(LC_ALL, lang.toUtf8()); |
204 | + Q_EMIT languageChanged(); |
205 | +} |
206 | + |
207 | +/*! |
208 | + * \qmlmethod string i18n::tr(string text) |
209 | + * Translate \a text using gettext and return the translation. |
210 | + */ |
211 | +QString UbuntuI18n::tr(const QString& text) |
212 | +{ |
213 | + return QString::fromUtf8(C::gettext(text.toUtf8())); |
214 | +} |
215 | + |
216 | +/*! |
217 | + * \qmlmethod string i18n::tr(string singular, string plural, int n) |
218 | + * Translate the given input string \a singular or \a plural (depending on the number of items \a n) |
219 | + * using gettext. |
220 | + * Note that tr() does not automatically insert the values in the QString, |
221 | + * so it should be called like this: |
222 | + * tr("%1 file", "%1 files", count).arg(count) |
223 | + */ |
224 | +QString UbuntuI18n::tr(const QString &singular, const QString &plural, int n) |
225 | +{ |
226 | + return QString::fromUtf8(C::ngettext(singular.toUtf8(), plural.toUtf8(), n)); |
227 | +} |
228 | + |
229 | +/*! |
230 | + * \qmlmethod string i18n::dtr(string domain, string text) |
231 | + * Translate \a text using gettext. Uses the specified domain \a domain instead of i18n.domain. |
232 | + */ |
233 | +QString UbuntuI18n::dtr(const QString& domain, const QString& text) |
234 | +{ |
235 | + if (domain.isNull()) { |
236 | + return QString::fromUtf8(C::dgettext(NULL, text.toUtf8())); |
237 | + } else { |
238 | + return QString::fromUtf8(C::dgettext(domain.toUtf8(), text.toUtf8())); |
239 | + } |
240 | +} |
241 | + |
242 | +/*! |
243 | + * \qmlmethod string i18n::dtr(string domain, string singular, string plural, int n) |
244 | + * Translate the given text using gettext. Should be called like this: |
245 | + * tr(domain, "%1 file", "%1 files", count).arg(count) |
246 | + * Uses \a domain for the domain instead of i18n.domain, and \a singular or \a plural |
247 | + * as input for the translation depending on the number of items \a n. |
248 | + */ |
249 | +QString UbuntuI18n::dtr(const QString& domain, const QString& singular, const QString& plural, int n) |
250 | +{ |
251 | + if (domain.isNull()) { |
252 | + return QString::fromUtf8(C::dngettext(NULL, singular.toUtf8(), plural.toUtf8(), n)); |
253 | + } else { |
254 | + return QString::fromUtf8(C::dngettext(domain.toUtf8(), singular.toUtf8(), plural.toUtf8(), n)); |
255 | + } |
256 | +} |
257 | + |
258 | +/*! |
259 | + * \qmlmethod string i18n::ctr(string context, string text) |
260 | + * Translate \a text using gettext and return the translation. |
261 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
262 | + */ |
263 | +QString UbuntuI18n::ctr(const QString& context, const QString& text) |
264 | +{ |
265 | + return dctr(QString(), context, text); |
266 | +} |
267 | + |
268 | +/*! |
269 | + * \qmlmethod string i18n::dctr(string domain, string context, string text) |
270 | + * Translate \a text using gettext. Uses the specified domain \a domain instead of i18n.domain. |
271 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
272 | + */ |
273 | +QString UbuntuI18n::dctr(const QString& domain, const QString& context, const QString& text) |
274 | +{ |
275 | + if (domain.isNull()) { |
276 | + return QString::fromUtf8(C::g_dpgettext2(NULL, context.toUtf8(), text.toUtf8())); |
277 | + } else { |
278 | + return QString::fromUtf8(C::g_dpgettext2(domain.toUtf8(), context.toUtf8(), text.toUtf8())); |
279 | + } |
280 | +} |
281 | + |
282 | +/*! |
283 | + * \qmlmethod string i18n::tag(string text) |
284 | + * Mark \a text for translation at a later point. Typically this allows an API |
285 | + * to take the original string and pass it to dtr (or dgettext). |
286 | + * |
287 | + * \qml |
288 | + * import QtQuick 2.4 |
289 | + * import UserMetrics 0.1 |
290 | + * |
291 | + * Metric { |
292 | + * name: "distance" |
293 | + * format: i18n.tag("Distance covered today: %1 km") |
294 | + * emptyFormat: i18n.tag("No running today") |
295 | + * domain: "runner.forest" |
296 | + * } |
297 | + * \endqml |
298 | + * |
299 | + * The strings tagged for localzation above are passed to the implementation |
300 | + * of UserMetrics verbatim, as well as the domain of the app. Display and |
301 | + * translation of the strings will happen in the lockscreen, where the same |
302 | + * strings will be passed to i18n.tr. |
303 | + */ |
304 | +QString UbuntuI18n::tag(const QString& text) |
305 | +{ |
306 | + return text; |
307 | +} |
308 | + |
309 | +/*! |
310 | + * \qmlmethod string i18n::tag(string context, string text) |
311 | + * Mark \a text for translation at a later point. Typically this allows an API |
312 | + * to take the original string and pass it to dctr (or g_dpgettext2). |
313 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
314 | + */ |
315 | +QString UbuntuI18n::tag(const QString& context, const QString& text) |
316 | +{ |
317 | + Q_UNUSED(context); |
318 | + return text; |
319 | +} |
320 | +/*! |
321 | + * \qmlmethod string i18n::relativeDateTime(datetime dateTime) |
322 | + * Translate a datetime based on proximity to current time. |
323 | + */ |
324 | +QString UbuntuI18n::relativeDateTime(const QDateTime& datetime) |
325 | +{ |
326 | + static const QString ubuntuUiToolkit = QStringLiteral("ubuntu-ui-toolkit"); |
327 | + |
328 | + QDateTime relativeTo(QDateTime::currentDateTime()); |
329 | + const date_proximity_t prox = getDateProximity(relativeTo, datetime); |
330 | + |
331 | + switch (prox) { |
332 | + case DATE_PROXIMITY_NOW: |
333 | + /* TRANSLATORS: Time based "this is happening/happened now" */ |
334 | + return dtr(ubuntuUiToolkit, QStringLiteral("Now")); |
335 | + |
336 | + case DATE_PROXIMITY_HOUR: |
337 | + { |
338 | + qint64 diff = datetime.toMSecsSinceEpoch() - relativeTo.toMSecsSinceEpoch(); |
339 | + qint64 minutes = qRound(float(diff) / 60000); |
340 | + if (minutes < 0) { |
341 | + return dtr(ubuntuUiToolkit, QStringLiteral("%1 minute ago"), |
342 | + QStringLiteral("%1 minutes ago"), qAbs(minutes)).arg(qAbs(minutes)); |
343 | + } |
344 | + return dtr(ubuntuUiToolkit, QStringLiteral("%1 minute"), |
345 | + QStringLiteral("%1 minutes"), minutes).arg(minutes); |
346 | + } |
347 | + |
348 | + case DATE_PROXIMITY_TODAY: |
349 | + /* en_US example: "1:00 PM" */ |
350 | + /* TRANSLATORS: Please translate these to your locale datetime |
351 | + format using the format specified by |
352 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
353 | + return datetime.toString(isLocale12h() |
354 | + ? dtr(ubuntuUiToolkit, QStringLiteral("h:mm ap")) |
355 | + /* TRANSLATORS: Please translate these to your locale datetime |
356 | + format using the format specified by |
357 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
358 | + : dtr(ubuntuUiToolkit, QStringLiteral("HH:mm"))); |
359 | + |
360 | + case DATE_PROXIMITY_YESTERDAY: |
361 | + /* en_US example: "Yesterday 13:00" */ |
362 | + /* TRANSLATORS: Please translate these to your locale datetime |
363 | + format using the format specified by |
364 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
365 | + return datetime.toString(isLocale12h() |
366 | + ? dtr(ubuntuUiToolkit, QStringLiteral("'Yesterday\u2003'h:mm ap")) |
367 | + /* TRANSLATORS: Please translate these to your locale datetime |
368 | + format using the format specified by |
369 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
370 | + : dtr(ubuntuUiToolkit, QStringLiteral("'Yesterday\u2003'HH:mm"))); |
371 | + |
372 | + case DATE_PROXIMITY_TOMORROW: |
373 | + /* en_US example: "Tomorrow 1:00 PM" */ |
374 | + /* TRANSLATORS: Please translate these to your locale datetime |
375 | + format using the format specified by |
376 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
377 | + return datetime.toString(isLocale12h() |
378 | + ? dtr(ubuntuUiToolkit, QStringLiteral("'Tomorrow\u2003'h:mm ap")) |
379 | + /* TRANSLATORS: Please translate these to your locale datetime |
380 | + format using the format specified by |
381 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
382 | + : dtr(ubuntuUiToolkit, QStringLiteral("'Tomorrow\u2003'HH:mm"))); |
383 | + |
384 | + case DATE_PROXIMITY_LAST_WEEK: |
385 | + case DATE_PROXIMITY_NEXT_WEEK: |
386 | + /* en_US example: "Fri 1:00 PM" */ |
387 | + /* TRANSLATORS: Please translate these to your locale datetime |
388 | + format using the format specified by |
389 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
390 | + return datetime.toString(isLocale12h() |
391 | + ? dtr(ubuntuUiToolkit, QStringLiteral("ddd'\u2003'h:mm ap")) |
392 | + /* TRANSLATORS: Please translate these to your locale datetime |
393 | + format using the format specified by |
394 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
395 | + : dtr(ubuntuUiToolkit, QStringLiteral("ddd'\u2003'HH:mm"))); |
396 | + |
397 | + case DATE_PROXIMITY_FAR_BACK: |
398 | + case DATE_PROXIMITY_FAR_FORWARD: |
399 | + default: |
400 | + /* TRANSLATORS: Please translate these to your locale datetime |
401 | + format using the format specified by |
402 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
403 | + return datetime.toString(isLocale12h() |
404 | + ? dtr(ubuntuUiToolkit, QStringLiteral("ddd d MMM'\u2003'h:mm ap")) |
405 | + /* TRANSLATORS: Please translate these to your locale datetime |
406 | + format using the format specified by |
407 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
408 | + : dtr(ubuntuUiToolkit, QStringLiteral("ddd d MMM'\u2003'HH:mm"))); |
409 | + } |
410 | + return datetime.toString(Qt::DefaultLocaleShortDate); |
411 | +} |
412 | + |
413 | +UT_NAMESPACE_END |
414 | |
415 | === added file 'src/UbuntuToolkit/i18n-macx.cpp' |
416 | --- src/UbuntuToolkit/i18n-macx.cpp 1970-01-01 00:00:00 +0000 |
417 | +++ src/UbuntuToolkit/i18n-macx.cpp 2016-09-22 08:32:15 +0000 |
418 | @@ -0,0 +1,365 @@ |
419 | +/* |
420 | + * Copyright 2012-2015 Canonical Ltd. |
421 | + * |
422 | + * This program is free software; you can redistribute it and/or modify |
423 | + * it under the terms of the GNU Lesser General Public License as published by |
424 | + * the Free Software Foundation; version 3. |
425 | + * |
426 | + * This program is distributed in the hope that it will be useful, |
427 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
428 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
429 | + * GNU Lesser General Public License for more details. |
430 | + * |
431 | + * You should have received a copy of the GNU Lesser General Public License |
432 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
433 | + * |
434 | + * Author: Tim Peeters <tim.peeters@canonical.om> |
435 | + */ |
436 | + |
437 | +#include "i18n_p.h" |
438 | + |
439 | +namespace C { |
440 | +#include <libintl.h> |
441 | +#include <glib.h> |
442 | +#include <glib/gi18n.h> |
443 | +} |
444 | +#include <stdlib.h> |
445 | +#include <locale.h> |
446 | + |
447 | +#include <QtCore/QDir> |
448 | + |
449 | +#include "timeutils_p.h" |
450 | + |
451 | +UT_NAMESPACE_BEGIN |
452 | +/*! |
453 | + * \qmltype i18n |
454 | + * \inqmlmodule Ubuntu.Components |
455 | + * \ingroup ubuntu |
456 | + * \brief i18n is a context property that provides internationalization support. |
457 | + * |
458 | + * i18n cannot be instantiated, and is already available as a context property. |
459 | + * It is based on \l {https://www.gnu.org/software/gettext/} {gettext}, and thus the standard gettext tools can be used for translating |
460 | + * a project. Example: |
461 | + * \qml |
462 | + * import QtQuick 2.4 |
463 | + * import Ubuntu.Components 0.1 |
464 | + * |
465 | + * Item { |
466 | + * width: units.gu(40) |
467 | + * height: units.gu(50) |
468 | + * |
469 | + * Button { |
470 | + * anchors.centerIn: parent |
471 | + * text: i18n.tr("Press me") |
472 | + * } |
473 | + * } |
474 | + * \endqml |
475 | + */ |
476 | +UbuntuI18n *UbuntuI18n::m_i18 = nullptr; |
477 | + |
478 | +UbuntuI18n::UbuntuI18n(QObject* parent) : QObject(parent) |
479 | +{ |
480 | + /* |
481 | + * setlocale |
482 | + * category = LC_ALL: All types of i18n: LC_MESSAGES, LC_NUMERIC, LC_TIME |
483 | + * locale = "": Lookup the environment for $LC_ALL, $LC_* and $LANG in that order |
484 | + * Returns: for example en_US.utf8, da_DK or POSIX |
485 | + * |
486 | + * Note: $LANGUAGE is implicitly respected by gettext() calls and |
487 | + * defines the order of multiple locales |
488 | + */ |
489 | + m_language = QString::fromLocal8Bit(setlocale(LC_ALL, "")); |
490 | +} |
491 | + |
492 | +UbuntuI18n::~UbuntuI18n() |
493 | +{ |
494 | + m_i18 = nullptr; |
495 | +} |
496 | + |
497 | +/*! |
498 | + * \qmlproperty string i18n::domain |
499 | + * The gettext domain to be used for the translation. The default domain |
500 | + * is the applicationName specified in the application's \l MainView, or the empty string "" if |
501 | + * no applicationName was given or no \l MainView is used. |
502 | + * Use dtr() functions instead of tr() to use a different domain for a single translation |
503 | + * that ignores i18n.domain. |
504 | + */ |
505 | +QString UbuntuI18n::domain() const { |
506 | + return m_domain; |
507 | +} |
508 | + |
509 | +/*! |
510 | + * \qmlproperty string i18n::language |
511 | + * The language that is used for the translation. The default value is |
512 | + * the user's locale dending on $LC_ALL, $LC_MESSAGES and $LANG at the time |
513 | + * of running the application. See the gettext manual for details. |
514 | + */ |
515 | +QString UbuntuI18n::language() const { |
516 | + return m_language; |
517 | +} |
518 | + |
519 | +/** |
520 | + * \qmlmethod void i18n::bindtextdomain(string domain_name, string dir_name) |
521 | + * Specify that the domain_name message catalog can be found |
522 | + * in dir_name rather than in the system locale data base. |
523 | + */ |
524 | +void UbuntuI18n::bindtextdomain(const QString& domain_name, const QString& dir_name) { |
525 | + C::bindtextdomain(domain_name.toUtf8(), dir_name.toUtf8()); |
526 | + Q_EMIT domainChanged(); |
527 | +} |
528 | + |
529 | +void UbuntuI18n::setDomain(const QString &domain) { |
530 | + if (m_domain == domain) |
531 | + return; |
532 | + |
533 | + m_domain = domain; |
534 | + C::textdomain(domain.toUtf8()); |
535 | + /* |
536 | + The default is /usr/share/locale if we don't set a folder |
537 | + For click we use APP_DIR/share/locale |
538 | + e.g. /usr/share/click/preinstalled/com.example.foo/current/share/locale |
539 | + */ |
540 | + QString appDir = QString::fromLocal8Bit(getenv("APP_DIR")); |
541 | + if (!QDir::isAbsolutePath (appDir)) { |
542 | + appDir = QStringLiteral("/usr"); |
543 | + } |
544 | + QString localePath(QDir(appDir).filePath(QStringLiteral("share/locale"))); |
545 | + C::bindtextdomain(domain.toUtf8(), localePath.toUtf8()); |
546 | + Q_EMIT domainChanged(); |
547 | +} |
548 | + |
549 | +void UbuntuI18n::setLanguage(const QString &lang) { |
550 | + if (m_language == lang) |
551 | + return; |
552 | + |
553 | + m_language = lang; |
554 | + |
555 | + /* |
556 | + This is needed for LP: #1263163. |
557 | + |
558 | + LANGUAGE may be set to one or more languages for example "fi" or |
559 | + "sv:de". gettext prioritizes LANGUAGE over LC_ALL, LC_*, and |
560 | + LANG, so if the session has already set LANGUAGE, calls to |
561 | + gettext will only use that. We must override it here so that |
562 | + future calls to gettext are done in the new language. |
563 | + |
564 | + This only affects the current process. It does not override the |
565 | + user's session LANGUAGE. |
566 | + */ |
567 | + setenv("LANGUAGE", lang.toUtf8().constData(), 1); |
568 | + |
569 | + /* |
570 | + The inverse form of setlocale as used in the constructor, passing |
571 | + a valid locale string updates all category type defaults. |
572 | + */ |
573 | + setlocale(LC_ALL, lang.toUtf8()); |
574 | + Q_EMIT languageChanged(); |
575 | +} |
576 | + |
577 | +/*! |
578 | + * \qmlmethod string i18n::tr(string text) |
579 | + * Translate \a text using gettext and return the translation. |
580 | + */ |
581 | +QString UbuntuI18n::tr(const QString& text) |
582 | +{ |
583 | + return QString::fromUtf8(C::gettext(text.toUtf8())); |
584 | +} |
585 | + |
586 | +/*! |
587 | + * \qmlmethod string i18n::tr(string singular, string plural, int n) |
588 | + * Translate the given input string \a singular or \a plural (depending on the number of items \a n) |
589 | + * using gettext. |
590 | + * Note that tr() does not automatically insert the values in the QString, |
591 | + * so it should be called like this: |
592 | + * tr("%1 file", "%1 files", count).arg(count) |
593 | + */ |
594 | +QString UbuntuI18n::tr(const QString &singular, const QString &plural, int n) |
595 | +{ |
596 | + return QString::fromUtf8(C::ngettext(singular.toUtf8(), plural.toUtf8(), n)); |
597 | +} |
598 | + |
599 | +/*! |
600 | + * \qmlmethod string i18n::dtr(string domain, string text) |
601 | + * Translate \a text using gettext. Uses the specified domain \a domain instead of i18n.domain. |
602 | + */ |
603 | +QString UbuntuI18n::dtr(const QString& domain, const QString& text) |
604 | +{ |
605 | + if (domain.isNull()) { |
606 | + return QString::fromUtf8(C::dgettext(NULL, text.toUtf8())); |
607 | + } else { |
608 | + return QString::fromUtf8(C::dgettext(domain.toUtf8(), text.toUtf8())); |
609 | + } |
610 | +} |
611 | + |
612 | +/*! |
613 | + * \qmlmethod string i18n::dtr(string domain, string singular, string plural, int n) |
614 | + * Translate the given text using gettext. Should be called like this: |
615 | + * tr(domain, "%1 file", "%1 files", count).arg(count) |
616 | + * Uses \a domain for the domain instead of i18n.domain, and \a singular or \a plural |
617 | + * as input for the translation depending on the number of items \a n. |
618 | + */ |
619 | +QString UbuntuI18n::dtr(const QString& domain, const QString& singular, const QString& plural, int n) |
620 | +{ |
621 | + if (domain.isNull()) { |
622 | + return QString::fromUtf8(C::dngettext(NULL, singular.toUtf8(), plural.toUtf8(), n)); |
623 | + } else { |
624 | + return QString::fromUtf8(C::dngettext(domain.toUtf8(), singular.toUtf8(), plural.toUtf8(), n)); |
625 | + } |
626 | +} |
627 | + |
628 | +/*! |
629 | + * \qmlmethod string i18n::ctr(string context, string text) |
630 | + * Translate \a text using gettext and return the translation. |
631 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
632 | + */ |
633 | +QString UbuntuI18n::ctr(const QString& context, const QString& text) |
634 | +{ |
635 | + return dctr(QString(), context, text); |
636 | +} |
637 | + |
638 | +/*! |
639 | + * \qmlmethod string i18n::dctr(string domain, string context, string text) |
640 | + * Translate \a text using gettext. Uses the specified domain \a domain instead of i18n.domain. |
641 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
642 | + */ |
643 | +QString UbuntuI18n::dctr(const QString& domain, const QString& context, const QString& text) |
644 | +{ |
645 | + if (domain.isNull()) { |
646 | + return QString::fromUtf8(C::g_dpgettext2(NULL, context.toUtf8(), text.toUtf8())); |
647 | + } else { |
648 | + return QString::fromUtf8(C::g_dpgettext2(domain.toUtf8(), context.toUtf8(), text.toUtf8())); |
649 | + } |
650 | +} |
651 | + |
652 | +/*! |
653 | + * \qmlmethod string i18n::tag(string text) |
654 | + * Mark \a text for translation at a later point. Typically this allows an API |
655 | + * to take the original string and pass it to dtr (or dgettext). |
656 | + * |
657 | + * \qml |
658 | + * import QtQuick 2.4 |
659 | + * import UserMetrics 0.1 |
660 | + * |
661 | + * Metric { |
662 | + * name: "distance" |
663 | + * format: i18n.tag("Distance covered today: %1 km") |
664 | + * emptyFormat: i18n.tag("No running today") |
665 | + * domain: "runner.forest" |
666 | + * } |
667 | + * \endqml |
668 | + * |
669 | + * The strings tagged for localzation above are passed to the implementation |
670 | + * of UserMetrics verbatim, as well as the domain of the app. Display and |
671 | + * translation of the strings will happen in the lockscreen, where the same |
672 | + * strings will be passed to i18n.tr. |
673 | + */ |
674 | +QString UbuntuI18n::tag(const QString& text) |
675 | +{ |
676 | + return text; |
677 | +} |
678 | + |
679 | +/*! |
680 | + * \qmlmethod string i18n::tag(string context, string text) |
681 | + * Mark \a text for translation at a later point. Typically this allows an API |
682 | + * to take the original string and pass it to dctr (or g_dpgettext2). |
683 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
684 | + */ |
685 | +QString UbuntuI18n::tag(const QString& context, const QString& text) |
686 | +{ |
687 | + Q_UNUSED(context); |
688 | + return text; |
689 | +} |
690 | +/*! |
691 | + * \qmlmethod string i18n::relativeDateTime(datetime dateTime) |
692 | + * Translate a datetime based on proximity to current time. |
693 | + */ |
694 | +QString UbuntuI18n::relativeDateTime(const QDateTime& datetime) |
695 | +{ |
696 | + static const QString ubuntuUiToolkit = QStringLiteral("ubuntu-ui-toolkit"); |
697 | + |
698 | + QDateTime relativeTo(QDateTime::currentDateTime()); |
699 | + const date_proximity_t prox = getDateProximity(relativeTo, datetime); |
700 | + |
701 | + switch (prox) { |
702 | + case DATE_PROXIMITY_NOW: |
703 | + /* TRANSLATORS: Time based "this is happening/happened now" */ |
704 | + return dtr(ubuntuUiToolkit, QStringLiteral("Now")); |
705 | + |
706 | + case DATE_PROXIMITY_HOUR: |
707 | + { |
708 | + qint64 diff = datetime.toMSecsSinceEpoch() - relativeTo.toMSecsSinceEpoch(); |
709 | + qint64 minutes = qRound(float(diff) / 60000); |
710 | + if (minutes < 0) { |
711 | + return dtr(ubuntuUiToolkit, QStringLiteral("%1 minute ago"), |
712 | + QStringLiteral("%1 minutes ago"), qAbs(minutes)).arg(qAbs(minutes)); |
713 | + } |
714 | + return dtr(ubuntuUiToolkit, QStringLiteral("%1 minute"), |
715 | + QStringLiteral("%1 minutes"), minutes).arg(minutes); |
716 | + } |
717 | + |
718 | + case DATE_PROXIMITY_TODAY: |
719 | + /* en_US example: "1:00 PM" */ |
720 | + /* TRANSLATORS: Please translate these to your locale datetime |
721 | + format using the format specified by |
722 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
723 | + return datetime.toString(isLocale12h() |
724 | + ? dtr(ubuntuUiToolkit, QStringLiteral("h:mm ap")) |
725 | + /* TRANSLATORS: Please translate these to your locale datetime |
726 | + format using the format specified by |
727 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
728 | + : dtr(ubuntuUiToolkit, QStringLiteral("HH:mm"))); |
729 | + |
730 | + case DATE_PROXIMITY_YESTERDAY: |
731 | + /* en_US example: "Yesterday 13:00" */ |
732 | + /* TRANSLATORS: Please translate these to your locale datetime |
733 | + format using the format specified by |
734 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
735 | + return datetime.toString(isLocale12h() |
736 | + ? dtr(ubuntuUiToolkit, QStringLiteral("'Yesterday\u2003'h:mm ap")) |
737 | + /* TRANSLATORS: Please translate these to your locale datetime |
738 | + format using the format specified by |
739 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
740 | + : dtr(ubuntuUiToolkit, QStringLiteral("'Yesterday\u2003'HH:mm"))); |
741 | + |
742 | + case DATE_PROXIMITY_TOMORROW: |
743 | + /* en_US example: "Tomorrow 1:00 PM" */ |
744 | + /* TRANSLATORS: Please translate these to your locale datetime |
745 | + format using the format specified by |
746 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
747 | + return datetime.toString(isLocale12h() |
748 | + ? dtr(ubuntuUiToolkit, QStringLiteral("'Tomorrow\u2003'h:mm ap")) |
749 | + /* TRANSLATORS: Please translate these to your locale datetime |
750 | + format using the format specified by |
751 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
752 | + : dtr(ubuntuUiToolkit, QStringLiteral("'Tomorrow\u2003'HH:mm"))); |
753 | + |
754 | + case DATE_PROXIMITY_LAST_WEEK: |
755 | + case DATE_PROXIMITY_NEXT_WEEK: |
756 | + /* en_US example: "Fri 1:00 PM" */ |
757 | + /* TRANSLATORS: Please translate these to your locale datetime |
758 | + format using the format specified by |
759 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
760 | + return datetime.toString(isLocale12h() |
761 | + ? dtr(ubuntuUiToolkit, QStringLiteral("ddd'\u2003'h:mm ap")) |
762 | + /* TRANSLATORS: Please translate these to your locale datetime |
763 | + format using the format specified by |
764 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
765 | + : dtr(ubuntuUiToolkit, QStringLiteral("ddd'\u2003'HH:mm"))); |
766 | + |
767 | + case DATE_PROXIMITY_FAR_BACK: |
768 | + case DATE_PROXIMITY_FAR_FORWARD: |
769 | + default: |
770 | + /* TRANSLATORS: Please translate these to your locale datetime |
771 | + format using the format specified by |
772 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
773 | + return datetime.toString(isLocale12h() |
774 | + ? dtr(ubuntuUiToolkit, QStringLiteral("ddd d MMM'\u2003'h:mm ap")) |
775 | + /* TRANSLATORS: Please translate these to your locale datetime |
776 | + format using the format specified by |
777 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
778 | + : dtr(ubuntuUiToolkit, QStringLiteral("ddd d MMM'\u2003'HH:mm"))); |
779 | + } |
780 | + return datetime.toString(Qt::DefaultLocaleShortDate); |
781 | +} |
782 | + |
783 | +UT_NAMESPACE_END |
784 | |
785 | === renamed file 'src/UbuntuToolkit/i18n.cpp' => 'src/UbuntuToolkit/i18n-ubuntu.cpp' |
786 | === added file 'src/UbuntuToolkit/i18n-windows.cpp' |
787 | --- src/UbuntuToolkit/i18n-windows.cpp 1970-01-01 00:00:00 +0000 |
788 | +++ src/UbuntuToolkit/i18n-windows.cpp 2016-09-22 08:32:15 +0000 |
789 | @@ -0,0 +1,365 @@ |
790 | +/* |
791 | + * Copyright 2012-2015 Canonical Ltd. |
792 | + * |
793 | + * This program is free software; you can redistribute it and/or modify |
794 | + * it under the terms of the GNU Lesser General Public License as published by |
795 | + * the Free Software Foundation; version 3. |
796 | + * |
797 | + * This program is distributed in the hope that it will be useful, |
798 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
799 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
800 | + * GNU Lesser General Public License for more details. |
801 | + * |
802 | + * You should have received a copy of the GNU Lesser General Public License |
803 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
804 | + * |
805 | + * Author: Tim Peeters <tim.peeters@canonical.om> |
806 | + */ |
807 | + |
808 | +#include "i18n_p.h" |
809 | + |
810 | +namespace C { |
811 | +#include <libintl.h> |
812 | +#include <glib.h> |
813 | +#include <glib/gi18n.h> |
814 | +} |
815 | +#include <stdlib.h> |
816 | +#include <locale.h> |
817 | + |
818 | +#include <QtCore/QDir> |
819 | + |
820 | +#include "timeutils_p.h" |
821 | + |
822 | +UT_NAMESPACE_BEGIN |
823 | +/*! |
824 | + * \qmltype i18n |
825 | + * \inqmlmodule Ubuntu.Components |
826 | + * \ingroup ubuntu |
827 | + * \brief i18n is a context property that provides internationalization support. |
828 | + * |
829 | + * i18n cannot be instantiated, and is already available as a context property. |
830 | + * It is based on \l {https://www.gnu.org/software/gettext/} {gettext}, and thus the standard gettext tools can be used for translating |
831 | + * a project. Example: |
832 | + * \qml |
833 | + * import QtQuick 2.4 |
834 | + * import Ubuntu.Components 0.1 |
835 | + * |
836 | + * Item { |
837 | + * width: units.gu(40) |
838 | + * height: units.gu(50) |
839 | + * |
840 | + * Button { |
841 | + * anchors.centerIn: parent |
842 | + * text: i18n.tr("Press me") |
843 | + * } |
844 | + * } |
845 | + * \endqml |
846 | + */ |
847 | +UbuntuI18n *UbuntuI18n::m_i18 = nullptr; |
848 | + |
849 | +UbuntuI18n::UbuntuI18n(QObject* parent) : QObject(parent) |
850 | +{ |
851 | + /* |
852 | + * setlocale |
853 | + * category = LC_ALL: All types of i18n: LC_MESSAGES, LC_NUMERIC, LC_TIME |
854 | + * locale = "": Lookup the environment for $LC_ALL, $LC_* and $LANG in that order |
855 | + * Returns: for example en_US.utf8, da_DK or POSIX |
856 | + * |
857 | + * Note: $LANGUAGE is implicitly respected by gettext() calls and |
858 | + * defines the order of multiple locales |
859 | + */ |
860 | + m_language = QString::fromLocal8Bit(setlocale(LC_ALL, "")); |
861 | +} |
862 | + |
863 | +UbuntuI18n::~UbuntuI18n() |
864 | +{ |
865 | + m_i18 = nullptr; |
866 | +} |
867 | + |
868 | +/*! |
869 | + * \qmlproperty string i18n::domain |
870 | + * The gettext domain to be used for the translation. The default domain |
871 | + * is the applicationName specified in the application's \l MainView, or the empty string "" if |
872 | + * no applicationName was given or no \l MainView is used. |
873 | + * Use dtr() functions instead of tr() to use a different domain for a single translation |
874 | + * that ignores i18n.domain. |
875 | + */ |
876 | +QString UbuntuI18n::domain() const { |
877 | + return m_domain; |
878 | +} |
879 | + |
880 | +/*! |
881 | + * \qmlproperty string i18n::language |
882 | + * The language that is used for the translation. The default value is |
883 | + * the user's locale dending on $LC_ALL, $LC_MESSAGES and $LANG at the time |
884 | + * of running the application. See the gettext manual for details. |
885 | + */ |
886 | +QString UbuntuI18n::language() const { |
887 | + return m_language; |
888 | +} |
889 | + |
890 | +/** |
891 | + * \qmlmethod void i18n::bindtextdomain(string domain_name, string dir_name) |
892 | + * Specify that the domain_name message catalog can be found |
893 | + * in dir_name rather than in the system locale data base. |
894 | + */ |
895 | +void UbuntuI18n::bindtextdomain(const QString& domain_name, const QString& dir_name) { |
896 | + C::bindtextdomain(domain_name.toUtf8(), dir_name.toUtf8()); |
897 | + Q_EMIT domainChanged(); |
898 | +} |
899 | + |
900 | +void UbuntuI18n::setDomain(const QString &domain) { |
901 | + if (m_domain == domain) |
902 | + return; |
903 | + |
904 | + m_domain = domain; |
905 | + C::textdomain(domain.toUtf8()); |
906 | + /* |
907 | + The default is /usr/share/locale if we don't set a folder |
908 | + For click we use APP_DIR/share/locale |
909 | + e.g. /usr/share/click/preinstalled/com.example.foo/current/share/locale |
910 | + */ |
911 | + QString appDir = QString::fromLocal8Bit(getenv("APP_DIR")); |
912 | + if (!QDir::isAbsolutePath (appDir)) { |
913 | + appDir = QStringLiteral("/usr"); |
914 | + } |
915 | + QString localePath(QDir(appDir).filePath(QStringLiteral("share/locale"))); |
916 | + C::bindtextdomain(domain.toUtf8(), localePath.toUtf8()); |
917 | + Q_EMIT domainChanged(); |
918 | +} |
919 | + |
920 | +void UbuntuI18n::setLanguage(const QString &lang) { |
921 | + if (m_language == lang) |
922 | + return; |
923 | + |
924 | + m_language = lang; |
925 | + |
926 | + /* |
927 | + This is needed for LP: #1263163. |
928 | + |
929 | + LANGUAGE may be set to one or more languages for example "fi" or |
930 | + "sv:de". gettext prioritizes LANGUAGE over LC_ALL, LC_*, and |
931 | + LANG, so if the session has already set LANGUAGE, calls to |
932 | + gettext will only use that. We must override it here so that |
933 | + future calls to gettext are done in the new language. |
934 | + |
935 | + This only affects the current process. It does not override the |
936 | + user's session LANGUAGE. |
937 | + */ |
938 | + setenv("LANGUAGE", lang.toUtf8().constData(), 1); |
939 | + |
940 | + /* |
941 | + The inverse form of setlocale as used in the constructor, passing |
942 | + a valid locale string updates all category type defaults. |
943 | + */ |
944 | + setlocale(LC_ALL, lang.toUtf8()); |
945 | + Q_EMIT languageChanged(); |
946 | +} |
947 | + |
948 | +/*! |
949 | + * \qmlmethod string i18n::tr(string text) |
950 | + * Translate \a text using gettext and return the translation. |
951 | + */ |
952 | +QString UbuntuI18n::tr(const QString& text) |
953 | +{ |
954 | + return QString::fromUtf8(C::gettext(text.toUtf8())); |
955 | +} |
956 | + |
957 | +/*! |
958 | + * \qmlmethod string i18n::tr(string singular, string plural, int n) |
959 | + * Translate the given input string \a singular or \a plural (depending on the number of items \a n) |
960 | + * using gettext. |
961 | + * Note that tr() does not automatically insert the values in the QString, |
962 | + * so it should be called like this: |
963 | + * tr("%1 file", "%1 files", count).arg(count) |
964 | + */ |
965 | +QString UbuntuI18n::tr(const QString &singular, const QString &plural, int n) |
966 | +{ |
967 | + return QString::fromUtf8(C::ngettext(singular.toUtf8(), plural.toUtf8(), n)); |
968 | +} |
969 | + |
970 | +/*! |
971 | + * \qmlmethod string i18n::dtr(string domain, string text) |
972 | + * Translate \a text using gettext. Uses the specified domain \a domain instead of i18n.domain. |
973 | + */ |
974 | +QString UbuntuI18n::dtr(const QString& domain, const QString& text) |
975 | +{ |
976 | + if (domain.isNull()) { |
977 | + return QString::fromUtf8(C::dgettext(NULL, text.toUtf8())); |
978 | + } else { |
979 | + return QString::fromUtf8(C::dgettext(domain.toUtf8(), text.toUtf8())); |
980 | + } |
981 | +} |
982 | + |
983 | +/*! |
984 | + * \qmlmethod string i18n::dtr(string domain, string singular, string plural, int n) |
985 | + * Translate the given text using gettext. Should be called like this: |
986 | + * tr(domain, "%1 file", "%1 files", count).arg(count) |
987 | + * Uses \a domain for the domain instead of i18n.domain, and \a singular or \a plural |
988 | + * as input for the translation depending on the number of items \a n. |
989 | + */ |
990 | +QString UbuntuI18n::dtr(const QString& domain, const QString& singular, const QString& plural, int n) |
991 | +{ |
992 | + if (domain.isNull()) { |
993 | + return QString::fromUtf8(C::dngettext(NULL, singular.toUtf8(), plural.toUtf8(), n)); |
994 | + } else { |
995 | + return QString::fromUtf8(C::dngettext(domain.toUtf8(), singular.toUtf8(), plural.toUtf8(), n)); |
996 | + } |
997 | +} |
998 | + |
999 | +/*! |
1000 | + * \qmlmethod string i18n::ctr(string context, string text) |
1001 | + * Translate \a text using gettext and return the translation. |
1002 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
1003 | + */ |
1004 | +QString UbuntuI18n::ctr(const QString& context, const QString& text) |
1005 | +{ |
1006 | + return dctr(QString(), context, text); |
1007 | +} |
1008 | + |
1009 | +/*! |
1010 | + * \qmlmethod string i18n::dctr(string domain, string context, string text) |
1011 | + * Translate \a text using gettext. Uses the specified domain \a domain instead of i18n.domain. |
1012 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
1013 | + */ |
1014 | +QString UbuntuI18n::dctr(const QString& domain, const QString& context, const QString& text) |
1015 | +{ |
1016 | + if (domain.isNull()) { |
1017 | + return QString::fromUtf8(C::g_dpgettext2(NULL, context.toUtf8(), text.toUtf8())); |
1018 | + } else { |
1019 | + return QString::fromUtf8(C::g_dpgettext2(domain.toUtf8(), context.toUtf8(), text.toUtf8())); |
1020 | + } |
1021 | +} |
1022 | + |
1023 | +/*! |
1024 | + * \qmlmethod string i18n::tag(string text) |
1025 | + * Mark \a text for translation at a later point. Typically this allows an API |
1026 | + * to take the original string and pass it to dtr (or dgettext). |
1027 | + * |
1028 | + * \qml |
1029 | + * import QtQuick 2.4 |
1030 | + * import UserMetrics 0.1 |
1031 | + * |
1032 | + * Metric { |
1033 | + * name: "distance" |
1034 | + * format: i18n.tag("Distance covered today: %1 km") |
1035 | + * emptyFormat: i18n.tag("No running today") |
1036 | + * domain: "runner.forest" |
1037 | + * } |
1038 | + * \endqml |
1039 | + * |
1040 | + * The strings tagged for localzation above are passed to the implementation |
1041 | + * of UserMetrics verbatim, as well as the domain of the app. Display and |
1042 | + * translation of the strings will happen in the lockscreen, where the same |
1043 | + * strings will be passed to i18n.tr. |
1044 | + */ |
1045 | +QString UbuntuI18n::tag(const QString& text) |
1046 | +{ |
1047 | + return text; |
1048 | +} |
1049 | + |
1050 | +/*! |
1051 | + * \qmlmethod string i18n::tag(string context, string text) |
1052 | + * Mark \a text for translation at a later point. Typically this allows an API |
1053 | + * to take the original string and pass it to dctr (or g_dpgettext2). |
1054 | + * \a context is only visible to the translator and helps disambiguating for very short texts |
1055 | + */ |
1056 | +QString UbuntuI18n::tag(const QString& context, const QString& text) |
1057 | +{ |
1058 | + Q_UNUSED(context); |
1059 | + return text; |
1060 | +} |
1061 | +/*! |
1062 | + * \qmlmethod string i18n::relativeDateTime(datetime dateTime) |
1063 | + * Translate a datetime based on proximity to current time. |
1064 | + */ |
1065 | +QString UbuntuI18n::relativeDateTime(const QDateTime& datetime) |
1066 | +{ |
1067 | + static const QString ubuntuUiToolkit = QStringLiteral("ubuntu-ui-toolkit"); |
1068 | + |
1069 | + QDateTime relativeTo(QDateTime::currentDateTime()); |
1070 | + const date_proximity_t prox = getDateProximity(relativeTo, datetime); |
1071 | + |
1072 | + switch (prox) { |
1073 | + case DATE_PROXIMITY_NOW: |
1074 | + /* TRANSLATORS: Time based "this is happening/happened now" */ |
1075 | + return dtr(ubuntuUiToolkit, QStringLiteral("Now")); |
1076 | + |
1077 | + case DATE_PROXIMITY_HOUR: |
1078 | + { |
1079 | + qint64 diff = datetime.toMSecsSinceEpoch() - relativeTo.toMSecsSinceEpoch(); |
1080 | + qint64 minutes = qRound(float(diff) / 60000); |
1081 | + if (minutes < 0) { |
1082 | + return dtr(ubuntuUiToolkit, QStringLiteral("%1 minute ago"), |
1083 | + QStringLiteral("%1 minutes ago"), qAbs(minutes)).arg(qAbs(minutes)); |
1084 | + } |
1085 | + return dtr(ubuntuUiToolkit, QStringLiteral("%1 minute"), |
1086 | + QStringLiteral("%1 minutes"), minutes).arg(minutes); |
1087 | + } |
1088 | + |
1089 | + case DATE_PROXIMITY_TODAY: |
1090 | + /* en_US example: "1:00 PM" */ |
1091 | + /* TRANSLATORS: Please translate these to your locale datetime |
1092 | + format using the format specified by |
1093 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1094 | + return datetime.toString(isLocale12h() |
1095 | + ? dtr(ubuntuUiToolkit, QStringLiteral("h:mm ap")) |
1096 | + /* TRANSLATORS: Please translate these to your locale datetime |
1097 | + format using the format specified by |
1098 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1099 | + : dtr(ubuntuUiToolkit, QStringLiteral("HH:mm"))); |
1100 | + |
1101 | + case DATE_PROXIMITY_YESTERDAY: |
1102 | + /* en_US example: "Yesterday 13:00" */ |
1103 | + /* TRANSLATORS: Please translate these to your locale datetime |
1104 | + format using the format specified by |
1105 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1106 | + return datetime.toString(isLocale12h() |
1107 | + ? dtr(ubuntuUiToolkit, QStringLiteral("'Yesterday\u2003'h:mm ap")) |
1108 | + /* TRANSLATORS: Please translate these to your locale datetime |
1109 | + format using the format specified by |
1110 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1111 | + : dtr(ubuntuUiToolkit, QStringLiteral("'Yesterday\u2003'HH:mm"))); |
1112 | + |
1113 | + case DATE_PROXIMITY_TOMORROW: |
1114 | + /* en_US example: "Tomorrow 1:00 PM" */ |
1115 | + /* TRANSLATORS: Please translate these to your locale datetime |
1116 | + format using the format specified by |
1117 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1118 | + return datetime.toString(isLocale12h() |
1119 | + ? dtr(ubuntuUiToolkit, QStringLiteral("'Tomorrow\u2003'h:mm ap")) |
1120 | + /* TRANSLATORS: Please translate these to your locale datetime |
1121 | + format using the format specified by |
1122 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1123 | + : dtr(ubuntuUiToolkit, QStringLiteral("'Tomorrow\u2003'HH:mm"))); |
1124 | + |
1125 | + case DATE_PROXIMITY_LAST_WEEK: |
1126 | + case DATE_PROXIMITY_NEXT_WEEK: |
1127 | + /* en_US example: "Fri 1:00 PM" */ |
1128 | + /* TRANSLATORS: Please translate these to your locale datetime |
1129 | + format using the format specified by |
1130 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1131 | + return datetime.toString(isLocale12h() |
1132 | + ? dtr(ubuntuUiToolkit, QStringLiteral("ddd'\u2003'h:mm ap")) |
1133 | + /* TRANSLATORS: Please translate these to your locale datetime |
1134 | + format using the format specified by |
1135 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1136 | + : dtr(ubuntuUiToolkit, QStringLiteral("ddd'\u2003'HH:mm"))); |
1137 | + |
1138 | + case DATE_PROXIMITY_FAR_BACK: |
1139 | + case DATE_PROXIMITY_FAR_FORWARD: |
1140 | + default: |
1141 | + /* TRANSLATORS: Please translate these to your locale datetime |
1142 | + format using the format specified by |
1143 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1144 | + return datetime.toString(isLocale12h() |
1145 | + ? dtr(ubuntuUiToolkit, QStringLiteral("ddd d MMM'\u2003'h:mm ap")) |
1146 | + /* TRANSLATORS: Please translate these to your locale datetime |
1147 | + format using the format specified by |
1148 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
1149 | + : dtr(ubuntuUiToolkit, QStringLiteral("ddd d MMM'\u2003'HH:mm"))); |
1150 | + } |
1151 | + return datetime.toString(Qt::DefaultLocaleShortDate); |
1152 | +} |
1153 | + |
1154 | +UT_NAMESPACE_END |
FAILED: Continuous integration, rev:2121 /jenkins. ubuntu. com/ubuntu- sdk/job/ ubuntu- ui-toolkit- ci-i386- gles-stable/ 1227/ /jenkins. ubuntu. com/ubuntu- sdk/job/ generic- update- mp/6681/ console
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild: /jenkins. ubuntu. com/ubuntu- sdk/job/ ubuntu- ui-toolkit- ci-i386- gles-stable/ 1227/rebuild
https:/