view lib/IMPL/Resources/StringLocaleMap.pm @ 420:df591e3afd10 ref20150831

sync
author cin
date Sat, 25 Feb 2017 22:35:26 +0300
parents c6e90e02dd17
children
line wrap: on
line source

package IMPL::Resources::StringLocaleMap;
use strict;

use List::Util qw(first);
use IMPL::lang qw(:base);
use IMPL::Const qw(:prop);
use IMPL::declare {
	require => {
		Resources => 'IMPL::Resources',
		StringMap => 'IMPL::Resources::StringMap',
		Exception => 'IMPL::Exception',
		FS => 'File::Spec'
	},
	base => {
		'IMPL::Object' => '@_'
	},
	props => [
		_maps => PROP_RW,
		name => PROP_RW,
		paths => PROP_RW | PROP_LIST
	]
};

sub CTOR {
	my ($this,$data,$parent) = @_;
	
	if (is($data, StringMap)) {
		$this->_maps({ default => $data });
	} elsif ( ref($data) eq 'HASH' ) {
		$this->_maps({ default => StringMap->new($data,$parent)});
	} else {
		# в данном случае таблица строк по-умолчанию будет загружена
		# из файла при необходимости
		$this->_maps({});
	}
}

sub GetString {
	my ($this,$id,$args) = @_;
	
	my $locale = Resources->currentLocale || 'default';
	my $map;
	
	#warn "id: $id,\t\tlocale: $locale";
	
	if(not $map = $this->_maps->{$locale}) {
		my $default = $this->GetDefaultMap();
		$map = $this->LoadMap($locale,$default);
		if (is($map,StringMap)) {
			#nop
		} elsif (ref($map) eq 'HASH') {
			$map = StringMap->new($map,$default);
		} elsif( not $map ) {
			$map = $default;
		} else {
			die Exception->new("ResolveLocale returned unexpected data", $map);
		}
		
		$this->_maps->{$locale} = $map;
	}
	
	return $map->GetString($id,$args);
}

sub GetDefaultMap {
	my ($this) = @_;
	
	my $map = $this->_maps->{default};
	return $map
		if $map;
	
	$map = $this->LoadMap('default') || StringMap->new({});
	$this->_maps->{default} = $map;
	
	return $map;
}

sub LoadMap {
	my ($this,$locale,$default) = @_;
	
	my @spec = split /_/, $locale;
	
	my @locales;
	
	do {
		push @locales, join('_', @spec);
	} while(pop @spec);
	
	my $file = first { -f } map {
		my $path = $_;
		
		map {
			my $name = FS->catfile($path,$_,$this->name);
			("$name.s", "$name.p");
		} @locales;
	} $this->paths;
	
	if($file) {
		if ($file =~ /\.s$/) {
			return $this->LoadStringMap($file);
		} else {
			return $this->LoadPerlMap($file,$default);
		}
	}
	
	return;
}

sub LoadPerlMap {
	my ($self,$file,$parent) = @_;
	
	my $data = do $file;
	my $e = $@;
	die Exception->new("Failed to load file '$file'", $e) if $e;
	die IOException->new("Failed to load file '$file'", $!) if not defined $data and $!;
	die Exception->new("Failed to load file '$file'", "A hash data is expected") unless ref($data) eq 'HASH';
	
	return StringMap->new($data,$parent);
}

sub LoadStringMap {
    my ($this,$fname) = @_;
    
    open my $hRes, "<:encoding(utf-8)", $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;