0
|
1 |
#!/usr/bin/perl -w
|
|
2 |
# vi:wrap:
|
|
3 |
|
|
4 |
# See Qt I18N documentation for usage information.
|
|
5 |
|
|
6 |
use POSIX qw(strftime);
|
|
7 |
|
|
8 |
$projectid='PROJECT VERSION';
|
|
9 |
$datetime = strftime "%Y-%m-%d %X %Z", localtime;
|
|
10 |
$charset='iso-8859-1';
|
|
11 |
$translator='FULLNAME <EMAIL@ADDRESS>';
|
|
12 |
$revision_date='YYYY-MM-DD';
|
|
13 |
|
|
14 |
$real_mark = "tr";
|
|
15 |
$noop_mark = "QT_TR_NOOP";
|
|
16 |
$scoped_mark = "qApp->translate";
|
|
17 |
$noop_scoped_mark = "QT_TRANSLATE_NOOP";
|
|
18 |
|
|
19 |
$header=
|
|
20 |
'# This is a Qt message file in .po format. Each msgid starts with
|
|
21 |
# a scope. This scope should *NOT* be translated - eg. translating
|
|
22 |
# from French to English, "Foo::Bar" would be translated to "Pub",
|
|
23 |
# not "Foo::Pub".
|
|
24 |
msgid ""
|
|
25 |
msgstr ""
|
|
26 |
"Project-Id-Version: '.$projectid.'\n"
|
|
27 |
"POT-Creation-Date: '.$datetime.'\n"
|
|
28 |
"PO-Revision-Date: '.$revision_date.'\n"
|
|
29 |
"Last-Translator: '.$translator.'\n"
|
|
30 |
"Content-Type: text/plain; charset='.$charset.'\n"
|
|
31 |
|
|
32 |
';
|
|
33 |
|
|
34 |
|
|
35 |
|
|
36 |
|
|
37 |
$scope = "";
|
|
38 |
|
|
39 |
if ( $#ARGV < 0 ) {
|
|
40 |
print STDERR "Usage: findtr sourcefile ... >project.po\n";
|
|
41 |
exit 1;
|
|
42 |
}
|
|
43 |
|
|
44 |
|
|
45 |
sub outmsg {
|
|
46 |
my ($file, $line, $scope, $msgid) = @_;
|
|
47 |
# unesc
|
|
48 |
$msgid =~ s/$esc:$esc:$esc/::/gs;
|
|
49 |
$msgid =~ s|$esc/$esc/$esc|//|gs;
|
|
50 |
|
|
51 |
# Remove blank lines
|
|
52 |
$msgid =~ s/\n\n+/\n/gs;
|
|
53 |
$msgid = "\"\"\n$msgid" if $msgid =~ /\n/s;
|
|
54 |
print "#: $file:$line\n";
|
|
55 |
$msgid =~ s/^"//; #"emacs bug
|
|
56 |
print "msgid \"${scope}::$msgid\n";
|
|
57 |
#print "msgstr \"$msgid\n";
|
|
58 |
print "msgstr \"\"\n";
|
|
59 |
print "\n";
|
|
60 |
}
|
|
61 |
|
|
62 |
sub justlines {
|
|
63 |
my $l = @_;
|
|
64 |
$l =~ tr|\n||dc;
|
|
65 |
return $l;
|
|
66 |
}
|
|
67 |
|
|
68 |
print $header;
|
|
69 |
|
|
70 |
|
|
71 |
foreach $file ( @ARGV ) {
|
|
72 |
next unless open( I, "< $file" );
|
|
73 |
|
|
74 |
$source = join( "", <I> );
|
|
75 |
|
|
76 |
# Find esc. Avoid bad case 1/// -> 1/1/1/1 -> ///1
|
|
77 |
$esc = 1;
|
|
78 |
while ( $source =~ m!(?:$esc/$esc/$esc)|(?:$esc///)
|
|
79 |
|(?:$esc:$esc:$esc)|(?:$esc:\:\:)! ) {
|
|
80 |
$esc++;
|
|
81 |
}
|
|
82 |
|
|
83 |
# Hide quoted :: in practically all strings
|
|
84 |
$source =~ s/\"([^"\n]*)::([^"\n]*)\"/\"$1$esc:$esc:$esc$2\"/g;
|
|
85 |
|
|
86 |
# Hide quoted // in practically all strings
|
|
87 |
$source =~ s|\"([^"\n]*)//([^"\n]*)\"|\"$1$esc/$esc/$esc$2\"|g;
|
|
88 |
|
|
89 |
|
|
90 |
# strip comments -- does not handle "/*" in strings
|
|
91 |
while( $source =~ s|/\*(.*?)\*/|justlines($1)|ges ) { }
|
|
92 |
while( $source =~ s|//(.*?)\n|\n|g ) { }
|
|
93 |
|
|
94 |
while( $source =~ /
|
|
95 |
(?:
|
|
96 |
# Some doublequotes are "escaped" to help vim syntax highlight
|
|
97 |
|
|
98 |
# $1 = scope; $2 = parameters etc.
|
|
99 |
(?:
|
|
100 |
# Scoped function name ($1 is scope).
|
|
101 |
(\w+)::(?:\w+)
|
|
102 |
\s*
|
|
103 |
# Parameters etc up to open-curly - no semicolons
|
|
104 |
\(([^();]*)\)
|
|
105 |
\s*
|
|
106 |
(?:\{|:)
|
|
107 |
)
|
|
108 |
|
|
|
109 |
# $3 - one-argument msgid
|
|
110 |
(?:\b
|
|
111 |
# One of the marks
|
|
112 |
(?:$real_mark|$noop_mark)
|
|
113 |
\s*
|
|
114 |
# The parameter
|
|
115 |
\(\s*((?:"(?:[^"]|[^\\]\\")*"\s*)+)\)
|
|
116 |
)
|
|
117 |
|
|
|
118 |
# $4,$5 - two-argument msgid
|
|
119 |
(?:\b
|
|
120 |
# One of the scoped marks
|
|
121 |
(?:$scoped_mark|$noop_scoped_mark)
|
|
122 |
\s*
|
|
123 |
# The parameters
|
|
124 |
\(
|
|
125 |
# The scope parameter
|
|
126 |
\s*"([^\"]*)"
|
|
127 |
\s*,\s*
|
|
128 |
# The msgid parameter
|
|
129 |
\s*((?:\"(?:[^"]|[^\\]\\")*"\s*)+) #"emacs
|
|
130 |
\)
|
|
131 |
)
|
|
132 |
|
|
|
133 |
# $6,$7 - scoped one-argument msgid
|
|
134 |
(?:\b
|
|
135 |
# The scope
|
|
136 |
(\w+)::
|
|
137 |
# One of the marks
|
|
138 |
(?:$real_mark)
|
|
139 |
\s*
|
|
140 |
# The parameter
|
|
141 |
\(\s*((?:"(?:[^"]|[^\\]\\")*"\s*)+)\)
|
|
142 |
)
|
|
143 |
)/gsx )
|
|
144 |
{
|
|
145 |
@lines = split /^/m, "$`";
|
|
146 |
$line = @lines;
|
|
147 |
if ( defined( $1 ) ) {
|
|
148 |
if ( $scope ne $1 ) {
|
|
149 |
$sc=$1;
|
|
150 |
$etc=$2;
|
|
151 |
# remove strings
|
|
152 |
$etc =~ s/"(?:[^"]|[^\\]\\")"//g;
|
|
153 |
# count ( and )
|
|
154 |
@open = split /\(/m, $etc;
|
|
155 |
@close = split /\)/m, $etc;
|
|
156 |
if ( $#open == $#close ) {
|
|
157 |
$scope = $sc;
|
|
158 |
}
|
|
159 |
}
|
|
160 |
next;
|
|
161 |
}
|
|
162 |
|
|
163 |
if ( defined( $3 ) ) {
|
|
164 |
$this_scope = $scope;
|
|
165 |
$msgid = $3;
|
|
166 |
} elsif ( defined( $4 ) ) {
|
|
167 |
$this_scope = $4;
|
|
168 |
$msgid = $5;
|
|
169 |
} elsif ( defined( $6 ) ) {
|
|
170 |
$this_scope = $6;
|
|
171 |
$msgid = $7;
|
|
172 |
} else {
|
|
173 |
next;
|
|
174 |
}
|
|
175 |
|
|
176 |
$msgid =~ s/^\s*//;
|
|
177 |
$msgid =~ s/\s*$//;
|
|
178 |
|
|
179 |
# Might still be non-unique eg. tr("A" "B") vs. tr("A" "B").
|
|
180 |
|
|
181 |
$location{"${this_scope}::${msgid}"} = "$file:$line";
|
|
182 |
}
|
|
183 |
}
|
|
184 |
|
|
185 |
for $scoped_msgid ( sort keys %location ) {
|
|
186 |
($scope,$msgid) = $scoped_msgid =~ m/([^:]*)::(.*)/s;
|
|
187 |
($file,$line) = $location{$scoped_msgid} =~ m/([^:]*):(.*)/s;
|
|
188 |
outmsg($file,$line,$scope,$msgid);
|
|
189 |
}
|