b785ed3f631f3499fd2b932f4f6a771f4ecc3da9
[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
28 @ARGV >= 1 or die "Usage: extract-localizable-js-strings <file to update> [ directory... ]\nDid you mean to run update-webkit-localizable-strings instead?\n";
29
30 my $fileToUpdate = shift @ARGV;
31 -f $fileToUpdate or die "Couldn't find file to update $fileToUpdate\n";
32
33 my @directories = ();
34 my @directoriesToSkip = ();
35 if (@ARGV < 1) {
36     push(@directories, ".");
37 } else {
38     for my $dir (@ARGV) {
39         if ($dir =~ /^-(.*)$/) {
40             push @directoriesToSkip, $1;
41         } else {
42             push @directories, $dir;
43         }
44     }
45 }
46
47 my $sawError = 0;
48
49 my $keyCollisionCount = 0;
50
51 my $quotedDirectoriesString = '"' . join('" "', @directories) . '"';
52 for my $dir (@directoriesToSkip) {
53     $quotedDirectoriesString .= ' -path "' . $dir . '" -prune -o';
54 }
55
56 my @files = ( split "\n", `find $quotedDirectoriesString \\( -name "*.html" -o -name "*.js" \\)` );
57
58 for my $file (sort @files) {
59     $file =~ s-^./--;
60
61     open SOURCE, $file or die "can't open $file\n";
62
63     while (<SOURCE>) {
64         chomp;
65
66         # Handle WebInspector strings. Prints a warning if a non-string literal is passed to WebInspector.UIString().
67         HandleUIString($1, $1, "", $file, $.) while s/WebInspector\.UIString\("([^"]+)"\)//;
68         print "$file:$.:WARNING: $&\n" while s/WebInspector\.UIString\(.*?\)//;
69
70         # Handle strings for other projects that also use this script.
71         HandleUIString($2, $2, "", $file, $.) while s/(\bclass="[^"]*l12n-tooltip[^"]*"[^>]*)title="([^"]+)"/$1/;
72         HandleUIString($1, $1, "", $file, $.) while s/\btitle="([^"]+)"([^>]*class="[^"]*l12n-tooltip[^"]*")/$2/;
73         HandleUIString($2, $2, "", $file, $.) while s/<(\w+)[^>]*\bclass="[^"]*l12n[^"]*"[^>]*>([^>]+)<\/\1>//;
74         HandleUIString($1, $1, "", $file, $.) while s/HTMLViewController\.UIString\("([^"]+)"\)//;
75         HandleUIString($1, $1, "", $file, $.) while s/\bgetLocalizedString\("([^"]+)"\)//;
76         HandleUIString($1, $1, "", $file, $.) while s/\blocalizedStrings\["([^"]+)"\]//;
77     }
78
79     close SOURCE;
80 }
81
82 my %stringByKey;
83 my %commentByKey;
84 my %fileByKey;
85 my %lineByKey;
86
87 sub HandleUIString
88 {
89     my ($string, $key, $comment, $file, $line) = @_;
90     my $bad = 0;
91
92     if (grep { $_ == 0xFFFD } unpack "U*", $string) {
93         print "$file:$line:ERROR:string for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
94         $bad = 1;
95     }
96
97     if ($string ne $key && grep { $_ == 0xFFFD } unpack "U*", $key) {
98         print "$file:$line:ERROR:key has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
99         $bad = 1;
100     }
101
102     if (grep { $_ == 0xFFFD } unpack "U*", $comment) {
103         print "$file:$line:ERROR:comment for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
104         $bad = 1;
105     }
106
107     if ($bad) {
108         $sawError = 1;
109         return;
110     }
111
112     if ($stringByKey{$key} && $stringByKey{$key} ne $string) {
113         print "$file:$line:encountered the same key, \"$key\", twice, with different strings\n";
114         print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
115         $keyCollisionCount++;
116         return;
117     }
118
119     if ($commentByKey{$key} && $commentByKey{$key} ne $comment) {
120         print "$file:$line:encountered the same key, \"$key\", twice, with different comments\n";
121         print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
122         $keyCollisionCount++;
123         return;
124     }
125
126     $fileByKey{$key} = $file;
127     $lineByKey{$key} = $line;
128     $stringByKey{$key} = $string;
129     $commentByKey{$key} = $comment;
130 }
131
132 print "\n" if $sawError;
133
134 print "$keyCollisionCount key collisions\n" if $keyCollisionCount;
135
136 if ($sawError) {
137     print "\nErrors encountered. Exiting without writing to $fileToUpdate.\n";
138     exit 1;
139 }
140
141 my $localizedStrings = "var localizedStrings = new Object;\n\n";
142
143 for my $key (sort keys %commentByKey) {
144     $localizedStrings .= "localizedStrings[\"$key\"] = \"$stringByKey{$key}\";\n";
145 }
146
147 # Write out the strings file in UTF-16 with a BOM.
148 utf8::decode($localizedStrings) if $^V ge v5.8;
149 my $output = pack "n*", (0xFEFF, unpack "U*", $localizedStrings);
150
151 if (-e "$fileToUpdate") {
152     open STRINGS, ">", "$fileToUpdate" or die;
153     print STRINGS $output;
154     close STRINGS;
155 } else {
156     print "$fileToUpdate does not exist\n";
157     exit 1;
158 }