Bugzilla – Attachment 62326 Details for
Bug 15395
Internationalization: plural forms, context, and more
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 15395: Allow correct handling of plural translation
Bug-15395-Allow-correct-handling-of-plural-transla.patch (text/plain), 10.61 KB, created by
Marc Véron
on 2017-04-18 19:41:05 UTC
(
hide
)
Description:
Bug 15395: Allow correct handling of plural translation
Filename:
MIME Type:
Creator:
Marc Véron
Created:
2017-04-18 19:41:05 UTC
Size:
10.61 KB
patch
obsolete
>From d59334698da1c3925891d015620c674fa449d2c7 Mon Sep 17 00:00:00 2001 >From: Julian Maurice <julian.maurice@biblibre.com> >Date: Tue, 15 Dec 2015 02:31:03 +0100 >Subject: [PATCH] Bug 15395: Allow correct handling of plural translation >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >Locale::Maketext does not allow correct handling of plural translation >for languages that have more than one plural forms. >Locale::Messages does. > >So Koha::I18N is now a wrapper around Locale::Messages, just like >Locale::TextDomain, and export the same symbols as Locale::TextDomain. >You can refer to documentation of Locale::TextDomain to know how to use >exported subroutines. > >The PO file moves from misc/translator/po/xx-XX-messages.po to >misc/translator/po/xx_XX/LC_MESSAGES/Koha.po and now needs to be >compiled to MO in order to be used by Koha. >Compilation of PO file is done by running: > ./translate install xx-XX > >Remove dependency to Locale::Maketext and Locale::Maketext::Lexicon >Add dependency to Locale::Messages > >Test plan: >1. Open a .pl script or .pm module with your favorite text editor >2. Add 'use Koha::I18N;' in the beginning of file >3. Use one of the subroutines exported by Koha::I18N and be sure to have > a way to visualize the result (pass result to the template for > example, or simply warn and watch the log file) >4. cd misc/translator && ./translate update fr-FR # try other languages >5. Open misc/translator/po/fr_FR/LC_MESSAGES/Koha.po and translate your > string(s) > You will need to change the "Plural-Forms" header. See > https://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html >6. ./translate install fr-FR >7. Use your web browser to go to the page that should display the > translation, change language and verify the translation is correct > >Example usage: > __("Hi") > __x("Hi {name}", name => 'Bob') > __n("item", "items", $num_items) > __nx("one item", "{count} items", $num_items, count => $num_items) > __p("Bibliographic record", "item") > >Signed-off-by: Marc Véron <veron@veron.ch> >--- > C4/Installer/PerlDependencies.pm | 9 +-- > Koha/I18N.pm | 141 ++++++++++++++++++++++++++++++++------- > misc/translator/LangInstaller.pm | 60 ++++++++++++++--- > 3 files changed, 171 insertions(+), 39 deletions(-) > >diff --git a/C4/Installer/PerlDependencies.pm b/C4/Installer/PerlDependencies.pm >index a9e0ba9..8a043ed 100644 >--- a/C4/Installer/PerlDependencies.pm >+++ b/C4/Installer/PerlDependencies.pm >@@ -717,15 +717,10 @@ our $PERL_DEPS = { > required => 1, > min_ver => '2.125', > }, >- 'Locale::Maketext' => { >+ 'Locale::Messages' => { > 'usage' => 'Core', > 'required' => '1', >- 'min_ver' => '1.19', >- }, >- 'Locale::Maketext::Lexicon' => { >- 'usage' => 'Core', >- 'required' => '1', >- 'min_ver' => '0.91', >+ 'min_ver' => '1.20', > }, > 'LWP::Protocol::https' => { > 'usage' => 'OverDrive integration', >diff --git a/Koha/I18N.pm b/Koha/I18N.pm >index 33730f9..56d48d8 100644 >--- a/Koha/I18N.pm >+++ b/Koha/I18N.pm >@@ -18,41 +18,136 @@ package Koha::I18N; > # along with Koha; if not, see <http://www.gnu.org/licenses>. > > use Modern::Perl; >-use base qw(Locale::Maketext Exporter); > > use CGI; > use C4::Languages; >+use C4::Context; > >-use Locale::Maketext::Lexicon { >- 'en' => ['Auto'], >- '*' => [ >- Gettext => >- C4::Context->config('intranetdir') >- . '/misc/translator/po/*-messages.po' >- ], >- '_AUTO' => 1, >- '_style' => 'gettext', >-}; >+use Encode; >+use Locale::Util qw(set_locale); >+use Locale::Messages qw(:locale_h :libintl_h nl_putenv); > >-our @EXPORT = qw( gettext ); >+use parent 'Exporter'; >+our @EXPORT = qw( >+ __ >+ __x >+ __n >+ __nx >+ __xn >+ __p >+ __px >+ __np >+ __npx >+ N__ >+ N__n >+ N__p >+ N__np >+); > >-my %language_handles; >+my $textdomain; > >-sub get_language_handle { >- my $cgi = new CGI; >- my $language = C4::Languages::getlanguage; >+BEGIN { >+ $textdomain = 'Koha'; > >- if (not exists $language_handles{$language}) { >- $language_handles{$language} = __PACKAGE__->get_handle($language) >- or die "No language handle for '$language'"; >+ my $langtag = C4::Languages::getlanguage; >+ my @subtags = split /-/, $langtag; >+ my ($language, $region) = @subtags; >+ if ($region && length $region == 4) { >+ $region = $subtags[2]; > } >+ my $locale = set_locale(LC_ALL, $language, $region, 'utf-8'); >+ unless ($locale) { >+ set_locale(LC_MESSAGES, 'C'); >+ Locale::Messages->select_package('gettext_pp'); >+ $locale = $language; >+ if ($region) { >+ $locale .= '_' . $region; >+ } >+ nl_putenv("LANGUAGE=$locale"); >+ nl_putenv("LANG=$locale"); >+ nl_putenv('OUTPUT_CHARSET=utf-8'); >+ } >+ >+ my $directory = C4::Context->config('intranetdir') . '/misc/translator/po'; >+ textdomain($textdomain); >+ bindtextdomain($textdomain, $directory); >+} >+ >+sub __ { >+ my ($msgid) = @_; >+ my $text = dgettext($textdomain, $msgid); >+ return __decode($text); >+} >+ >+sub __x { >+ my ($msgid, %vars) = @_; >+ return __expand(__($msgid), %vars); >+} >+ >+sub __n { >+ my ($msgid, $msgid_plural, $count) = @_; >+ my $text = dngettext($textdomain, $msgid, $msgid_plural, $count); >+ return __decode($text); >+} >+ >+sub __nx { >+ my ($msgid, $msgid_plural, $count, %vars) = @_; >+ return __expand(__n($msgid, $msgid_plural, $count), %vars); >+} >+ >+sub __xn { >+ return __nx(@_); >+} >+ >+sub __p { >+ my ($msgctxt, $msgid) = @_; >+ my $text = dpgettext($textdomain, $msgctxt, $msgid); >+ return __decode($text); >+} >+ >+sub __px { >+ my ($msgctxt, $msgid, %vars) = @_; >+ return __expand(__p($msgctxt, $msgid), %vars); >+} >+ >+sub __np { >+ my ($msgctxt, $msgid, $msgid_plural, $count) = @_; >+ my $text = dnpgettext($textdomain, $msgctxt, $msgid, $msgid_plural, $count); >+ return __decode($text); >+} >+ >+sub __npx { >+ my ($msgctxt, $msgid, $msgid_plural, $count, %vars) = @_; >+ return __expand(__np($msgctxt, $msgid, $msgid_plural, $count), %vars); >+} >+ >+sub N__ { >+ return @_; >+} >+ >+sub N__n { >+ return @_; >+} >+ >+sub N__p { >+ return @_; >+} >+ >+sub N__np { >+ return @_; >+} >+ >+sub __expand { >+ my ($text, %vars) = @_; >+ >+ my $re = join '|', map { quotemeta $_ } keys %vars; >+ $text =~ s/\{($re)\}/defined $vars{$1} ? $vars{$1} : "{$1}"/ge; > >- return $language_handles{$language}; >+ return $text; > } > >-sub gettext { >- my $lh = get_language_handle; >- $lh->maketext(@_); >+sub __decode { >+ return Encode::decode_utf8(shift); > } > > 1; >diff --git a/misc/translator/LangInstaller.pm b/misc/translator/LangInstaller.pm >index 683897d..42f844c 100644 >--- a/misc/translator/LangInstaller.pm >+++ b/misc/translator/LangInstaller.pm >@@ -25,6 +25,7 @@ use C4::Context; > use YAML::Syck qw( Dump LoadFile ); > use Locale::PO; > use FindBin qw( $Bin ); >+use File::Path qw( make_path ); > > $YAML::Syck::ImplicitTyping = 1; > >@@ -66,13 +67,15 @@ sub new { > $self->{process} = "$Bin/tmpl_process3.pl " . ($verbose ? '' : '-q'); > $self->{path_po} = "$Bin/po"; > $self->{po} = { '' => $default_pref_po_header }; >- $self->{domain} = 'messages'; >+ $self->{domain} = 'Koha'; > $self->{cp} = `which cp`; > $self->{msgmerge} = `which msgmerge`; >+ $self->{msgfmt} = `which msgfmt`; > $self->{xgettext} = `which xgettext`; > $self->{sed} = `which sed`; > chomp $self->{cp}; > chomp $self->{msgmerge}; >+ chomp $self->{msgfmt}; > chomp $self->{xgettext}; > chomp $self->{sed}; > >@@ -466,19 +469,34 @@ sub create_tmpl { > sub create_messages { > my $self = shift; > >- print "Create messages ($self->{lang})\n" if $self->{verbose}; >+ my ($language, $country) = split /-/, $self->{lang}; >+ my $locale = $language; >+ if ($country) { >+ $locale .= '_' . $country; >+ } >+ my $podir = "$self->{path_po}/$locale/LC_MESSAGES"; >+ >+ make_path($podir); >+ say "Create messages ($locale)" if $self->{verbose}; > system > "$self->{cp} $self->{domain}.pot " . >- "$self->{path_po}/$self->{lang}-$self->{domain}.po"; >+ "$podir/$self->{domain}.po"; > } > > sub update_messages { > my $self = shift; > >- my $pofile = "$self->{path_po}/$self->{lang}-$self->{domain}.po"; >- print "Update messages ($self->{lang})\n" if $self->{verbose}; >+ my ($language, $country) = split /-/, $self->{lang}; >+ my $locale = $language; >+ if ($country) { >+ $locale .= '_' . $country; >+ } >+ my $podir = "$self->{path_po}/$locale/LC_MESSAGES"; >+ my $pofile = "$podir/$self->{domain}.po"; >+ >+ say "Update messages ($locale)" if $self->{verbose}; > if ( not -f $pofile ) { >- print "File $pofile does not exist\n" if $self->{verbose}; >+ say "File $pofile does not exist" if $self->{verbose}; > $self->create_messages(); > } > system "$self->{msgmerge} -U $pofile $self->{domain}.pot"; >@@ -506,8 +524,11 @@ sub extract_messages { > } > } > >- my $xgettext_cmd = "$self->{xgettext} -L Perl --from-code=UTF-8 " . >- "-o $Bin/$self->{domain}.pot -D $intranetdir"; >+ my $xgettext_cmd = "$self->{xgettext} -L Perl --from-code=UTF-8 " >+ . "-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 " >+ . "-o $Bin/$self->{domain}.pot -D $intranetdir"; > $xgettext_cmd .= " $_" foreach (@files_to_scan); > > if (system($xgettext_cmd) != 0) { >@@ -522,12 +543,32 @@ sub extract_messages { > die "system call failed: $replace_charset_cmd"; > } > } else { >- print "No messages found\n" if $self->{verbose}; >+ say "No messages found" if $self->{verbose}; > return; > } > return 1; > } > >+sub install_messages { >+ my ($self) = @_; >+ >+ my ($language, $country) = split /-/, $self->{lang}; >+ my $locale = $language; >+ if ($country) { >+ $locale .= '_' . $country; >+ } >+ my $podir = "$self->{path_po}/$locale/LC_MESSAGES"; >+ my $pofile = "$podir/$self->{domain}.po"; >+ my $mofile = "$podir/$self->{domain}.mo"; >+ >+ say "Install messages ($locale)" if $self->{verbose}; >+ if ( not -f $pofile ) { >+ say "File $pofile does not exist" if $self->{verbose}; >+ $self->create_messages(); >+ } >+ system "$self->{msgfmt} -o $mofile $pofile"; >+} >+ > sub remove_pot { > my $self = shift; > >@@ -539,6 +580,7 @@ sub install { > return unless $self->{lang}; > $self->install_tmpl($files) unless $self->{pref_only}; > $self->install_prefs(); >+ $self->install_messages(); > } > > >-- >2.1.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 15395
:
45797
|
45798
|
45799
|
46337
|
50023
|
50024
|
50025
|
50026
|
61873
|
61874
|
61875
|
61876
|
61934
|
61935
|
61977
|
62008
|
62041
|
62326
|
62327
|
62328
|
62329
|
62330
|
62331
|
62332
|
62333
|
62335
|
62709
|
65894
|
70974
|
70975
|
70976
|
71940
|
71941
|
71942
|
71943
|
71944
|
71945
|
71946
|
71947
|
71948
|
71949
|
71950
|
71951
|
71952
|
73901
|
73902
|
73903
|
73904
|
73905
|
73906
|
73907
|
73908
|
73909
|
73910
|
73911
|
73912
|
73913
|
76328
|
76329
|
76330
|
77475
|
77476
|
81152
|
81153
|
81154
|
81155
|
81156
|
81157
|
81158
|
81159
|
81167
|
81734
|
81735
|
81736
|
81737
|
81738
|
81739
|
81741
|
81742
|
81743