Bug 9098 Replace tabulations by spaces in opac-user.pl
[koha.git] / misc / translator / LangInstaller.pm
blob00daaf4499294f9cc4dced01c4fe5515b1c9ce5f
1 package LangInstaller;
3 # Copyright (C) 2010 Tamil s.a.r.l.
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 use Modern::Perl;
22 use C4::Context;
23 # WARNING: Any other tested YAML library fails to work properly in this
24 # script content
25 use YAML::Syck qw( Dump LoadFile );
26 use Locale::PO;
27 use FindBin qw( $Bin );
29 $YAML::Syck::ImplicitTyping = 1;
32 sub set_lang {
33 my ($self, $lang) = @_;
35 $self->{lang} = $lang;
36 $self->{po_path_lang} = $self->{context}->config('intrahtdocs') .
37 "/prog/$lang/modules/admin/preferences";
41 sub new {
42 my ($class, $lang, $pref_only, $verbose) = @_;
44 my $self = { };
46 my $context = C4::Context->new();
47 $self->{context} = $context;
48 $self->{path_pref_en} = $context->config('intrahtdocs') .
49 '/prog/en/modules/admin/preferences';
50 set_lang( $self, $lang ) if $lang;
51 $self->{pref_only} = $pref_only;
52 $self->{verbose} = $verbose;
53 $self->{process} = "$Bin/tmpl_process3.pl " . ($verbose ? '' : '-q');
54 $self->{path_po} = "$Bin/po";
55 $self->{po} = {};
57 # Get all .pref file names
58 opendir my $fh, $self->{path_pref_en};
59 my @pref_files = grep { /.pref/ } readdir($fh);
60 close $fh;
61 $self->{pref_files} = \@pref_files;
63 # Get all available language codes
64 opendir $fh, $self->{path_po};
65 my @langs = map { ($_) =~ /(.*)-i-opac/ }
66 grep { $_ =~ /.*-opac-t-prog/ } readdir($fh);
67 closedir $fh;
68 $self->{langs} = \@langs;
70 # Map for both interfaces opac/intranet
71 my $opachtdocs = $context->config('opachtdocs');
72 $self->{interface} = [
74 name => 'OPAC prog',
75 dir => "$opachtdocs/prog",
76 suffix => '-i-opac-t-prog-v-3006000.po',
79 name => 'Intranet prog',
80 dir => $context->config('intrahtdocs') . '/prog',
81 suffix => '-i-staff-t-prog-v-3006000.po',
85 # Alternate opac themes
86 opendir $fh, $context->config('opachtdocs');
87 for ( grep { not /^\.|\.\.|prog|lib$/ } readdir($fh) ) {
88 push @{$self->{interface}}, {
89 name => "OPAC $_",
90 dir => "$opachtdocs/$_",
91 suffix => "-opac-$_.po",
95 bless $self, $class;
99 sub po_filename {
100 my $self = shift;
102 my $context = C4::Context->new;
103 my $trans_path = $Bin . '/po';
104 my $trans_file = "$trans_path/" . $self->{lang} . "-pref.po";
105 return $trans_file;
109 sub po_append {
110 my ($self, $id, $comment) = @_;
111 my $po = $self->{po};
112 my $p = $po->{$id};
113 if ( $p ) {
114 $p->comment( $p->comment . "\n" . $comment );
116 else {
117 $po->{$id} = Locale::PO->new(
118 -comment => $comment,
119 -msgid => $id,
120 -msgstr => ''
126 sub add_prefs {
127 my ($self, $comment, $prefs) = @_;
129 for my $pref ( @$prefs ) {
130 my $pref_name = '';
131 for my $element ( @$pref ) {
132 if ( ref( $element) eq 'HASH' ) {
133 $pref_name = $element->{pref};
134 last;
137 for my $element ( @$pref ) {
138 if ( ref( $element) eq 'HASH' ) {
139 while ( my ($key, $value) = each(%$element) ) {
140 next unless $key eq 'choices';
141 next unless ref($value) eq 'HASH';
142 for my $ckey ( keys %$value ) {
143 my $id = $self->{file} . "#$pref_name# " . $value->{$ckey};
144 $self->po_append( $id, $comment );
148 elsif ( $element && $pref_name ) {
149 $self->po_append( $self->{file} . "#$pref_name# $element", $comment );
156 sub get_trans_text {
157 my ($self, $id) = @_;
159 my $po = $self->{po}->{$id};
160 return unless $po;
161 return Locale::PO->dequote($po->msgstr);
165 sub update_tab_prefs {
166 my ($self, $pref, $prefs) = @_;
168 for my $p ( @$prefs ) {
169 my $pref_name = '';
170 next unless $p;
171 for my $element ( @$p ) {
172 if ( ref( $element) eq 'HASH' ) {
173 $pref_name = $element->{pref};
174 last;
177 for my $i ( 0..@$p-1 ) {
178 my $element = $p->[$i];
179 if ( ref( $element) eq 'HASH' ) {
180 while ( my ($key, $value) = each(%$element) ) {
181 next unless $key eq 'choices';
182 next unless ref($value) eq 'HASH';
183 for my $ckey ( keys %$value ) {
184 my $id = $self->{file} . "#$pref_name# " . $value->{$ckey};
185 my $text = $self->get_trans_text( $id );
186 $value->{$ckey} = $text if $text;
190 elsif ( $element && $pref_name ) {
191 my $id = $self->{file} . "#$pref_name# $element";
192 my $text = $self->get_trans_text( $id );
193 $p->[$i] = $text if $text;
200 sub get_po_from_prefs {
201 my $self = shift;
203 for my $file ( @{$self->{pref_files}} ) {
204 my $pref = LoadFile( $self->{path_pref_en} . "/$file" );
205 $self->{file} = $file;
206 # Entries for tab titles
207 $self->po_append( $self->{file}, $_ ) for keys %$pref;
208 while ( my ($tab, $tab_content) = each %$pref ) {
209 if ( ref($tab_content) eq 'ARRAY' ) {
210 $self->add_prefs( $tab, $tab_content );
211 next;
213 while ( my ($section, $sysprefs) = each %$tab_content ) {
214 my $comment = "$tab > $section";
215 $self->po_append( $self->{file} . " " . $section, $comment );
216 $self->add_prefs( $comment, $sysprefs );
223 sub save_po {
224 my $self = shift;
225 # Write .po entries into a file put in Koha standard po directory
226 Locale::PO->save_file_fromhash( $self->po_filename, $self->{po} );
227 say "Saved in file: ", $self->po_filename if $self->{verbose};
231 sub get_po_merged_with_en {
232 my $self = shift;
234 # Get po from current 'en' .pref files
235 $self->get_po_from_prefs();
236 my $po_current = $self->{po};
238 # Get po from previous generation
239 my $po_previous = Locale::PO->load_file_ashash( $self->po_filename );
241 for my $id ( keys %$po_current ) {
242 my $po = $po_previous->{Locale::PO->quote($id)};
243 next unless $po;
244 my $text = Locale::PO->dequote( $po->msgstr );
245 $po_current->{$id}->msgstr( $text );
250 sub update_prefs {
251 my $self = shift;
252 print "Update '", $self->{lang},
253 "' preferences .po file from 'en' .pref files\n" if $self->{verbose};
254 $self->get_po_merged_with_en();
255 $self->save_po();
259 sub install_prefs {
260 my $self = shift;
262 unless ( -r $self->{po_path_lang} ) {
263 print "Koha directories hierarchy for ", $self->{lang}, " must be created first\n";
264 exit;
267 # Get the language .po file merged with last modified 'en' preferences
268 $self->get_po_merged_with_en();
270 for my $file ( @{$self->{pref_files}} ) {
271 my $pref = LoadFile( $self->{path_pref_en} . "/$file" );
272 $self->{file} = $file;
273 # First, keys are replaced (tab titles)
274 $pref = do {
275 my %pref = map {
276 $self->get_trans_text( $self->{file} ) || $_ => $pref->{$_}
277 } keys %$pref;
278 \%pref;
280 while ( my ($tab, $tab_content) = each %$pref ) {
281 if ( ref($tab_content) eq 'ARRAY' ) {
282 $self->update_tab_prefs( $pref, $tab_content );
283 next;
285 while ( my ($section, $sysprefs) = each %$tab_content ) {
286 $self->update_tab_prefs( $pref, $sysprefs );
288 my $ntab = {};
289 for my $section ( keys %$tab_content ) {
290 my $id = $self->{file} . " $section";
291 my $text = $self->get_trans_text($id);
292 my $nsection = $text ? $text : $section;
293 $ntab->{$nsection} = $tab_content->{$section};
295 $pref->{$tab} = $ntab;
297 my $file_trans = $self->{po_path_lang} . "/$file";
298 print "Write $file\n" if $self->{verbose};
299 open my $fh, ">", $file_trans;
300 print $fh Dump($pref);
305 sub install_tmpl {
306 my $self = shift;
307 say "Install templates" if $self->{verbose};
308 for my $trans ( @{$self->{interface}} ) {
309 print
310 " Install templates '$trans->{name}'\n",
311 " From: $trans->{dir}/en/\n",
312 " To : $trans->{dir}/$self->{lang}\n",
313 " With: $self->{path_po}/$self->{lang}$trans->{suffix}\n"
314 if $self->{verbose};
315 my $lang_dir = "$trans->{dir}/$self->{lang}";
316 mkdir $lang_dir unless -d $lang_dir;
317 system
318 "$self->{process} install " .
319 "-i $trans->{dir}/en/ " .
320 "-o $trans->{dir}/$self->{lang} ".
321 "-s $self->{path_po}/$self->{lang}$trans->{suffix} -r"
326 sub update_tmpl {
327 my $self = shift;
329 say "Update templates" if $self->{verbose};
330 for my $trans ( @{$self->{interface}} ) {
331 print
332 " Update templates '$trans->{name}'\n",
333 " From: $trans->{dir}/en/\n",
334 " To : $self->{path_po}/$self->{lang}$trans->{suffix}\n"
335 if $self->{verbose};
336 my $lang_dir = "$trans->{dir}/$self->{lang}";
337 mkdir $lang_dir unless -d $lang_dir;
338 system
339 "$self->{process} update " .
340 "-i $trans->{dir}/en/ " .
341 "-s $self->{path_po}/$self->{lang}$trans->{suffix} -r"
346 sub create_prefs {
347 my $self = shift;
349 if ( -e $self->po_filename ) {
350 say "Preferences .po file already exists. Delete it if you want to recreate it.";
351 return;
353 $self->get_po_from_prefs();
354 $self->save_po();
358 sub create_tmpl {
359 my $self = shift;
361 say "Create templates\n" if $self->{verbose};
362 for my $trans ( @{$self->{interface}} ) {
363 print
364 " Create templates .po files for '$trans->{name}'\n",
365 " From: $trans->{dir}/en/\n",
366 " To : $self->{path_po}/$self->{lang}$trans->{suffix}\n"
367 if $self->{verbose};
368 system
369 "$self->{process} create " .
370 "-i $trans->{dir}/en/ " .
371 "-s $self->{path_po}/$self->{lang}$trans->{suffix} -r"
376 sub install {
377 my $self = shift;
378 return unless $self->{lang};
379 $self->install_tmpl() unless $self->{pref_only};
380 $self->install_prefs();
384 sub get_all_langs {
385 my $self = shift;
386 opendir( my $dh, $self->{path_po} );
387 my @files = grep { $_ =~ /-i-opac-t-prog-v-3006000.po$/ }
388 readdir $dh;
389 @files = map { $_ =~ s/-i-opac-t-prog-v-3006000.po$//; $_ } @files;
393 sub update {
394 my $self = shift;
395 my @langs = $self->{lang} ? ($self->{lang}) : $self->get_all_langs();
396 for my $lang ( @langs ) {
397 $self->set_lang( $lang );
398 $self->update_tmpl() unless $self->{pref_only};
399 $self->update_prefs();
404 sub create {
405 my $self = shift;
406 return unless $self->{lang};
407 $self->create_tmpl() unless $self->{pref_only};
408 $self->create_prefs();
416 =head1 NAME
418 LangInstaller.pm - Handle templates and preferences translation
420 =head1 SYNOPSYS
422 my $installer = LangInstaller->new( 'fr-FR' );
423 $installer->create();
424 $installer->update();
425 $installer->install();
426 for my $lang ( @{$installer->{langs} ) {
427 $installer->set_lang( $lan );
428 $installer->install();
431 =head1 METHODS
433 =head2 new
435 Create a new instance of the installer object.
437 =head2 create
439 For the current language, create .po files for templates and preferences based
440 of the english ('en') version.
442 =head2 update
444 For the current language, update .po files.
446 =head2 install
448 For the current langage C<$self->{lang}, use .po files to translate the english
449 version of templates and preferences files and copy those files in the
450 appropriate directory.
452 =over
454 =item translate create F<lang>
456 Create 3 .po files in F<po> subdirectory: (1) from opac pages templates, (2)
457 intranet templates, and (3) from preferences.
459 =over
461 =item F<lang>-opac.po
463 Contains extracted text from english (en) OPAC templates found in
464 <KOHA_ROOT>/koha-tmpl/opac-tmpl/prog/en/ directory.
466 =item F<lang>-intranet.po
468 Contains extracted text from english (en) intranet templates found in
469 <KOHA_ROOT>/koha-tmpl/intranet-tmpl/prog/en/ directory.
471 =item F<lang>-pref.po
473 Contains extracted text from english (en) preferences. They are found in files
474 located in <KOHA_ROOT>/koha-tmpl/intranet-tmpl/prog/en/admin/preferences
475 directory.
477 =back
479 =item pref-trans update F<lang>
481 Update .po files in F<po> directory, named F<lang>-*.po.
483 =item pref-trans install F<lang>
485 =back
487 =cut