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
}