8000 feature #14003 [2.7][Translation][Profiler] Added a Translation profi… · symfony/symfony@2533d8f · GitHub
[go: up one dir, main page]

Skip to content

Commit 2533d8f

Browse files
committed
feature #14003 [2.7][Translation][Profiler] Added a Translation profiler. (aitboudad)
This PR was merged into the 2.7 branch. Discussion ---------- [2.7][Translation][Profiler] Added a Translation profiler. | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Fixed tickets | ~ | Tests pass? | yes | License | MIT - [x] tests ![selection_005](https://cloud.githubusercontent.com/assets/1753742/6762405/7e355396-cf57-11e4-9836-cdaebb541d13.png) ![selection_006](https://cloud.githubusercontent.com/assets/1753742/6762407/91dc9422-cf57-11e4-8f6f-f89c9d067b03.png) Commits ------- c923b2a [Translation][Profiler] Added a Translation profiler.
2 parents a49c432 + c923b2a commit 2533d8f

File tree

7 files changed

+481
-5
lines changed

7 files changed

+481
-5
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
class FrameworkExtension extends Extension
3636
{
3737
private $formConfigEnabled = false;
38+
private $translationConfigEnabled = false;
3839
private $sessionConfigEnabled = false;
3940

4041
/**
@@ -116,8 +117,8 @@ public function load(array $configs, ContainerBuilder $container)
116117
$this->registerEsiConfiguration($config['esi'], $container, $loader);
117118
$this->registerSsiConfiguration($config['ssi'], $container, $loader);
118119
$this->registerFragmentsConfiguration($config['fragments'], $container, $loader);
119-
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
120120
$this->registerTranslatorConfiguration($config['translator'], $container);
121+
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
121122

122123
if (isset($config['router'])) {
123124
$this->registerRouterConfiguration($config['router'], $container, $loader);
@@ -288,10 +289,15 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $
288289
$loader->load('profiling.xml');
289290
$loader->load('collectors.xml');
290291

291-
if (true === $this->formConfigEnabled) {
292+
if ($this->formConfigEnabled) {
292293
$loader->load('form_debug.xml');
293294
}
294295

296+
if ($this->translationConfigEnabled) {
297+
$loader->load('translation_debug.xml');
298+
$container->getDefinition('translator.data_collector')->setDecoratedService('translator');
299+
}
300+
295301
$container->setParameter('profiler_listener.only_exceptions', $config['only_exceptions']);
296302
$container->setParameter('profiler_listener.only_master_requests', $config['only_master_requests']);
297303

@@ -644,6 +650,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
644650
if (!$this->isConfigEnabled($container, $config)) {
645651
return;
646652
}
653+
$this->translationConfigEnabled = true;
647654

648655
// Use the "real" translator instead of the identity default
649656
$container->setAlias('translator', 'translator.default');
@@ -865,9 +872,9 @@ private function registerSecurityCsrfConfiguration(array $config, ContainerBuild
865872
/**
866873
* Loads the serializer configuration.
867874
*
868-
* @param array $config A serializer configuration array
875+
* @param array $config A serializer configuration array
869876
* @param ContainerBuilder $container A ContainerBuilder instance
870-
* @param XmlFileLoader $loader An XmlFileLoader instance
877+
* @param XmlFileLoader $loader An XmlFileLoader instance
871878
*/
872879
private function registerSerializerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
873880
{
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<!-- DataCollectorTranslator -->
9+
<service id="translator.data_collector" class="Symfony\Component\Translation\DataCollectorTranslator" public="false">
10+
<argument type="service" id="translator.data_collector.inner" />
11+
</service>
12+
13+
<!-- DataCollector -->
14+
<service id="data_collector.translation" class="Symfony\Component\Translation\DataCollector\TranslationDataCollector">
15+
<tag name="data_collector" template="@WebProfiler/Collector/translation.html.twig" id="translation" priority="255" />
16+
<argument type="service" id="translator.data_collector" />
17+
</service>
18+
</services>
19+
</container>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
2+
3+
{% import _self as translator %}
4+
5+
{% block toolbar %}
6+
{% if collector.messages|length %}
7+
{% set icon %}
8+
<svg width="28" height="28" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 417 300" enable-background="new 0 0 417 300" xml:space="preserve"><g id="Layer_1_1_"><g id="outline_1_"><path fill="#B5B5B6" d="M275.9,145c0,18.2-14.799,33-33,33H120.701l-36.3,42l-0.3-42H40c-18.2,0-33-14.8-33-33V44c0-18.2,14.8-33,33-33h202.9c18.199,0,33,14.8,33,33V145L275.9,145z"/></g><g enable-background="new"><path fill="#FFFFFF" d="M194.501,146.962h-23.898l-9.5-24.715h-43.492l-8.98,24.715H85.326l42.379-108.805h23.23L194.501,146.962zM154.052,103.915L139.06,63.54l-14.695,40.375H154.052z"/></g></g><g id="Layer_2_1_"><g id="japanese"><g id="outline"><path fill="#414141" d="M141.451,214c0,18.2,14.8,33,33,33h122.2l36.301,42l0.301-42h44.1c18.201,0,33-14.8,33-33V113c0-18.2-14.799-33-33-33H174.453c-18.201,0-33,14.8-33,33L141.451,214L141.451,214z"/></g><g enable-background="new"><path fill="#FFFFFF" d="M312.158,143.327c-0.455,1.672-0.912,3.344-1.215,5.016c22.039,6.08,31.766,21.431,31.766,38.455c0,24.318-18.238,40.733-57.301,45.598c-1.217-3.952-5.016-11.248-7.904-15.352c27.359-3.04,45.295-12.159,45.295-29.791c0-5.016-1.672-16.871-18.088-22.19c-6.688,15.199-16.871,29.335-28.727,39.519c0.607,1.976,1.367,3.647,2.127,5.167l-15.654,10.032c-0.76-1.521-1.52-3.192-2.129-5.017c-7.6,4.256-15.959,6.992-24.471,6.992c-13.375,0-22.189-8.512-22.189-22.647c0-20.975,16.111-37.542,37.693-46.357c-0.305-6.536-0.305-13.223-0.305-20.215c-11.398,0.304-23.711,0.608-29.789,0.456l-0.912-17.783c6.99,0.152,19.758,0.152,31.006,0.152c0.305-6.536,0.457-14.135,0.76-20.519l23.863,1.824c-0.305,1.52-1.52,2.736-4.104,3.04c-0.457,4.408-0.76,10.184-1.217,15.047c16.568-0.76,37.391-2.736,54.262-6.384l1.672,18.391c-16.719,3.04-38.605,4.56-56.846,5.168c-0.15,5.319-0.303,10.487-0.303,15.503c6.383-1.52,15.654-2.432,22.799-1.976c0.607-2.28,1.063-4.56,1.215-6.84L312.158,143.327z M255.77,198.044c-1.672-8.056-2.736-17.479-3.496-27.814c-12.008,5.927-20.215,15.199-20.215,25.382c0,8.664,6.535,8.36,8.512,8.209C245.281,203.668,250.449,201.539,255.77,198.044zM286.473,162.021c-2.129-0.304-10.033,0.305-16.871,2.128c0.455,7.6,0.91,14.591,1.975,20.671C277.504,178.589,282.672,170.686,286.473,162.021z"/></g></g></g></svg>
9+
{% if collector.countMissings %}
10+
{% set status_color = "red" %}
11+
{% elseif collector.countFallbacks %}
12+
{% set status_color = "yellow" %}
13+
{% endif %}
14+
{% set error_count = collector.countMissings + collector.countFallbacks %}
15+
<span class="sf-toolbar-status{% if status_color is defined %} sf-toolbar-status-{{ status_color }}{% endif %}">{{ error_count ?: collector.countdefines }}</span>
16+
{% endset %}
17+
{% set text %}
18+
{% if collector.countMissings %}
19+
<div class="sf-toolbar-info-piece">
20+
<b>Missing messages</b>
21+
<span class="sf-toolbar-status sf-toolbar-status-red">{{ collector.countMissings }}</span>
22+
</div>
23+
{% endif %}
24+
{% if collector.countFallbacks %}
25+
<div class="sf-toolbar-info-piece">
26+
<b>Fallback messages</b>
27+
<span class="sf-toolbar-status sf-toolbar-status-yellow">{{ collector.countFallbacks }}</span>
28+
</div>
29+
{% endif %}
30+
{% if collector.countdefines %}
31+
<div class="sf-toolbar-info-piece">
32+
<b>Defined messages</b>
33+
<span class="sf-toolbar-status sf-toolbar-status-green">{{ collector.countdefines }}</span>
34+
</div>
35+
{% endif %}
36+
{% endset %}
37+
{% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': profiler_url } %}
38+
{% endif %}
39+
{% endblock %}
40+
41+
{% block menu %}
42+
<span class="label">
43+
<span class="icon"><svg width="35" height="28" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 417 300" enable-background="new 0 0 417 300" xml:space="preserve"><g id="Layer_1_1_"><g id="outline_1_"><path fill="#B5B5B6" d="M275.9,145c0,18.2-14.799,33-33,33H120.701l-36.3,42l-0.3-42H40c-18.2,0-33-14.8-33-33V44c0-18.2,14.8-33,33-33h202.9c18.199,0,33,14.8,33,33V145L275.9,145z"/></g><g enable-background="new"><path fill="#FFFFFF" d="M194.501,146.962h-23.898l-9.5-24.715h-43.492l-8.98,24.715H85.326l42.379-108.805h23.23L194.501,146.962zM154.052,103.915L139.06,63.54l-14.695,40.375H154.052z"/></g></g><g id="Layer_2_1_"><g id="japanese"><g id="outline"><path fill="#414141" d="M141.451,214c0,18.2,14.8,33,33,33h122.2l36.301,42l0.301-42h44.1c18.201,0,33-14.8,33-33V113c0-18.2-14.799-33-33-33H174.453c-18.201,0-33,14.8-33,33L141.451,214L141.451,214z"/></g><g enable-background="new"><path fill="#FFFFFF" d="M312.158,143.327c-0.455,1.672-0.912,3.344-1.215,5.016c22.039,6.08,31.766,21.431,31.766,38.455c0,24.318-18.238,40.733-57.301,45.598c-1.217-3.952-5.016-11.248-7.904-15.352c27.359-3.04,45.295-12.159,45.295-29.791c0-5.016-1.672-16.871-18.088-22.19c-6.688,15.199-16.871,29.335-28.727,39.519c0.607,1.976,1.367,3.647,2.127,5.167l-15.654,10.032c-0.76-1.521-1.52-3.192-2.129-5.017c-7.6,4.256-15.959,6.992-24.471,6.992c-13.375,0-22.189-8.512-22.189-22.647c0-20.975,16.111-37.542,37.693-46.357c-0.305-6.536-0.305-13.223-0.305-20.215c-11.398,0.304-23.711,0.608-29.789,0.456l-0.912-17.783c6.99,0.152,19.758,0.152,31.006,0.152c0.305-6.536,0.457-14.135,0.76-20.519l23.863,1.824c-0.305,1.52-1.52,2.736-4.104,3.04c-0.457,4.408-0.76,10.184-1.217,15.047c16.568-0.76,37.391-2.736,54.262-6.384l1.672,18.391c-16.719,3.04-38.605,4.56-56.846,5.168c-0.15,5.319-0.303,10.487-0.303,15.503c6.383-1.52,15.654-2.432,22.799-1.976c0.607-2.28,1.063-4.56,1.215-6.84L312.158,143.327z M255.77,198.044c-1.672-8.056-2.736-17.479-3.496-27.814c-12.008,5.927-20.215,15.199-20.215,25.382c0,8.664,6.535,8.36,8.512,8.209C245.281,203.668,250.449,201.539,255.77,198.044zM286.473,162.021c-2.129-0.304-10.033,0.305-16.871,2.128c0.455,7.6,0.91,14.591,1.975,20.671C277.504,178.589,282.672,170.686,286.473,162.021z"/></g></g></g></svg></span>
44+
<strong>Translation</strong>
45+
</span>
46+
{% endblock %}
47+
48+
{% block panel %}
49+
{% if collector.messages is empty %}
50+
<h2>Translations</h2>
51+
<p>
52+
<em>No translations have been called.</em>
53+
</p>
54+
{% else %}
55+
{{ block('panelContent') }}
56+
{% endif %}
57+
{% endblock %}
58+
59+
{% block panelContent %}
60+
<h2>Called Translations</h2>
61+
<ul>
62+
<li><strong>Defined messages: {{ collector.countdefines }}</strong></li>
63+
<li><strong>Fallback messages: {{ collector.countFallbacks }}</strong></li>
64+
<li><strong>Missing messages: {{ collector.countMissings }}</strong></li>
65+
</ul>
66+
67+
<table>
68+
<tr>
69+
<th>State</th>
70+
<th>Locale</th>
71+
<th>Domain</th>
72+
<th>Id</th>
73+
<th>Message Preview</th>
74+
</tr>
75+
{% for message in collector.messages %}
76+
<tr>
77+
<td><code>{{ translator.state(message) }}</code></td>
78+
<td><code>{{ message.locale }}</code></td>
79+
<td><code>{{ message.domain }}</code></td>
80+
<td><code>{{ message.id }}</code></td>
81+
<td><code>{{ message.translation }}</code></td>
82+
</tr>
83+
{% endfor %}
84+
</table>
85+
{% endblock %}
86+
87+
{% macro state(translation) %}
88+
{% if translation.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK') %}
89+
same as fallback
90+
{% elseif translation.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_MISSING') %}
91+
missing
92+
{% endif %}
93+
{% endmacro %}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Translation\DataCollector;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
17+
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
18+
use Symfony\Component\Translation\DataCollectorTranslator;
19+
20+
/**
21+
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
22+
*/
23+
class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface
24+
{
25+
/**
26+
* @var DataCollectorTranslator
27+
*/
28+
private $translator;
29+
30+
/**
31+
* @param DataCollectorTranslator $translator
32+
*/
33+
public function __construct(DataCollectorTranslator $translator)
34+
{
35+
$this->translator = $translator;
36+
}
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
public function lateCollect()
42+
{
43+
$this->data = $this->computeCount();
44+
$this->data['messages'] = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());
45+
}
46+
47+
/**
48+
* {@inheritdoc}
49+
*/
50+
public function collect(Request $request, Response $response, \Exception $exception = null)
51+
{
52+
}
53+
54+
/**
55+
* @return array
56+
*/
57+
public function getMessages()
58+
{
59+
return isset($this->data['messages']) ? $this->data['messages'] : array();
60+
}
61+
62+
/**
63+
* @return int
64+
*/
65+
public function getCountMissings()
66+
{
67+
return isset($this->data[DataCollectorTranslator::MESSAGE_MISSING]) ? $this->data[DataCollectorTranslator::MESSAGE_MISSING] : 0;
68+
}
69+
70+
/**
71+
* @return int
72+
*/
73+
public function getCountFallbacks()
74+
{
75+
return isset($this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK]) ? $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] : 0;
76+
}
77+
78+
/**
79+
* @return int
80+
*/
81+
public function getCountDefines()
82+
{
83+
return isset($this->data[DataCollectorTranslator::MESSAGE_DEFINED]) ? $this->data[DataCollectorTranslator::MESSAGE_DEFINED] : 0;
84+
}
85+
86+
/**
87+
* {@inheritdoc}
88+
*/
89+
public function getName()
90+
{
91+
return 'translation';
92+
}
93+
94+
private function sanitizeCollectedMessages($messages)
95+
{
96+
foreach ($messages as $key => $message) {
97+
$messages[$key]['translation'] = $this->sanitizeString($messages[$key]['translation']);
98+
}
99+
100+
return $messages;
101+
}
102+
103+
private function computeCount()
104+
{
105+
$count = array(
106+
DataCollectorTranslator::MESSAGE_DEFINED => 0,
107+
DataCollectorTranslator::MESSAGE_MISSING => 0,
108+
DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,
109+
);
110+
111+
foreach ($this->translator->getCollectedMessages() as $message) {
112+
++$count[$message['state']];
113+
}
114+
115+
return $count;
116+
}
117+
118+
private function sanitizeString($string, $length = 80)
119+
{
120+
$string = trim(preg_replace('/\s+/', ' ', $string));
121+
122+
if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($string)) {
123+
if (mb_strlen($string, $encoding) > $length) {
124+
return mb_substr($string, 0, $length - 3, $encoding).'...';
125+
}
126+
} elseif (strlen($string) > $length) {
127+
return substr($string, 0, $length - 3).'...';
128+
}
129+
130+
return $string;
131+
}
132+
}

0 commit comments

Comments
 (0)
0