| 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 | }
 | 
|---|