Merge lp:~dpm/intltool/add-qtdesigner-support into lp:intltool

Proposed by David Planella
Status: Merged
Merged at revision: 744
Proposed branch: lp:~dpm/intltool/add-qtdesigner-support
Merge into: lp:intltool
Diff against target: 392 lines (+306/-1)
7 files modified
doc/intltool-extract.8 (+2/-0)
intltool-extract.in (+73/-1)
tests/cases/Makefile.am (+2/-0)
tests/cases/extract-qtdesigner.ui (+210/-0)
tests/results/Makefile.am (+1/-0)
tests/results/extract-qtdesigner.ui.h (+13/-0)
tests/selftest.pl.in (+5/-0)
To merge this branch: bzr merge lp:~dpm/intltool/add-qtdesigner-support
Reviewer Review Type Date Requested Status
Данило Шеган Approve
Review via email: mp+145112@code.launchpad.net

Description of the change

This branch adds support for extracting translatable strings from Qt Designer files through a new gettext/qtdesigner type (lp:953342).

Notes: the regexp used to extract the strings from the XML attributes of the <string> tag used by Qt .ui files is similar to the one used to extraxt strings from Glade .ui files in the sense that it relies on those tags being present in a particular order.

To post a comment you must log in.
Revision history for this message
Данило Шеган (danilo) wrote :

Btw, at least the doc links are incorrect in intltool-extract.in:

 - http://qt-project.org/doc/qt-5.0/qtlinguist/linguist-ts-file-format.html
 - http://qt-project.org/doc/qt-5.0/qtdesigner/designer-ui-file-format.html

are currently correct links (I assume they have changed since you started work on this).

Btw, I would prefer if the support was done using the real XML parser: that would ensure that a lot more of the XML syntax is supported, and that we don't accidentally break when eg. the order of attributes changes in the XML file.

A good example is type_gsettings/traverse_gsettings functions.

review: Needs Fixing
739. By David Planella

Updated links to Qt translation format specs

740. By David Planella

Updated test case for Qt Designer extraction: no escapes

741. By David Planella

Added Qt Designer .ui file extraction support using the internal XML parser

742. By David Planella

Updated man page with the new gettext/qtdesigner type for extraction

743. By David Planella

Added files for gettext/qtdesigner testcase and result to the corresponding Makefile.am files

Revision history for this message
David Planella (dpm) wrote :

Ok, addressed the two points above and re-submitted MP.

Revision history for this message
Rohan Garg (rohangarg) wrote :

Any ETA when this is going to land? This also fixes bug 1234106 for Kubuntu so it'll be nice to have it land soon.

Revision history for this message
Данило Шеган (danilo) wrote :

Hi David (and other interested parties): sorry for taking this long to take another look at this. It somehow slipped my radar (so thanks everyone for reminding me).

The branch looks pretty good. Since you are also doing special whitespace handling, it would be good to have at least one of the strings in a test case actually demonstrate that. Since I've taken this long to review it, I'll do this myself.

I'll be merging this branch, but I won't be releasing it until we clarify a few other things. I am most worried about the escaping support. One of the examples in the test case is an HTML string, but ideally, that'd be unescaped in PO files (for translators' benefit). Where's the code that actually reads MO files? Is there any good example code for me to check out to see how would everything fit together?

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/intltool-extract.8'
2--- doc/intltool-extract.8 2011-10-08 19:24:23 +0000
3+++ doc/intltool-extract.8 2013-05-10 09:59:25 +0000
4@@ -54,6 +54,8 @@
5 "gettext/scheme" (.scm)
6 .br
7 "gettext/xml" (Generic XML file)
8+.br
9+"gettext/qtdesigner" (Qt Designer .ui files)
10 .IP "\fB\-v\fR" 4
11 .PD 0
12 .IP "\fB\--version\fR" 4
13
14=== modified file 'intltool-extract.in'
15--- intltool-extract.in 2012-08-23 03:39:02 +0000
16+++ intltool-extract.in 2013-05-10 09:59:25 +0000
17@@ -165,7 +165,7 @@
18 "gettext/glade", "gettext/ini", "gettext/keys"
19 "gettext/rfc822deb", "gettext/schemas",
20 "gettext/gsettings", "gettext/xml", "gettext/quoted",
21- "gettext/quotedxml", "gettext/tlk"
22+ "gettext/quotedxml", "gettext/tlk", "gettext/qtdesigner"
23 -l, --local Writes output into current working directory
24 (conflicts with --update)
25 --update Writes output into the same directory the source file
26@@ -225,6 +225,7 @@
27 &type_quoted if $gettext_type eq "quoted";
28 &type_quotedxml if $gettext_type eq "quotedxml";
29 &type_tlk if $gettext_type eq "tlk";
30+ &type_qtdesigner if $gettext_type eq "qtdesigner";
31 }
32
33 sub entity_decode_minimal
34@@ -828,6 +829,77 @@
35 }
36 }
37
38+# Parse the tree as returned by readXml() for Qt Designer .ui files.
39+sub traverse_qtdesigner {
40+ my $nodename = shift;
41+ my $content = shift;
42+ my @list = @{ $content };
43+ my $attrs_ref = shift @list;
44+ my %attrs = %{ $attrs_ref };
45+ if ($nodename eq 'string' and !exists $attrs{"notr"}) {
46+ # Preserve whitespace. Deal with it ourselves, below.
47+ my $message = getXMLstring($content, 1);
48+
49+ # We strip leading and trailing whitespace but
50+ # preserve whitespace within (e.g. newlines)
51+ $message =~ s/^\s+//;
52+ $message =~ s/\s+$//;
53+
54+ my $context = $attrs{'comment'};
55+ # Remove enclosing quotes from msgctxt
56+ $context =~ s/^["'](.*)["']/$1/ if $context;
57+ $message = $context . "\004" . $message if $context;
58+ add_message($message);
59+ my $comment = $attrs{'extracomment'};
60+ # Remove enclosing quotes from developer comments
61+ $comment =~ s/^["'](.*)["']/$1/ if $comment;
62+ $comments{$message} = $comment if $comment;
63+ } else {
64+ my $index = 0;
65+ while (scalar(@list) > 1) {
66+ my $type = shift @list;
67+ my $content = shift @list;
68+ if (!$type || "$type" eq "1") {
69+ next;
70+ } else {
71+ traverse_qtdesigner($type, $content);
72+ }
73+ }
74+ }
75+}
76+
77+sub type_qtdesigner {
78+ ### For translatable Qt Designer XML files ###
79+ #
80+ # Specs:
81+ #
82+ # - http://qt-project.org/doc/qt-5.0/qtlinguist/linguist-ts-file-format.html
83+ # - http://qt-project.org/doc/qt-5.0/qtdesigner/designer-ui-file-format.html
84+ #
85+ # <string> tag attributes:
86+ #
87+ # notr="true" means the string is not translatable
88+ # extracomment maps to a developer comment in gettext
89+ # comment corresponds to "disambiguation" in the Qt Linguist API, and maps
90+ # to msgctxt in gettext
91+ #
92+ # Example:
93+ #
94+ # <string comment="Button" extracomment="TRANSLATORS: refers to the
95+ # action of accepting something">Ok</string>
96+
97+ my $tree = readXml($input);
98+ my @tree_nodes = @{ $tree };
99+ my $node = shift @tree_nodes;
100+ while (!$node || "$node" eq "1") {
101+ shift @tree_nodes;
102+ $node = shift @tree_nodes;
103+ }
104+ my $content = shift @tree_nodes;
105+ traverse_qtdesigner($node, $content);
106+
107+}
108+
109 sub type_glade {
110 ### For translatable Glade XML files ###
111
112
113=== modified file 'tests/cases/Makefile.am'
114--- tests/cases/Makefile.am 2011-10-08 18:08:58 +0000
115+++ tests/cases/Makefile.am 2013-05-10 09:59:25 +0000
116@@ -16,6 +16,7 @@
117 extract8.glade \
118 extract9.po \
119 extract9.xml.in \
120+ extract-qtdesigner.ui \
121 fr.po \
122 fr_BE.po \
123 fr_FR.po \
124@@ -58,6 +59,7 @@
125 extract14.xml.in.h \
126 extract9.xml \
127 extract9.xml.in.h \
128+ extract-qtdesigner.ui.h \
129 gsettings.gschema.xml.h \
130 iso88591text.xml.in.h \
131 merge-cdata.xml \
132
133=== added file 'tests/cases/extract-qtdesigner.ui'
134--- tests/cases/extract-qtdesigner.ui 1970-01-01 00:00:00 +0000
135+++ tests/cases/extract-qtdesigner.ui 2013-05-10 09:59:25 +0000
136@@ -0,0 +1,210 @@
137+<?xml version="1.0" encoding="UTF-8"?>
138+<ui version="4.0">
139+ <class>main</class>
140+ <widget class="QWidget" name="main">
141+ <property name="geometry">
142+ <rect>
143+ <x>0</x>
144+ <y>0</y>
145+ <width>640</width>
146+ <height>457</height>
147+ </rect>
148+ </property>
149+ <property name="sizePolicy">
150+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
151+ <horstretch>0</horstretch>
152+ <verstretch>0</verstretch>
153+ </sizepolicy>
154+ </property>
155+ <property name="windowTitle">
156+ <string>Form</string>
157+ </property>
158+ <layout class="QHBoxLayout" name="horizontalLayout">
159+ <property name="spacing">
160+ <number>0</number>
161+ </property>
162+ <property name="margin">
163+ <number>0</number>
164+ </property>
165+ <item>
166+ <widget class="QTabWidget" name="tabWidget">
167+ <property name="currentIndex">
168+ <number>0</number>
169+ </property>
170+ <widget class="QWidget" name="tabWelcome">
171+ <attribute name="title">
172+ <string notr="true">Do not translate this</string>
173+ </attribute>
174+ <layout class="QHBoxLayout" name="horizontalLayout_5">
175+ <property name="spacing">
176+ <number>0</number>
177+ </property>
178+ <property name="margin">
179+ <number>0</number>
180+ </property>
181+ <item>
182+ <layout class="QVBoxLayout" name="verticalLayout_5">
183+ <property name="spacing">
184+ <number>0</number>
185+ </property>
186+ <item>
187+ <widget class="QWidget" name="welcomeTop" native="true">
188+ <property name="sizePolicy">
189+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
190+ <horstretch>0</horstretch>
191+ <verstretch>0</verstretch>
192+ </sizepolicy>
193+ </property>
194+ <property name="minimumSize">
195+ <size>
196+ <width>0</width>
197+ <height>100</height>
198+ </size>
199+ </property>
200+ <layout class="QVBoxLayout" name="verticalLayout_6">
201+ <property name="spacing">
202+ <number>0</number>
203+ </property>
204+ <property name="margin">
205+ <number>0</number>
206+ </property>
207+ <item>
208+ <layout class="QHBoxLayout" name="horizontalLayout_4">
209+ <property name="spacing">
210+ <number>0</number>
211+ </property>
212+ <item>
213+ <widget class="QWidget" name="welcomeTopText" native="true">
214+ <widget class="QLabel" name="welcomeLabel">
215+ <property name="geometry">
216+ <rect>
217+ <x>30</x>
218+ <y>20</y>
219+ <width>330</width>
220+ <height>51</height>
221+ </rect>
222+ </property>
223+ <property name="font">
224+ <font>
225+ <family>Ubuntu</family>
226+ <pointsize>21</pointsize>
227+ </font>
228+ </property>
229+ <property name="text">
230+ <string extracomment="TRANSLATORS: this is the main title of the authentication dialog">This is a translatable title</string>
231+ </property>
232+ </widget>
233+ </widget>
234+ </item>
235+ </layout>
236+ </item>
237+ </layout>
238+ </widget>
239+ </item>
240+ <item>
241+ <widget class="QWidget" name="welcomeBottom" native="true">
242+ <property name="sizePolicy">
243+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
244+ <horstretch>0</horstretch>
245+ <verstretch>0</verstretch>
246+ </sizepolicy>
247+ </property>
248+ <property name="minimumSize">
249+ <size>
250+ <width>0</width>
251+ <height>0</height>
252+ </size>
253+ </property>
254+ <widget class="QTextEdit" name="welcomeTextBox">
255+ <property name="geometry">
256+ <rect>
257+ <x>30</x>
258+ <y>20</y>
259+ <width>571</width>
260+ <height>181</height>
261+ </rect>
262+ </property>
263+ <property name="frameShape">
264+ <enum>QFrame::NoFrame</enum>
265+ </property>
266+ <property name="frameShadow">
267+ <enum>QFrame::Plain</enum>
268+ </property>
269+ <property name="readOnly">
270+ <bool>true</bool>
271+ </property>
272+ <property name="html">
273+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
274+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;title&gt;HTML document extraction test&lt;/title&gt;&lt;style type=&quot;text/css&quot;&gt;
275+p, li { white-space: pre-wrap; }
276+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
277+&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Once upon a time, in a galaxy far, far away... &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
278+ </property>
279+ </widget>
280+ <widget class="QPushButton" name="friendlyTestsButton">
281+ <property name="geometry">
282+ <rect>
283+ <x>30</x>
284+ <y>210</y>
285+ <width>571</width>
286+ <height>31</height>
287+ </rect>
288+ </property>
289+ <property name="font">
290+ <font>
291+ <pointsize>9</pointsize>
292+ </font>
293+ </property>
294+ <property name="text">
295+ <string comment="Button" extracomment="TRANSLATORS: refers to the action of accepting something">Ok</string>
296+ </property>
297+ </widget>
298+ <widget class="QCheckBox" name="checkBox">
299+ <property name="geometry">
300+ <rect>
301+ <x>30</x>
302+ <y>280</y>
303+ <width>321</width>
304+ <height>20</height>
305+ </rect>
306+ </property>
307+ <property name="font">
308+ <font>
309+ <family>Ubuntu</family>
310+ </font>
311+ </property>
312+ <property name="text">
313+ <string comment="WelcomeDialog">Don't show me this message in the future</string>
314+ </property>
315+ </widget>
316+ <widget class="QCheckBox" name="checkBox_2">
317+ <property name="geometry">
318+ <rect>
319+ <x>30</x>
320+ <y>260</y>
321+ <width>321</width>
322+ <height>20</height>
323+ </rect>
324+ </property>
325+ <property name="font">
326+ <font>
327+ <family>Ubuntu</family>
328+ </font>
329+ </property>
330+ <property name="text">
331+ <string extracomment="TRANSLATORS: authentication is required to perform this action">Require authentication</string>
332+ </property>
333+ </widget>
334+ </widget>
335+ </item>
336+ </layout>
337+ </item>
338+ </layout>
339+ </widget>
340+ </widget>
341+ </item>
342+ </layout>
343+ </widget>
344+ <resources/>
345+ <connections/>
346+</ui>
347
348=== modified file 'tests/results/Makefile.am'
349--- tests/results/Makefile.am 2011-10-08 18:08:58 +0000
350+++ tests/results/Makefile.am 2013-05-10 09:59:25 +0000
351@@ -17,6 +17,7 @@
352 extract12.xml.in.h \
353 extract14.xml.in.h \
354 extract-gtkbuilder.ui.h \
355+ extract-qtdesigner.ui.h \
356 gsettings.gschema.xml.h \
357 iso88591text.xml.in.h \
358 merge-cdata.xml \
359
360=== added file 'tests/results/extract-qtdesigner.ui.h'
361--- tests/results/extract-qtdesigner.ui.h 1970-01-01 00:00:00 +0000
362+++ tests/results/extract-qtdesigner.ui.h 2013-05-10 09:59:25 +0000
363@@ -0,0 +1,13 @@
364+char *s = N_("Form");
365+/* TRANSLATORS: this is the main title of the authentication dialog */
366+char *s = N_("This is a translatable title");
367+char *s = N_("&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;\n"
368+ "&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;title&gt;HTML document extraction test&lt;/title&gt;&lt;style type=&quot;text/css&quot;&gt;\n"
369+ "p, li { white-space: pre-wrap; }\n"
370+ "&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;\n"
371+ "&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Once upon a time, in a galaxy far, far away... &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;");
372+/* TRANSLATORS: refers to the action of accepting something */
373+char *s = C_("Button", "Ok");
374+char *s = C_("WelcomeDialog", "Don't show me this message in the future");
375+/* TRANSLATORS: authentication is required to perform this action */
376+char *s = N_("Require authentication");
377
378=== modified file 'tests/selftest.pl.in'
379--- tests/selftest.pl.in 2012-08-23 03:39:02 +0000
380+++ tests/selftest.pl.in 2013-05-10 09:59:25 +0000
381@@ -294,6 +294,11 @@
382 system("$INTLTOOL_EXTRACT --type=gettext/glade --quiet --update cases/$case") == 0 or $failed = 1;
383 check_extract_result($case);
384
385+print "40. Extract messages from a Qt Designer UI file: ";
386+$case = "extract-qtdesigner.ui";
387+system("$INTLTOOL_EXTRACT --type=gettext/qtdesigner --quiet --update cases/$case") == 0 or $failed = 1;
388+check_extract_result($case);
389+
390
391 system("rm -f cases/*.*") if $srcdir ne ".";
392 system("rm -rf C az extract9 fr fr_BE fr_FR merge6 schemasmerge1 schemasmerge2 spacepreserve test test-quoted merge6.xml");

Subscribers

People subscribed via source and target branches