bin/findtr
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 }