File Coverage

blib/lib/Locale/TextDomain/OO/Extract/Xslate.pm
Criterion Covered Total %
statement 92 120 76.6
branch 29 42 69.0
condition 41 99 41.4
subroutine 13 13 100.0
pod 1 1 100.0
total 176 275 64.0


line stmt bran cond sub pod time code
1             package Locale::TextDomain::OO::Extract::Xslate;
2             # vim:syntax=perl:tabstop=4:number:noexpandtab:
3             $Locale::TextDomain::OO::Extract::Xslate::VERSION = '0.02';
4             # ABSTRACT: Extract messages from Text::Xslate templates for translation with Locale::TextDomain::OO
5            
6 3     3   13869 use strict;
  3         4  
  3         69  
7 3     3   9 use warnings;
  3         2  
  3         58  
8 3     3   1301 use Moo;
  3         27536  
  3         12  
9 3     3   4970 use Path::Tiny;
  3         28603  
  3         137  
10 3     3   1895 use namespace::autoclean;
  3         27544  
  3         8  
11            
12             with qw(
13             Locale::TextDomain::OO::Extract::Role::File
14             );
15              
16             has 'debug' => (
17             is => 'rw',
18             default => 0,
19             );
20              
21             has 'syntax' => (
22             is => 'ro',
23             default => 'Kolon',
24             );
25              
26             has 'parser' => (
27             is => 'lazy',
28             init_arg => undef,
29             );
30              
31             has 'l10n_function_re' => (
32             is => 'ro',
33             default => sub {
34             qr{\A
35             N?
36             (?:loc|_)
37             _
38             (x|n|nx|p|px|np|npx)?
39             \Z
40             }x
41             },
42             );
43              
44             has 'addl_l10n_function_re' => (
45             is => 'rw',
46             );
47              
48             sub _build_parser {
49 4     4   621 my $self = shift;
50 4         15 my $syntax = $self->syntax;
51 4     2   278 eval "use Text::Xslate::Syntax::${syntax};";
  2     2   933  
  2         79243  
  2         40  
  2         11  
  2         4  
  2         29  
52 4 50       16 die $@ if $@;
53 4         43 "Text::Xslate::Syntax::${syntax}"->new();
54             }
55              
56             sub extract {
57 8     8 1 9722 my $self = shift;
58 8         11 my $messages = [];
59 8         16 my $filename = $self->filename;
60 8         141 $self->_scan_file( $messages, $filename );
61              
62 8         33 my ( $cat, $dom ) = ( $self->category, $self->domain );
63 8         380 foreach my $msg (@{ $messages }) {
  8         15  
64             $self->add_message({
65             category => ( $cat // '' ),
66             domain => ( $dom // '' ),
67             msgctxt => ( $msg->{'MSGCTXT'} // '' ),
68             msgid => ( $msg->{'MSGID'} // '' ),
69             msgid_plural => ( $msg->{'MSGID_PLURAL'} // '' ),
70 48   50     4519 reference => sprintf( '%s:%s', $msg->{'FILE'}, $msg->{'LINE'} ),
      50        
      100        
      50        
      100        
71             # automatic => 'my automatic comment',
72             });
73             }
74             }
75              
76             our $RESULT;
77             our $FILENAME;
78            
79             sub _scan {
80 8     8   12 my($self, $result, $filename, $data) = @_;
81 8         113 my $ast = $self->parser->parse($data);
82 8         82680 local $FILENAME = $filename;
83 8         15 local $RESULT = $result;
84 8         18 $self->_walker($ast);
85 8         639 return $result;
86             }
87            
88             sub _scan_file {
89 8     8   9 my ($self, $result, $filename) = @_;
90 8         19 my $data = path($filename)->slurp_utf8;
91 8         2483 return $self->_scan($result, $filename, $data);
92             }
93            
94             my $sp = '';
95             sub _walker {
96 2210     2210   1503 my($self, $ast) = @_;
97 2210 100 100     3542 $ast = [ $ast ] if $ast && ref($ast) eq 'Text::Xslate::Symbol';
98 2210 100 66     3661 return unless $ast && ref($ast) eq 'ARRAY';
99              
100 434         387 my $l10n_fns = $self->l10n_function_re;
101 434 100       568 if (my $addl_l10n_fns = $self->addl_l10n_function_re){
102 98         421 $l10n_fns = qr{
103             (?: $l10n_fns )
104             |
105             (?: \A N? $addl_l10n_fns \z )
106             }x;
107             }
108            
109 434         263 for my $sym (@{ $ast }) {
  434         482  
110              
111 734 100 66     4445 if ( $sym->arity eq 'methodcall' && $sym->value eq '.' ) {
    100 100        
      100        
112 20         25 my $second = $sym->second;
113 20 50 33     71 if ( $second && ref($second) eq 'Text::Xslate::Symbol' ) {
114 20 100 66     207 if ( $second->arity eq 'literal'
115             && $second->value =~ $l10n_fns
116             ) {
117 14   100     42 my $flags = ( $1 || '' );
118 14         25 my $third = $sym->third;
119 14 50 33     90 if ( $third
      33        
      33        
120             && ref($third) eq 'ARRAY'
121             && $third->[0]
122             && ref( $third->[0] ) eq 'Text::Xslate::Symbol'
123             ) {
124 14         50 my %msg = ( FILE => $FILENAME, LINE => $second->line, FLAGS => $flags, );
125 14 50       21 if ( _parseMsg( \%msg, $flags, $third ) ) {
126 14         9 push @{$RESULT}, \%msg;
  14         29  
127             }
128             else {
129 0         0 warn "Invalid parameters for translation command at '$FILENAME', line " . $second->line;
130             }
131             }
132             else {
133 0         0 warn "Invalid parameters for translation command at '$FILENAME', line " . $second->line;
134             }
135             }
136             }
137             }
138             elsif ( $sym->arity eq 'call' &&
139             # __x("foo") "foo" | __x
140             ($sym->value eq '(' ) || $sym->value eq '(call)') {
141 34         44 my $first = $sym->first;
142 34 50 33     127 if ( $first && ref($first) eq 'Text::Xslate::Symbol' ) {
143 34 50 33     353 if ( $first->arity eq 'name'
144             && $first->value =~ $l10n_fns
145             ) {
146 34   100     101 my $flags = ( $1 || '' );
147 34         42 my $second = $sym->second;
148 34 50 33     218 if ( $second
      33        
      33        
149             && ref($second) eq 'ARRAY'
150             && $second->[0]
151             && ref( $second->[0] ) eq 'Text::Xslate::Symbol'
152             ) {
153 34         117 my %msg = ( FILE => $FILENAME, LINE => $first->line, FLAGS => $flags, );
154 34 50       49 if ( _parseMsg( \%msg, $flags, $second ) ) {
155 34         21 push @{$RESULT}, \%msg;
  34         57  
156             }
157             else {
158 0         0 warn "Invalid parameters for translation command at '$FILENAME', line " . $first->line;
159             }
160             }
161             else {
162 0         0 warn "Invalid parameters for translation command at '$FILENAME', line " . $first->line;
163             }
164             }
165             }
166             }
167            
168 734 50       862 unless ( $self->debug ) {
169 734         1051 $self->_walker( $sym->first );
170 734         983 $self->_walker( $sym->second );
171 734         972 $self->_walker( $sym->third );
172             }
173             else {
174 0   0     0 warn $sp . "id: " . ( $sym->id // "undef()" ) . "\n";
175 0   0     0 warn $sp . "line: " . ( $sym->line // "undef()" ) . "\n";
176 0   0     0 warn $sp . "ldp: " . ( $sym->lbp // "undef()" ) . "\n";
177 0   0     0 warn $sp . "udp: " . ( $sym->ubp // "undef()" ) . "\n";
178 0   0     0 warn $sp . "type: " . ( $sym->type // "undef()" ) . "\n";
179 0   0     0 warn $sp . "arity: " . ( $sym->arity // "undef()" ) . "\n";
180 0   0     0 warn $sp . "assignment: " . ( $sym->assignment // "undef()" ) . "\n";
181 0   0     0 warn $sp . "value: " . ( $sym->value // "undef()" ) . "\n";
182            
183 0   0     0 warn $sp . "= first: " . ( $sym->first // "undef()" ) . "\n";
184 0         0 $sp .= ' ';
185 0         0 $self->_walker( $sym->first );
186 0         0 $sp =~ s/^..//;
187            
188 0   0     0 warn $sp . "= second: " . ( $sym->second // "undef()" ) . "\n";
189 0         0 $sp .= ' ';
190 0         0 $self->_walker( $sym->second );
191 0         0 $sp =~ s/^..//;
192            
193 0   0     0 warn $sp . "= third: " . ( $sym->third // "undef()" ) . "\n";
194 0         0 $sp .= ' ';
195 0         0 $self->_walker( $sym->third );
196 0         0 $sp =~ s/^..//;
197            
198 0         0 warn $sp . "----------\n";
199             }
200             }
201             }
202              
203             sub _parseMsg {
204 48     48   47 my ( $msg_r, $flags, $params ) = @_;
205              
206 48         32 my @p = @{ $params };
  48         75  
207 48         46 eval {
208 48 100       100 if ( index( $flags, 'p' ) >= 0 ) {
209 10 50 33     54 if ( defined $p[0] and $p[0]->arity eq 'literal' ) {
210 10         20 $msg_r->{'MSGCTXT'} = $p[0]->value;
211 10         10 shift @p;
212             }
213             else {
214 0         0 die;
215             }
216             }
217              
218 48 100       69 if ( index( $flags, 'n' ) >= 0 ) {
219 8 50 33     78 if ( defined $p[0] and $p[0]->arity eq 'literal'
      33        
      33        
      33        
220             and defined $p[1] and $p[1]->arity eq 'literal'
221             and defined $p[2]
222             ) {
223 8         13 $msg_r->{'MSGID'} = $p[0]->value;
224 8         16 $msg_r->{'MSGID_PLURAL'} = $p[1]->value;
225             }
226             else {
227 0         0 die;
228             }
229             }
230             else {
231 40 50 33     146 if ( defined $p[0] and $p[0]->arity eq 'literal' ) {
232 40         82 $msg_r->{'MSGID'} = $p[0]->value;
233             }
234             else {
235 0         0 die;
236             }
237             }
238             };
239              
240 48 50       59 return 0 if $@;
241 48         82 return 1;
242             }
243              
244             __PACKAGE__->meta->make_immutable;
245              
246             1;
247              
248             __END__