Web Inspector: Make localizedString.js diff and commit friendly (UTF16 -> UTF8)
[WebKit-https.git] / Tools / Scripts / extract-localizable-js-strings
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2013 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 #    notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 #    notice, this list of conditions and the following disclaimer in the
12 #    documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 # THE POSSIBILITY OF SUCH DAMAGE.
25
26 use strict;
27 use Getopt::Long;
28
29 my $utf8 = 0;
30
31 my %options = (
32     'utf8' => \$utf8,
33 );
34
35 GetOptions(%options);
36
37 @ARGV >= 1 or die "Usage: extract-localizable-js-strings [--utf8] <file to update> [ directory... ]\nDid you mean to run update-webkit-localizable-strings instead?\n";
38
39 my $fileToUpdate = shift @ARGV;
40 -f $fileToUpdate or die "Couldn't find file to update $fileToUpdate\n";
41
42 my @directories = ();
43 my @directoriesToSkip = ();
44 if (@ARGV < 1) {
45     push(@directories, ".");
46 } else {
47     for my $dir (@ARGV) {
48         if ($dir =~ /^-(.*)$/) {
49             push @directoriesToSkip, $1;
50         } else {
51             push @directories, $dir;
52         }
53     }
54 }
55
56 my $sawError = 0;
57
58 my $keyCollisionCount = 0;
59
60 my $quotedDirectoriesString = '"' . join('" "', @directories) . '"';
61 for my $dir (@directoriesToSkip) {
62     $quotedDirectoriesString .= ' -path "' . $dir . '" -prune -o';
63 }
64
65 my @files = ( split "\n", `find $quotedDirectoriesString \\( -name "*.html" -o -name "*.js" \\)` );
66
67 for my $file (sort @files) {
68     $file =~ s-^./--;
69
70     open SOURCE, $file or die "can't open $file\n";
71
72     while (<SOURCE>) {
73         chomp;
74
75         # Handle WebInspector strings. Prints a warning if a non-string literal is passed to WebInspector.UIString().
76         HandleUIString($1, $1, "", $file, $.) while s/WebInspector\.UIString\("([^"]+)"\)//;
77         print "$file:$.:WARNING: $&\n" while s/WebInspector\.UIString\(.*?\)//;
78
79         # Handle strings for other projects that also use this script.
80         HandleUIString($2, $2, "", $file, $.) while s/(\bclass="[^"]*l12n-tooltip[^"]*"[^>]*)title="([^"]+)"/$1/;
81         HandleUIString($1, $1, "", $file, $.) while s/\btitle="([^"]+)"([^>]*class="[^"]*l12n-tooltip[^"]*")/$2/;
82         HandleUIString($2, $2, "", $file, $.) while s/<(\w+)[^>]*\bclass="[^"]*l12n[^"]*"[^>]*>([^>]+)<\/\1>//;
83         HandleUIString($1, $1, "", $file, $.) while s/HTMLViewController\.UIString\("([^"]+)"\)//;
84         HandleUIString($1, $1, "", $file, $.) while s/\bgetLocalizedString\("([^"]+)"\)//;
85         HandleUIString($1, $1, "", $file, $.) while s/\blocalizedStrings\["([^"]+)"\]//;
86     }
87
88     close SOURCE;
89 }
90
91 my %stringByKey;
92 my %commentByKey;
93 my %fileByKey;
94 my %lineByKey;
95
96 sub HandleUIString
97 {
98     my ($string, $key, $comment, $file, $line) = @_;
99     my $bad = 0;
100
101     if (grep { $_ == 0xFFFD } unpack "U*", $string) {
102         print "$file:$line:ERROR:string for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
103         $bad = 1;
104     }
105
106     if ($string ne $key && grep { $_ == 0xFFFD } unpack "U*", $key) {
107         print "$file:$line:ERROR:key has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
108         $bad = 1;
109     }
110
111     if (grep { $_ == 0xFFFD } unpack "U*", $comment) {
112         print "$file:$line:ERROR:comment for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
113         $bad = 1;
114     }
115
116     if ($bad) {
117         $sawError = 1;
118         return;
119     }
120
121     if ($stringByKey{$key} && $stringByKey{$key} ne $string) {
122         print "$file:$line:encountered the same key, \"$key\", twice, with different strings\n";
123         print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
124         $keyCollisionCount++;
125         return;
126     }
127
128     if ($commentByKey{$key} && $commentByKey{$key} ne $comment) {
129         print "$file:$line:encountered the same key, \"$key\", twice, with different comments\n";
130         print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
131         $keyCollisionCount++;
132         return;
133     }
134
135     $fileByKey{$key} = $file;
136     $lineByKey{$key} = $line;
137     $stringByKey{$key} = $string;
138     $commentByKey{$key} = $comment;
139 }
140
141 print "\n" if $sawError;
142
143 print "$keyCollisionCount key collisions\n" if $keyCollisionCount;
144
145 if ($sawError) {
146     print "\nErrors encountered. Exiting without writing to $fileToUpdate.\n";
147     exit 1;
148 }
149
150 my $localizedStrings = "var localizedStrings = new Object;\n\n";
151
152 for my $key (sort keys %commentByKey) {
153     $localizedStrings .= "localizedStrings[\"$key\"] = \"$stringByKey{$key}\";\n";
154 }
155
156 if (-e "$fileToUpdate") {
157     open STRINGS, ">", "$fileToUpdate" or die;
158     if ($utf8) {
159         # Write out the strings file in UTF-8.
160         print STRINGS $localizedStrings;
161     } else {
162         # Write out the strings file in UTF-16 with a BOM.
163         utf8::decode($localizedStrings) if $^V ge v5.8;
164         my $output = pack "n*", (0xFEFF, unpack "U*", $localizedStrings);
165         print STRINGS $output;
166     }    
167     close STRINGS;
168 } else {
169     print "$fileToUpdate does not exist\n";
170     exit 1;
171 }