Mercurial > pub > Impl
view Lib/IMPL/Resources/Strings.pm @ 340:c090d9102a38
web application security refactoring
author | cin |
---|---|
date | Fri, 21 Jun 2013 02:43:56 +0400 |
parents | f4e14f32cf54 |
children | 2eed076cb944 |
line wrap: on
line source
package IMPL::Resources::Strings; use strict; use File::Spec; use List::Util qw(first); use IMPL::Resources::Format qw(FormatMessage); use IMPL::require { Resources => 'IMPL::Resources' }; our $Encoding ||= 'utf-8'; our @Locations; my %maps; sub import { my ($self,$refStrings,%options) = @_; no strict 'refs'; my $class = caller; my $methods = $options{methods}; if (ref $refStrings eq 'HASH') { my $map = ( $maps{$class} ||= {} ); while(my ($name,$format) = each %$refStrings) { $map->{default}{$name} = $format; *{"${class}::$name"} = sub { shift if $methods; my $args = @_ == 1 ? shift : { @_ }; return _FormatMapMessage($class,$name,$map,Resources->currentLocale,$args); } } } } sub _FormatMapMessage { my ($class,$msg,$map,$locale,$args) = @_; if (not exists $map->{$locale} ) { $map->{$locale} = LoadStrings($class,$locale); } return FormatMessage( ($map->{$locale} || $map->{default})->{$msg}, $args ); } sub LoadStrings { my ($class,$locale) = @_; # Foo::Bar -> ('Foo','Bar') my @classNamespace = split /::/,$class; my $classShortName = pop @classNamespace; # Foo::Bar -> 'Foo/Bar.pm' my $classModuleName = File::Spec->catfile(@classNamespace,"${classShortName}.pm"); # 'Foo/Bar.pm' -> '/full/path/to/Foo/Bar.pm' my $fullModulePath = first { -f } map( File::Spec->catfile($_,$classModuleName), @INC ); my @ways = map { my @path = ($_); push @path,Resources->currentLocale; File::Spec->catfile($_,Resources->currentLocale,@classNamespace,$classShortName); } @Locations; if ($fullModulePath) { # '/full/path/to/Foo/Bar.pm' -> '/full/path/to/Foo' my ($vol,$dir,$file) = File::Spec->splitpath($fullModulePath); my $baseDir = File::Spec->catpath($vol,$dir,''); # '/full/path/to/Foo' -> '/full/path/to/Foo/locale/En_US/Bar' push @ways, File::Spec->catfile($baseDir,'locale',Resources->currentLocale,$classShortName); } my $mapFile = first { -f } @ways; return unless $mapFile; return ParseStringsMap($mapFile); } sub ParseStringsMap { my ($fname) = @_; open my $hRes, "<:encoding($Encoding)", $fname or die "Failed to open file $fname: $!"; local $_; my %Map; my $line = 1; while (<$hRes>) { chomp; $line ++ and next if /^\s*$/; if (/^(\w+)\s*=\s*(.*)$/) { $Map{$1} = $2; } else { die "Invalid resource format in $fname at $line"; } $line ++; } return \%Map; } 1; __END__ =pod =head1 NAME C<IMPL::Resources::Strings> - Строковые ресурсы =head1 SYNOPSIS =begin code package Foo; use IMPL::Resources::Strings { msg_say_hello => "Hello, %name%!", msg_module_name => "Simple Foo class" }; sub InviteUser { my ($this,$uname) = @_; print msg_say_hello(name => $uname); } =end code =head1 DESCRIPTION Импортирует в целевой модуль функции, которые возвращают локализованные параметризованные сообщения. При импорте ищутся модули по следующему алгоритму: В каталогах из массива C<@Locations> ищется файл с относительным путем C<$Locale/$ModName>, где C<$Locale> - глобальная переменная модуля C<IMPL::Resourses::Strings>, а переменная C<$ModName> получена путем замены 'C<::>' в имени целевого модуля на 'C</>'. Если файл не был найден, то производится поиск в каталоге, где расположен сам модуль, файла с относительным путем C<locale/$Locale/$ShortModName>, где C<$ShortModeName> - последняя часть после 'C<::>' из имени целевого модуля. Если файл не найден, то используются строки, указанные при объявлении сообщений в целевом модуле. =head1 FORMAT =begin code text msg_name = any text with named %params% msg_hello = hello, %name%!!! msg_resolve = this is a value of the property: %user.age% msg_short_err = %error.Message% msg_full_err = %error% =end code text =cut