blob: 68c70bdec97b774b23a799d6c570e4eecac8d10e [file] [log] [blame]
#!/usr/bin/env perl
# Copyright (C) 2013 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
use strict;
use warnings;
use Getopt::Long;
my $utf8 = 0;
my %options = (
'utf8' => \$utf8,
);
GetOptions(%options);
@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";
my $fileToUpdate = shift @ARGV;
-f $fileToUpdate or die "Couldn't find file to update $fileToUpdate\n";
my @directories = ();
my @directoriesToSkip = ();
if (@ARGV < 1) {
push(@directories, ".");
} else {
for my $dir (@ARGV) {
if ($dir =~ /^-(.*)$/) {
push @directoriesToSkip, $1;
} else {
push @directories, $dir;
}
}
}
my $sawError = 0;
my $keyCollisionCount = 0;
my $quotedDirectoriesString = '"' . join('" "', @directories) . '"';
for my $dir (@directoriesToSkip) {
$quotedDirectoriesString .= ' -path "' . $dir . '" -prune -o';
}
my @files = ( split "\n", `find $quotedDirectoriesString \\( -name "*.html" -o -name "*.js" \\)` );
for my $file (sort @files) {
$file =~ s-^./--;
open SOURCE, $file or die "can't open $file\n";
while (<SOURCE>) {
chomp;
# Handle WebInspector strings. Prints a warning if a non-string literal is passed to WI.UIString().
# Allow: WI.UIString(string, comment)
# WI.UIString(string, key, comment)
HandleUIString(
$1,
($3 || (defined $3 and length $3 == 0)) ? $2 : $1,
($3 || (defined $3 and length $3 == 0)) ? $3 : $2 || "",
$file,
$.
) while s/WI\.UIString\("([^"]+)"(?:,\s*"([^"]*)"(?:,\s*"([^"]*)")?)?\)//;
print "$file:$.:WARNING: $&\n" while s/WI\.UIString\(.*?\)//;
# Handle strings for other projects that also use this script.
HandleUIString($2, $2, "", $file, $.) while s/(\bclass="[^"]*l12n-tooltip[^"]*"[^>]*)title="([^"]+)"/$1/;
HandleUIString($1, $1, "", $file, $.) while s/\btitle="([^"]+)"([^>]*class="[^"]*l12n-tooltip[^"]*")/$2/;
HandleUIString($2, $2, "", $file, $.) while s/<(\w+)[^>]*\bclass="[^"]*l12n[^"]*"[^>]*>([^>]+)<\/\1>//;
HandleUIString($1, $1, "", $file, $.) while s/HTMLViewController\.UIString\("([^"]+)"\)//;
HandleUIString($1, $1, "", $file, $.) while s/\bgetLocalizedString\("([^"]+)"\)//;
HandleUIString($1, $1, "", $file, $.) while s/\blocalizedStrings\["([^"]+)"\]//;
}
close SOURCE;
}
my %stringByKey;
my %commentByKey;
my %fileByKey;
my %lineByKey;
sub HandleUIString
{
my ($string, $key, $comment, $file, $line) = @_;
my $bad = 0;
if (grep { $_ == 0xFFFD } unpack "U*", $string) {
print "$file:$line:ERROR:string for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
$bad = 1;
}
if ($string ne $key && grep { $_ == 0xFFFD } unpack "U*", $key) {
print "$file:$line:ERROR:key has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
$bad = 1;
}
if (grep { $_ == 0xFFFD } unpack "U*", $comment) {
print "$file:$line:ERROR:comment for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
$bad = 1;
}
if ($bad) {
$sawError = 1;
return;
}
if ($stringByKey{$key} && $stringByKey{$key} ne $string) {
print "$file:$line:encountered the same key, \"$key\", twice, with different strings\n";
print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
$keyCollisionCount++;
return;
}
if ($commentByKey{$key} && $commentByKey{$key} ne $comment) {
print "$file:$line:encountered the same key, \"$key\", twice, with different comments\n";
print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
$keyCollisionCount++;
return;
}
$fileByKey{$key} = $file;
$lineByKey{$key} = $line;
$stringByKey{$key} = $string;
$commentByKey{$key} = $comment;
}
print "\n" if $sawError;
print "$keyCollisionCount key collisions\n" if $keyCollisionCount;
if ($sawError) {
print "\nErrors encountered. Exiting without writing to $fileToUpdate.\n";
exit 1;
}
my $localizedStrings = "var localizedStrings = new Object;\n\n";
for my $key (sort keys %commentByKey) {
$localizedStrings .= "/* $commentByKey{$key} */\n" if length $commentByKey{$key};
$localizedStrings .= "localizedStrings[\"$key\"] = \"$stringByKey{$key}\";\n";
}
if (-e "$fileToUpdate") {
open STRINGS, ">", "$fileToUpdate" or die;
if ($utf8) {
# Write out the strings file in UTF-8.
print STRINGS $localizedStrings;
} else {
# Write out the strings file in UTF-16 with a BOM.
utf8::decode($localizedStrings) if $^V ge v5.8;
my $output = pack "n*", (0xFEFF, unpack "U*", $localizedStrings);
print STRINGS $output;
}
close STRINGS;
} else {
print "$fileToUpdate does not exist\n";
exit 1;
}