package AN::Tools::Words; # # This module contains methods used to handle storage related tasks # use strict; use warnings; use Data::Dumper; use XML::Simple qw(:strict); our $VERSION = "3.0.0"; my $THIS_FILE = "Words.pm"; # Setup for UTF-8 mode. # use utf8; # $ENV{'PERL_UNICODE'} = 1; ### Methods; # key # read =pod =encoding utf8 =head1 NAME AN::Tools::Words Provides all methods related to generating translated strings for users. =head1 SYNOPSIS use AN::Tools::Words; # Get a common object handle on all AN::Tools modules. my $an = AN::Tools->new(); # Access to methods using '$an->Words->X'. # # Example using 'read()'; my $foo_path = $an->Words->read({file => $an->data->{path}{words}{'an-tools.xml'}}); =head1 METHODS Methods in this module; =cut sub new { my $class = shift; my $self = {}; bless $self, $class; return ($self); } # Get a handle on the AN::Tools object. I know that technically that is a sibling module, but it makes more # sense in this case to think of it as a parent. sub parent { my $self = shift; my $parent = shift; $self->{HANDLE}{TOOLS} = $parent if $parent; return ($self->{HANDLE}{TOOLS}); } ############################################################################################################# # Public methods # ############################################################################################################# =head2 key NOTE: This is likely not the method you want. This method does no parsing at all. It returns the raw string from the 'words' file. You probably want C<< $an->Words->string() >> if you want to inject variables and get a string back ready to display to the user. This returns a string by its key name. Optionally, a language and/or a source file can be specified. When no file is specified, loaded files will be search in alphabetical order (including path) and the first match is returned. If the requested string is not found, 'C<< #!not_found!# >>' is returned. Example to retrieve 'C<< t_0001 >>'; my $string = $an->Words->key({key => 't_0001'}); Same, but specifying the key from Canadian english; my $string = $an->Words->key({ key => 't_0001', language => 'en_CA', }) Same, but specifying a source file. my $string = $an->Words->key({ key => 't_0001', language => 'en_CA', file => 'an-tools.xml', }) Parameters; =head3 key (required) This is the key to return the string for. =head3 language (optional) This is the ISO code for the language you wish to read. For example, 'en_CA' to get the Canadian English string, or 'jp' for the Japanese string. When no language is passed, 'C<< $an->data->{defaults}{languages}{output} >>' is used. =head3 file (optional) This is the specific file to read the string from. It should generally not be needed as string keys should not be reused. However, if it happens, this is a way to specify which file's version you want. The file can be the file name, or a path. The specified file is search for by matching the the passed in string against the end of the file path. For example, 'C<< file => 'AN/an-tools.xml' >> will match the file 'c<< /usr/share/perl5/AN/an-tools.xml >>'. =cut sub key { my $self = shift; my $parameter = shift; my $an = $self->parent; # Setup default values my $key = defined $parameter->{key} ? $parameter->{key} : ""; my $language = defined $parameter->{language} ? $parameter->{language} : $an->data->{defaults}{languages}{output}; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $string = "#!not_found!#"; my $error = 0; #print $THIS_FILE." ".__LINE__."; [ Debug ] - key: [$key], language: [$language], file: [$file]\n"; if (not $key) { #print $THIS_FILE." ".__LINE__."; AN::Tools::Words->key()' called without a key name to read.\n"; $error = 1; } if (not $language) { #print $THIS_FILE." ".__LINE__."; AN::Tools::Words->key()' called without a language, and 'defaults::languages::output' is not set.\n"; $error = 2; } if (not $error) { foreach my $this_file (sort {$a cmp $b} keys %{$an->data->{words}}) { #print $THIS_FILE." ".__LINE__."; [ Debug ] - this_file: [$this_file], file: [$file]\n"; # If they've specified a file and this doesn't match, skip it. next if (($file) && ($this_file !~ /$file$/)); if (exists $an->data->{words}{$this_file}{language}{$language}{key}{$key}{content}) { $string = $an->data->{words}{$this_file}{language}{$language}{key}{$key}{content}; #print $THIS_FILE." ".__LINE__."; [ Debug ] - string: [$string]\n"; last; } } } #print $THIS_FILE." ".__LINE__."; [ Debug ] - string: [$string]\n"; return($string); } =head2 read This reads in a words file containing translated strings used to generated output for the user. Example to read 'C<< an-tools.xml >>'; my $words_file = $an->data->{path}{words}{'an-words.xml'}; my $an->Words->read({file => $words_file}) or die "Failed to read: [$words_file]. Does the file exist?\n"; Successful read will return '0'. Non-0 is an error; 0 = OK 1 = Invalid file name or path 2 = File not found 3 = File not readable 4 = File found, failed to read for another reason. The error details will be printed. NOTE: Read works are stored in 'C<< $an->data->{words}{}{language}{}{string}{content} >>'. Metadata, like what languages are provided, are stored under 'C<< $an->data->{words}{}{meta}{...} >>'. Parameters; =head3 file (required) This is the file to read. =cut sub read { my $self = shift; my $parameter = shift; my $an = $self->parent; # Setup default values my $file = defined $parameter->{file} ? $parameter->{file} : 0; my $return_code = 0; if (not $file) { # TODO: Log the problem, do not translate. print $THIS_FILE." ".__LINE__."; [ Warning ] - AN::Tools::Words->read()' called without a file name to read.\n"; $return_code = 1; } elsif (not -e $file) { # TODO: Log the problem, do not translate. print $THIS_FILE." ".__LINE__."; [ Warning ] - AN::Tools::Words->read()' asked to read: [$file] which was not found.\n"; $return_code = 2; } elsif (not -r $file) { # TODO: Log the problem, do not translate. print $THIS_FILE." ".__LINE__."; [ Warning ] - AN::Tools::Words->read()' asked to read: [$file] which was not readable by: [".getpwuid($<)."/".getpwuid($>)."] (uid/euid: [".$<."/".$>."]).\n"; $return_code = 3; } else { # Read the file with XML::Simple my $xml = XML::Simple->new(); eval { $an->data->{words}{$file} = $xml->XMLin($file, KeyAttr => { language => 'name', key => 'name' }, ForceArray => [ 'language', 'key' ]) }; if ($@) { chomp $@; print $THIS_FILE." ".__LINE__."; [ Error ] - The was a problem reading: [$file]. The error was:\n"; print "===========================================================\n"; print $@."\n"; print "===========================================================\n"; $return_code = 4; } else { # Successfully read. ### Some debug stuff # Read the meta data #my $version = $an->data->{words}{$file}{meta}{version}; #my $languages = $an->data->{words}{$file}{meta}{languages}; #print $THIS_FILE." ".__LINE__."; [ Debug ] - Version: [$version], languages: [$languages]\n"; #foreach my $this_language (sort {$a cmp $b} keys %{$an->data->{words}{$file}{language}}) #{ # my $long_name = $an->data->{words}{$file}{language}{$this_language}{long_name}; # print $THIS_FILE." ".__LINE__."; [ Debug ] - this_language: [$this_language], long_name: [$long_name]\n"; # print $THIS_FILE." ".__LINE__."; [ Debug ] - "$this_language:t_0001: [".$an->data->{words}{$file}{language}{$this_language}{key}{t_0001}{content}."]\n"; #} } } return($return_code); } # =head3 # # Private Functions; # # =cut ############################################################################################################# # Private functions # ############################################################################################################# 1;