1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace ICanBoogie\I18n;
13
14 use ICanBoogie\FileCache;
15 use ICanBoogie\I18n;
16 use ICanBoogie\Object;
17
18 class Translator extends Object implements \ArrayAccess
19 {
20 static private $translators=array();
21
22 23 24 25 26 27 28
29 static public function get($id)
30 {
31 if (isset(self::$translators[$id]))
32 {
33 return self::$translators[$id];
34 }
35
36 self::$translators[$id] = $translator = new static($id);
37
38 return $translator;
39 }
40
41 static protected $cache;
42
43 static protected function get_cache()
44 {
45 global $core;
46
47 if (!self::$cache)
48 {
49 self::$cache = new FileCache
50 (
51 array
52 (
53 FileCache::T_COMPRESS => true,
54 FileCache::T_REPOSITORY => $core->config['repository.cache'] . '/core',
55 FileCache::T_SERIALIZE => true
56 )
57 );
58 }
59
60 return self::$cache;
61 }
62
63 static public function messages_construct($id)
64 {
65 $messages = array();
66
67 foreach (I18n::$load_paths as $path)
68 {
69 $filename = $path . DIRECTORY_SEPARATOR . $id . '.php';
70
71 if (!file_exists($filename))
72 {
73 continue;
74 }
75
76 $messages[] = \ICanBoogie\array_flatten(require $filename);
77 }
78
79 return count($messages) ? call_user_func_array('array_merge', $messages) : array();
80 }
81
82 83 84 85 86
87 protected $messages;
88
89 protected function lazy_get_messages()
90 {
91 global $core;
92
93 $messages = array();
94 $id = $this->id;
95
96 if (isset($core) && $core->config['cache catalogs'])
97 {
98 $messages = self::get_cache()->load('i18n_' . $id, array(__CLASS__, 'messages_construct'), $id);
99 }
100 else
101 {
102 $messages = self::messages_construct($id);
103 }
104
105 if ($this->fallback)
106 {
107 $messages += $this->fallback->messages;
108 }
109
110 return $messages;
111 }
112
113 114 115 116 117
118 protected $fallback;
119
120 121 122 123 124 125
126 protected function lazy_get_fallback()
127 {
128 list($id, $territory) = explode('-', $this->id) + array(1 => null);
129
130 if (!$territory && $id == 'en')
131 {
132 return;
133 }
134 else if (!$territory)
135 {
136 $id = 'en';
137 }
138
139 return self::get($id);
140 }
141
142 143 144 145 146
147 protected $id;
148
149 150 151 152 153
154 protected function __construct($id)
155 {
156 unset($this->messages);
157 unset($this->fallback);
158
159 $this->id = $id;
160 }
161
162 static public $missing = array();
163
164 165 166 167 168 169 170 171 172 173
174 public function __invoke($native, array $args=array(), array $options=array())
175 {
176 $native = (string) $native;
177 $messages = $this->messages;
178 $translated = null;
179
180 $suffix = null;
181
182 if ($args && array_key_exists(':count', $args))
183 {
184 $count = $args[':count'];
185
186 if ($count == 0)
187 {
188 $suffix = '.none';
189 }
190 else if ($count == 1)
191 {
192 $suffix = '.one';
193 }
194 else
195 {
196 $suffix = '.other';
197 }
198 }
199
200 $scope = I18n::get_scope();
201
202 if (isset($options['scope']))
203 {
204 if ($scope)
205 {
206 $scope .= '.';
207 }
208
209 $scope .= is_array($options['scope']) ? implode('.', $options['scope']) : $options['scope'];
210 }
211
212 $prefix = $scope;
213
214 while ($scope)
215 {
216 $try = $scope . '.' . $native . $suffix;
217
218 if (isset($messages[$try]))
219 {
220 $translated = $messages[$try];
221
222 break;
223 }
224
225 $pos = strpos($scope, '.');
226
227 if ($pos === false)
228 {
229 break;
230 }
231
232 $scope = substr($scope, $pos + 1);
233 }
234
235 if (!$translated)
236 {
237 if (isset($messages[$native . $suffix]))
238 {
239 $translated = $messages[$native . $suffix];
240 }
241 }
242
243 if (!$translated)
244 {
245 self::$missing[] = ($prefix ? $prefix . '.' : '') . $native;
246
247 if (!empty($options['default']))
248 {
249 $default = $options['default'];
250
251 if (!($default instanceof \Closure))
252 {
253 return $default;
254 }
255
256 $native = $default($this, $native, $options, $args) ?: $native;
257 }
258
259
260
261
262
263
264
265 $this->messages[($prefix ? $prefix . '.' : '') . $native] = $native;
266
267 $translated = $native;
268 }
269
270 if ($args)
271 {
272 $translated = \ICanBoogie\format($translated, $args);
273 }
274
275 return $translated;
276 }
277
278 public function offsetExists($offset)
279 {
280 return isset($this->messages[$offset]);
281 }
282
283 public function offsetGet($offset)
284 {
285 return isset($this->messages[$offset]) ? $this->messages[$offset] : null;
286 }
287
288 public function offsetSet($offset, $value)
289 {
290
291 }
292
293 public function offsetUnset($offset)
294 {
295
296 }
297 }