#! /usr/bin/env perl
sub
decompose_po;
sub
decompose_po_sg;
sub
compose_po;
sub
german_handler;
sub
american_english_handler;
sub
british_english_handler;
sub
swiss_german_handler;
sub
austrian_german_handler;
sub
display_usage;
sub
usage_error;
my
(
$option_language
,
$option_input
,
$option_output
,
$option_help
,
$option_verbose
);
GetOptions (
'language=s'
=> \
$option_language
,
'input=s'
=> \
$option_input
,
'output=s'
=> \
$option_output
,
'help'
=> \
$option_help
,
'verbose'
=> \
$option_verbose
,
) or
exit
1;
display_usage
if
$option_help
;
usage_error
"the option '--language' is mandatory."
unless
$option_language
;
usage_error
"the option '--input' is mandatory."
unless
$option_input
;
usage_error
"the option '--output' is mandatory."
unless
$option_output
;
my
@filters
;
if
(
$option_language
=~ /^de_CH$/) {
push
@filters
, \
&swiss_german_handler
;
}
elsif
(
$option_language
=~ /^de_AT$/) {
push
@filters
, \
&austrian_german_handler
;
}
elsif
(
$option_language
=~ /^en_GB$/) {
push
@filters
, \
&british_english_handler
;
}
elsif
(
$option_language
=~ /^en.*$/) {
push
@filters
, \
&american_english_handler
;
}
elsif
(
$option_language
=~ /^de/) {
push
@filters
, \
&german_handler
;
}
elsif
(
$option_language
=~ /^bg/) {
push
@filters
, \
&german_handler
;
}
my
$entries
= Locale::PO->load_file_asarray (
$option_input
,
'utf-8'
) or
die
"cannot read file '$option_input': $!\n"
;
my
$alpine_entries
;
my
$german_to_alpine
= {
Samstag
=>
'Sonnabend'
,
Januar
=>
"J\xe4nner"
,
Februar
=>
"Feber"
,
};
my
$german_to_alpine_re_string
=
join
'|'
,
keys
%$german_to_alpine
;
my
$german_to_alpine_re
=
qr /($german_to_alpine_re_string)/o;
autoflush
STDERR;
print
STDERR
"$option_language\n"
;
my
$count
= 0;
my
$file_dirty
;
foreach
my
$entry
(
@$entries
) {
++
$count
;
print
STDERR
'.'
if
0 ==
$count
% 10 &&
$option_verbose
;
next
if
$entry
->obsolete;
foreach
my
$filter
(
@filters
) {
$file_dirty
= 1
if
&$filter
(
$entry
);
}
}
print
STDERR
" done.\n"
if
$option_verbose
;
if
(
$file_dirty
) {
Locale::PO->save_file_fromarray(
$option_output
,
$entries
,
'utf-8'
)
or
die
"cannot write file '$option_output': $!\n"
;
}
sub
decompose_po {
my
(
$entry
) =
@_
;
my
@msgstrs
;
if
(
$entry
->msgid_plural) {
my
$msgstr_n
=
$entry
->msgstr_n;
foreach
my
$num
(
sort
keys
%$msgstr_n
) {
push
@msgstrs
,
$entry
->dequote(
$msgstr_n
->{
$num
});
}
}
else
{
@msgstrs
=
$entry
->dequote(
$entry
->msgstr);
}
return
@msgstrs
;
}
sub
decompose_po_sg {
my
(
$entry
) =
@_
;
my
@msgids
=
$entry
->dequote(
$entry
->msgid);
push
@msgids
,
$entry
->dequote(
$entry
->msgid_plural)
if
$entry
->msgid_plural;
return
@msgids
;
}
sub
compose_po {
my
(
$entry
,
@msgstrs
) =
@_
;
my
$dirty
;
if
(
@msgstrs
> 1) {
my
$msgstr_n
=
$entry
->msgstr_n;
foreach
my
$num
(0 ..
@msgstrs
) {
my
$old
=
$entry
->dequote(
$msgstr_n
->{
$num
});
my
$new
=
$msgstrs
[
$num
];
if
(
$old
ne
$new
) {
$dirty
= 1;
$msgstr_n
->{
$num
} =
$new
;
}
}
$entry
->msgstr_n(
$msgstr_n
)
if
$dirty
;
}
else
{
my
$old
=
$entry
->dequote(
$entry
->msgstr);
if
(
$old
ne
$msgstrs
[0]) {
$entry
->msgstr(
$msgstrs
[0]);
$dirty
= 1;
}
}
return
unless
$dirty
;
return
1;
}
sub
_english_quotes {
my
(
$entry
,
$country
) =
@_
;
my
$msgid
=
$entry
->dequote(
$entry
->msgid);
return
1
if
$msgid
eq
''
;
my
@msgstrs
= decompose_po
$entry
;
return
1
if
length
$msgstrs
[0];
my
$open_quote
=
$country
eq
'US'
?
"\x{201c}"
:
"\x{2018}"
;
my
$close_quote
=
$country
eq
'US'
?
"\x{201d}"
:
"\x{2019}"
;
my
$dirty
;
undef
@msgstrs
;
foreach
my
$msg
(decompose_po_sg
$entry
) {
$msg
=~ s/(\w)'(\w)/$1\x{2019}$2/;
$msg
=~ s/
'(.*?)'
/${open_quote}$1${close_quote}/g;
push
@msgstrs
,
$msg
;
}
return
compose_po
$entry
,
@msgstrs
;
}
sub
_german_quotes {
my
(
$entry
,
$country
) =
@_
;
my
$msgid
=
$entry
->dequote(
$entry
->msgid);
return
1
if
$msgid
eq
''
;
my
@msgstrs
= decompose_po
$entry
;
my
%open
= (
DE
=>
"\x{201e}"
,
CH
=>
"\x{ab}"
,
);
my
%closed
= (
DE
=>
"\x{201c}"
,
CH
=>
"\x{bb}"
,
);
my
$open_quote
=
$open
{
$country
} ||
$open
{DE};
my
$closed_quote
=
$closed
{
$country
} ||
$open
{DE};
my
$dirty
;
foreach
my
$msg
(
@msgstrs
) {
$msg
=~ s/(\w)'(\w)/$1\x{2019}$2/g;
$msg
=~ s/(["'])(.*?)\1/${open_quote}$2${closed_quote}/g;
$msg
=~ s/(
$open
{DE})(.*?)
$closed
{DE}/${open_quote}$2${closed_quote}/g;
}
return
compose_po
$entry
,
@msgstrs
;
}
sub
_swiss_sharp_s {
my
(
$entry
,
$country
) =
@_
;
my
$msgid
=
$entry
->dequote(
$entry
->msgid);
return
1
if
$msgid
eq
''
;
my
@msgstrs
= decompose_po
$entry
;
my
$dirty
;
foreach
my
$msg
(
@msgstrs
) {
$msg
=~ s/\x{df}/ss/;
}
return
compose_po
$entry
,
@msgstrs
;
}
sub
american_english_handler {
return
_english_quotes
shift
,
'US'
;
}
sub
british_english_handler {
return
_english_quotes
shift
,
'GB'
;
}
sub
_alpine_german {
my
(
$entry
) =
@_
;
unless
(
$alpine_entries
) {
$alpine_entries
= Locale::PO->load_file_asarray(
'de.po'
,
'utf8'
)
or
die
"cannot read file 'de.po': $!\n"
;
}
my
$msgid
=
$entry
->dequote(
$entry
->msgid);
return
unless
length
$msgid
;
my
@msgstrs
= decompose_po
$entry
;
return
if
length
$msgstrs
[0];
undef
@msgstrs
;
foreach
my
$alpine_entry
(
@$alpine_entries
) {
my
$alpine_msgid
=
$alpine_entry
->dequote(
$alpine_entry
->msgid);
next
if
$alpine_msgid
ne
$msgid
;
my
$alpine_msgctxt
=
$alpine_entry
->msgctxt;
next
if
$alpine_msgctxt
ne
$entry
->msgctxt;
@msgstrs
= decompose_po
$alpine_entry
;
return
if
!
length
$msgstrs
[0];
}
return
unless
@msgstrs
;
foreach
my
$msgstr
(
@msgstrs
) {
$msgstr
=~ s/
$german_to_alpine_re
/
$german_to_alpine
->{$1}/gs;
}
my
$dirty
= compose_po
$entry
,
@msgstrs
;
return
if
!
$dirty
;
return
1;
}
sub
austrian_german_handler {
my
(
$entry
) =
@_
;
my
$dirty
= _alpine_german
$entry
,
'AT'
;
$dirty
= 1
if
_german_quotes
$entry
,
'AT'
;
return
if
!
$dirty
;
return
1;
}
sub
swiss_german_handler {
my
(
$entry
) =
@_
;
my
$dirty
= _alpine_german
$entry
,
'CH'
;
$dirty
= 1
if
_german_quotes
$entry
,
'CH'
;
$dirty
= 1
if
_swiss_sharp_s
$entry
,
'CH'
;
return
if
!
$dirty
;
return
1;
}
sub
german_handler {
return
_german_quotes
shift
,
'DE'
;
}
sub
display_usage {
print
<<EOF;
Usage: $0 [OPTIONS]
Mandatory arguments to long options, are mandatory to short options, too.
-l, --language=LANGUAGE The translations are in language LANGUAGE
-i, --input=INPUT Read input from file INPUT
-o, --output=OUTPUT Write output to file OUTPUT
-h, --help Display this help and exit
-v, --verbose Display progress on standard error
Reads a PO file and writes it back after some language-dependent
cosmetic corrections.
EOF
}
sub
usage_error {
my
$message
=
shift
;
if
(
$message
) {
$message
=~ s/\s+$//;
$message
=
"$0: $message\n"
;
}
else
{
$message
=
''
;
}
die
<<EOF;
${message}Usage: $0 [OPTIONS]
Try '$0 --help' for more information!
EOF
}