├── .gitattributes
├── README.md
├── bin
└── translala
├── box.json
├── build
└── translala.phar
├── composer.json
├── composer.lock
└── src
└── Translala
├── App
├── Command
│ ├── AbstractCommand.php
│ ├── CommonCommand.php
│ ├── DeadCommand.php
│ ├── HealthCommand.php
│ ├── StatsCommand.php
│ └── TranslateCommand.php
├── Loader
│ ├── LoaderInterface.php
│ └── ProjectLoader.php
└── Templates
│ ├── common.html.twig
│ ├── dead.html.twig
│ ├── layout.html.twig
│ └── stats.html.twig
├── Domain
├── Exception
│ └── HealthException.php
├── Model
│ ├── CommandContext.php
│ ├── CommonTranslation.php
│ ├── ConfigFile.php
│ ├── ConfigFileInterface.php
│ ├── LocaleStats.php
│ ├── Project.php
│ ├── ProjectInterface.php
│ ├── Translation.php
│ ├── TranslationFile.php
│ ├── TranslationFileInterface.php
│ └── TranslationInterface.php
├── Parser
│ └── ParserInterface.php
└── Processor
│ ├── CommonProcessor.php
│ └── HealthProcessor.php
└── Infra
├── Application
└── Application.php
├── Job
├── CommonJob.php
├── DeadJob.php
├── StatsJob.php
└── TranslateJob.php
└── Parser
├── AbstractFileParser.php
├── JsonFileParser.php
├── PhpFileParser.php
└── YamlFileParser.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.phar linguist-language=Php
2 | build/translala.phar linguist-vendored=false
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Translala
2 | ==================
3 |
4 | Your new toolbox to manage your (Symfony/Laravel/Other) projects translations.
5 | It provide commands to translate your missing translations, detect commons translations, report translations stats and detect dead translations.
6 |
7 | It can also be integrated in your CI process.
8 |
9 | 
10 |
11 | Availables commands:
12 | - Stats command
13 | - Common command
14 | - Dead command
15 | - Health command (CI Process)
16 | - Translation command
17 |
18 | Availables Files format:
19 | - Yaml
20 | - Php
21 | - Json
22 |
23 | ## Install
24 | Grab the translala.phar and move it to your bin.
25 |
26 | ``` bash
27 | $ git clone git@github.com:Translala/translala.git && cp translala/build/translala.phar /usr/local/bin/translala
28 | ```
29 |
30 | ## Configure your project
31 | Here is what a complete `.translation.yml` file look like. You can add many path for each of your translation path.
32 | The translala report are dumped in your export path.
33 |
34 | ``` yml
35 | master_language: fr
36 | languages:
37 | - en
38 | - fr
39 | - da
40 |
41 | paths:
42 | - ./app/Resources/translations/
43 | - ./resources/lang/en/
44 | - ./src/AcmeBundle/Resources/translations/
45 |
46 | export_path: /tmp
47 |
48 | api:
49 | google: my_very_secret_api_key
50 |
51 | project_path: ./
52 |
53 |
54 | health:
55 | fr: 100
56 | en: 95
57 | da: 70
58 | ```
59 |
60 | `master_language` is the locale of reference for your project.
61 |
62 | `languages` list of locales your project have to manage.
63 |
64 | `paths` are filepaths where your translations file are stored.
65 |
66 | `export_path` is the directory where Translala dump your reports
67 |
68 | ## Stats command
69 | `translala translala:project:stats --config ./app/Resources/translations/.translation.yml`
70 |
71 | The stats command report project stats about translations achievements.
72 | 
73 |
74 | ## Common command
75 | `translala translala:project:common --config ./app/Resources/translations/.translation.yml`
76 |
77 | Do you have a different translation key for each "save" buttons of your form? With many locales, it can have a significant cost.
78 | 
79 |
80 | ## Dead command
81 | `translala translala:project:dead --config ./app/Resources/translations/.translation.yml`
82 |
83 | This search each translations keys in your project to help you find dead key.
84 | 
85 |
86 | ## Health command
87 | `translala translala:health:status --config ./app/Resources/translations/.translation.yml`
88 |
89 | Check percentage of missing translation for each locale. Return an exit code if check fail. Made for CI process.
90 |
91 | ## Translation command
92 | `translala translala:project:translate --config ./app/Resources/translations/.translation.yml`
93 |
94 | Using php-translation it translate missing or empty keys for each locale in each file.
95 |
96 | ## Contribution
97 | Feel free to remove array manipulation, fix typo and create new file parser with a PR ;)
--------------------------------------------------------------------------------
/bin/translala:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
--------------------------------------------------------------------------------
/box.json:
--------------------------------------------------------------------------------
1 | {
2 | "algorithm": "SHA1",
3 | "alias": "translala.phar",
4 | "banner": "",
5 | "chmod": "0755",
6 | "compactors": [
7 | "Herrera\\Box\\Compactor\\Json",
8 | "Herrera\\Box\\Compactor\\Php"
9 | ],
10 | "directories": "src",
11 | "extract": true,
12 | "files": [
13 | "vendor/autoload.php",
14 | "vendor/composer/installed.json"
15 | ],
16 | "finder": [
17 | {
18 | "exclude": [
19 | "tests",
20 | "Tests"
21 | ],
22 | "in": [
23 | "vendor",
24 | "vendor/guzzlehttp",
25 | "vendor/php-http",
26 | "vendor/php-translation",
27 | "vendor/psr",
28 | "vendor/symfony"
29 | ],
30 | "name": "*.php"
31 | }
32 | ],
33 | "git-version": "package_version",
34 | "main": "bin/translala",
35 | "output": "build/translala.phar",
36 | "stub": true
37 | }
--------------------------------------------------------------------------------
/build/translala.phar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScullWM/translala/8319ebeb5f368acdc3d09d3a955c946e09ecbe4a/build/translala.phar
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "translala/translala",
3 | "type": "library",
4 | "require": {
5 | "php": "^5.5|^7.0",
6 | "symfony/console": "^2.7|^3.0",
7 | "symfony/process": "^2.7|^3.0",
8 | "symfony/finder": "^2.7|^3.0",
9 | "symfony/filesystem": "^2.7|^3.0",
10 | "symfony/yaml": "^2.7|^3.0",
11 | "symfony/event-dispatcher": "^2.7|^3.0",
12 | "symfony/property-access": "^2.7|^3.0",
13 | "php-http/guzzle6-adapter": "^1.1",
14 | "php-translation/translator": "^0.1.0",
15 | "php-http/discovery": "^1.1",
16 | "php-http/message": "^1.4",
17 | "twig/twig": "^1.31"
18 | },
19 | "bin": [
20 | "bin/tanslala"
21 | ],
22 | "config": {
23 | "bin-dir": "bin"
24 | },
25 | "autoload": {
26 | "psr-4": {"Translala\\": "src/Translala"}
27 | },
28 | "extra": {
29 | "branch-alias": {
30 | "dev-master": "1.0-dev"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "a726c54effd76e08da69587dce3d9bb8",
8 | "packages": [
9 | {
10 | "name": "clue/stream-filter",
11 | "version": "v1.3.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/clue/php-stream-filter.git",
15 | "reference": "e3bf9415da163d9ad6701dccb407ed501ae69785"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/clue/php-stream-filter/zipball/e3bf9415da163d9ad6701dccb407ed501ae69785",
20 | "reference": "e3bf9415da163d9ad6701dccb407ed501ae69785",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": ">=5.3"
25 | },
26 | "type": "library",
27 | "autoload": {
28 | "psr-4": {
29 | "Clue\\StreamFilter\\": "src/"
30 | },
31 | "files": [
32 | "src/functions.php"
33 | ]
34 | },
35 | "notification-url": "https://packagist.org/downloads/",
36 | "license": [
37 | "MIT"
38 | ],
39 | "authors": [
40 | {
41 | "name": "Christian Lück",
42 | "email": "christian@lueck.tv"
43 | }
44 | ],
45 | "description": "A simple and modern approach to stream filtering in PHP",
46 | "homepage": "https://github.com/clue/php-stream-filter",
47 | "keywords": [
48 | "bucket brigade",
49 | "callback",
50 | "filter",
51 | "php_user_filter",
52 | "stream",
53 | "stream_filter_append",
54 | "stream_filter_register"
55 | ],
56 | "time": "2015-11-08T23:41:30+00:00"
57 | },
58 | {
59 | "name": "guzzlehttp/guzzle",
60 | "version": "6.2.2",
61 | "source": {
62 | "type": "git",
63 | "url": "https://github.com/guzzle/guzzle.git",
64 | "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60"
65 | },
66 | "dist": {
67 | "type": "zip",
68 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
69 | "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
70 | "shasum": ""
71 | },
72 | "require": {
73 | "guzzlehttp/promises": "^1.0",
74 | "guzzlehttp/psr7": "^1.3.1",
75 | "php": ">=5.5"
76 | },
77 | "require-dev": {
78 | "ext-curl": "*",
79 | "phpunit/phpunit": "^4.0",
80 | "psr/log": "^1.0"
81 | },
82 | "type": "library",
83 | "extra": {
84 | "branch-alias": {
85 | "dev-master": "6.2-dev"
86 | }
87 | },
88 | "autoload": {
89 | "files": [
90 | "src/functions_include.php"
91 | ],
92 | "psr-4": {
93 | "GuzzleHttp\\": "src/"
94 | }
95 | },
96 | "notification-url": "https://packagist.org/downloads/",
97 | "license": [
98 | "MIT"
99 | ],
100 | "authors": [
101 | {
102 | "name": "Michael Dowling",
103 | "email": "mtdowling@gmail.com",
104 | "homepage": "https://github.com/mtdowling"
105 | }
106 | ],
107 | "description": "Guzzle is a PHP HTTP client library",
108 | "homepage": "http://guzzlephp.org/",
109 | "keywords": [
110 | "client",
111 | "curl",
112 | "framework",
113 | "http",
114 | "http client",
115 | "rest",
116 | "web service"
117 | ],
118 | "time": "2016-10-08T15:01:37+00:00"
119 | },
120 | {
121 | "name": "guzzlehttp/promises",
122 | "version": "v1.3.1",
123 | "source": {
124 | "type": "git",
125 | "url": "https://github.com/guzzle/promises.git",
126 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
127 | },
128 | "dist": {
129 | "type": "zip",
130 | "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
131 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
132 | "shasum": ""
133 | },
134 | "require": {
135 | "php": ">=5.5.0"
136 | },
137 | "require-dev": {
138 | "phpunit/phpunit": "^4.0"
139 | },
140 | "type": "library",
141 | "extra": {
142 | "branch-alias": {
143 | "dev-master": "1.4-dev"
144 | }
145 | },
146 | "autoload": {
147 | "psr-4": {
148 | "GuzzleHttp\\Promise\\": "src/"
149 | },
150 | "files": [
151 | "src/functions_include.php"
152 | ]
153 | },
154 | "notification-url": "https://packagist.org/downloads/",
155 | "license": [
156 | "MIT"
157 | ],
158 | "authors": [
159 | {
160 | "name": "Michael Dowling",
161 | "email": "mtdowling@gmail.com",
162 | "homepage": "https://github.com/mtdowling"
163 | }
164 | ],
165 | "description": "Guzzle promises library",
166 | "keywords": [
167 | "promise"
168 | ],
169 | "time": "2016-12-20T10:07:11+00:00"
170 | },
171 | {
172 | "name": "guzzlehttp/psr7",
173 | "version": "1.3.1",
174 | "source": {
175 | "type": "git",
176 | "url": "https://github.com/guzzle/psr7.git",
177 | "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b"
178 | },
179 | "dist": {
180 | "type": "zip",
181 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
182 | "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
183 | "shasum": ""
184 | },
185 | "require": {
186 | "php": ">=5.4.0",
187 | "psr/http-message": "~1.0"
188 | },
189 | "provide": {
190 | "psr/http-message-implementation": "1.0"
191 | },
192 | "require-dev": {
193 | "phpunit/phpunit": "~4.0"
194 | },
195 | "type": "library",
196 | "extra": {
197 | "branch-alias": {
198 | "dev-master": "1.4-dev"
199 | }
200 | },
201 | "autoload": {
202 | "psr-4": {
203 | "GuzzleHttp\\Psr7\\": "src/"
204 | },
205 | "files": [
206 | "src/functions_include.php"
207 | ]
208 | },
209 | "notification-url": "https://packagist.org/downloads/",
210 | "license": [
211 | "MIT"
212 | ],
213 | "authors": [
214 | {
215 | "name": "Michael Dowling",
216 | "email": "mtdowling@gmail.com",
217 | "homepage": "https://github.com/mtdowling"
218 | }
219 | ],
220 | "description": "PSR-7 message implementation",
221 | "keywords": [
222 | "http",
223 | "message",
224 | "stream",
225 | "uri"
226 | ],
227 | "time": "2016-06-24T23:00:38+00:00"
228 | },
229 | {
230 | "name": "php-http/discovery",
231 | "version": "v1.1.1",
232 | "source": {
233 | "type": "git",
234 | "url": "https://github.com/php-http/discovery.git",
235 | "reference": "47fc36bd73ab615b55c31f4134e6bae70f1c04c1"
236 | },
237 | "dist": {
238 | "type": "zip",
239 | "url": "https://api.github.com/repos/php-http/discovery/zipball/47fc36bd73ab615b55c31f4134e6bae70f1c04c1",
240 | "reference": "47fc36bd73ab615b55c31f4134e6bae70f1c04c1",
241 | "shasum": ""
242 | },
243 | "require": {
244 | "php": "^5.5 || ^7.0"
245 | },
246 | "require-dev": {
247 | "henrikbjorn/phpspec-code-coverage": "^2.0.2",
248 | "php-http/httplug": "^1.0",
249 | "php-http/message-factory": "^1.0",
250 | "phpspec/phpspec": "^2.4",
251 | "puli/composer-plugin": "1.0.0-beta10"
252 | },
253 | "suggest": {
254 | "php-http/message": "Allow to use Guzzle, Diactoros or Slim Framework factories",
255 | "puli/composer-plugin": "Sets up Puli which is recommended for Discovery to work. Check http://docs.php-http.org/en/latest/discovery.html for more details."
256 | },
257 | "type": "library",
258 | "extra": {
259 | "branch-alias": {
260 | "dev-master": "1.2-dev"
261 | }
262 | },
263 | "autoload": {
264 | "psr-4": {
265 | "Http\\Discovery\\": "src/"
266 | }
267 | },
268 | "notification-url": "https://packagist.org/downloads/",
269 | "license": [
270 | "MIT"
271 | ],
272 | "authors": [
273 | {
274 | "name": "Márk Sági-Kazár",
275 | "email": "mark.sagikazar@gmail.com"
276 | }
277 | ],
278 | "description": "Finds installed HTTPlug implementations and PSR-7 message factories",
279 | "homepage": "http://php-http.org",
280 | "keywords": [
281 | "adapter",
282 | "client",
283 | "discovery",
284 | "factory",
285 | "http",
286 | "message",
287 | "psr7"
288 | ],
289 | "time": "2016-11-27T12:21:25+00:00"
290 | },
291 | {
292 | "name": "php-http/guzzle6-adapter",
293 | "version": "v1.1.1",
294 | "source": {
295 | "type": "git",
296 | "url": "https://github.com/php-http/guzzle6-adapter.git",
297 | "reference": "a56941f9dc6110409cfcddc91546ee97039277ab"
298 | },
299 | "dist": {
300 | "type": "zip",
301 | "url": "https://api.github.com/repos/php-http/guzzle6-adapter/zipball/a56941f9dc6110409cfcddc91546ee97039277ab",
302 | "reference": "a56941f9dc6110409cfcddc91546ee97039277ab",
303 | "shasum": ""
304 | },
305 | "require": {
306 | "guzzlehttp/guzzle": "^6.0",
307 | "php": ">=5.5.0",
308 | "php-http/httplug": "^1.0"
309 | },
310 | "provide": {
311 | "php-http/async-client-implementation": "1.0",
312 | "php-http/client-implementation": "1.0"
313 | },
314 | "require-dev": {
315 | "ext-curl": "*",
316 | "php-http/adapter-integration-tests": "^0.4"
317 | },
318 | "type": "library",
319 | "extra": {
320 | "branch-alias": {
321 | "dev-master": "1.2-dev"
322 | }
323 | },
324 | "autoload": {
325 | "psr-4": {
326 | "Http\\Adapter\\Guzzle6\\": "src/"
327 | }
328 | },
329 | "notification-url": "https://packagist.org/downloads/",
330 | "license": [
331 | "MIT"
332 | ],
333 | "authors": [
334 | {
335 | "name": "Márk Sági-Kazár",
336 | "email": "mark.sagikazar@gmail.com"
337 | },
338 | {
339 | "name": "David de Boer",
340 | "email": "david@ddeboer.nl"
341 | }
342 | ],
343 | "description": "Guzzle 6 HTTP Adapter",
344 | "homepage": "http://httplug.io",
345 | "keywords": [
346 | "Guzzle",
347 | "http"
348 | ],
349 | "time": "2016-05-10T06:13:32+00:00"
350 | },
351 | {
352 | "name": "php-http/httplug",
353 | "version": "v1.1.0",
354 | "source": {
355 | "type": "git",
356 | "url": "https://github.com/php-http/httplug.git",
357 | "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018"
358 | },
359 | "dist": {
360 | "type": "zip",
361 | "url": "https://api.github.com/repos/php-http/httplug/zipball/1c6381726c18579c4ca2ef1ec1498fdae8bdf018",
362 | "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018",
363 | "shasum": ""
364 | },
365 | "require": {
366 | "php": ">=5.4",
367 | "php-http/promise": "^1.0",
368 | "psr/http-message": "^1.0"
369 | },
370 | "require-dev": {
371 | "henrikbjorn/phpspec-code-coverage": "^1.0",
372 | "phpspec/phpspec": "^2.4"
373 | },
374 | "type": "library",
375 | "extra": {
376 | "branch-alias": {
377 | "dev-master": "1.1-dev"
378 | }
379 | },
380 | "autoload": {
381 | "psr-4": {
382 | "Http\\Client\\": "src/"
383 | }
384 | },
385 | "notification-url": "https://packagist.org/downloads/",
386 | "license": [
387 | "MIT"
388 | ],
389 | "authors": [
390 | {
391 | "name": "Eric GELOEN",
392 | "email": "geloen.eric@gmail.com"
393 | },
394 | {
395 | "name": "Márk Sági-Kazár",
396 | "email": "mark.sagikazar@gmail.com"
397 | }
398 | ],
399 | "description": "HTTPlug, the HTTP client abstraction for PHP",
400 | "homepage": "http://httplug.io",
401 | "keywords": [
402 | "client",
403 | "http"
404 | ],
405 | "time": "2016-08-31T08:30:17+00:00"
406 | },
407 | {
408 | "name": "php-http/message",
409 | "version": "v1.4.1",
410 | "source": {
411 | "type": "git",
412 | "url": "https://github.com/php-http/message.git",
413 | "reference": "bfd895a4e753bdde99bed64d75b999e0c9fa6147"
414 | },
415 | "dist": {
416 | "type": "zip",
417 | "url": "https://api.github.com/repos/php-http/message/zipball/bfd895a4e753bdde99bed64d75b999e0c9fa6147",
418 | "reference": "bfd895a4e753bdde99bed64d75b999e0c9fa6147",
419 | "shasum": ""
420 | },
421 | "require": {
422 | "clue/stream-filter": "^1.3",
423 | "php": ">=5.4",
424 | "php-http/message-factory": "^1.0.2",
425 | "psr/http-message": "^1.0"
426 | },
427 | "require-dev": {
428 | "akeneo/phpspec-skip-example-extension": "^1.0",
429 | "coduo/phpspec-data-provider-extension": "^1.0",
430 | "ext-zlib": "*",
431 | "guzzlehttp/psr7": "^1.0",
432 | "henrikbjorn/phpspec-code-coverage": "^1.0",
433 | "phpspec/phpspec": "^2.4",
434 | "slim/slim": "^3.0",
435 | "zendframework/zend-diactoros": "^1.0"
436 | },
437 | "suggest": {
438 | "ext-zlib": "Used with compressor/decompressor streams",
439 | "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories",
440 | "slim/slim": "Used with Slim Framework PSR-7 implementation",
441 | "zendframework/zend-diactoros": "Used with Diactoros Factories"
442 | },
443 | "type": "library",
444 | "extra": {
445 | "branch-alias": {
446 | "dev-master": "1.5-dev"
447 | }
448 | },
449 | "autoload": {
450 | "psr-4": {
451 | "Http\\Message\\": "src/"
452 | },
453 | "files": [
454 | "src/filters.php"
455 | ]
456 | },
457 | "notification-url": "https://packagist.org/downloads/",
458 | "license": [
459 | "MIT"
460 | ],
461 | "authors": [
462 | {
463 | "name": "Márk Sági-Kazár",
464 | "email": "mark.sagikazar@gmail.com"
465 | }
466 | ],
467 | "description": "HTTP Message related tools",
468 | "homepage": "http://php-http.org",
469 | "keywords": [
470 | "http",
471 | "message",
472 | "psr-7"
473 | ],
474 | "time": "2016-12-16T21:09:21+00:00"
475 | },
476 | {
477 | "name": "php-http/message-factory",
478 | "version": "v1.0.2",
479 | "source": {
480 | "type": "git",
481 | "url": "https://github.com/php-http/message-factory.git",
482 | "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1"
483 | },
484 | "dist": {
485 | "type": "zip",
486 | "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1",
487 | "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1",
488 | "shasum": ""
489 | },
490 | "require": {
491 | "php": ">=5.4",
492 | "psr/http-message": "^1.0"
493 | },
494 | "type": "library",
495 | "extra": {
496 | "branch-alias": {
497 | "dev-master": "1.0-dev"
498 | }
499 | },
500 | "autoload": {
501 | "psr-4": {
502 | "Http\\Message\\": "src/"
503 | }
504 | },
505 | "notification-url": "https://packagist.org/downloads/",
506 | "license": [
507 | "MIT"
508 | ],
509 | "authors": [
510 | {
511 | "name": "Márk Sági-Kazár",
512 | "email": "mark.sagikazar@gmail.com"
513 | }
514 | ],
515 | "description": "Factory interfaces for PSR-7 HTTP Message",
516 | "homepage": "http://php-http.org",
517 | "keywords": [
518 | "factory",
519 | "http",
520 | "message",
521 | "stream",
522 | "uri"
523 | ],
524 | "time": "2015-12-19T14:08:53+00:00"
525 | },
526 | {
527 | "name": "php-http/promise",
528 | "version": "v1.0.0",
529 | "source": {
530 | "type": "git",
531 | "url": "https://github.com/php-http/promise.git",
532 | "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980"
533 | },
534 | "dist": {
535 | "type": "zip",
536 | "url": "https://api.github.com/repos/php-http/promise/zipball/dc494cdc9d7160b9a09bd5573272195242ce7980",
537 | "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980",
538 | "shasum": ""
539 | },
540 | "require-dev": {
541 | "henrikbjorn/phpspec-code-coverage": "^1.0",
542 | "phpspec/phpspec": "^2.4"
543 | },
544 | "type": "library",
545 | "extra": {
546 | "branch-alias": {
547 | "dev-master": "1.1-dev"
548 | }
549 | },
550 | "autoload": {
551 | "psr-4": {
552 | "Http\\Promise\\": "src/"
553 | }
554 | },
555 | "notification-url": "https://packagist.org/downloads/",
556 | "license": [
557 | "MIT"
558 | ],
559 | "authors": [
560 | {
561 | "name": "Márk Sági-Kazár",
562 | "email": "mark.sagikazar@gmail.com"
563 | },
564 | {
565 | "name": "Joel Wurtz",
566 | "email": "joel.wurtz@gmail.com"
567 | }
568 | ],
569 | "description": "Promise used for asynchronous HTTP requests",
570 | "homepage": "http://httplug.io",
571 | "keywords": [
572 | "promise"
573 | ],
574 | "time": "2016-01-26T13:27:02+00:00"
575 | },
576 | {
577 | "name": "php-translation/translator",
578 | "version": "0.1.0",
579 | "source": {
580 | "type": "git",
581 | "url": "https://github.com/php-translation/translator.git",
582 | "reference": "036711160406d94d414e2dfa12a94a0dc36c2322"
583 | },
584 | "dist": {
585 | "type": "zip",
586 | "url": "https://api.github.com/repos/php-translation/translator/zipball/036711160406d94d414e2dfa12a94a0dc36c2322",
587 | "reference": "036711160406d94d414e2dfa12a94a0dc36c2322",
588 | "shasum": ""
589 | },
590 | "require": {
591 | "php": "^5.5 || ^7.0",
592 | "php-http/client-implementation": "^1.0",
593 | "php-http/httplug": "^1.0",
594 | "psr/log": "~1.0"
595 | },
596 | "require-dev": {
597 | "nyholm/nsa": "^1.0",
598 | "php-http/curl-client": "^1.0",
599 | "phpunit/phpunit": "^4.5 || ^5.4"
600 | },
601 | "type": "library",
602 | "autoload": {
603 | "psr-4": {
604 | "Translation\\Translator\\": "src/"
605 | }
606 | },
607 | "notification-url": "https://packagist.org/downloads/",
608 | "license": [
609 | "MIT"
610 | ],
611 | "authors": [
612 | {
613 | "name": "Tobias Nyholm",
614 | "email": "tobias.nyholm@gmail.com"
615 | }
616 | ],
617 | "description": "Translator services",
618 | "time": "2016-12-05T10:06:43+00:00"
619 | },
620 | {
621 | "name": "psr/http-message",
622 | "version": "1.0.1",
623 | "source": {
624 | "type": "git",
625 | "url": "https://github.com/php-fig/http-message.git",
626 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
627 | },
628 | "dist": {
629 | "type": "zip",
630 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
631 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
632 | "shasum": ""
633 | },
634 | "require": {
635 | "php": ">=5.3.0"
636 | },
637 | "type": "library",
638 | "extra": {
639 | "branch-alias": {
640 | "dev-master": "1.0.x-dev"
641 | }
642 | },
643 | "autoload": {
644 | "psr-4": {
645 | "Psr\\Http\\Message\\": "src/"
646 | }
647 | },
648 | "notification-url": "https://packagist.org/downloads/",
649 | "license": [
650 | "MIT"
651 | ],
652 | "authors": [
653 | {
654 | "name": "PHP-FIG",
655 | "homepage": "http://www.php-fig.org/"
656 | }
657 | ],
658 | "description": "Common interface for HTTP messages",
659 | "homepage": "https://github.com/php-fig/http-message",
660 | "keywords": [
661 | "http",
662 | "http-message",
663 | "psr",
664 | "psr-7",
665 | "request",
666 | "response"
667 | ],
668 | "time": "2016-08-06T14:39:51+00:00"
669 | },
670 | {
671 | "name": "psr/log",
672 | "version": "1.0.2",
673 | "source": {
674 | "type": "git",
675 | "url": "https://github.com/php-fig/log.git",
676 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
677 | },
678 | "dist": {
679 | "type": "zip",
680 | "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
681 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
682 | "shasum": ""
683 | },
684 | "require": {
685 | "php": ">=5.3.0"
686 | },
687 | "type": "library",
688 | "extra": {
689 | "branch-alias": {
690 | "dev-master": "1.0.x-dev"
691 | }
692 | },
693 | "autoload": {
694 | "psr-4": {
695 | "Psr\\Log\\": "Psr/Log/"
696 | }
697 | },
698 | "notification-url": "https://packagist.org/downloads/",
699 | "license": [
700 | "MIT"
701 | ],
702 | "authors": [
703 | {
704 | "name": "PHP-FIG",
705 | "homepage": "http://www.php-fig.org/"
706 | }
707 | ],
708 | "description": "Common interface for logging libraries",
709 | "homepage": "https://github.com/php-fig/log",
710 | "keywords": [
711 | "log",
712 | "psr",
713 | "psr-3"
714 | ],
715 | "time": "2016-10-10T12:19:37+00:00"
716 | },
717 | {
718 | "name": "symfony/console",
719 | "version": "v3.0.4",
720 | "source": {
721 | "type": "git",
722 | "url": "https://github.com/symfony/console.git",
723 | "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd"
724 | },
725 | "dist": {
726 | "type": "zip",
727 | "url": "https://api.github.com/repos/symfony/console/zipball/6b1175135bc2a74c08a28d89761272de8beed8cd",
728 | "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd",
729 | "shasum": ""
730 | },
731 | "require": {
732 | "php": ">=5.5.9",
733 | "symfony/polyfill-mbstring": "~1.0"
734 | },
735 | "require-dev": {
736 | "psr/log": "~1.0",
737 | "symfony/event-dispatcher": "~2.8|~3.0",
738 | "symfony/process": "~2.8|~3.0"
739 | },
740 | "suggest": {
741 | "psr/log": "For using the console logger",
742 | "symfony/event-dispatcher": "",
743 | "symfony/process": ""
744 | },
745 | "type": "library",
746 | "extra": {
747 | "branch-alias": {
748 | "dev-master": "3.0-dev"
749 | }
750 | },
751 | "autoload": {
752 | "psr-4": {
753 | "Symfony\\Component\\Console\\": ""
754 | },
755 | "exclude-from-classmap": [
756 | "/Tests/"
757 | ]
758 | },
759 | "notification-url": "https://packagist.org/downloads/",
760 | "license": [
761 | "MIT"
762 | ],
763 | "authors": [
764 | {
765 | "name": "Fabien Potencier",
766 | "email": "fabien@symfony.com"
767 | },
768 | {
769 | "name": "Symfony Community",
770 | "homepage": "https://symfony.com/contributors"
771 | }
772 | ],
773 | "description": "Symfony Console Component",
774 | "homepage": "https://symfony.com",
775 | "time": "2016-03-16T17:00:50+00:00"
776 | },
777 | {
778 | "name": "symfony/event-dispatcher",
779 | "version": "v3.0.4",
780 | "source": {
781 | "type": "git",
782 | "url": "https://github.com/symfony/event-dispatcher.git",
783 | "reference": "9002dcf018d884d294b1ef20a6f968efc1128f39"
784 | },
785 | "dist": {
786 | "type": "zip",
787 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9002dcf018d884d294b1ef20a6f968efc1128f39",
788 | "reference": "9002dcf018d884d294b1ef20a6f968efc1128f39",
789 | "shasum": ""
790 | },
791 | "require": {
792 | "php": ">=5.5.9"
793 | },
794 | "require-dev": {
795 | "psr/log": "~1.0",
796 | "symfony/config": "~2.8|~3.0",
797 | "symfony/dependency-injection": "~2.8|~3.0",
798 | "symfony/expression-language": "~2.8|~3.0",
799 | "symfony/stopwatch": "~2.8|~3.0"
800 | },
801 | "suggest": {
802 | "symfony/dependency-injection": "",
803 | "symfony/http-kernel": ""
804 | },
805 | "type": "library",
806 | "extra": {
807 | "branch-alias": {
808 | "dev-master": "3.0-dev"
809 | }
810 | },
811 | "autoload": {
812 | "psr-4": {
813 | "Symfony\\Component\\EventDispatcher\\": ""
814 | },
815 | "exclude-from-classmap": [
816 | "/Tests/"
817 | ]
818 | },
819 | "notification-url": "https://packagist.org/downloads/",
820 | "license": [
821 | "MIT"
822 | ],
823 | "authors": [
824 | {
825 | "name": "Fabien Potencier",
826 | "email": "fabien@symfony.com"
827 | },
828 | {
829 | "name": "Symfony Community",
830 | "homepage": "https://symfony.com/contributors"
831 | }
832 | ],
833 | "description": "Symfony EventDispatcher Component",
834 | "homepage": "https://symfony.com",
835 | "time": "2016-03-10T10:34:12+00:00"
836 | },
837 | {
838 | "name": "symfony/filesystem",
839 | "version": "v3.0.4",
840 | "source": {
841 | "type": "git",
842 | "url": "https://github.com/symfony/filesystem.git",
843 | "reference": "f82499a459dcade2ea56df94cc58b19c8bde3d20"
844 | },
845 | "dist": {
846 | "type": "zip",
847 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/f82499a459dcade2ea56df94cc58b19c8bde3d20",
848 | "reference": "f82499a459dcade2ea56df94cc58b19c8bde3d20",
849 | "shasum": ""
850 | },
851 | "require": {
852 | "php": ">=5.5.9"
853 | },
854 | "type": "library",
855 | "extra": {
856 | "branch-alias": {
857 | "dev-master": "3.0-dev"
858 | }
859 | },
860 | "autoload": {
861 | "psr-4": {
862 | "Symfony\\Component\\Filesystem\\": ""
863 | },
864 | "exclude-from-classmap": [
865 | "/Tests/"
866 | ]
867 | },
868 | "notification-url": "https://packagist.org/downloads/",
869 | "license": [
870 | "MIT"
871 | ],
872 | "authors": [
873 | {
874 | "name": "Fabien Potencier",
875 | "email": "fabien@symfony.com"
876 | },
877 | {
878 | "name": "Symfony Community",
879 | "homepage": "https://symfony.com/contributors"
880 | }
881 | ],
882 | "description": "Symfony Filesystem Component",
883 | "homepage": "https://symfony.com",
884 | "time": "2016-03-27T10:24:39+00:00"
885 | },
886 | {
887 | "name": "symfony/finder",
888 | "version": "v3.0.4",
889 | "source": {
890 | "type": "git",
891 | "url": "https://github.com/symfony/finder.git",
892 | "reference": "c54e407b35bc098916704e9fd090da21da4c4f52"
893 | },
894 | "dist": {
895 | "type": "zip",
896 | "url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52",
897 | "reference": "c54e407b35bc098916704e9fd090da21da4c4f52",
898 | "shasum": ""
899 | },
900 | "require": {
901 | "php": ">=5.5.9"
902 | },
903 | "type": "library",
904 | "extra": {
905 | "branch-alias": {
906 | "dev-master": "3.0-dev"
907 | }
908 | },
909 | "autoload": {
910 | "psr-4": {
911 | "Symfony\\Component\\Finder\\": ""
912 | },
913 | "exclude-from-classmap": [
914 | "/Tests/"
915 | ]
916 | },
917 | "notification-url": "https://packagist.org/downloads/",
918 | "license": [
919 | "MIT"
920 | ],
921 | "authors": [
922 | {
923 | "name": "Fabien Potencier",
924 | "email": "fabien@symfony.com"
925 | },
926 | {
927 | "name": "Symfony Community",
928 | "homepage": "https://symfony.com/contributors"
929 | }
930 | ],
931 | "description": "Symfony Finder Component",
932 | "homepage": "https://symfony.com",
933 | "time": "2016-03-10T11:13:05+00:00"
934 | },
935 | {
936 | "name": "symfony/polyfill-mbstring",
937 | "version": "v1.1.1",
938 | "source": {
939 | "type": "git",
940 | "url": "https://github.com/symfony/polyfill-mbstring.git",
941 | "reference": "1289d16209491b584839022f29257ad859b8532d"
942 | },
943 | "dist": {
944 | "type": "zip",
945 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
946 | "reference": "1289d16209491b584839022f29257ad859b8532d",
947 | "shasum": ""
948 | },
949 | "require": {
950 | "php": ">=5.3.3"
951 | },
952 | "suggest": {
953 | "ext-mbstring": "For best performance"
954 | },
955 | "type": "library",
956 | "extra": {
957 | "branch-alias": {
958 | "dev-master": "1.1-dev"
959 | }
960 | },
961 | "autoload": {
962 | "psr-4": {
963 | "Symfony\\Polyfill\\Mbstring\\": ""
964 | },
965 | "files": [
966 | "bootstrap.php"
967 | ]
968 | },
969 | "notification-url": "https://packagist.org/downloads/",
970 | "license": [
971 | "MIT"
972 | ],
973 | "authors": [
974 | {
975 | "name": "Nicolas Grekas",
976 | "email": "p@tchwork.com"
977 | },
978 | {
979 | "name": "Symfony Community",
980 | "homepage": "https://symfony.com/contributors"
981 | }
982 | ],
983 | "description": "Symfony polyfill for the Mbstring extension",
984 | "homepage": "https://symfony.com",
985 | "keywords": [
986 | "compatibility",
987 | "mbstring",
988 | "polyfill",
989 | "portable",
990 | "shim"
991 | ],
992 | "time": "2016-01-20T09:13:37+00:00"
993 | },
994 | {
995 | "name": "symfony/process",
996 | "version": "v3.0.4",
997 | "source": {
998 | "type": "git",
999 | "url": "https://github.com/symfony/process.git",
1000 | "reference": "e6f1f98bbd355d209a992bfff45e7edfbd4a0776"
1001 | },
1002 | "dist": {
1003 | "type": "zip",
1004 | "url": "https://api.github.com/repos/symfony/process/zipball/e6f1f98bbd355d209a992bfff45e7edfbd4a0776",
1005 | "reference": "e6f1f98bbd355d209a992bfff45e7edfbd4a0776",
1006 | "shasum": ""
1007 | },
1008 | "require": {
1009 | "php": ">=5.5.9"
1010 | },
1011 | "type": "library",
1012 | "extra": {
1013 | "branch-alias": {
1014 | "dev-master": "3.0-dev"
1015 | }
1016 | },
1017 | "autoload": {
1018 | "psr-4": {
1019 | "Symfony\\Component\\Process\\": ""
1020 | },
1021 | "exclude-from-classmap": [
1022 | "/Tests/"
1023 | ]
1024 | },
1025 | "notification-url": "https://packagist.org/downloads/",
1026 | "license": [
1027 | "MIT"
1028 | ],
1029 | "authors": [
1030 | {
1031 | "name": "Fabien Potencier",
1032 | "email": "fabien@symfony.com"
1033 | },
1034 | {
1035 | "name": "Symfony Community",
1036 | "homepage": "https://symfony.com/contributors"
1037 | }
1038 | ],
1039 | "description": "Symfony Process Component",
1040 | "homepage": "https://symfony.com",
1041 | "time": "2016-03-30T10:41:14+00:00"
1042 | },
1043 | {
1044 | "name": "symfony/property-access",
1045 | "version": "v3.0.4",
1046 | "source": {
1047 | "type": "git",
1048 | "url": "https://github.com/symfony/property-access.git",
1049 | "reference": "475e661a0b90f0e6942a7d2fdf4e0dbf8104fef3"
1050 | },
1051 | "dist": {
1052 | "type": "zip",
1053 | "url": "https://api.github.com/repos/symfony/property-access/zipball/475e661a0b90f0e6942a7d2fdf4e0dbf8104fef3",
1054 | "reference": "475e661a0b90f0e6942a7d2fdf4e0dbf8104fef3",
1055 | "shasum": ""
1056 | },
1057 | "require": {
1058 | "php": ">=5.5.9"
1059 | },
1060 | "type": "library",
1061 | "extra": {
1062 | "branch-alias": {
1063 | "dev-master": "3.0-dev"
1064 | }
1065 | },
1066 | "autoload": {
1067 | "psr-4": {
1068 | "Symfony\\Component\\PropertyAccess\\": ""
1069 | },
1070 | "exclude-from-classmap": [
1071 | "/Tests/"
1072 | ]
1073 | },
1074 | "notification-url": "https://packagist.org/downloads/",
1075 | "license": [
1076 | "MIT"
1077 | ],
1078 | "authors": [
1079 | {
1080 | "name": "Fabien Potencier",
1081 | "email": "fabien@symfony.com"
1082 | },
1083 | {
1084 | "name": "Symfony Community",
1085 | "homepage": "https://symfony.com/contributors"
1086 | }
1087 | ],
1088 | "description": "Symfony PropertyAccess Component",
1089 | "homepage": "https://symfony.com",
1090 | "keywords": [
1091 | "access",
1092 | "array",
1093 | "extraction",
1094 | "index",
1095 | "injection",
1096 | "object",
1097 | "property",
1098 | "property path",
1099 | "reflection"
1100 | ],
1101 | "time": "2016-03-23T13:23:25+00:00"
1102 | },
1103 | {
1104 | "name": "symfony/yaml",
1105 | "version": "v3.0.4",
1106 | "source": {
1107 | "type": "git",
1108 | "url": "https://github.com/symfony/yaml.git",
1109 | "reference": "0047c8366744a16de7516622c5b7355336afae96"
1110 | },
1111 | "dist": {
1112 | "type": "zip",
1113 | "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96",
1114 | "reference": "0047c8366744a16de7516622c5b7355336afae96",
1115 | "shasum": ""
1116 | },
1117 | "require": {
1118 | "php": ">=5.5.9"
1119 | },
1120 | "type": "library",
1121 | "extra": {
1122 | "branch-alias": {
1123 | "dev-master": "3.0-dev"
1124 | }
1125 | },
1126 | "autoload": {
1127 | "psr-4": {
1128 | "Symfony\\Component\\Yaml\\": ""
1129 | },
1130 | "exclude-from-classmap": [
1131 | "/Tests/"
1132 | ]
1133 | },
1134 | "notification-url": "https://packagist.org/downloads/",
1135 | "license": [
1136 | "MIT"
1137 | ],
1138 | "authors": [
1139 | {
1140 | "name": "Fabien Potencier",
1141 | "email": "fabien@symfony.com"
1142 | },
1143 | {
1144 | "name": "Symfony Community",
1145 | "homepage": "https://symfony.com/contributors"
1146 | }
1147 | ],
1148 | "description": "Symfony Yaml Component",
1149 | "homepage": "https://symfony.com",
1150 | "time": "2016-03-04T07:55:57+00:00"
1151 | },
1152 | {
1153 | "name": "twig/twig",
1154 | "version": "v1.31.0",
1155 | "source": {
1156 | "type": "git",
1157 | "url": "https://github.com/twigphp/Twig.git",
1158 | "reference": "ddc9e3e20ee9c0b6908f401ac8353635b750eca7"
1159 | },
1160 | "dist": {
1161 | "type": "zip",
1162 | "url": "https://api.github.com/repos/twigphp/Twig/zipball/ddc9e3e20ee9c0b6908f401ac8353635b750eca7",
1163 | "reference": "ddc9e3e20ee9c0b6908f401ac8353635b750eca7",
1164 | "shasum": ""
1165 | },
1166 | "require": {
1167 | "php": ">=5.2.7"
1168 | },
1169 | "require-dev": {
1170 | "symfony/debug": "~2.7",
1171 | "symfony/phpunit-bridge": "~3.2"
1172 | },
1173 | "type": "library",
1174 | "extra": {
1175 | "branch-alias": {
1176 | "dev-master": "1.31-dev"
1177 | }
1178 | },
1179 | "autoload": {
1180 | "psr-0": {
1181 | "Twig_": "lib/"
1182 | }
1183 | },
1184 | "notification-url": "https://packagist.org/downloads/",
1185 | "license": [
1186 | "BSD-3-Clause"
1187 | ],
1188 | "authors": [
1189 | {
1190 | "name": "Fabien Potencier",
1191 | "email": "fabien@symfony.com",
1192 | "homepage": "http://fabien.potencier.org",
1193 | "role": "Lead Developer"
1194 | },
1195 | {
1196 | "name": "Armin Ronacher",
1197 | "email": "armin.ronacher@active-4.com",
1198 | "role": "Project Founder"
1199 | },
1200 | {
1201 | "name": "Twig Team",
1202 | "homepage": "http://twig.sensiolabs.org/contributors",
1203 | "role": "Contributors"
1204 | }
1205 | ],
1206 | "description": "Twig, the flexible, fast, and secure template language for PHP",
1207 | "homepage": "http://twig.sensiolabs.org",
1208 | "keywords": [
1209 | "templating"
1210 | ],
1211 | "time": "2017-01-11T19:36:15+00:00"
1212 | }
1213 | ],
1214 | "packages-dev": [],
1215 | "aliases": [],
1216 | "minimum-stability": "stable",
1217 | "stability-flags": [],
1218 | "prefer-stable": false,
1219 | "prefer-lowest": false,
1220 | "platform": {
1221 | "php": "^5.5|^7.0"
1222 | },
1223 | "platform-dev": []
1224 | }
1225 |
--------------------------------------------------------------------------------
/src/Translala/App/Command/AbstractCommand.php:
--------------------------------------------------------------------------------
1 | addOption(
14 | '--config',
15 | '-c',
16 | InputOption::VALUE_OPTIONAL,
17 | "Config file directory",
18 | getcwd()
19 | )
20 | ->addOption(
21 | '--domain',
22 | '-d',
23 | InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
24 | "Desired domains",
25 | []
26 | )
27 | ->addOption(
28 | '--language',
29 | '-l',
30 | InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
31 | "Desired languages",
32 | []
33 | )
34 | ;
35 | }
36 | }
--------------------------------------------------------------------------------
/src/Translala/App/Command/CommonCommand.php:
--------------------------------------------------------------------------------
1 | setName('translala:project:common')
20 | ->setDescription('Display common translations')
21 | ;
22 | }
23 |
24 | protected function execute(InputInterface $input, OutputInterface $output)
25 | {
26 | $projectLoader = new ProjectLoader($input->getOption('config'));
27 | $projectLoader->load(new CommandContext($input->getOption('domain'), $input->getOption('language')));
28 |
29 | $output->writeln('√ Launching Common Command');
30 |
31 | $job = new CommonJob($projectLoader->getTranslationFiles(), $projectLoader->getConfig());
32 | $stats = $job->process();
33 | $output->writeln('√ Done');
34 |
35 | $projectLoader->render('common.html.twig', ['listing' => $stats->getTranslationsListing()]);
36 | $output->writeln('Report generated in common.html');
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Translala/App/Command/DeadCommand.php:
--------------------------------------------------------------------------------
1 | setName('translala:project:dead')
20 | ->setDescription('I see dead translations')
21 | ;
22 | }
23 |
24 | protected function execute(InputInterface $input, OutputInterface $output)
25 | {
26 | $projectLoader = new ProjectLoader($input->getOption('config'));
27 | $projectLoader->load(new CommandContext($input->getOption('domain'), $input->getOption('language')));
28 |
29 | $output->writeln('√ Launching Dead Command');
30 |
31 | $job = new DeadJob($projectLoader->getTranslationFiles(), $projectLoader->getConfig());
32 | $deads = $job->process();
33 | $output->writeln('√ Done');
34 |
35 | $projectLoader->render('dead.html.twig', ['deads' => $deads]);
36 | $output->writeln('Report generated in dead.html');
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Translala/App/Command/HealthCommand.php:
--------------------------------------------------------------------------------
1 | setName('translala:status:health')
22 | ->setDescription('Check if translations are ok')
23 | ;
24 | }
25 |
26 | protected function execute(InputInterface $input, OutputInterface $output)
27 | {
28 | $projectLoader = new ProjectLoader($input->getOption('config'));
29 | $projectLoader->load(new CommandContext($input->getOption('domain'), $input->getOption('language')));
30 |
31 | $configFileData = $projectLoader->getConfig()->getData();
32 |
33 | if (!isset($configFileData['health'])) {
34 | throw new \Exception("Undefined data for health cmd");
35 | }
36 |
37 | $job = new StatsJob($projectLoader->getTranslationFiles(), $projectLoader->getConfig());
38 | $statsPerLocale = $job->process();
39 |
40 | $healthProcessor = new HealthProcessor($configFileData['health']);
41 |
42 | try {
43 | $healthProcessor->process($statsPerLocale);
44 | } catch (HealthException $e) {
45 | $output->writeln('Error: ' . $e->getMessage());
46 | exit(255);
47 | }
48 |
49 | exit(0);
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Translala/App/Command/StatsCommand.php:
--------------------------------------------------------------------------------
1 | setName('translala:project:stats')
20 | ->setDescription('Display stats translations')
21 | ;
22 | }
23 |
24 | protected function execute(InputInterface $input, OutputInterface $output)
25 | {
26 | $projectLoader = new ProjectLoader($input->getOption('config'));
27 | $projectLoader->load(new CommandContext($input->getOption('domain'), $input->getOption('language')));
28 |
29 | $output->writeln('√ Launching Stats Command');
30 |
31 | $job = new StatsJob($projectLoader->getTranslationFiles(), $projectLoader->getConfig());
32 | $statsLocale = $job->process();
33 | $output->writeln('√ Done');
34 |
35 | $projectLoader->render('stats.html.twig', ['locales' => $statsLocale]);
36 | $output->writeln('Report generated in stats.html');
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Translala/App/Command/TranslateCommand.php:
--------------------------------------------------------------------------------
1 | setName('translala:project:translate')
20 | ->setDescription('Guess missing translations')
21 | ;
22 | }
23 |
24 | protected function execute(InputInterface $input, OutputInterface $output)
25 | {
26 | $projectLoader = new ProjectLoader($input->getOption('config'));
27 | $projectLoader->load(new CommandContext($input->getOption('domain'), $input->getOption('language')));
28 |
29 | $output->writeln('√ Launching Translate Command');
30 |
31 | $job = new TranslateJob($projectLoader->getTranslationFiles(), $projectLoader->getConfig());
32 | $job->process();
33 |
34 | $output->writeln('√ Done');
35 | }
36 | }
--------------------------------------------------------------------------------
/src/Translala/App/Loader/LoaderInterface.php:
--------------------------------------------------------------------------------
1 | configFile = new ConfigFile($filepath);
30 | }
31 |
32 | /**
33 | * @param CommandContext $context
34 | */
35 | public function load(CommandContext $context)
36 | {
37 | $translationPaths = $this->configFile->getTranslationPaths();
38 |
39 | if ($directoryManagement = $this->configFile->getDirectoryManagement()) {
40 | $regex = $this->configFile->getMasterLocale() . DIRECTORY_SEPARATOR . '*.{yml,php,json}';
41 | } else {
42 | $regex = '*.' . $this->configFile->getMasterLocale() . '.{yml,php,json}';
43 | }
44 |
45 | foreach ($translationPaths as $path) {
46 | foreach (glob($path . $regex, GLOB_BRACE) as $translationFile) {
47 | $translationFileModel = new TranslationFile($translationFile, $this->getFileParser($translationFile), $this->configFile->getMasterLocale());
48 | $translationFileModel->parse();
49 | $this->translationsFiles[] = $translationFileModel;
50 | }
51 | }
52 | }
53 |
54 | /**
55 | * @param string $translationFilePath
56 | * @return FileParserInterface
57 | */
58 | private function getFileParser($translationFilePath)
59 | {
60 | $fileInfo = pathinfo($translationFilePath);
61 | switch ($fileInfo['extension']) {
62 | case 'yml':
63 | $fileParser = new YamlFileParser($translationFilePath);
64 | break;
65 |
66 | case 'php':
67 | $fileParser = new PhpFileParser($translationFilePath);
68 | break;
69 |
70 | case 'json':
71 | $fileParser = new JsonFileParser($translationFilePath);
72 | break;
73 | }
74 |
75 | return $fileParser;
76 | }
77 |
78 | /**
79 | * @return array
80 | */
81 | public function getTranslationFiles()
82 | {
83 | return $this->translationsFiles;
84 | }
85 |
86 | /**
87 | * @return ConfigFileInterface
88 | */
89 | public function getConfig()
90 | {
91 | return $this->configFile;
92 | }
93 |
94 | /**
95 | * @param string $viewPath
96 | * @param array $datas
97 | */
98 | public function render($viewPath, array $datas)
99 | {
100 | \Twig_Autoloader::register();
101 | $loader = new \Twig_Loader_Filesystem(__DIR__.'/../Templates');
102 | $twig = new \Twig_Environment($loader, array('cache' => false));
103 |
104 | $initDatas = [
105 | 'config' => $this->configFile,
106 | ];
107 |
108 | $exportPath = str_replace('.twig', '', $this->configFile->getExportPath() . DIRECTORY_SEPARATOR . $viewPath);
109 | file_put_contents($exportPath, $twig->render($viewPath, array_merge($initDatas, $datas)));
110 | }
111 | }
--------------------------------------------------------------------------------
/src/Translala/App/Templates/common.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.html.twig' %}
2 |
3 | {% block content %}
4 |
5 |
Common translations
6 |
7 |
8 |
9 |
10 | Repeat |
11 | Translation |
12 | Keys |
13 |
14 |
15 |
16 | {% for item in listing %}
17 |
18 | {{ item.counter }} |
19 | {{ item.translation }} |
20 |
21 | {% for ref in item.references %}
22 | {{ ref }}
23 | {% endfor %}
24 | |
25 |
26 | {% endfor %}
27 |
28 |
29 |
30 | {% endblock %}
--------------------------------------------------------------------------------
/src/Translala/App/Templates/dead.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.html.twig' %}
2 |
3 | {% block content %}
4 |
5 |
Dead translations
6 |
7 |
8 |
9 |
10 | Keys |
11 |
12 |
13 |
14 | {% for key in deads %}
15 |
16 | {{ key }} |
17 |
18 | {% endfor %}
19 |
20 |
21 |
22 | {% endblock %}
--------------------------------------------------------------------------------
/src/Translala/App/Templates/layout.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Translala
10 |
11 |
12 |
13 |
14 |
23 |
24 |
28 |
29 |
30 |
52 |
53 |
54 | {% block content %}{% endblock %}
55 |
56 |
58 |
59 |
60 |
61 |
65 | {% block javascript %}{% endblock %}
66 |
67 |
--------------------------------------------------------------------------------
/src/Translala/App/Templates/stats.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.html.twig' %}
2 |
3 | {% block content %}
4 |
5 |
Translations Stats
6 |
7 | {% for locale in locales %}
8 |
9 |
{{ locale.locale|upper }} Translations
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | File |
18 | Total |
19 | Missing |
20 |
21 |
22 | {% for filepath, nbre in locale.geStatsPerFilepath() %}
23 |
24 |
25 | {{ filepath }} |
26 | {{ nbre.total }} |
27 | 0 %} class="danger"{% endif %}>{{ nbre.missing }} |
28 |
29 |
30 | {% endfor %}
31 |
32 |
33 |
34 | {% endfor %}
35 |
36 |
37 |
46 | {% endblock %}
47 |
48 |
49 | {% block javascript %}
50 |
64 | {% endblock %}
--------------------------------------------------------------------------------
/src/Translala/Domain/Exception/HealthException.php:
--------------------------------------------------------------------------------
1 | domain = $domain;
24 | $this->locale = $locale;
25 | }
26 |
27 | /**
28 | * Gets the value of domain.
29 | *
30 | * @return string
31 | */
32 | public function getDomain()
33 | {
34 | return $this->domain;
35 | }
36 |
37 | /**
38 | * Gets the value of locale.
39 | *
40 | * @return string
41 | */
42 | public function getLocale()
43 | {
44 | return $this->locale;
45 | }
46 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/CommonTranslation.php:
--------------------------------------------------------------------------------
1 | hash = $hash;
33 | $this->counter = 0;
34 | $this->keysReferences = [];
35 | $this->translation = $translation;
36 | }
37 |
38 | /**
39 | * @param string $reference
40 | * @return this
41 | */
42 | public function increment($reference)
43 | {
44 | $this->counter++;
45 | $this->keysReferences[] = $reference;
46 |
47 | return $this;
48 | }
49 |
50 | /**
51 | * @return int
52 | */
53 | public function getCounter()
54 | {
55 | return $this->counter;
56 | }
57 |
58 | /**
59 | * @return int
60 | */
61 | public function getReferences()
62 | {
63 | return $this->keysReferences;
64 | }
65 |
66 | /**
67 | * @return string
68 | */
69 | public function getTranslation()
70 | {
71 | return $this->translation;
72 | }
73 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/ConfigFile.php:
--------------------------------------------------------------------------------
1 | filepath = $filepath;
26 |
27 | $yamlParser = new Parser();
28 | $this->data = $yamlParser->parse(file_get_contents($filepath));
29 | }
30 |
31 | /**
32 | * @return string
33 | */
34 | public function getFilepath()
35 | {
36 | return $this->filepath;
37 | }
38 |
39 | /**
40 | * @return array
41 | */
42 | public function getData()
43 | {
44 | return $this->data;
45 | }
46 |
47 | /**
48 | * @return array
49 | */
50 | public function getTranslationPaths()
51 | {
52 | return $this->data[ConfigFileInterface::PATHS_KEY];
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getMasterLocale()
59 | {
60 | return $this->data[ConfigFileInterface::MASTER_LOCALE_KEY];
61 | }
62 |
63 | /**
64 | * @return array
65 | */
66 | public function getLanguages()
67 | {
68 | return $this->data[ConfigFileInterface::LANGUAGES_KEY];
69 | }
70 |
71 | /**
72 | * @return string
73 | */
74 | public function getProjectPath()
75 | {
76 | return $this->data[ConfigFileInterface::PROJECT_PATH];
77 | }
78 |
79 | /**
80 | * @return bool
81 | */
82 | public function getDirectoryManagement()
83 | {
84 | if (isset($this->data[ConfigFileInterface::PROJECT_DIRECTORY_MANAGEMENT])) {
85 | return $this->data[ConfigFileInterface::PROJECT_DIRECTORY_MANAGEMENT];
86 | }
87 |
88 | return false;
89 | }
90 |
91 | /**
92 | * @return array
93 | */
94 | public function getOthersLanguages()
95 | {
96 | $allLanguages = $this->getLanguages();
97 | if(($key = array_search($this->getMasterLocale(), $allLanguages)) !== false) {
98 | unset($allLanguages[$key]);
99 | }
100 |
101 | return $allLanguages;
102 | }
103 |
104 | /**
105 | * @return string
106 | */
107 | public function getExportPath()
108 | {
109 | return $this->data[ConfigFileInterface::EXPORT_PATH_KEY];
110 | }
111 |
112 | /**
113 | * @return array
114 | */
115 | public function getApiKey()
116 | {
117 | return $this->data[ConfigFileInterface::API_KEY];
118 | }
119 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/ConfigFileInterface.php:
--------------------------------------------------------------------------------
1 | locale = $locale;
33 | }
34 |
35 | /**
36 | * @return string
37 | */
38 | public function getLocale()
39 | {
40 | return $this->locale;
41 | }
42 |
43 | /**
44 | * @return string
45 | */
46 | public function getFilespath()
47 | {
48 | return $this->filespath;
49 | }
50 |
51 | /**
52 | * @param string $filespath the filespath
53 | *
54 | * @return this
55 | */
56 | public function addFilespath($filespath)
57 | {
58 | $this->filespath[] = $filespath;
59 |
60 | return $this;
61 | }
62 |
63 | /**
64 | * @return this
65 | */
66 | public function setTotalTranslationsPerFilepath($filepath, $total)
67 | {
68 | $this->totalTranslationsPerFilepath[$filepath] = $total;
69 |
70 | return $this;
71 | }
72 |
73 | /**
74 | * @return this
75 | */
76 | public function setMissingTranslationsPerFilepath($filepath, $total)
77 | {
78 | $this->missingTranslationsPerFilepath[$filepath] = $total;
79 |
80 | return $this;
81 | }
82 |
83 | /**
84 | * @return integer
85 | */
86 | public function getTotalTranslations()
87 | {
88 | return array_sum($this->totalTranslationsPerFilepath);
89 | }
90 |
91 | /**
92 | * @return integer
93 | */
94 | public function getTotalMissingTranslations()
95 | {
96 | return array_sum($this->missingTranslationsPerFilepath);
97 | }
98 |
99 | /**
100 | * @return array
101 | */
102 | public function geStatsPerFilepath()
103 | {
104 | $statsPerFile = [];
105 | foreach ($this->totalTranslationsPerFilepath as $filepath => $value) {
106 | $missing = (isset($this->missingTranslationsPerFilepath[$filepath])) ? $this->missingTranslationsPerFilepath[$filepath] : $value;
107 | $statsPerFile[$filepath] = ['total' => $value, 'missing' => $missing];
108 | }
109 |
110 | return $statsPerFile;
111 | }
112 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/Project.php:
--------------------------------------------------------------------------------
1 | locales;
13 | }
14 |
15 | public function getConfigFile()
16 | {
17 | return $this->configFile;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/ProjectInterface.php:
--------------------------------------------------------------------------------
1 | key = $key;
36 | $this->value = $value;
37 | $this->language = $language;
38 | $this->domain = $domain;
39 | }
40 |
41 | /**
42 | * Gets the value of key.
43 | *
44 | * @return string
45 | */
46 | public function getKey()
47 | {
48 | return $this->key;
49 | }
50 |
51 | /**
52 | * Gets the value of value.
53 | *
54 | * @return string
55 | */
56 | public function getValue()
57 | {
58 | return $this->value;
59 | }
60 |
61 | /**
62 | * Gets the value of language.
63 | *
64 | * @return string
65 | */
66 | public function getLanguage()
67 | {
68 | return $this->language;
69 | }
70 |
71 | /**
72 | * Gets the value of domain.
73 | *
74 | * @return string
75 | */
76 | public function getDomain()
77 | {
78 | return $this->domain;
79 | }
80 |
81 | /**
82 | * @return array
83 | */
84 | public function getKeypath()
85 | {
86 | $array = (!empty($this->getValue())) ? $this->getValue() : '~';
87 | foreach (array_reverse(explode('.', $this->key)) as $arr) {
88 | $array = [$arr => $array];
89 | }
90 |
91 | return $array;
92 | }
93 |
94 | /**
95 | * @return boolean
96 | */
97 | public function isEmpty()
98 | {
99 | return empty($this->getValue());
100 | }
101 |
102 | /**
103 | * @param string $value
104 | */
105 | public function setValue($value)
106 | {
107 | $this->value = $value;
108 |
109 | return $this;
110 | }
111 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/TranslationFile.php:
--------------------------------------------------------------------------------
1 | path = $path;
39 | $this->fileParser = $fileParser;
40 | $this->currentLocale = $currentLocale;
41 | }
42 |
43 | /**
44 | * @param string $locale
45 | * @return string
46 | */
47 | private function getPathForLocale($locale)
48 | {
49 | $distantLocale = sprintf($this->fileParser->getStrategyName(), $locale);
50 | $currentLocale = sprintf($this->fileParser->getStrategyName(), $this->currentLocale);
51 |
52 | return str_replace($currentLocale, $distantLocale, $this->path);
53 | }
54 |
55 | /**
56 | * @param string $locale
57 | * @return boolean
58 | */
59 | public function isMissingForLocale($locale)
60 | {
61 | return (bool) file_exists($this->getPathForLocale($locale));
62 | }
63 |
64 | /**
65 | * @return null
66 | */
67 | public function parse()
68 | {
69 | $this->translations = $this->fileParser->parse($this->getPath());
70 | }
71 |
72 | /**
73 | * @return string
74 | */
75 | public function getPath()
76 | {
77 | return $this->path;
78 | }
79 |
80 | /**
81 | * @return array
82 | */
83 | public function getTranslations()
84 | {
85 | return $this->translations;
86 | }
87 |
88 | /**
89 | * @param string $locale
90 | * @return TranslationFileInterface
91 | */
92 | public function getTranslationFileForLocale($locale)
93 | {
94 | $parserFqcn = get_class($this->fileParser);
95 | $newParser = new $parserFqcn($this->getPathForLocale($locale));
96 |
97 | return new TranslationFile($this->getPathForLocale($locale), $newParser, $locale);
98 | }
99 |
100 | /**
101 | * @param string $key
102 | * @return boolean
103 | */
104 | public function isTranslationEmpty($key)
105 | {
106 | if (!isset($this->translations[$key])) {
107 | return true;
108 | }
109 |
110 | return (bool) (empty($this->translations[$key]->getValue()));
111 | }
112 |
113 | /**
114 | * Dump translation in new file
115 | *
116 | * @return null
117 | */
118 | public function dump()
119 | {
120 | $datas = [];
121 | foreach ($this->translations as $translation) {
122 | $datas = array_merge_recursive($translation->getKeypath(), $datas);
123 | }
124 |
125 | $this->fileParser->dump($datas, $this->getPath());
126 | }
127 |
128 | /**
129 | * @param TranslationInterface $translation
130 | * @return this
131 | */
132 | public function updateTranslation(TranslationInterface $translation)
133 | {
134 | $this->translations[$translation->getKey()] = $translation;
135 |
136 | return $this;
137 | }
138 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Model/TranslationFileInterface.php:
--------------------------------------------------------------------------------
1 | translationsCounter, function($b, $a) { return strcmp($a->getCounter(), $b->getCounter()); });
21 |
22 | return $this->translationsCounter;
23 | }
24 |
25 | /**
26 | * @param TranslationInterface $translation
27 | */
28 | public function process(TranslationInterface $translation)
29 | {
30 | $translationKey = md5($this->cannonicalize($translation->getValue()));
31 |
32 | if (!isset($this->translationsCounter[$translationKey])) {
33 | $this->translationsCounter[$translationKey] = new CommonTranslation($translationKey, $translation->getValue());
34 | }
35 |
36 | $this->translationsCounter[$translationKey]->increment($translation->getKey());
37 | }
38 |
39 | /**
40 | * @param string $key
41 | * @return string
42 | */
43 | private function cannonicalize($key)
44 | {
45 | return strtolower(trim($key));
46 | }
47 | }
--------------------------------------------------------------------------------
/src/Translala/Domain/Processor/HealthProcessor.php:
--------------------------------------------------------------------------------
1 | healthGoalsPerLocale = $healthGoalsPerLocale;
17 | }
18 |
19 | /**
20 | * @param StatsJob $statsJob
21 | * @return array
22 | */
23 | public function process(array $statsPerLocale = [])
24 | {
25 | $missingTranslationPercentagePerLocale = [];
26 |
27 | foreach ($statsPerLocale as $locale) {
28 | $percentage = (($locale->getTotalTranslations()-$locale->getTotalMissingTranslations())/$locale->getTotalTranslations())*100;
29 |
30 | if (isset($this->healthGoalsPerLocale[$locale->getLocale()]) && $percentage < $this->healthGoalsPerLocale[$locale->getLocale()]) {
31 | throw new HealthException(
32 | sprintf("Health fail for locale %s (Get %s while require at minial %s)", $locale->getLocale(), $percentage, $this->healthGoalsPerLocale[$locale->getLocale()])
33 | );
34 |
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Application/Application.php:
--------------------------------------------------------------------------------
1 | translationsFiles = $translationsFiles;
33 | $this->configFile = $configFile;
34 | }
35 |
36 | /**
37 | * @return CommonProcessor
38 | */
39 | public function process()
40 | {
41 | $commonProcessor = new CommonProcessor();
42 | foreach ($this->translationsFiles as $translationFile) {
43 | array_map([$commonProcessor, 'process'], $translationFile->getTranslations());
44 | }
45 |
46 | return $commonProcessor;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Job/DeadJob.php:
--------------------------------------------------------------------------------
1 | translationsFiles = $translationsFiles;
35 | $this->configFile = $configFile;
36 | }
37 |
38 | public function process()
39 | {
40 | foreach ($this->translationsFiles as $translationFile) {
41 | array_map([$this, 'checkDeadTranslations'], $translationFile->getTranslations());
42 | }
43 |
44 | return $this->missingTranslations;
45 | }
46 |
47 | /**
48 | * @param TranslationInterface $translation
49 | */
50 | protected function checkDeadTranslations(TranslationInterface $translation)
51 | {
52 | $process = new Process('grep -r "' . $translation->getKey() . '" ' . $this->configFile->getProjectPath());
53 | $process->run();
54 |
55 | if (!strstr($process->getOutput(), $translation->getKey())) {
56 | $this->missingTranslations[] = $translation->getKey();
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Job/StatsJob.php:
--------------------------------------------------------------------------------
1 | translationsFiles = $translationsFiles;
28 | $this->configFile = $configFile;
29 | }
30 |
31 | /**
32 | * @return LocaleStats[]
33 | */
34 | public function process()
35 | {
36 | $masterLocale = $this->configFile->getMasterLocale();
37 | $statsPerLocale = [];
38 | foreach ($this->configFile->getLanguages() as $locale) {
39 | $statsPerLocale[$locale] = new LocaleStats($locale);
40 | }
41 |
42 | foreach ($this->translationsFiles as $translationFile) {
43 | foreach ($this->configFile->getLanguages() as $locale) {
44 | $this->statsPerFile($translationFile, $statsPerLocale[$locale]);
45 | }
46 | }
47 |
48 | return $statsPerLocale;
49 | }
50 |
51 | /**
52 | * @param TranslationFileInterface $translationFile
53 | * @param string $locale
54 | */
55 | private function statsPerFile(TranslationFileInterface $translationFile, LocaleStats $localeStats)
56 | {
57 | $toTranslateFile = $translationFile->getTranslationFileForLocale($localeStats->getLocale());
58 | $toTranslateFile->parse();
59 |
60 | $localeStats->addFilespath($toTranslateFile->getPath());
61 |
62 | $totalTranslation = $missingTranslation = 0;
63 | foreach ($translationFile->getTranslations() as $translation) {
64 | if ($toTranslateFile->isTranslationEmpty($translation->getKey())) {
65 | $missingTranslation++;
66 | }
67 | $totalTranslation++;
68 | }
69 |
70 | $localeStats->setTotalTranslationsPerFilepath($toTranslateFile->getPath(), $totalTranslation);
71 | $localeStats->setMissingTranslationsPerFilepath($toTranslateFile->getPath(), $missingTranslation);
72 | }
73 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Job/TranslateJob.php:
--------------------------------------------------------------------------------
1 | translationsFiles = $translationsFiles;
33 | $this->configFile = $configFile;
34 | }
35 |
36 | public function process()
37 | {
38 | $apiKeys = $this->configFile->getApiKey();
39 | $this->checkKey($apiKeys);
40 |
41 | $this->translationClient = new Translator();
42 | $this->translationClient->addTranslatorService(new GoogleTranslator($apiKeys['google']));
43 | $masterLocale = $this->configFile->getMasterLocale();
44 |
45 | foreach ($this->translationsFiles as $translationFile) {
46 | foreach ($this->configFile->getOthersLanguages() as $locale) {
47 | $this->translateFile($translationFile, $locale);
48 | }
49 | }
50 | }
51 |
52 | /**
53 | * @param TranslationFileInterface $translationFile
54 | * @param string $locale
55 | */
56 | private function translateFile(TranslationFileInterface $translationFile, $locale)
57 | {
58 | $countUpdatedTranslation = 0;
59 |
60 | $toTranslateFile = $translationFile->getTranslationFileForLocale($locale);
61 | foreach ($translationFile->getTranslations() as $translation) {
62 | if ($toTranslateFile->isTranslationEmpty($translation->getKey())) {
63 |
64 | $translatedValue = $this->translationClient->translate($translation->getValue(), $translation->getLanguage(), $locale);
65 | $updatedTranslation = clone($translation);
66 | $updatedTranslation->setValue($translatedValue);
67 |
68 | $toTranslateFile->updateTranslation($updatedTranslation);
69 | $countUpdatedTranslation++;
70 | }
71 | }
72 |
73 | if ($countUpdatedTranslation > 0) {
74 | $toTranslateFile->dump();
75 | }
76 | }
77 |
78 | private function checkKey($apiKeys)
79 | {
80 | if (empty($apiKeys['google'])) {
81 | throw new \Exception(sprintf("GoogleTranslator api key is missing: %s", $apiKeys['google']));
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Parser/AbstractFileParser.php:
--------------------------------------------------------------------------------
1 | filepath = $filepath;
45 | $exploded = explode('.', $filepath);
46 |
47 | $this->domain = $exploded[0];
48 | $this->language = $exploded[1];
49 | $this->extension = $exploded[2];
50 | }
51 |
52 | /**
53 | * @param array $datas
54 | */
55 | protected function loadTranslationData($datas, $prefix = null, $iteration = 0)
56 | {
57 | foreach ($datas as $key => $value) {
58 | if (is_array($value)) {
59 | $tmpPrefix = trim($prefix . '.' . $key, '.');
60 | $iteration++;
61 | $this->loadTranslationData($value, $tmpPrefix, $iteration);
62 | } else {
63 | $tmpPrefix = $prefix . '.' . $key;
64 |
65 | $this->translations[$tmpPrefix] = new Translation($tmpPrefix, $value, $this->language, $this->domain);
66 | }
67 | if ($iteration == 0) {
68 | $prefix = '';
69 | $iteration = 0;
70 | }
71 | }
72 | }
73 |
74 | /**
75 | * @return array
76 | */
77 | public function getTranslations()
78 | {
79 | return $this->translations;
80 | }
81 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Parser/JsonFileParser.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | public function parse($filepath = null)
21 | {
22 | $filepath = ($filepath) ? $filepath : $this->filepath;
23 |
24 | if (file_exists($filepath)) {
25 | $datas = json_decode($filepath);
26 | $this->loadTranslationData($datas);
27 | } else {
28 | $this->translations = [];
29 | }
30 |
31 | return $this->translations;
32 | }
33 |
34 | /**
35 | * @param array $datas
36 | * @param string $path
37 | */
38 | public function dump(array $datas, $path)
39 | {
40 | file_put_contents($path, json_encode($datas));
41 | }
42 | }
--------------------------------------------------------------------------------
/src/Translala/Infra/Parser/PhpFileParser.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | public function parse($filepath = null)
21 | {
22 | $filepath = ($filepath) ? $filepath : $this->filepath;
23 |
24 | if (file_exists($filepath)) {
25 | $datas = require($filepath);
26 | $this->loadTranslationData($datas);
27 | } else {
28 | $this->translations = [];
29 | }
30 |
31 | return $this->translations;
32 | }
33 |
34 | /**
35 | * @param array $datas
36 | * @param string $path
37 | */
38 | public function dump(array $datas, $path)
39 | {
40 | $phpContent = "
20 | */
21 | public function parse($filepath = null)
22 | {
23 | $filepath = ($filepath) ? $filepath : $this->filepath;
24 |
25 | $yamlParser = new Yaml();
26 |
27 | if (file_exists($filepath)) {
28 | $datas = $yamlParser->parse(file_get_contents($filepath));
29 | $this->loadTranslationData($datas);
30 | } else {
31 | $this->translations = [];
32 | }
33 |
34 | return $this->translations;
35 | }
36 |
37 | /**
38 | * @param array $datas
39 | * @param string $path
40 | */
41 | public function dump(array $datas, $path)
42 | {
43 | $yamlParser = new Yaml();
44 | $yamlContent = $yamlParser->dump($datas, 100);
45 |
46 | file_put_contents($path, $yamlContent);
47 | }
48 | }
--------------------------------------------------------------------------------