package MGH_Biostat::Locale::POCatalog; use Modern::Perl '2012'; use experimental 'switch'; use Carp; use Path::Tiny; use Set::Tiny 'set'; use MGH_Biostat::Locale::PO; use Moo; use namespace::clean; use constant CTXSEP => chr(4); # @GROUP attributes # the directory that holds the .po files. # this can be changed an instantiation, but not after has 'dir' => ( is => 'ro', default => 'po/', ); # the default language has 'default_lang' => ( is => 'ro', default => 'en-US', ); # a set of the supported languages has 'langs' => ( is => 'lazy', ); # a list of the languages in a sorted order # (default language first, then the rest alphabetically) has 'langs_order' => ( is => 'lazy', ); # the actual translation data has 'data' => ( is => 'lazy', ); # @GROUP builders # any language we have a .po file is supported sub _build_langs { my $self = shift; my $langs = []; for ( path( $self->dir )->children(qr/\.po$/) ) { push @$langs, $_->basename('.po'); } return set($langs); } # build the order of the languages sub _build_langs_order { my $self = shift; my $order = []; my $default = $self->default_lang; push @$order, $default; foreach my $lang ( sort $self->langs->members ) { next if $lang eq $default; push @$order, $lang; } return $order; } # read in the translation data sub _build_data { my $self = shift; my $data = {}; foreach my $lang ( $self->langs->members ) { my $pos = MGH_Biostat::Locale::PO->load_file_asarray( $self->dir . $lang . '.po', 'utf8' ); foreach my $po (@$pos) { my $key = $po->hashkey; if ( !defined( $po->msgid_plural ) and ( !defined( $po->msgstr ) or ( $po->msgstr eq '' ) ) ) { no warnings 'uninitialized'; warn 'Missing translation for [' . $lang . '|' . $po->msgctxt . '|' . $po->msgid . ']; setting to msgid.' . "\n"; $po->msgstr( $po->msgid ); } $data->{$lang}{$key} = $po; } } return $data; } # force the data to be loaded when the object is created sub BUILD { my $self = shift; $self->data; return; } # @GROUP methods # sub is_valid_lang { my $self = shift; my ($lang) = @_; return $self->langs->member($lang); } # look up a translation # returns a MGH_Biostat::Locale::PO object # the first parameter *must* be the language # the second parameter is the lookup string # if there is a context to be provided, you can either pass a third parameter, # or use the CTXSEP constant to create a context lookup string # if there is any kind of error, a warning will be fired, # and a Locale::PO object with the same string as request will be returned sub lookup { my $self = shift; my ( $lang, $msgid, $context ) = @_; if ( $self->is_valid_lang($lang) ) { my $key = ( defined($context) ? $context . CTXSEP : '' ) . $msgid; my $data = $self->data; if ( defined( $data->{$lang}{$key} ) ) { return $data->{$lang}{$key}; } elsif ( defined( $data->{ $self->default_lang }{$key} ) ) { no warnings 'uninitialized'; # $context may not be defined carp "Key [$context|$msgid] not defined for $lang."; return $data->{ $self->default_lang }{$key}; } else { no warnings 'uninitialized'; # $context may not be defined carp "Key [$context|$msgid] not defined for any lang."; return MGH_Biostat::Locale::PO->new( -msgid => $msgid, -msgstr => $msgid, -msgctxt => $context ); } } else { carp "Language $lang not supported."; return MGH_Biostat::Locale::PO->new( -msgid => $msgid, -msgstr => $msgid, -msgctxt => $context ); } } 1;