Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 283 lines (237 sloc) 8.91 kb
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
1 <?php
2 require_once 'Kblom/FunctionParamParser.php';
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
3 require_once 'Zend/Translate.php';
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
4
5 /**
6 * CLI tool for translation resource file generation
7 *
8 * @category Kblom
9 * @package Kblom_Tool_Locale
0975663 @kblomqvist Update copyright year and license link
authored
10 * @copyright Copyright (c) 2010-2011 Kim Blomqvist
11 * @license http://github.com/kblomqvist/kblom-zf1/raw/master/LICENSE The MIT License
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
12 */
13 class Kblom_Tool_Locale extends Zend_Tool_Project_Provider_Abstract
14 {
15 /** Default patter for function parameter parsing */
16 const DEFAULT_PATTERN = "^'(.+)'\s*,|^'(.+)'$";
17
18 /**
19 * Parser matches to these function names and parses
20 * function parameters with the given regexp pattern.
21 */
22 protected $_func_kwords = array(
23 'translate' => array(
24 self::DEFAULT_PATTERN,
25 "^array\(\s*'(.+)'\s*,\s*'(.+)'",
26 ),
27 'plural' => array(
28 "^'(.+)',\s*'(.+)'",
29 ),
30 'setLabel',
31 'setDescription'
32 );
33
34 /** Parser matches to these array key names */
35 protected $_arr_kwords = array(
36 'label',
37 'legend',
38 'description',
39 );
40
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
41 /** Supported adapters with their file extensions */
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
42 protected $_adapters = array(
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
43 'array' => 'php',
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
44 );
45
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
46 protected $_profile;
47 protected $_response;
48
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
49 /**
50 * Updates or creates a new translation resource file to match translation
51 * message ids found from application source files.
52 */
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
53 public function create($locale, $module = 'all',
54 $adapter = 'array', $kwords = null)
55 {
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
56 if (!$this->moduleExists($module)) {
57 return $this->_responseModuleDoesNotExist($module);
58 }
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
59 if (!array_key_exists($adapter, $this->_adapters)) {
60 return $this->_responseUnknownAdapter($adapter);
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
61 }
62 if (null !== $kwords) {
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
63 $this->addKeyWords($kwords);
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
64 }
65
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
66 /** Get translations */
67 $translations = $this->getTranslations($locale, $module, $adapter);
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
68
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
69 /** Save translations */
70 $this->_saveTranslations($locale, $module, $adapter, $translations);
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
71
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
72 /** Create response */
73 $response = $this->_getResponse();
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
74
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
75 if ($i = count($translations['new'])) {
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
76 $response->appendContent("Added $i message id(s)", array('color' => 'green'));
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
77 $response->appendContent(var_export($translations['new'], true));
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
78 } else {
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
79 $response->appendContent("No new message ids", array('color' => 'green'));
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
80 }
81
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
82 if ($i = count($translations['depricated'])) {
83 $response->appendContent("Resource file includes $i depricated translation(s)", array('color' => 'yellow'));
84 $response->appendContent(var_export($translations['depricated'], true));
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
85 } else {
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
86 $response->appendContent("No depricated translations", array('color' => 'green'));
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
87 }
88
89 return true;
90 }
91
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
92 public function sortTranslations(array $currentTranslations, array $matchedMessageIds)
93 {
94 $matches = array_fill_keys($matchedMessageIds, '');
95
96 $new = array_diff_key($matches, $currentTranslations);
97 $depricated = array_diff_key($currentTranslations, $matches);
98 $active = array_diff_key(array_merge($new, $currentTranslations), $depricated);
99
100 ksort($new, SORT_STRING);
101 ksort($depricated, SORT_STRING);
102 ksort($active, SORT_STRING);
103
104 return array('new' => $new, 'depricated' => $depricated, 'active' => $active);
105 }
106
107 public function getTranslations($locale, $module, $adapter)
108 {
109 $currentTranslations = $this->_loadTranslations($locale, $module, $adapter);
110 $matchedMessageIds = $this->getMatches($module);
111
112 return $this->sortTranslations($currentTranslations, $matchedMessageIds);
113 }
114
115 public function getMatches($module)
116 {
117 $path = $this->getModulePath($module);
118
119 $parser = new Kblom_FunctionParamParser(array(
120 'basepath' => $path,
121 'funcKeyWords' => $this->_func_kwords,
122 'arrKeyWords' => $this->_arr_kwords,
123 'defaultPattern' => self::DEFAULT_PATTERN
124 ));
125 if ($module == 'default' || $module == 'application') {
126 $parser->setExcludePaths(array('modules'));
127 }
128
129 return $parser->getMatches(false);
130 }
131
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
132 /**
133 * Returns path to module, which is 'application/modules/$module' or
134 * 'application' if $module == 'all' OR 'application'.
135 */
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
136 public function getModulePath($module)
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
137 {
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
138 $module = (string) $module;
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
139 $profile = $this->_getProfile();
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
140 $path = $profile->search('ApplicationDirectory')->getPath();
141
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
142 if ($module === 'all' || $module === 'application') {
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
143 return $path;
144 }
145
146 return $path . "/modules/$module";
147 }
148
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
149 /** Check if module exists */
150 public function moduleExists($module)
151 {
152 $path = $this->getModulePath($module);
153 return file_exists($path);
154 }
155
156 public function addKeyWords($list)
157 {
158 $kwords = explode(':', (string) $list);
159 foreach ($kwords as $k) {
160 preg_match('/^\[(.+)\]$/', $k, $arr_key);
161 if (isset($arr_key[1])) {
162 $this->_arr_kwords[] = $arr_key[1];
163 } else {
164 $this->_func_kwords[] = $k;
165 }
166 }
167 }
168
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
169 /**
170 * Returns path where to save translation resource file, which is
171 * 'data/locales/$locale/modules', or 'data/locales/$locale' if
172 * $module == 'all' OR 'application'.
173 */
174 protected function _getLocalesPath($locale, $module)
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
175 {
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
176 $profile = $this->_getProfile();
177 $path = $profile->search('LocalesDirectory')->create()->getPath();
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
178 $path .= "/$locale";
179
180 if ($module == 'all' || $module == 'application') {
181 return $path;
182 }
183
184 return $path . "/modules";
185 }
186
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
187 /** Try to load current translations */
188 protected function _loadTranslations($locale, $module, $adapter)
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
189 {
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
190 $profile = $this->_getProfile();
191 $path = $this->_getLocalesPath($locale, $module);
192 $content = $path . '/' . $module . '.' . $this->_adapters[$adapter];
193
194 try {
195 $translate = new Zend_Translate(array(
196 'adapter' => $adapter,
197 'content' => $content,
198 'locale' => $locale,
199 'disableNotices' => true
200 ));
201 } catch(Exception $e) {
202 if (!file_exists($content)) {
203 return array(); // The file will be created later
204 }
205 throw $e; // File exists, but consist from unkown format
206 }
207
208 // Translation file can be empty, thus this check
209 if ($messageIds = $translate->getMessageIds()) {
210 return array_combine($messageIds, $translate->getMessages());
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
211 }
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
212
213 return array();
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
214 }
215
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
216 protected function _saveTranslations($locale, $module, $adapter, array $translations)
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
217 {
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
218 if ($adapter == 'array') {
219 $input = $this->_createArray($translations);
220 }
221
222 $path = $this->_getLocalesPath($locale, $module);
223 $file = $path . '/' . $module . '.' . $this->_adapters[$adapter];
224
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
225 if (!file_exists($path)) {
226 mkdir($path);
227 }
228
c5c2fb9 @kblomqvist Kblom_Tool_Locale refactored
authored
229 return file_put_contents($file, $input);
230 }
231
232 protected function _createArray(array $translations)
233 {
234 $input = "<?php\nreturn array (\n";
235 foreach ($translations['active'] as $key => $val) {
236 $input .= " '$key' => '$val',\n";
237 }
238 if (!empty($translations['depricated'])) {
239 $input .= "\n /** Depricated translations. Remove manually or save for reuse. */\n";
240 foreach($translations['depricated'] as $key => $val) {
241 $input .= " '$key' => '$val',\n";
242 }
243 }
244 $input .= ");\n";
245
246 return $input;
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
247 }
248
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
249 protected function _responseUnknownAdapter($adapter)
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
250 {
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
251 $response = $this->_getResponse();
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
252 $response->appendContent("$adapter: unknown adapter", array('color' => 'yellow'));
253
254 return false;
255 }
256
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
257 protected function _responseModuleDoesNotExist($module)
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
258 {
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
259 $response = $this->_getResponse();
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
260 $response->appendContent("$module: module does not exist", array('color' => 'yellow'));
261
262 return false;
263 }
5344c30 @kblomqvist Current translation file reading is refactored to use Zend_Translate …
authored
264
265 /** Proxy for profile loader */
266 protected function _getProfile()
267 {
268 if (!isset($this->_profile)) {
269 $this->_profile = $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION);
270 }
271 return $this->_profile;
272 }
273
274 /** Proxy for getting response from registry */
275 protected function _getResponse()
276 {
277 if (!isset($this->_response)) {
278 $this->_response = $this->_registry->getResponse();
279 }
280 return $this->_response;
281 }
326ad8b @kblomqvist CLI tool for parsing translation msg from app source files
authored
282 }
Something went wrong with that request. Please try again.