Lines 20-69
package LangInstaller;
Link Here
|
20 |
use Modern::Perl; |
20 |
use Modern::Perl; |
21 |
|
21 |
|
22 |
use C4::Context; |
22 |
use C4::Context; |
|
|
23 |
|
23 |
# WARNING: Any other tested YAML library fails to work properly in this |
24 |
# WARNING: Any other tested YAML library fails to work properly in this |
24 |
# script content |
25 |
# script content |
25 |
# FIXME Really? |
26 |
# FIXME Really? |
26 |
use YAML::XS; |
27 |
use YAML::XS; |
27 |
use Locale::PO; |
28 |
use Locale::PO; |
28 |
use FindBin qw( $Bin ); |
29 |
use FindBin qw( $Bin ); |
29 |
use File::Path qw( make_path ); |
30 |
use File::Path qw( make_path ); |
30 |
use File::Copy; |
31 |
use File::Copy; |
31 |
use File::Slurp qw( read_file ); |
32 |
use File::Slurp qw( read_file ); |
32 |
use JSON qw( decode_json encode_json ); |
33 |
use JSON qw( decode_json encode_json ); |
33 |
|
34 |
|
34 |
use Koha::Plugins; |
35 |
use Koha::Plugins; |
35 |
|
36 |
|
36 |
sub set_lang { |
37 |
sub set_lang { |
37 |
my ($self, $lang) = @_; |
38 |
my ( $self, $lang ) = @_; |
38 |
|
39 |
|
39 |
$self->{lang} = $lang; |
40 |
$self->{lang} = $lang; |
40 |
$self->{po_path_lang} = C4::Context->config('intrahtdocs') . |
41 |
$self->{po_path_lang} = C4::Context->config('intrahtdocs') . "/prog/$lang/modules/admin/preferences"; |
41 |
"/prog/$lang/modules/admin/preferences"; |
|
|
42 |
} |
42 |
} |
43 |
|
43 |
|
44 |
sub new { |
44 |
sub new { |
45 |
my ($class, $args) = @_; |
45 |
my ( $class, $args ) = @_; |
46 |
|
46 |
|
47 |
my $lang = $args->{lang}; |
47 |
my $lang = $args->{lang}; |
48 |
my $pref_only = $args->{pref_only}; |
48 |
my $pref_only = $args->{pref_only}; |
49 |
my $verbose = $args->{verbose}; |
49 |
my $verbose = $args->{verbose}; |
50 |
|
50 |
|
51 |
my $self = { }; |
51 |
my $self = {}; |
52 |
|
52 |
|
53 |
$self->{path_pref_en} = C4::Context->config('intrahtdocs') . |
53 |
$self->{path_pref_en} = C4::Context->config('intrahtdocs') . '/prog/en/modules/admin/preferences'; |
54 |
'/prog/en/modules/admin/preferences'; |
|
|
55 |
set_lang( $self, $lang ) if $lang; |
54 |
set_lang( $self, $lang ) if $lang; |
56 |
$self->{pref_only} = $pref_only; |
55 |
$self->{pref_only} = $pref_only; |
57 |
$self->{verbose} = $verbose; |
56 |
$self->{verbose} = $verbose; |
58 |
$self->{process} = "$Bin/tmpl_process3.pl " . ($verbose ? '' : '-q'); |
57 |
$self->{process} = "$Bin/tmpl_process3.pl " . ( $verbose ? '' : '-q' ); |
59 |
$self->{path_po} = "$Bin/po"; |
58 |
$self->{path_po} = "$Bin/po"; |
60 |
$self->{po} = {}; |
59 |
$self->{po} = {}; |
61 |
$self->{domain} = 'Koha'; |
60 |
$self->{domain} = 'Koha'; |
62 |
$self->{msgfmt} = `which msgfmt`; |
61 |
$self->{msgfmt} = `which msgfmt`; |
63 |
$self->{po2json} = "yarn run po2json"; |
62 |
$self->{po2json} = "yarn run po2json"; |
64 |
$self->{gzip} = `which gzip`; |
63 |
$self->{gzip} = `which gzip`; |
65 |
$self->{gunzip} = `which gunzip`; |
64 |
$self->{gunzip} = `which gunzip`; |
66 |
$self->{plugin_dirs} = _identify_translatable_plugins(); |
65 |
$self->{plugin_dirs} = _identify_translatable_plugins(); |
67 |
chomp $self->{msgfmt}; |
66 |
chomp $self->{msgfmt}; |
68 |
chomp $self->{gzip}; |
67 |
chomp $self->{gzip}; |
69 |
chomp $self->{gunzip}; |
68 |
chomp $self->{gunzip}; |
Lines 76-82
sub new {
Link Here
|
76 |
|
75 |
|
77 |
# Get all available language codes |
76 |
# Get all available language codes |
78 |
opendir $fh, $self->{path_po}; |
77 |
opendir $fh, $self->{path_po}; |
79 |
my @langs = map { ($_) =~ /(.*)-pref/ } |
78 |
my @langs = map { ($_) =~ /(.*)-pref/ } |
80 |
grep { $_ =~ /.*-pref/ } readdir($fh); |
79 |
grep { $_ =~ /.*-pref/ } readdir($fh); |
81 |
closedir $fh; |
80 |
closedir $fh; |
82 |
$self->{langs} = \@langs; |
81 |
$self->{langs} = \@langs; |
Lines 94-100
sub new {
Link Here
|
94 |
# OPAC themes |
93 |
# OPAC themes |
95 |
opendir my $dh, C4::Context->config('opachtdocs'); |
94 |
opendir my $dh, C4::Context->config('opachtdocs'); |
96 |
for my $theme ( grep { not /^\.|lib|xslt/ } readdir($dh) ) { |
95 |
for my $theme ( grep { not /^\.|lib|xslt/ } readdir($dh) ) { |
97 |
push @{$self->{interface}}, { |
96 |
push @{ $self->{interface} }, { |
98 |
name => "OPAC $theme", |
97 |
name => "OPAC $theme", |
99 |
dir => "$opachtdocs/$theme", |
98 |
dir => "$opachtdocs/$theme", |
100 |
suffix => "-opac-$theme.po", |
99 |
suffix => "-opac-$theme.po", |
Lines 103-115
sub new {
Link Here
|
103 |
|
102 |
|
104 |
# MARC flavours (hardcoded list) |
103 |
# MARC flavours (hardcoded list) |
105 |
for ( "MARC21", "UNIMARC" ) { |
104 |
for ( "MARC21", "UNIMARC" ) { |
|
|
105 |
|
106 |
# search for strings on staff & opac marc files |
106 |
# search for strings on staff & opac marc files |
107 |
my $dirs = C4::Context->config('intrahtdocs') . '/prog'; |
107 |
my $dirs = C4::Context->config('intrahtdocs') . '/prog'; |
108 |
opendir $fh, C4::Context->config('opachtdocs'); |
108 |
opendir $fh, C4::Context->config('opachtdocs'); |
109 |
for ( grep { not /^\.|\.\.|lib$|xslt/ } readdir($fh) ) { |
109 |
for ( grep { not /^\.|\.\.|lib$|xslt/ } readdir($fh) ) { |
110 |
$dirs .= ' ' . "$opachtdocs/$_"; |
110 |
$dirs .= ' ' . "$opachtdocs/$_"; |
111 |
} |
111 |
} |
112 |
push @{$self->{interface}}, { |
112 |
push @{ $self->{interface} }, { |
113 |
name => "$_", |
113 |
name => "$_", |
114 |
dir => $dirs, |
114 |
dir => $dirs, |
115 |
suffix => "-marc-$_.po", |
115 |
suffix => "-marc-$_.po", |
Lines 117-146
sub new {
Link Here
|
117 |
} |
117 |
} |
118 |
|
118 |
|
119 |
# EN YAML installer files |
119 |
# EN YAML installer files |
120 |
push @{$self->{installer}}, { |
120 |
push @{ $self->{installer} }, { |
121 |
name => "YAML installer files", |
121 |
name => "YAML installer files", |
122 |
dirs => [ 'installer/data/mysql/en/mandatory', |
122 |
dirs => [ |
123 |
'installer/data/mysql/en/optional'], |
123 |
'installer/data/mysql/en/mandatory', |
|
|
124 |
'installer/data/mysql/en/optional' |
125 |
], |
124 |
suffix => "-installer.po", |
126 |
suffix => "-installer.po", |
125 |
}; |
127 |
}; |
126 |
|
128 |
|
127 |
# EN MARC21 YAML installer files |
129 |
# EN MARC21 YAML installer files |
128 |
push @{$self->{installer}}, { |
130 |
push @{ $self->{installer} }, { |
129 |
name => "MARC21 YAML installer files", |
131 |
name => "MARC21 YAML installer files", |
130 |
dirs => [ 'installer/data/mysql/en/marcflavour/marc21/mandatory', |
132 |
dirs => [ |
131 |
'installer/data/mysql/en/marcflavour/marc21/optional'], |
133 |
'installer/data/mysql/en/marcflavour/marc21/mandatory', |
|
|
134 |
'installer/data/mysql/en/marcflavour/marc21/optional' |
135 |
], |
132 |
suffix => "-installer-MARC21.po", |
136 |
suffix => "-installer-MARC21.po", |
133 |
}; |
137 |
}; |
134 |
|
138 |
|
135 |
# EN UNIMARC YAML installer files |
139 |
# EN UNIMARC YAML installer files |
136 |
push @{$self->{installer}}, { |
140 |
push @{ $self->{installer} }, { |
137 |
name => "UNIMARC YAML installer files", |
141 |
name => "UNIMARC YAML installer files", |
138 |
dirs => [ 'installer/data/mysql/en/marcflavour/unimarc/mandatory', |
142 |
dirs => [ |
139 |
'installer/data/mysql/en/marcflavour/unimarc/optional'], |
143 |
'installer/data/mysql/en/marcflavour/unimarc/mandatory', |
|
|
144 |
'installer/data/mysql/en/marcflavour/unimarc/optional' |
145 |
], |
140 |
suffix => "-installer-UNIMARC.po", |
146 |
suffix => "-installer-UNIMARC.po", |
141 |
}; |
147 |
}; |
142 |
|
148 |
|
143 |
|
|
|
144 |
bless $self, $class; |
149 |
bless $self, $class; |
145 |
} |
150 |
} |
146 |
|
151 |
|
Lines 154-165
sub po_filename {
Link Here
|
154 |
} |
159 |
} |
155 |
|
160 |
|
156 |
sub get_trans_text { |
161 |
sub get_trans_text { |
157 |
my ($self, $msgid, $default) = @_; |
162 |
my ( $self, $msgid, $default ) = @_; |
158 |
|
163 |
|
159 |
my $po = $self->{po}->{Locale::PO->quote($msgid)}; |
164 |
my $po = $self->{po}->{ Locale::PO->quote($msgid) }; |
160 |
if ( $po and not defined( $po->fuzzy() ) ) { |
165 |
if ( $po and not defined( $po->fuzzy() ) ) { |
161 |
my $msgstr = Locale::PO->dequote($po->msgstr); |
166 |
my $msgstr = Locale::PO->dequote( $po->msgstr ); |
162 |
if ($msgstr and length($msgstr) > 0) { |
167 |
if ( $msgstr and length($msgstr) > 0 ) { |
163 |
return $msgstr; |
168 |
return $msgstr; |
164 |
} |
169 |
} |
165 |
} |
170 |
} |
Lines 168-197
sub get_trans_text {
Link Here
|
168 |
} |
173 |
} |
169 |
|
174 |
|
170 |
sub get_translated_tab_content { |
175 |
sub get_translated_tab_content { |
171 |
my ($self, $file, $tab_content) = @_; |
176 |
my ( $self, $file, $tab_content ) = @_; |
172 |
|
177 |
|
173 |
if ( ref($tab_content) eq 'ARRAY' ) { |
178 |
if ( ref($tab_content) eq 'ARRAY' ) { |
174 |
return $self->get_translated_prefs($file, $tab_content); |
179 |
return $self->get_translated_prefs( $file, $tab_content ); |
175 |
} |
180 |
} |
176 |
|
181 |
|
177 |
my $translated_tab_content = { |
182 |
my $translated_tab_content = { |
178 |
map { |
183 |
map { |
179 |
my $section = $_; |
184 |
my $section = $_; |
180 |
my $sysprefs = $tab_content->{$section}; |
185 |
my $sysprefs = $tab_content->{$section}; |
181 |
my $msgid = sprintf('%s %s', $file, $section); |
186 |
my $msgid = sprintf( '%s %s', $file, $section ); |
182 |
|
187 |
|
183 |
$self->get_trans_text($msgid, $section) => $self->get_translated_prefs($file, $sysprefs); |
188 |
$self->get_trans_text( $msgid, $section ) => $self->get_translated_prefs( $file, $sysprefs ); |
184 |
} keys %$tab_content |
189 |
} keys %$tab_content |
185 |
}; |
190 |
}; |
186 |
|
191 |
|
187 |
if ( keys %$translated_tab_content != keys %$tab_content ) { |
192 |
if ( keys %$translated_tab_content != keys %$tab_content ) { |
188 |
my %duplicates; |
193 |
my %duplicates; |
189 |
for my $section (keys %$tab_content) { |
194 |
for my $section ( keys %$tab_content ) { |
190 |
push @{$duplicates{$self->get_trans_text("$file $section", $section)}}, $section; |
195 |
push @{ $duplicates{ $self->get_trans_text( "$file $section", $section ) } }, $section; |
191 |
} |
196 |
} |
192 |
for my $translation (keys %duplicates) { |
197 |
for my $translation ( keys %duplicates ) { |
193 |
if (@{$duplicates{$translation}} > 1) { |
198 |
if ( @{ $duplicates{$translation} } > 1 ) { |
194 |
warn qq(In file "$file", "$translation" is a translation for sections ") . join('", "', @{$duplicates{$translation}}) . '"'; |
199 |
warn qq(In file "$file", "$translation" is a translation for sections ") |
|
|
200 |
. join( '", "', @{ $duplicates{$translation} } ) . '"'; |
195 |
} |
201 |
} |
196 |
} |
202 |
} |
197 |
} |
203 |
} |
Lines 200-217
sub get_translated_tab_content {
Link Here
|
200 |
} |
206 |
} |
201 |
|
207 |
|
202 |
sub get_translated_prefs { |
208 |
sub get_translated_prefs { |
203 |
my ($self, $file, $sysprefs) = @_; |
209 |
my ( $self, $file, $sysprefs ) = @_; |
204 |
|
210 |
|
205 |
my $translated_prefs = [ |
211 |
my $translated_prefs = [ |
206 |
map { |
212 |
map { |
207 |
my ($pref_elt) = grep { ref($_) eq 'HASH' && exists $_->{pref} } @$_; |
213 |
my ($pref_elt) = grep { ref($_) eq 'HASH' && exists $_->{pref} } @$_; |
208 |
my $pref_name = $pref_elt ? $pref_elt->{pref} : ''; |
214 |
my $pref_name = $pref_elt ? $pref_elt->{pref} : ''; |
209 |
|
215 |
|
210 |
my $translated_syspref = [ |
216 |
my $translated_syspref = [ map { $self->get_translated_pref( $file, $pref_name, $_ ); } @$_ ]; |
211 |
map { |
|
|
212 |
$self->get_translated_pref($file, $pref_name, $_); |
213 |
} @$_ |
214 |
]; |
215 |
|
217 |
|
216 |
$translated_syspref; |
218 |
$translated_syspref; |
217 |
} @$sysprefs |
219 |
} @$sysprefs |
Lines 221-247
sub get_translated_prefs {
Link Here
|
221 |
} |
223 |
} |
222 |
|
224 |
|
223 |
sub get_translated_pref { |
225 |
sub get_translated_pref { |
224 |
my ($self, $file, $pref_name, $syspref) = @_; |
226 |
my ( $self, $file, $pref_name, $syspref ) = @_; |
225 |
|
227 |
|
226 |
unless (ref($syspref)) { |
228 |
unless ( ref($syspref) ) { |
227 |
$syspref //= ''; |
229 |
$syspref //= ''; |
228 |
my $msgid = sprintf('%s#%s# %s', $file, $pref_name, $syspref); |
230 |
my $msgid = sprintf( '%s#%s# %s', $file, $pref_name, $syspref ); |
229 |
return $self->get_trans_text($msgid, $syspref); |
231 |
return $self->get_trans_text( $msgid, $syspref ); |
230 |
} |
232 |
} |
231 |
|
233 |
|
232 |
my $translated_pref = { |
234 |
my $translated_pref = { |
233 |
map { |
235 |
map { |
234 |
my $key = $_; |
236 |
my $key = $_; |
235 |
my $value = $syspref->{$key}; |
237 |
my $value = $syspref->{$key}; |
236 |
|
238 |
|
237 |
my $translated_value = $value; |
239 |
my $translated_value = $value; |
238 |
if (($key eq 'choices' || $key eq 'multiple') && ref($value) eq 'HASH') { |
240 |
if ( ( $key eq 'choices' || $key eq 'multiple' ) && ref($value) eq 'HASH' ) { |
239 |
$translated_value = { |
241 |
$translated_value = { |
240 |
map { |
242 |
map { |
241 |
my $msgid = sprintf('%s#%s# %s', $file, $pref_name, $value->{$_}); |
243 |
my $msgid = sprintf( '%s#%s# %s', $file, $pref_name, $value->{$_} ); |
242 |
$_ => $self->get_trans_text($msgid, $value->{$_}) |
244 |
$_ => $self->get_trans_text( $msgid, $value->{$_} ) |
243 |
} keys %$value |
245 |
} keys %$value |
244 |
} |
246 |
}; |
245 |
} |
247 |
} |
246 |
|
248 |
|
247 |
$key => $translated_value |
249 |
$key => $translated_value |
Lines 259-304
sub install_prefs {
Link Here
|
259 |
exit; |
261 |
exit; |
260 |
} |
262 |
} |
261 |
|
263 |
|
262 |
$self->{po} = Locale::PO->load_file_ashash($self->po_filename("-pref.po"), 'utf8'); |
264 |
$self->{po} = Locale::PO->load_file_ashash( $self->po_filename("-pref.po"), 'utf8' ); |
263 |
|
265 |
|
264 |
for my $file ( @{$self->{pref_files}} ) { |
266 |
for my $file ( @{ $self->{pref_files} } ) { |
265 |
my $pref = YAML::XS::LoadFile( $self->{path_pref_en} . "/$file" ); |
267 |
my $pref = YAML::XS::LoadFile( $self->{path_pref_en} . "/$file" ); |
266 |
|
268 |
|
267 |
my $translated_pref = { |
269 |
my $translated_pref = { |
268 |
map { |
270 |
map { |
269 |
my $tab = $_; |
271 |
my $tab = $_; |
270 |
my $tab_content = $pref->{$tab}; |
272 |
my $tab_content = $pref->{$tab}; |
271 |
|
273 |
|
272 |
$self->get_trans_text($file, $tab) => $self->get_translated_tab_content($file, $tab_content); |
274 |
$self->get_trans_text( $file, $tab ) => $self->get_translated_tab_content( $file, $tab_content ); |
273 |
} keys %$pref |
275 |
} keys %$pref |
274 |
}; |
276 |
}; |
275 |
|
277 |
|
276 |
if ( keys %$translated_pref != keys %$pref ) { |
278 |
if ( keys %$translated_pref != keys %$pref ) { |
277 |
my %duplicates; |
279 |
my %duplicates; |
278 |
for my $tab (keys %$pref) { |
280 |
for my $tab ( keys %$pref ) { |
279 |
push @{$duplicates{$self->get_trans_text($file, $tab)}}, $tab; |
281 |
push @{ $duplicates{ $self->get_trans_text( $file, $tab ) } }, $tab; |
280 |
} |
282 |
} |
281 |
for my $translation (keys %duplicates) { |
283 |
for my $translation ( keys %duplicates ) { |
282 |
if (@{$duplicates{$translation}} > 1) { |
284 |
if ( @{ $duplicates{$translation} } > 1 ) { |
283 |
warn qq(In file "$file", "$translation" is a translation for tabs ") . join('", "', @{$duplicates{$translation}}) . '"'; |
285 |
warn qq(In file "$file", "$translation" is a translation for tabs ") |
|
|
286 |
. join( '", "', @{ $duplicates{$translation} } ) . '"'; |
284 |
} |
287 |
} |
285 |
} |
288 |
} |
286 |
} |
289 |
} |
287 |
|
290 |
|
288 |
my $file_trans = $self->{po_path_lang} . "/$file"; |
291 |
my $file_trans = $self->{po_path_lang} . "/$file"; |
289 |
print "Write $file\n" if $self->{verbose}; |
292 |
print "Write $file\n" if $self->{verbose}; |
290 |
YAML::XS::DumpFile($file_trans, $translated_pref); |
293 |
YAML::XS::DumpFile( $file_trans, $translated_pref ); |
291 |
} |
294 |
} |
292 |
} |
295 |
} |
293 |
|
296 |
|
294 |
|
|
|
295 |
sub install_tmpl { |
297 |
sub install_tmpl { |
296 |
my ($self, $files) = @_; |
298 |
my ( $self, $files ) = @_; |
297 |
say "Install templates" if $self->{verbose}; |
299 |
say "Install templates" if $self->{verbose}; |
298 |
for my $trans ( @{$self->{interface}} ) { |
300 |
for my $trans ( @{ $self->{interface} } ) { |
299 |
my @t_dirs = split(" ", $trans->{dir}); |
301 |
my @t_dirs = split( " ", $trans->{dir} ); |
300 |
for my $t_dir ( @t_dirs ) { |
302 |
for my $t_dir (@t_dirs) { |
301 |
my @files = @$files; |
303 |
my @files = @$files; |
302 |
my @nomarc = (); |
304 |
my @nomarc = (); |
303 |
print |
305 |
print |
304 |
" Install templates '$trans->{name}'\n", |
306 |
" Install templates '$trans->{name}'\n", |
Lines 311-329
sub install_tmpl {
Link Here
|
311 |
my $lang_dir = "$t_dir/$self->{lang}"; |
313 |
my $lang_dir = "$t_dir/$self->{lang}"; |
312 |
$lang_dir =~ s|/en/|/$self->{lang}/|; |
314 |
$lang_dir =~ s|/en/|/$self->{lang}/|; |
313 |
mkdir $lang_dir unless -d $lang_dir; |
315 |
mkdir $lang_dir unless -d $lang_dir; |
|
|
316 |
|
314 |
# if installing MARC po file, only touch corresponding files |
317 |
# if installing MARC po file, only touch corresponding files |
315 |
my $marc = ( $trans->{name} =~ /MARC/ )?"-m \"$trans->{name}\"":""; # for MARC translations |
318 |
my $marc = ( $trans->{name} =~ /MARC/ ) ? "-m \"$trans->{name}\"" : ""; # for MARC translations |
316 |
# if not installing MARC po file, ignore all MARC files |
319 |
# if not installing MARC po file, ignore all MARC files |
317 |
@nomarc = ( 'marc21', 'unimarc' ) if ( $trans->{name} !~ /MARC/ ); # hardcoded MARC variants |
320 |
@nomarc = ( 'marc21', 'unimarc' ) if ( $trans->{name} !~ /MARC/ ); # hardcoded MARC variants |
318 |
|
321 |
|
319 |
system |
322 |
system "$self->{process} install " |
320 |
"$self->{process} install " . |
323 |
. "-i $trans_dir " |
321 |
"-i $trans_dir " . |
324 |
. "-o $lang_dir " |
322 |
"-o $lang_dir ". |
325 |
. "-s $self->{path_po}/$self->{lang}$trans->{suffix} -r " |
323 |
"-s $self->{path_po}/$self->{lang}$trans->{suffix} -r " . |
326 |
. "$marc " |
324 |
"$marc " . |
327 |
. ( @files ? ' -f ' . join ' -f ', @files : '' ) |
325 |
( @files ? ' -f ' . join ' -f ', @files : '') . |
328 |
. ( @nomarc ? ' -n ' . join ' -n ', @nomarc : '' ); |
326 |
( @nomarc ? ' -n ' . join ' -n ', @nomarc : ''); |
|
|
327 |
} |
329 |
} |
328 |
} |
330 |
} |
329 |
|
331 |
|
Lines 353-404
sub translate_yaml {
Link Here
|
353 |
my $po_file = $self->po_filename( $target->{suffix} ); |
355 |
my $po_file = $self->po_filename( $target->{suffix} ); |
354 |
return $srcyml unless ( -e $po_file ); |
356 |
return $srcyml unless ( -e $po_file ); |
355 |
|
357 |
|
356 |
my $po_ref = Locale::PO->load_file_ashash( $po_file, 'utf8' ); |
358 |
my $po_ref = Locale::PO->load_file_ashash( $po_file, 'utf8' ); |
357 |
|
359 |
|
358 |
my $dstyml = YAML::XS::LoadFile( $srcyml ); |
360 |
my $dstyml = YAML::XS::LoadFile($srcyml); |
359 |
|
361 |
|
360 |
# translate fields in table rows |
362 |
# translate fields in table rows |
361 |
my @tables = @{ $dstyml->{'tables'} }; |
363 |
my @tables = @{ $dstyml->{'tables'} }; |
362 |
for my $table ( @tables ) { # each table |
364 |
for my $table (@tables) { # each table |
363 |
my $table_name = ( keys %$table )[0]; |
365 |
my $table_name = ( keys %$table )[0]; |
364 |
my @translatable = @{ $table->{$table_name}->{translatable} }; |
366 |
my @translatable = @{ $table->{$table_name}->{translatable} }; |
365 |
my @rows = @{ $table->{$table_name}->{rows} }; |
367 |
my @rows = @{ $table->{$table_name}->{rows} }; |
366 |
my @multiline = @{ $table->{$table_name}->{'multiline'} }; # to check multiline values |
368 |
my @multiline = @{ $table->{$table_name}->{'multiline'} }; # to check multiline values |
367 |
for my $row ( @rows ) { # each row |
369 |
for my $row (@rows) { # each row |
368 |
for my $field ( @translatable ) { # each translatable field |
370 |
for my $field (@translatable) { # each translatable field |
369 |
if ( @multiline and grep { $_ eq $field } @multiline ) { # multiline fields, only notices ATM |
371 |
if ( @multiline and grep { $_ eq $field } @multiline ) { # multiline fields, only notices ATM |
370 |
foreach my $line ( @{$row->{$field}} ) { |
372 |
foreach my $line ( @{ $row->{$field} } ) { |
371 |
my @ttvar; |
373 |
my @ttvar; |
372 |
while ( $line =~ s/(<<.*?>>|\[\%.*?\%\]|<.*?>)/\%s/ ) { # put placeholders, save matches |
374 |
while ( $line =~ s/(<<.*?>>|\[\%.*?\%\]|<.*?>)/\%s/ ) { # put placeholders, save matches |
373 |
my $var = $1; |
375 |
my $var = $1; |
374 |
push @ttvar, $var; |
376 |
push @ttvar, $var; |
375 |
} |
377 |
} |
376 |
|
378 |
|
377 |
if ( $line =~ /^(\s|%s|-|[[:punct:]]|\(|\))*$/ ) { # ignore non strings |
379 |
if ( $line =~ /^(\s|%s|-|[[:punct:]]|\(|\))*$/ ) { # ignore non strings |
378 |
while ( @ttvar ) { # restore placeholders |
380 |
while (@ttvar) { # restore placeholders |
379 |
my $var = shift @ttvar; |
381 |
my $var = shift @ttvar; |
380 |
$line =~ s/\%s/$var/; |
382 |
$line =~ s/\%s/$var/; |
381 |
} |
383 |
} |
382 |
next; |
384 |
next; |
383 |
} else { |
385 |
} else { |
384 |
my $po = $po_ref->{"\"$line\""}; # quoted key |
386 |
my $po = $po_ref->{"\"$line\""}; # quoted key |
385 |
if ( $po and not defined( $po->fuzzy() ) # not fuzzy |
387 |
if ( |
386 |
and length( $po->msgid() ) > 2 # not empty msgid |
388 |
$po and not defined( $po->fuzzy() ) # not fuzzy |
387 |
and length( $po->msgstr() ) > 2 ) { # not empty msgstr |
389 |
and length( $po->msgid() ) > 2 # not empty msgid |
|
|
390 |
and length( $po->msgstr() ) > 2 |
391 |
) |
392 |
{ # not empty msgstr |
388 |
$line = $po->dequote( $po->msgstr() ); |
393 |
$line = $po->dequote( $po->msgstr() ); |
389 |
} |
394 |
} |
390 |
while ( @ttvar ) { # restore placeholders |
395 |
while (@ttvar) { # restore placeholders |
391 |
my $var = shift @ttvar; |
396 |
my $var = shift @ttvar; |
392 |
$line =~ s/\%s/$var/; |
397 |
$line =~ s/\%s/$var/; |
393 |
} |
398 |
} |
394 |
} |
399 |
} |
395 |
} |
400 |
} |
396 |
} else { |
401 |
} else { |
397 |
next unless defined $row->{$field}; # next if null value |
402 |
next unless defined $row->{$field}; # next if null value |
398 |
my $po = $po_ref->{"\"$row->{$field}\""}; # quoted key |
403 |
my $po = $po_ref->{"\"$row->{$field}\""}; # quoted key |
399 |
if ( $po and not defined( $po->fuzzy() ) # not fuzzy |
404 |
if ( |
400 |
and length( $po->msgid() ) > 2 # not empty msgid |
405 |
$po and not defined( $po->fuzzy() ) # not fuzzy |
401 |
and length( $po->msgstr() ) > 2 ) { # not empty msgstr |
406 |
and length( $po->msgid() ) > 2 # not empty msgid |
|
|
407 |
and length( $po->msgstr() ) > 2 |
408 |
) |
409 |
{ # not empty msgstr |
402 |
$row->{$field} = $po->dequote( $po->msgstr() ); |
410 |
$row->{$field} = $po->dequote( $po->msgstr() ); |
403 |
} |
411 |
} |
404 |
} |
412 |
} |
Lines 409-417
sub translate_yaml {
Link Here
|
409 |
# translate descriptions |
417 |
# translate descriptions |
410 |
for my $description ( @{ $dstyml->{'description'} } ) { |
418 |
for my $description ( @{ $dstyml->{'description'} } ) { |
411 |
my $po = $po_ref->{"\"$description\""}; |
419 |
my $po = $po_ref->{"\"$description\""}; |
412 |
if ( $po and not defined( $po->fuzzy() ) |
420 |
if ( $po |
413 |
and length( $po->msgid() ) > 2 |
421 |
and not defined( $po->fuzzy() ) |
414 |
and length( $po->msgstr() ) > 2 ) { |
422 |
and length( $po->msgid() ) > 2 |
|
|
423 |
and length( $po->msgstr() ) > 2 ) |
424 |
{ |
415 |
$description = $po->dequote( $po->msgstr() ); |
425 |
$description = $po->dequote( $po->msgstr() ); |
416 |
} |
426 |
} |
417 |
} |
427 |
} |
Lines 425-431
sub install_installer {
Link Here
|
425 |
|
435 |
|
426 |
my $intradir = C4::Context->config('intranetdir'); |
436 |
my $intradir = C4::Context->config('intranetdir'); |
427 |
my $db_scheme = C4::Context->config('db_scheme'); |
437 |
my $db_scheme = C4::Context->config('db_scheme'); |
428 |
my $langdir = "$intradir/installer/data/$db_scheme/$self->{lang}"; |
438 |
my $langdir = "$intradir/installer/data/$db_scheme/$self->{lang}"; |
429 |
|
439 |
|
430 |
say "Install installer files\n" if $self->{verbose}; |
440 |
say "Install installer files\n" if $self->{verbose}; |
431 |
|
441 |
|
Lines 435-445
sub install_installer {
Link Here
|
435 |
( my $tdir = "$dir" ) =~ s|/en/|/$self->{lang}/|; |
445 |
( my $tdir = "$dir" ) =~ s|/en/|/$self->{lang}/|; |
436 |
make_path("$intradir/$tdir"); |
446 |
make_path("$intradir/$tdir"); |
437 |
|
447 |
|
438 |
opendir( my $dh, "$intradir/$dir" ) or die ("Can't open $intradir/$dir"); |
448 |
opendir( my $dh, "$intradir/$dir" ) or die("Can't open $intradir/$dir"); |
439 |
my @files = grep { ! /^\.+$/ } readdir($dh); |
449 |
my @files = grep { !/^\.+$/ } readdir($dh); |
440 |
close($dh); |
450 |
close($dh); |
441 |
|
451 |
|
442 |
for my $file ( @files ) { |
452 |
for my $file (@files) { |
443 |
if ( $file =~ /yml$/ ) { |
453 |
if ( $file =~ /yml$/ ) { |
444 |
my $translated_yaml = translate_yaml( $self, $target, "$intradir/$dir/$file" ); |
454 |
my $translated_yaml = translate_yaml( $self, $target, "$intradir/$dir/$file" ); |
445 |
YAML::XS::DumpFile( "$intradir/$tdir/$file", $translated_yaml ); |
455 |
YAML::XS::DumpFile( "$intradir/$tdir/$file", $translated_yaml ); |
Lines 454-463
sub install_installer {
Link Here
|
454 |
sub locale_name { |
464 |
sub locale_name { |
455 |
my $self = shift; |
465 |
my $self = shift; |
456 |
|
466 |
|
457 |
my ($language, $region, $country) = split /-/, $self->{lang}; |
467 |
my ( $language, $region, $country ) = split /-/, $self->{lang}; |
458 |
$country //= $region; |
468 |
$country //= $region; |
459 |
my $locale = $language; |
469 |
my $locale = $language; |
460 |
if ($country && length($country) == 2) { |
470 |
if ( $country && length($country) == 2 ) { |
461 |
$locale .= '_' . $country; |
471 |
$locale .= '_' . $country; |
462 |
} |
472 |
} |
463 |
|
473 |
|
Lines 467-476
sub locale_name {
Link Here
|
467 |
sub install_messages { |
477 |
sub install_messages { |
468 |
my ($self) = @_; |
478 |
my ($self) = @_; |
469 |
|
479 |
|
470 |
my $locale = $self->locale_name(); |
480 |
my $locale = $self->locale_name(); |
471 |
my $modir = "$self->{path_po}/$locale/LC_MESSAGES"; |
481 |
my $modir = "$self->{path_po}/$locale/LC_MESSAGES"; |
472 |
my $pofile = "$self->{path_po}/$self->{lang}-messages.po"; |
482 |
my $pofile = "$self->{path_po}/$self->{lang}-messages.po"; |
473 |
my $mofile = "$modir/$self->{domain}.mo"; |
483 |
my $mofile = "$modir/$self->{domain}.mo"; |
474 |
my $js_pofile = "$self->{path_po}/$self->{lang}-messages-js.po"; |
484 |
my $js_pofile = "$self->{path_po}/$self->{lang}-messages-js.po"; |
475 |
|
485 |
|
476 |
unless ( -f $pofile && -f $js_pofile ) { |
486 |
unless ( -f $pofile && -f $js_pofile ) { |
Lines 481-487
sub install_messages {
Link Here
|
481 |
make_path($modir); |
491 |
make_path($modir); |
482 |
system "$self->{msgfmt} -o $mofile $pofile"; |
492 |
system "$self->{msgfmt} -o $mofile $pofile"; |
483 |
|
493 |
|
484 |
my $tmp_po = sprintf '/tmp/%s-messages.po', $self->{lang}; |
494 |
my $tmp_po = sprintf '/tmp/%s-messages.po', $self->{lang}; |
485 |
my $po2json_cmd = sprintf '%s %s %s', $self->{po2json}, $js_pofile, $tmp_po; |
495 |
my $po2json_cmd = sprintf '%s %s %s', $self->{po2json}, $js_pofile, $tmp_po; |
486 |
`$po2json_cmd`; |
496 |
`$po2json_cmd`; |
487 |
my $json = read_file($tmp_po); |
497 |
my $json = read_file($tmp_po); |
Lines 508-521
sub install_messages {
Link Here
|
508 |
my $combined_json = encode_json($js_po_data); |
518 |
my $combined_json = encode_json($js_po_data); |
509 |
|
519 |
|
510 |
my $js_locale_data = sprintf 'var json_locale_data = {"Koha":%s};', $combined_json; |
520 |
my $js_locale_data = sprintf 'var json_locale_data = {"Koha":%s};', $combined_json; |
511 |
my $progdir = C4::Context->config('intrahtdocs') . '/prog'; |
521 |
my $progdir = C4::Context->config('intrahtdocs') . '/prog'; |
512 |
mkdir "$progdir/$self->{lang}/js"; |
522 |
mkdir "$progdir/$self->{lang}/js"; |
513 |
open my $fh, '>', "$progdir/$self->{lang}/js/locale_data.js"; |
523 |
open my $fh, '>', "$progdir/$self->{lang}/js/locale_data.js"; |
514 |
print $fh $js_locale_data; |
524 |
print $fh $js_locale_data; |
515 |
close $fh; |
525 |
close $fh; |
516 |
|
526 |
|
517 |
my $opachtdocs = C4::Context->config('opachtdocs'); |
527 |
my $opachtdocs = C4::Context->config('opachtdocs'); |
518 |
opendir(my $dh, $opachtdocs); |
528 |
opendir( my $dh, $opachtdocs ); |
519 |
for my $theme ( grep { not /^\.|lib|xslt/ } readdir($dh) ) { |
529 |
for my $theme ( grep { not /^\.|lib|xslt/ } readdir($dh) ) { |
520 |
mkdir "$opachtdocs/$theme/$self->{lang}/js"; |
530 |
mkdir "$opachtdocs/$theme/$self->{lang}/js"; |
521 |
open my $fh, '>', "$opachtdocs/$theme/$self->{lang}/js/locale_data.js"; |
531 |
open my $fh, '>', "$opachtdocs/$theme/$self->{lang}/js/locale_data.js"; |
Lines 525-537
sub install_messages {
Link Here
|
525 |
} |
535 |
} |
526 |
|
536 |
|
527 |
sub compress { |
537 |
sub compress { |
528 |
my ($self, $files) = @_; |
538 |
my ( $self, $files ) = @_; |
529 |
my @langs = $self->{lang} ? ($self->{lang}) : $self->get_all_langs(); |
539 |
my @langs = $self->{lang} ? ( $self->{lang} ) : $self->get_all_langs(); |
530 |
for my $lang ( @langs ) { |
540 |
for my $lang (@langs) { |
531 |
$self->set_lang( $lang ); |
541 |
$self->set_lang($lang); |
532 |
opendir( my $dh, $self->{path_po} ); |
542 |
opendir( my $dh, $self->{path_po} ); |
533 |
my @files = grep { $_ =~ /^$self->{lang}.*po$/ } readdir $dh; |
543 |
my @files = grep { $_ =~ /^$self->{lang}.*po$/ } readdir $dh; |
534 |
foreach my $file ( @files ) { |
544 |
foreach my $file (@files) { |
535 |
say "Compress file $file" if $self->{verbose}; |
545 |
say "Compress file $file" if $self->{verbose}; |
536 |
system "$self->{gzip} -9 $self->{path_po}/$file"; |
546 |
system "$self->{gzip} -9 $self->{path_po}/$file"; |
537 |
} |
547 |
} |
Lines 539-551
sub compress {
Link Here
|
539 |
} |
549 |
} |
540 |
|
550 |
|
541 |
sub uncompress { |
551 |
sub uncompress { |
542 |
my ($self, $files) = @_; |
552 |
my ( $self, $files ) = @_; |
543 |
my @langs = $self->{lang} ? ($self->{lang}) : $self->get_all_langs(); |
553 |
my @langs = $self->{lang} ? ( $self->{lang} ) : $self->get_all_langs(); |
544 |
for my $lang ( @langs ) { |
554 |
for my $lang (@langs) { |
545 |
opendir( my $dh, $self->{path_po} ); |
555 |
opendir( my $dh, $self->{path_po} ); |
546 |
$self->set_lang( $lang ); |
556 |
$self->set_lang($lang); |
547 |
my @files = grep { $_ =~ /^$self->{lang}.*po.gz$/ } readdir $dh; |
557 |
my @files = grep { $_ =~ /^$self->{lang}.*po.gz$/ } readdir $dh; |
548 |
foreach my $file ( @files ) { |
558 |
foreach my $file (@files) { |
549 |
say "Uncompress file $file" if $self->{verbose}; |
559 |
say "Uncompress file $file" if $self->{verbose}; |
550 |
system "$self->{gunzip} $self->{path_po}/$file"; |
560 |
system "$self->{gunzip} $self->{path_po}/$file"; |
551 |
} |
561 |
} |
Lines 553-563
sub uncompress {
Link Here
|
553 |
} |
563 |
} |
554 |
|
564 |
|
555 |
sub install { |
565 |
sub install { |
556 |
my ($self, $files) = @_; |
566 |
my ( $self, $files ) = @_; |
557 |
return unless $self->{lang}; |
567 |
return unless $self->{lang}; |
558 |
$self->uncompress(); |
568 |
$self->uncompress(); |
559 |
|
569 |
|
560 |
if ($self->{pref_only}) { |
570 |
if ( $self->{pref_only} ) { |
561 |
$self->install_prefs(); |
571 |
$self->install_prefs(); |
562 |
} else { |
572 |
} else { |
563 |
$self->install_tmpl($files); |
573 |
$self->install_tmpl($files); |
Lines 567-578
sub install {
Link Here
|
567 |
} |
577 |
} |
568 |
} |
578 |
} |
569 |
|
579 |
|
570 |
|
|
|
571 |
sub get_all_langs { |
580 |
sub get_all_langs { |
572 |
my $self = shift; |
581 |
my $self = shift; |
573 |
opendir( my $dh, $self->{path_po} ); |
582 |
opendir( my $dh, $self->{path_po} ); |
574 |
my @files = grep { $_ =~ /-pref.(po|po.gz)$/ } |
583 |
my @files = grep { $_ =~ /-pref.(po|po.gz)$/ } readdir $dh; |
575 |
readdir $dh; |
|
|
576 |
@files = map { $_ =~ s/-pref.(po|po.gz)$//r } @files; |
584 |
@files = map { $_ =~ s/-pref.(po|po.gz)$//r } @files; |
577 |
} |
585 |
} |
578 |
|
586 |
|
Lines 602-611
sub _identify_translatable_plugins {
Link Here
|
602 |
return \@plugin_dirs; |
610 |
return \@plugin_dirs; |
603 |
} |
611 |
} |
604 |
|
612 |
|
605 |
|
|
|
606 |
1; |
613 |
1; |
607 |
|
614 |
|
608 |
|
|
|
609 |
=head1 NAME |
615 |
=head1 NAME |
610 |
|
616 |
|
611 |
LangInstaller.pm - Handle templates and preferences translation |
617 |
LangInstaller.pm - Handle templates and preferences translation |
612 |
- |
|
|