Bug 25067: Move PO file manipulation code into gulp tasks
[koha-ffzg.git] / misc / translator / LangInstaller.pm
index 456532d..5baddee 100644 (file)
@@ -22,36 +22,15 @@ use Modern::Perl;
 use C4::Context;
 # WARNING: Any other tested YAML library fails to work properly in this
 # script content
-use YAML::Syck qw( Dump LoadFile DumpFile );
+use YAML::Syck qw( LoadFile DumpFile );
 use Locale::PO;
 use FindBin qw( $Bin );
 use File::Basename;
-use File::Find;
 use File::Path qw( make_path );
 use File::Copy;
-use File::Slurp;
-use File::Spec;
-use File::Temp qw( tempdir tempfile );
-use Template::Parser;
-use PPI;
-
 
 $YAML::Syck::ImplicitTyping = 1;
 
-
-# Default file header for .po syspref files
-my $default_pref_po_header = Locale::PO->new(-msgid => '', -msgstr =>
-    "Project-Id-Version: PACKAGE VERSION\\n" .
-    "PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\\n" .
-    "Last-Translator: FULL NAME <EMAIL\@ADDRESS>\\n" .
-    "Language-Team: Koha Translate List <koha-translate\@lists.koha-community.org>\\n" .
-    "MIME-Version: 1.0\\n" .
-    "Content-Type: text/plain; charset=UTF-8\\n" .
-    "Content-Transfer-Encoding: 8bit\\n" .
-    "Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-);
-
-
 sub set_lang {
     my ($self, $lang) = @_;
 
@@ -60,7 +39,6 @@ sub set_lang {
                             "/prog/$lang/modules/admin/preferences";
 }
 
-
 sub new {
     my ($class, $lang, $pref_only, $verbose) = @_;
 
@@ -75,32 +53,16 @@ sub new {
     $self->{verbose}         = $verbose;
     $self->{process}         = "$Bin/tmpl_process3.pl " . ($verbose ? '' : '-q');
     $self->{path_po}         = "$Bin/po";
-    $self->{po}              = { '' => $default_pref_po_header };
+    $self->{po}              = {};
     $self->{domain}          = 'Koha';
-    $self->{cp}              = `which cp`;
-    $self->{msgmerge}        = `which msgmerge`;
     $self->{msgfmt}          = `which msgfmt`;
-    $self->{msginit}         = `which msginit`;
-    $self->{msgattrib}       = `which msgattrib`;
-    $self->{xgettext}        = `which xgettext`;
-    $self->{sed}             = `which sed`;
     $self->{po2json}         = "$Bin/po2json";
     $self->{gzip}            = `which gzip`;
     $self->{gunzip}          = `which gunzip`;
-    chomp $self->{cp};
-    chomp $self->{msgmerge};
     chomp $self->{msgfmt};
-    chomp $self->{msginit};
-    chomp $self->{msgattrib};
-    chomp $self->{xgettext};
-    chomp $self->{sed};
     chomp $self->{gzip};
     chomp $self->{gunzip};
 
-    unless ($self->{xgettext}) {
-        die "Missing 'xgettext' executable. Have you installed the gettext package?\n";
-    }
-
     # Get all .pref file names
     opendir my $fh, $self->{path_pref_en};
     my @pref_files = grep { /\.pref$/ } readdir($fh);
@@ -175,7 +137,6 @@ sub new {
     bless $self, $class;
 }
 
-
 sub po_filename {
     my $self   = shift;
     my $suffix = shift;
@@ -186,162 +147,92 @@ sub po_filename {
     return $trans_file;
 }
 
+sub get_trans_text {
+    my ($self, $msgid, $default) = @_;
 
-sub po_append {
-    my ($self, $id, $comment) = @_;
-    my $po = $self->{po};
-    my $p = $po->{$id};
-    if ( $p ) {
-        $p->comment( $p->comment . "\n" . $comment );
-    }
-    else {
-        $po->{$id} = Locale::PO->new(
-            -comment => $comment,
-            -msgid   => $id,
-            -msgstr  => ''
-        );
-    }
-}
-
-
-sub add_prefs {
-    my ($self, $comment, $prefs) = @_;
-
-    for my $pref ( @$prefs ) {
-        my $pref_name = '';
-        for my $element ( @$pref ) {
-            if ( ref( $element) eq 'HASH' ) {
-                $pref_name = $element->{pref};
-                last;
-            }
-        }
-        for my $element ( @$pref ) {
-            if ( ref( $element) eq 'HASH' ) {
-                while ( my ($key, $value) = each(%$element) ) {
-                    next unless $key eq 'choices' or $key eq 'multiple';
-                    next unless ref($value) eq 'HASH';
-                    for my $ckey ( keys %$value ) {
-                        my $id = $self->{file} . "#$pref_name# " . $value->{$ckey};
-                        $self->po_append( $id, $comment );
-                    }
-                }
-            }
-            elsif ( $element ) {
-                $self->po_append( $self->{file} . "#$pref_name# $element", $comment );
-            }
+    my $po = $self->{po}->{Locale::PO->quote($msgid)};
+    if ($po) {
+        my $msgstr = Locale::PO->dequote($po->msgstr);
+        if ($msgstr and length($msgstr) > 0) {
+            return $msgstr;
         }
     }
-}
-
-
-sub get_trans_text {
-    my ($self, $id) = @_;
 
-    my $po = $self->{po}->{$id};
-    return unless $po;
-    return Locale::PO->dequote($po->msgstr);
+    return $default;
 }
 
+sub get_translated_tab_content {
+    my ($self, $file, $tab_content) = @_;
 
-sub update_tab_prefs {
-    my ($self, $pref, $prefs) = @_;
-
-    for my $p ( @$prefs ) {
-        my $pref_name = '';
-        next unless $p;
-        for my $element ( @$p ) {
-            if ( ref( $element) eq 'HASH' ) {
-                $pref_name = $element->{pref};
-                last;
-            }
-        }
-        for my $i ( 0..@$p-1 ) {
-            my $element = $p->[$i];
-            if ( ref( $element) eq 'HASH' ) {
-                while ( my ($key, $value) = each(%$element) ) {
-                    next unless $key eq 'choices' or $key eq 'multiple';
-                    next unless ref($value) eq 'HASH';
-                    for my $ckey ( keys %$value ) {
-                        my $id = $self->{file} . "#$pref_name# " . $value->{$ckey};
-                        my $text = $self->get_trans_text( $id );
-                        $value->{$ckey} = $text if $text;
-                    }
-                }
-            }
-            elsif ( $element ) {
-                my $id = $self->{file} . "#$pref_name# $element";
-                my $text = $self->get_trans_text( $id );
-                $p->[$i] = $text if $text;
-            }
-        }
+    if ( ref($tab_content) eq 'ARRAY' ) {
+        return $self->get_translated_prefs($file, $tab_content);
     }
-}
 
+    my $translated_tab_content = {
+        map {
+            my $section = $_;
+            my $sysprefs = $tab_content->{$section};
+            my $msgid = sprintf('%s %s', $file, $section);
 
-sub get_po_from_prefs {
-    my $self = shift;
+            $self->get_trans_text($msgid, $section) => $self->get_translated_prefs($file, $sysprefs);
+        } keys %$tab_content
+    };
 
-    for my $file ( @{$self->{pref_files}} ) {
-        my $pref = LoadFile( $self->{path_pref_en} . "/$file" );
-        $self->{file} = $file;
-        # Entries for tab titles
-        $self->po_append( $self->{file}, $_ ) for keys %$pref;
-        while ( my ($tab, $tab_content) = each %$pref ) {
-            if ( ref($tab_content) eq 'ARRAY' ) {
-                $self->add_prefs( $tab, $tab_content );
-                next;
-            }
-            while ( my ($section, $sysprefs) = each %$tab_content ) {
-                my $comment = "$tab > $section";
-                $self->po_append( $self->{file} . " " . $section, $comment );
-                $self->add_prefs( $comment, $sysprefs );
-            }
-        }
-    }
+    return $translated_tab_content;
 }
 
+sub get_translated_prefs {
+    my ($self, $file, $sysprefs) = @_;
 
-sub save_po {
-    my $self = shift;
+    my $translated_prefs = [
+        map {
+            my ($pref_elt) = grep { ref($_) eq 'HASH' && exists $_->{pref} } @$_;
+            my $pref_name = $pref_elt ? $pref_elt->{pref} : '';
+
+            my $translated_syspref = [
+                map {
+                    $self->get_translated_pref($file, $pref_name, $_);
+                } @$_
+            ];
 
-    # Create file header if it doesn't already exist
-    my $po = $self->{po};
-    $po->{''} ||= $default_pref_po_header;
+            $translated_syspref;
+        } @$sysprefs
+    ];
 
-    # Write .po entries into a file put in Koha standard po directory
-    Locale::PO->save_file_fromhash( $self->po_filename("-pref.po"), $po );
-    say "Saved in file: ", $self->po_filename("-pref.po") if $self->{verbose};
+    return $translated_prefs;
 }
 
+sub get_translated_pref {
+    my ($self, $file, $pref_name, $syspref) = @_;
 
-sub get_po_merged_with_en {
-    my $self = shift;
-
-    # Get po from current 'en' .pref files
-    $self->get_po_from_prefs();
-    my $po_current = $self->{po};
+    unless (ref($syspref)) {
+        $syspref //= '';
+        my $msgid = sprintf('%s#%s# %s', $file, $pref_name, $syspref);
+        return $self->get_trans_text($msgid, $syspref);
+    }
 
-    # Get po from previous generation
-    my $po_previous = Locale::PO->load_file_ashash( $self->po_filename("-pref.po") );
+    my $translated_pref = {
+        map {
+            my $key = $_;
+            my $value = $syspref->{$key};
 
-    for my $id ( keys %$po_current ) {
-        my $po =  $po_previous->{Locale::PO->quote($id)};
-        next unless $po;
-        my $text = Locale::PO->dequote( $po->msgstr );
-        $po_current->{$id}->msgstr( $text );
-    }
-}
+            my $translated_value = $value;
+            if (($key eq 'choices' || $key eq 'multiple') && ref($value) eq 'HASH') {
+                $translated_value = {
+                    map {
+                        my $msgid = sprintf('%s#%s# %s', $file, $pref_name, $value->{$_});
+                        $_ => $self->get_trans_text($msgid, $value->{$_})
+                    } keys %$value
+                }
+            }
 
+            $key => $translated_value
+        } keys %$syspref
+    };
 
-sub update_prefs {
-    my $self = shift;
-    print "Update '", $self->{lang},
-          "' preferences .po file from 'en' .pref files\n" if $self->{verbose};
-    $self->get_po_merged_with_en();
-    $self->save_po();
+    return $translated_pref;
 }
 
-
 sub install_prefs {
     my $self = shift;
 
@@ -350,45 +241,24 @@ sub install_prefs {
         exit;
     }
 
-    # Get the language .po file merged with last modified 'en' preferences
-    $self->get_po_merged_with_en();
+    $self->{po} = Locale::PO->load_file_ashash($self->po_filename("-pref.po"), 'utf8');
 
     for my $file ( @{$self->{pref_files}} ) {
         my $pref = LoadFile( $self->{path_pref_en} . "/$file" );
-        $self->{file} = $file;
-        # First, keys are replaced (tab titles)
-        $pref = do {
-            my %pref = map { 
-                $self->get_trans_text( $self->{file} ) || $_ => $pref->{$_}
-            } keys %$pref;
-            \%pref;
+
+        my $translated_pref = {
+            map {
+                my $tab = $_;
+                my $tab_content = $pref->{$tab};
+
+                $self->get_trans_text($file, $tab) => $self->get_translated_tab_content($file, $tab_content);
+            } keys %$pref
         };
-        while ( my ($tab, $tab_content) = each %$pref ) {
-            if ( ref($tab_content) eq 'ARRAY' ) {
-                $self->update_tab_prefs( $pref, $tab_content );
-                next;
-            }
-            while ( my ($section, $sysprefs) = each %$tab_content ) {
-                $self->update_tab_prefs( $pref, $sysprefs );
-            }
-            my $ntab = {};
-            for my $section ( keys %$tab_content ) {
-                my $id = $self->{file} . " $section";
-                my $text = $self->get_trans_text($id);
-                my $nsection = $text ? $text : $section;
-                if( exists $ntab->{$nsection} ) {
-                    # When translations collide (see BZ 18634)
-                    push @{$ntab->{$nsection}}, @{$tab_content->{$section}};
-                } else {
-                    $ntab->{$nsection} = $tab_content->{$section};
-                }
-            }
-            $pref->{$tab} = $ntab;
-        }
+
+
         my $file_trans = $self->{po_path_lang} . "/$file";
         print "Write $file\n" if $self->{verbose};
-        open my $fh, ">", $file_trans;
-        print $fh Dump($pref);
+        DumpFile($file_trans, $translated_pref);
     }
 }
 
@@ -429,180 +299,6 @@ sub install_tmpl {
     }
 }
 
-
-sub update_tmpl {
-    my ($self, $files) = @_;
-
-    say "Update templates" if $self->{verbose};
-    for my $trans ( @{$self->{interface}} ) {
-        my @files   = @$files;
-        my @nomarc = ();
-        print
-            "  Update templates '$trans->{name}'\n",
-            "    From: $trans->{dir}/en/\n",
-            "    To  : $self->{path_po}/$self->{lang}$trans->{suffix}\n"
-                if $self->{verbose};
-
-        my $trans_dir = join("/en/ -i ",split(" ",$trans->{dir}))."/en/"; # multiple source dirs
-        # if processing MARC po file, only use corresponding files
-        my $marc      = ( $trans->{name} =~ /MARC/ )?"-m \"$trans->{name}\"":"";            # for MARC translations
-        # if not processing MARC po file, ignore all MARC files
-        @nomarc       = ( 'marc21', 'unimarc', 'normarc' ) if ( $trans->{name} !~ /MARC/ );      # hardcoded MARC variants
-
-        system
-            "$self->{process} update " .
-            "-i $trans_dir " .
-            "-s $self->{path_po}/$self->{lang}$trans->{suffix} -r " .
-            "$marc "     .
-            ( @files   ? ' -f ' . join ' -f ', @files : '') .
-            ( @nomarc  ? ' -n ' . join ' -n ', @nomarc : '');
-    }
-}
-
-
-sub create_prefs {
-    my $self = shift;
-
-    if ( -e $self->po_filename("-pref.po") ) {
-        say "Preferences .po file already exists. Delete it if you want to recreate it.";
-        return;
-    }
-    $self->get_po_from_prefs();
-    $self->save_po();
-}
-
-sub get_po_from_target {
-    my $self   = shift;
-    my $target = shift;
-
-    my $po;
-    my $po_head = Locale::PO->new;
-    $po_head->{msgid}  = "\"\"";
-    $po_head->{msgstr} = "".
-        "Project-Id-Version: Koha Project - Installation files\\n" .
-        "PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\\n" .
-        "Last-Translator: FULL NAME <EMAIL\@ADDRESS>\\n" .
-        "Language-Team: Koha Translation Team\\n" .
-        "Language: ".$self->{lang}."\\n" .
-        "MIME-Version: 1.0\\n" .
-        "Content-Type: text/plain; charset=UTF-8\\n" .
-        "Content-Transfer-Encoding: 8bit\\n";
-
-    my @dirs = @{ $target->{dirs} };
-    my $intradir = $self->{context}->config('intranetdir');
-    for my $dir ( @dirs ) {                                                     # each dir
-        opendir( my $dh, "$intradir/$dir" ) or die ("Can't open $intradir/$dir");
-        my @filelist = grep { $_ =~ m/\.yml/ } readdir($dh);                    # Just yaml files
-        close($dh);
-        for my $file ( @filelist ) {                                            # each file
-            my $yaml   = LoadFile( "$intradir/$dir/$file" );
-            my @tables = @{ $yaml->{'tables'} };
-            my $tablec;
-            for my $table ( @tables ) {                                         # each table
-                $tablec++;
-                my $table_name = ( keys %$table )[0];
-                my @translatable = @{ $table->{$table_name}->{translatable} };
-                my @rows = @{ $table->{$table_name}->{rows} };
-                my @multiline = @{ $table->{$table_name}->{'multiline'} };      # to check multiline values
-                my $rowc;
-                for my $row ( @rows ) {                                         # each row
-                    $rowc++;
-                    for my $field ( @translatable ) {                           # each field
-                        if ( @multiline and grep { $_ eq $field } @multiline ) {    # multiline fields, only notices ATM
-                            my $mulc;
-                            foreach my $line ( @{$row->{$field}} ) {
-                                $mulc++;
-                                next if ( $line =~ /^(\s*<.*?>\s*$|^\s*\[.*?\]\s*|\s*)$/ );                     # discard pure html, TT, empty
-                                $line =~ s/(<<.*?>>|\[\%.*?\%\]|<.*?>)/\%s/g;                                   # put placeholders
-                                next if ( $line =~ /^(\s|%s|-|[[:punct:]]|\(|\))*$/ or length($line) < 2 );     # discard non strings
-                                if ( not $po->{ $line } ) {
-                                    my $msg = Locale::PO->new(
-                                                -msgid => $line, -msgstr => '',
-                                                -reference => "$dir/$file:$table_name:$tablec:row:$rowc:mul:$mulc" );
-                                    $po->{ $line } = $msg;
-                                }
-                            }
-                        } else {
-                            if ( defined $row->{$field} and length($row->{$field}) > 1                         # discard null values and small strings
-                                 and not $po->{ $row->{$field} } ) {
-                                my $msg = Locale::PO->new(
-                                            -msgid => $row->{$field}, -msgstr => '',
-                                            -reference => "$dir/$file:$table_name:$tablec:row:$rowc" );
-                                $po->{ $row->{$field} } = $msg;
-                            }
-                        }
-                    }
-                }
-            }
-            my $desccount;
-            for my $description ( @{ $yaml->{'description'} } ) {
-                $desccount++;
-                if ( length($description) > 1 and not $po->{ $description } ) {
-                    my $msg = Locale::PO->new(
-                                -msgid => $description, -msgstr => '',
-                                -reference => "$dir/$file:description:$desccount" );
-                    $po->{ $description } = $msg;
-                }
-            }
-        }
-    }
-    $po->{''} = $po_head if ( $po );
-
-    return $po;
-}
-
-sub create_installer {
-    my $self = shift;
-    return unless ( $self->{installer} );
-
-    say "Create installer translation files\n" if $self->{verbose};
-
-    my @targets = @{ $self->{installer} };             # each installer target (common,marc21,unimarc)
-
-    for my $target ( @targets ) {
-        if ( -e $self->po_filename( $target->{suffix} ) ) {
-            say "$self->{lang}$target->{suffix} file already exists. Delete it if you want to recreate it.";
-            return;
-        }
-    }
-
-    for my $target ( @targets ) {
-        my $po = get_po_from_target( $self, $target );
-        # create output file only if there is something to write
-        if ( $po ) {
-            my $po_file = $self->po_filename( $target->{suffix} );
-            Locale::PO->save_file_fromhash( $po_file, $po );
-            say "Saved in file: ", $po_file if $self->{verbose};
-        }
-    }
-}
-
-sub update_installer {
-    my $self = shift;
-    return unless ( $self->{installer} );
-
-    say "Update installer translation files\n" if $self->{verbose};
-
-    my @targets = @{ $self->{installer} };             # each installer target (common,marc21,unimarc)
-
-    for my $target ( @targets ) {
-        return unless ( -e $self->po_filename( $target->{suffix} ) );
-        my $po = get_po_from_target( $self, $target );
-        # update file only if there is something to update
-        if ( $po ) {
-            my ( $fh, $po_temp ) = tempfile();
-            binmode( $fh, ":encoding(UTF-8)" );
-            Locale::PO->save_file_fromhash( $po_temp, $po );
-            my $po_file = $self->po_filename( $target->{suffix} );
-            eval {
-                my $st = system($self->{msgmerge}." ".($self->{verbose}?'':'-q').
-                         " -s $po_file $po_temp -o - | ".$self->{msgattrib}." --no-obsolete -o $po_file");
-            };
-            say "Updated file: ", $po_file if $self->{verbose};
-        }
-    }
-}
-
 sub translate_yaml {
     my $self   = shift;
     my $target = shift;
@@ -716,35 +412,6 @@ sub install_installer {
     }
 }
 
-sub create_tmpl {
-    my ($self, $files) = @_;
-
-    say "Create templates\n" if $self->{verbose};
-    for my $trans ( @{$self->{interface}} ) {
-        my @files   = @$files;
-        my @nomarc = ();
-        print
-            "  Create templates .po files for '$trans->{name}'\n",
-            "    From: $trans->{dir}/en/\n",
-            "    To  : $self->{path_po}/$self->{lang}$trans->{suffix}\n"
-                if $self->{verbose};
-
-        my $trans_dir = join("/en/ -i ",split(" ",$trans->{dir}))."/en/"; # multiple source dirs
-        # if processing MARC po file, only use corresponding files
-        my $marc      = ( $trans->{name} =~ /MARC/ )?"-m \"$trans->{name}\"":"";            # for MARC translations
-        # if not processing MARC po file, ignore all MARC files
-        @nomarc       = ( 'marc21', 'unimarc', 'normarc' ) if ( $trans->{name} !~ /MARC/ ); # hardcoded MARC variants
-
-        system
-            "$self->{process} create " .
-            "-i $trans_dir " .
-            "-s $self->{path_po}/$self->{lang}$trans->{suffix} -r " .
-            "$marc " .
-            ( @files  ? ' -f ' . join ' -f ', @files   : '') .
-            ( @nomarc ? ' -n ' . join ' -n ', @nomarc : '');
-    }
-}
-
 sub locale_name {
     my $self = shift;
 
@@ -758,250 +425,6 @@ sub locale_name {
     return $locale;
 }
 
-sub create_messages {
-    my $self = shift;
-
-    my $pot = "$Bin/$self->{domain}.pot";
-    my $po = "$self->{path_po}/$self->{lang}-messages.po";
-    my $js_pot = "$self->{domain}-js.pot";
-    my $js_po = "$self->{path_po}/$self->{lang}-messages-js.po";
-
-    unless ( -f $pot && -f $js_pot ) {
-        $self->extract_messages();
-    }
-
-    say "Create messages ($self->{lang})" if $self->{verbose};
-    my $locale = $self->locale_name();
-    system "$self->{msginit} -i $pot -o $po -l $locale --no-translator 2> /dev/null";
-    warn "Problems creating $pot ".$? if ( $? == -1 );
-    system "$self->{msginit} -i $js_pot -o $js_po -l $locale --no-translator 2> /dev/null";
-    warn "Problems creating $js_pot ".$? if ( $? == -1 );
-
-    # If msginit failed to correctly set Plural-Forms, set a default one
-    system "$self->{sed} --in-place "
-        . "--expression='s/Plural-Forms: nplurals=INTEGER; plural=EXPRESSION/Plural-Forms: nplurals=2; plural=(n != 1)/' "
-        . "$po $js_po";
-}
-
-sub update_messages {
-    my $self = shift;
-
-    my $pot = "$Bin/$self->{domain}.pot";
-    my $po = "$self->{path_po}/$self->{lang}-messages.po";
-    my $js_pot = "$self->{domain}-js.pot";
-    my $js_po = "$self->{path_po}/$self->{lang}-messages-js.po";
-
-    unless ( -f $pot && -f $js_pot ) {
-        $self->extract_messages();
-    }
-
-    if ( -f $po && -f $js_pot ) {
-        say "Update messages ($self->{lang})" if $self->{verbose};
-        system "$self->{msgmerge} --backup=off --quiet -U $po $pot";
-        system "$self->{msgmerge} --backup=off --quiet -U $js_po $js_pot";
-    } else {
-        $self->create_messages();
-    }
-}
-
-sub extract_messages_from_templates {
-    my ($self, $tempdir, $type, @files) = @_;
-
-    my $htdocs = $type eq 'intranet' ? 'intrahtdocs' : 'opachtdocs';
-    my $dir = $self->{context}->config($htdocs);
-    my @keywords = qw(t tx tn txn tnx tp tpx tnp tnpx);
-    my $parser = Template::Parser->new();
-
-    foreach my $file (@files) {
-        say "Extract messages from $file" if $self->{verbose};
-        my $template = read_file(File::Spec->catfile($dir, $file));
-
-        # No need to process a file that doesn't use the i18n.inc file.
-        next unless $template =~ /i18n\.inc/;
-
-        my $data = $parser->parse($template);
-        unless ($data) {
-            warn "Error at $file : " . $parser->error();
-            next;
-        }
-
-        my $destfile = $type eq 'intranet' ?
-            File::Spec->catfile($tempdir, 'koha-tmpl', 'intranet-tmpl', $file) :
-            File::Spec->catfile($tempdir, 'koha-tmpl', 'opac-tmpl', $file);
-
-        make_path(dirname($destfile));
-        open my $fh, '>', $destfile;
-
-        my @blocks = ($data->{BLOCK}, values %{ $data->{DEFBLOCKS} });
-        foreach my $block (@blocks) {
-            my $document = PPI::Document->new(\$block);
-
-            # [% t('foo') %] is compiled to
-            # $output .= $stash->get(['t', ['foo']]);
-            # We try to find all nodes corresponding to keyword (here 't')
-            my $nodes = $document->find(sub {
-                my ($topnode, $element) = @_;
-
-                # Filter out non-valid keywords
-                return 0 unless ($element->isa('PPI::Token::Quote::Single'));
-                return 0 unless (grep {$element->content eq qq{'$_'}} @keywords);
-
-                # keyword (e.g. 't') should be the first element of the arrayref
-                # passed to $stash->get()
-                return 0 if $element->sprevious_sibling;
-
-                return 0 unless $element->snext_sibling
-                    && $element->snext_sibling->snext_sibling
-                    && $element->snext_sibling->snext_sibling->isa('PPI::Structure::Constructor');
-
-                # Check that it's indeed a call to $stash->get()
-                my $statement = $element->statement->parent->statement->parent->statement;
-                return 0 unless grep { $_->isa('PPI::Token::Symbol') && $_->content eq '$stash' } $statement->children;
-                return 0 unless grep { $_->isa('PPI::Token::Operator') && $_->content eq '->' } $statement->children;
-                return 0 unless grep { $_->isa('PPI::Token::Word') && $_->content eq 'get' } $statement->children;
-
-                return 1;
-            });
-
-            next unless $nodes;
-
-            # Write the Perl equivalent of calls to t* functions family, so
-            # xgettext can extract the strings correctly
-            foreach my $node (@$nodes) {
-                my @args = map {
-                    $_->significant && !$_->isa('PPI::Token::Operator') ? $_->content : ()
-                } $node->snext_sibling->snext_sibling->find_first('PPI::Statement')->children;
-
-                my $keyword = $node->content;
-                $keyword =~ s/^'t(.*)'$/__$1/;
-
-                # Only keep required args to have a clean output
-                my @required_args = shift @args;
-                push @required_args, shift @args if $keyword =~ /n/;
-                push @required_args, shift @args if $keyword =~ /p/;
-
-                say $fh "$keyword(" . join(', ', @required_args) . ");";
-            }
-
-        }
-
-        close $fh;
-    }
-
-    return $tempdir;
-}
-
-sub extract_messages {
-    my $self = shift;
-
-    say "Extract messages into POT file" if $self->{verbose};
-
-    my $intranetdir = $self->{context}->config('intranetdir');
-    my $opacdir = $self->{context}->config('opacdir');
-
-    # Find common ancestor directory
-    my @intranetdirs = File::Spec->splitdir($intranetdir);
-    my @opacdirs = File::Spec->splitdir($opacdir);
-    my @basedirs;
-    while (@intranetdirs and @opacdirs) {
-        my ($dir1, $dir2) = (shift @intranetdirs, shift @opacdirs);
-        last if $dir1 ne $dir2;
-        push @basedirs, $dir1;
-    }
-    my $basedir = File::Spec->catdir(@basedirs);
-
-    my @files_to_scan;
-    my @directories_to_scan = ('.');
-    my @blacklist = map { File::Spec->catdir(@intranetdirs, $_) } qw(blib koha-tmpl skel tmp t);
-    while (@directories_to_scan) {
-        my $dir = shift @directories_to_scan;
-        opendir DIR, File::Spec->catdir($basedir, $dir) or die "Unable to open $dir: $!";
-        foreach my $entry (readdir DIR) {
-            next if $entry =~ /^\./;
-            my $relentry = File::Spec->catfile($dir, $entry);
-            my $abspath = File::Spec->catfile($basedir, $relentry);
-            if (-d $abspath and not grep { $_ eq $relentry } @blacklist) {
-                push @directories_to_scan, $relentry;
-            } elsif (-f $abspath and $relentry =~ /\.(pl|pm)$/) {
-                push @files_to_scan, $relentry;
-            }
-        }
-    }
-
-    my $intrahtdocs = $self->{context}->config('intrahtdocs');
-    my $opachtdocs = $self->{context}->config('opachtdocs');
-
-    my @intranet_tt_files;
-    find(sub {
-        if ($File::Find::dir =~ m|/en/| && $_ =~ m/\.(tt|inc)$/) {
-            my $filename = $File::Find::name;
-            $filename =~ s|^$intrahtdocs/||;
-            push @intranet_tt_files, $filename;
-        }
-    }, $intrahtdocs);
-
-    my @opac_tt_files;
-    find(sub {
-        if ($File::Find::dir =~ m|/en/| && $_ =~ m/\.(tt|inc)$/) {
-            my $filename = $File::Find::name;
-            $filename =~ s|^$opachtdocs/||;
-            push @opac_tt_files, $filename;
-        }
-    }, $opachtdocs);
-
-    my $tempdir = tempdir('Koha-translate-XXXX', TMPDIR => 1, CLEANUP => 1);
-    $self->extract_messages_from_templates($tempdir, 'intranet', @intranet_tt_files);
-    $self->extract_messages_from_templates($tempdir, 'opac', @opac_tt_files);
-
-    @intranet_tt_files = map { File::Spec->catfile('koha-tmpl', 'intranet-tmpl', $_) } @intranet_tt_files;
-    @opac_tt_files = map { File::Spec->catfile('koha-tmpl', 'opac-tmpl', $_) } @opac_tt_files;
-    my @tt_files = grep { -e File::Spec->catfile($tempdir, $_) } @intranet_tt_files, @opac_tt_files;
-
-    push @files_to_scan, @tt_files;
-
-    my $xgettext_common_args = "--force-po --from-code=UTF-8 "
-        . "--package-name=Koha --package-version='' "
-        . "-k -k__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2 -k__p:1c,2 "
-        . "-k__px:1c,2 -k__np:1c,2,3 -k__npx:1c,2,3 -kN__ -kN__n:1,2 "
-        . "-kN__p:1c,2 -kN__np:1c,2,3 ";
-    my $xgettext_cmd = "$self->{xgettext} -L Perl $xgettext_common_args "
-        . "-o $Bin/$self->{domain}.pot -D $tempdir -D $basedir";
-    $xgettext_cmd .= " $_" foreach (@files_to_scan);
-
-    if (system($xgettext_cmd) != 0) {
-        die "system call failed: $xgettext_cmd";
-    }
-
-    my @js_dirs = (
-        "$intrahtdocs/prog/js",
-        "$opachtdocs/bootstrap/js",
-    );
-
-    my @js_files;
-    find(sub {
-        if ($_ =~ m/\.js$/) {
-            my $filename = $File::Find::name;
-            $filename =~ s|^$intranetdir/||;
-            push @js_files, $filename;
-        }
-    }, @js_dirs);
-
-    $xgettext_cmd = "$self->{xgettext} -L JavaScript $xgettext_common_args "
-        . "-o $Bin/$self->{domain}-js.pot -D $intranetdir";
-    $xgettext_cmd .= " $_" foreach (@js_files);
-
-    if (system($xgettext_cmd) != 0) {
-        die "system call failed: $xgettext_cmd";
-    }
-
-    my $replace_charset_cmd = "$self->{sed} --in-place " .
-        "--expression='s/charset=CHARSET/charset=UTF-8/' " .
-        "$Bin/$self->{domain}.pot $Bin/$self->{domain}-js.pot";
-    if (system($replace_charset_cmd) != 0) {
-        die "system call failed: $replace_charset_cmd";
-    }
-}
-
 sub install_messages {
     my ($self) = @_;
 
@@ -1012,8 +435,9 @@ sub install_messages {
     my $js_pofile = "$self->{path_po}/$self->{lang}-messages-js.po";
 
     unless ( -f $pofile && -f $js_pofile ) {
-        $self->create_messages();
+        die "PO files for language '$self->{lang}' do not exist";
     }
+
     say "Install messages ($locale)" if $self->{verbose};
     make_path($modir);
     system "$self->{msgfmt} -o $mofile $pofile";
@@ -1035,13 +459,6 @@ sub install_messages {
     }
 }
 
-sub remove_pot {
-    my $self = shift;
-
-    unlink "$Bin/$self->{domain}.pot";
-    unlink "$Bin/$self->{domain}-js.pot";
-}
-
 sub compress {
     my ($self, $files) = @_;
     my @langs = $self->{lang} ? ($self->{lang}) : $self->get_all_langs();
@@ -1074,11 +491,15 @@ sub install {
     my ($self, $files) = @_;
     return unless $self->{lang};
     $self->uncompress();
-    $self->install_tmpl($files) unless $self->{pref_only};
-    $self->install_prefs();
-    $self->install_messages();
-    $self->remove_pot();
-    $self->install_installer();
+
+    if ($self->{pref_only}) {
+        $self->install_prefs();
+    } else {
+        $self->install_tmpl($files);
+        $self->install_prefs();
+        $self->install_messages();
+        $self->install_installer();
+    }
 }
 
 
@@ -1090,34 +511,6 @@ sub get_all_langs {
     @files = map { $_ =~ s/-pref.(po|po.gz)$//r } @files;
 }
 
-
-sub update {
-    my ($self, $files) = @_;
-    my @langs = $self->{lang} ? ($self->{lang}) : $self->get_all_langs();
-    for my $lang ( @langs ) {
-        $self->set_lang( $lang );
-        $self->uncompress();
-        $self->update_tmpl($files) unless $self->{pref_only};
-        $self->update_prefs();
-        $self->update_messages();
-        $self->update_installer();
-    }
-    $self->remove_pot();
-}
-
-
-sub create {
-    my ($self, $files) = @_;
-    return unless $self->{lang};
-    $self->create_tmpl($files) unless $self->{pref_only};
-    $self->create_prefs();
-    $self->create_messages();
-    $self->remove_pot();
-    $self->create_installer();
-}
-
-
-
 1;