-
Notifications
You must be signed in to change notification settings - Fork 238
/
Code.php
189 lines (169 loc) · 4.92 KB
/
Code.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<?php
/**
* Lithium: the most rad php framework
*
* @copyright Copyright 2009, Union of RAD (http://union-of-rad.org)
* @license http://opensource.org/licenses/bsd-license.php The BSD License
*/
namespace lithium\g11n\catalog\adapter;
use \Exception;
use \RecursiveIteratorIterator;
use \RecursiveDirectoryIterator;
/**
* The `Code` class is an adapter which treats files containing code as just another source
* of globalized data. In fact it allows for extracting messages which are needed to build
* message catalog templates. Currently only code written in PHP is supported through a parser
* using the built-in tokenizer.
*
* @see lithium\g11n\Message
*/
class Code extends \lithium\g11n\catalog\adapter\Base {
/**
* Supported categories.
*
* @var array
*/
protected $_categories = array(
'message' => array(
'template' => array('read' => true)
));
/**
* Constructor.
*
* @param array $config Available configuration options are:
* - `'path'`: The path to the directory holding the data.
* - `'scope'`: Scope to use.
* @return object
*/
public function __construct($config = array()) {
$defaults = array('path' => null, 'scope' => null);
parent::__construct($config + $defaults);
}
/**
* Initializer. Checks if the configured path exists.
*
* @return void
* @throws \Exception
*/
protected function _init() {
parent::_init();
if (!is_dir($this->_config['path'])) {
throw new Exception("Code directory does not exist at `{$this->_config['path']}`");
}
}
/**
* Extracts data from files within configured path recursively.
*
* @param string $category Dot-delimited category.
* @param string $locale A locale identifier.
* @param string $scope The scope for the current operation.
* @return mixed
*/
public function read($category, $locale, $scope) {
if ($scope != $this->_config['scope']) {
return null;
}
$path = $this->_config['path'];
$base = new RecursiveDirectoryIterator($path);
$iterator = new RecursiveIteratorIterator($base);
$data = array();
foreach ($iterator as $item) {
$file = $item->getPathname();
switch (pathinfo($file, PATHINFO_EXTENSION)) {
case 'php':
$data += $this->_parsePhp($file);
break;
}
}
if ($data) {
return $data;
}
}
/**
* Writing is not supported.
*
* @param string $category Dot-delimited category.
* @param string $locale A locale identifier.
* @param string $scope The scope for the current operation.
* @param mixed $data The data to write.
* @return void
*/
public function write($category, $locale, $scope, $data) {}
/**
* Parses a PHP file for messages marked as translatable. Recognized as message
* marking are `$t()` and `$tn()` which are implemented in the `View` class. This
* is a rather simple and stupid parser but also fast and easy to grasp. It doesn't
* actively attempt to detect and work around syntax errors in marker functions.
*
* @param string $file Absolute path to a PHP file.
* @return array
* @see lithium\template\View
*/
protected function _parsePhp($file) {
$contents = file_get_contents($file);
$defaults = array(
'singularId' => null,
'pluralId' => null,
'open' => false,
'position' => 0,
'occurrence' => array('file' => $file, 'line' => null)
);
extract($defaults);
$data = array();
if (strpos($contents, '$t(') === false && strpos($contents, '$tn(') == false) {
return $data;
}
$tokens = token_get_all($contents);
unset($contents);
foreach ($tokens as $key => $token) {
if (!is_array($token)) {
$token = array(0 => null, 1 => $token, 2 => null);
}
if ($open) {
if ($position >= ($open === 'singular' ? 1 : 2)) {
$this->_mergeMessageItem($data, array(
'singularId' => $singularId,
'pluralId' => $pluralId,
'occurrences' => array($occurrence),
));
extract($defaults, EXTR_OVERWRITE);
} elseif ($token[0] === T_CONSTANT_ENCAPSED_STRING) {
$type = isset($singularId) ? 'pluralId' : 'singularId';
$$type = $token[1];
$position++;
}
} else {
if (isset($tokens[$key + 1]) && $tokens[$key + 1] === '(') {
if ($token[1] === '$t') {
$open = 'singular';
} elseif ($token[1] === '$tn') {
$open = 'plural';
} else {
continue;
}
$occurrence['line'] = $token[2];
}
}
}
return $data;
}
/**
* Merges a message item into given data and removes quotation marks
* from the beginning and end of message strings.
*
* @param array $data Data to merge item into.
* @param array $item Item to merge into $data.
* @return void
* @see lithium\g11n\catalog\adapter\Base::_mergeMessageItem()
*/
protected function _mergeMessageItem(&$data, $item) {
$fields = array('singularId', 'pluralId');
foreach ($fields as $field) {
if (isset($item[$field])) {
$item[$field] = substr($item[$field], 1, -1);
}
}
return parent::_mergeMessageItem($data, $item);
}
}
?>