Doku: Test-Doku aus t/README in die Haupt-Doku überführt & erweitert
[kivitendo-erp.git] / scripts / locales.pl
index f2bf870..f526416 100755 (executable)
@@ -6,6 +6,7 @@
 # this version of locles processes not only all required .pl files
 # but also all parse_html_templated files.
 
+use utf8;
 use strict;
 
 use Data::Dumper;
@@ -30,6 +31,7 @@ parse_args();
 my $basedir      = "../..";
 my $locales_dir  = ".";
 my $bindir       = "$basedir/bin/mozilla";
+my @progdirs     = ( "$basedir/SL" );
 my $dbupdir      = "$basedir/sql/Pg-upgrade";
 my $dbupdir2     = "$basedir/sql/Pg-upgrade2";
 my $menufile     = "menu.ini";
@@ -40,11 +42,38 @@ my ($ALL_HEADER, $MISSING_HEADER, $LOST_HEADER);
 
 init();
 
-opendir DIR, "$bindir" or die "$!";
-my @progfiles = grep { /\.pl$/ && !/(_custom|^\.)/ } readdir DIR;
-seekdir DIR, 0;
-my @customfiles = grep /_custom/, readdir DIR;
-closedir DIR;
+sub find_files {
+  my ($dir_name, $files) = @_;
+
+  $files ||= [];
+
+  my @dirs_to_check;
+
+  opendir my $dir, $dir_name or die "$! $dir_name";
+
+  foreach my $name (readdir $dir) {
+    next if $name eq '.' || $name eq '..';
+
+    my $full_name = "${dir_name}/${name}";
+    if (-d $full_name) {
+      push @dirs_to_check, $full_name;
+    } else {
+      push @{ $files }, $full_name;
+    }
+  }
+
+  closedir $dir;
+
+  map { find_files($_, $files) } @dirs_to_check;
+
+  return @{ $files };
+}
+
+my @bindir_files = find_files($bindir);
+my @progfiles    = map { m:^(.+)/([^/]+)$:; [ $2, $1 ]  } grep { /\.pl$/ && !/_custom/ } @bindir_files;
+my @customfiles  = grep /_custom/, @bindir_files;
+
+push @progfiles, map { m:^(.+)/([^/]+)$:; [ $2, $1 ] } grep { /\.pm$/ } map { find_files($_) } @progdirs;
 
 # put customized files into @customfiles
 my @menufiles;
@@ -85,9 +114,12 @@ if (-f "$locales_dir/lost") {
   unlink "$locales_dir/lost";
 }
 
+my $charset = slurp("$locales_dir/charset") || 'utf-8';
+chomp $charset;
+
 my %old_texts = %{ $self->{texts} || {} };
 
-map({ handle_file($_, $bindir); } @progfiles);
+map({ handle_file(@{ $_ }); } @progfiles);
 map({ handle_file($_, $dbupdir); } @dbplfiles);
 map({ handle_file($_, $dbupdir2); } @dbplfiles2);
 
@@ -125,7 +157,7 @@ if (scalar @lost) {
     delim     => '()',
     data_name => '@lost',
     data_sub  => sub {
-      _print_line($_->{text}, $_->{translation}, @_, template => "  { 'text' => %s, 'translation' => %s },") for @lost;
+      _print_line($_->{text}, $_->{translation}, @_, template => "  { 'text' => %s, 'translation' => %s },\n") for @lost;
     },
   );
 }
@@ -157,8 +189,8 @@ EOL
 # add the missing texts and run locales.pl to rebuild
 EOL
   $LOST_HEADER  = <<EOL;
-# The last 50 texts that have been removed.
-# This file will be auto-generated by locales.pl. Do not edit it.
+# The last 50 text strings, that have been removed.
+# This file has been auto-generated by locales.pl. Please don't edit!
 EOL
 }
 
@@ -222,20 +254,6 @@ sub handle_file {
     }
   }
 
-  # if this is the menu.pl file
-  if ($file eq 'menu.pl') {
-    foreach my $item (@menufiles) {
-      &scanmenu("$basedir/$item");
-    }
-  }
-
-  if ($file eq 'menunew.pl') {
-    foreach my $item (@menufiles) {
-      &scanmenu("$basedir/$item");
-      print "." if $opt_v;
-    }
-  }
-
   $file =~ s/\.pl//;
 
   foreach my $text (keys %$missing) {
@@ -279,11 +297,11 @@ sub extract_text_between_parenthesis {
 
     } else {
       if ($quote_next) {
+        $text .= '\\' unless $cur_char eq "'";
         $text .= $cur_char;
         $quote_next = 0;
 
       } elsif ($cur_char eq '\\') {
-        $text .= $cur_char;
         $quote_next = 1;
 
       } elsif ($cur_char eq $inside_string) {
@@ -320,6 +338,8 @@ sub scanfile {
     my ($is_submit, $line_no, $sub_line_no) = (0, 0, 0);
 
     while (<$fh>) {
+      last if /^\s*__END__/;
+
       $line_no++;
 
       # is this another file
@@ -335,7 +355,7 @@ sub scanfile {
       }
 
       # is this a template call?
-      if (/parse_html_template2?\s*\(\s*[\"\']([\w\/]+)\s*[\"\']/) {
+      if (/(?:parse_html_template2?|render)\s*\(\s*[\"\']([\w\/]+)\s*[\"\']/) {
         my $newfile = "$basedir/templates/webpages/$1.html";
         if (/parse_html_template2/) {
           print "E: " . strip_base($file) . " is still using 'parse_html_template2' for " . strip_base($newfile) . ".\n";
@@ -370,7 +390,7 @@ sub scanfile {
           }
         }
 
-        my ($found) = /locale->text.*?\(/;
+        my ($found) = / (?: locale->text | \b t8 ) \b .*? \(/x;
         $postmatch = "$'";
 
         if ($found) {
@@ -471,26 +491,26 @@ sub scanhtmlfile {
 
       while ($line =~ m/\[\%[^\w]*(\w+)\.\w+\(/g) {
         my $plugin = $1;
-        $plugins{needed}->{$plugin} = 1 if (first { $_ eq $plugin } qw(HTML LxERP JavaScript MultiColumnIterator));
+        $plugins{needed}->{$plugin} = 1 if (first { $_ eq $plugin } qw(HTML LxERP JavaScript MultiColumnIterator L));
       }
 
       while ($line =~ m/(?:             # Start von Variante 1: LxERP.t8('...'); ohne darumliegende [% ... %]-Tags
                           (LxERP\.t8)\( #   LxERP.t8(                             ::Parameter $1::
-                          ([\'\"])      #   Anfang des zu übersetzenden Strings   ::Parameter $2::
-                          (.*?)         #   Der zu übersetzende String            ::Parameter $3::
-                          (?<!\\)\2     #   Ende des zu übersetzenden Strings
+                          ([\'\"])      #   Anfang des zu übersetzenden Strings   ::Parameter $2::
+                          (.*?)         #   Der zu übersetzende String            ::Parameter $3::
+                          (?<!\\)\2     #   Ende des zu übersetzenden Strings
                         |               # Start von Variante 2: [% '...' | $T8 %]
                           \[\%          #   Template-Start-Tag
-                          [\-~#]?       #   Whitespace-Unterdrückung
+                          [\-~#]?       #   Whitespace-Unterdrückung
                           \s*           #   Optional beliebig viele Whitespace
-                          ([\'\"])      #   Anfang des zu übersetzenden Strings   ::Parameter $4::
-                          (.*?)         #   Der zu übersetzende String            ::Parameter $5::
-                          (?<!\\)\4     #   Ende des zu übersetzenden Strings
+                          ([\'\"])      #   Anfang des zu übersetzenden Strings   ::Parameter $4::
+                          (.*?)         #   Der zu übersetzende String            ::Parameter $5::
+                          (?<!\\)\4     #   Ende des zu übersetzenden Strings
                           \s*\|\s*      #   Pipe-Zeichen mit optionalen Whitespace davor und danach
                           (\$T8)        #   Filteraufruf                          ::Parameter $6::
-                          .*?           #   Optionale Argumente für den Filter
+                          .*?           #   Optionale Argumente für den Filter
                           \s*           #   Whitespaces
-                          [\-~#]?       #   Whitespace-Unterdrückung
+                          [\-~#]?       #   Whitespace-Unterdrückung
                           \%\]          #   Template-Ende-Tag
                         )
                        /ix) {
@@ -508,7 +528,7 @@ sub scanhtmlfile {
       }
 
       while ($line =~ m/\[\%          # Template-Start-Tag
-                        [\-~#]?       # Whitespace-Unterdrückung
+                        [\-~#]?       # Whitespace-Unterdrückung
                         \s*           # Optional beliebig viele Whitespace
                         (?:           # Die erkannten Template-Direktiven
                           PROCESS
@@ -573,7 +593,7 @@ sub strip_base {
 
 sub _single_quote {
   my $val = shift;
-  $val =~ s/('|\\$)/\\$1/g;
+  $val =~ s/(\'|\\$)/\\$1/g;
   return  "'" . $val .  "'";
 }
 
@@ -596,9 +616,12 @@ sub generate_file {
   my $data_name = $params{data_name};
   my @delim     = split //, ($params{delim} || '{}');
 
-  open my $fh, '>', $file or die "$! : $file";
+  open my $fh, '>:encoding(utf8)', $file or die "$! : $file";
+
+  $charset =~ s/\r?\n//g;
+  my $emacs_charset = lc $charset;
 
-  print $fh "#!/usr/bin/perl\n\n";
+  print $fh "#!/usr/bin/perl\n# -*- coding: $emacs_charset; -*-\n# vim: fenc=$charset\n\nuse utf8;\n\n";
   print $fh $header, "\n" if $header;
   print $fh "$data_name = $delim[0]\n" if $data_name;
 
@@ -608,6 +631,11 @@ sub generate_file {
   close $fh;
 }
 
+sub slurp {
+  my $file = shift;
+  do { local ( @ARGV, $/ ) = $file; <> }
+}
+
 __END__
 
 =head1 NAME
@@ -616,7 +644,7 @@ locales.pl - Collect strings for translation in Lx-Office
 
 =head1 SYNOPSIS
 
-locales.pl [options]
+locales.pl [options] lang_code
 
  Options:
   -n, --no-custom-files  Do not process files whose name contains "_"
@@ -647,7 +675,6 @@ Be more verbose.
 =head1 DESCRIPTION
 
 This script collects strings from Perl files, the menu.ini file and
-HTML templates and puts them into the file "all" for translation.  It
-also distributes those translations back to the individual files.
+HTML templates and puts them into the file "all" for translation.
 
 =cut