|
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 |
- |
|
|