PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.5
Independent Analytics – WordPress Analytics Plugin v2.15.5
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / symfony / translation / PseudoLocalizationTranslator.php
independent-analytics / vendor / symfony / translation Last commit date
Catalogue 1 month ago Command 1 month ago DataCollector 1 month ago DependencyInjection 1 month ago Dumper 1 month ago Exception 1 month ago Extractor 1 month ago Formatter 1 month ago Loader 1 month ago Provider 1 month ago Reader 1 month ago Resources 1 month ago Test 1 month ago Util 1 month ago Writer 1 month ago DataCollectorTranslator.php 1 month ago IdentityTranslator.php 2 years ago LoggingTranslator.php 1 month ago MessageCatalogue.php 1 month ago MessageCatalogueInterface.php 1 month ago MetadataAwareInterface.php 1 month ago PseudoLocalizationTranslator.php 1 month ago TranslatableMessage.php 1 month ago Translator.php 1 month ago TranslatorBag.php 1 month ago TranslatorBagInterface.php 1 month ago
PseudoLocalizationTranslator.php
217 lines
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 namespace IAWPSCOPED\Symfony\Component\Translation;
12
13 use IAWPSCOPED\Symfony\Contracts\Translation\TranslatorInterface;
14 /**
15 * This translator should only be used in a development environment.
16 * @internal
17 */
18 final class PseudoLocalizationTranslator implements TranslatorInterface
19 {
20 private const EXPANSION_CHARACTER = '~';
21 private $translator;
22 private bool $accents;
23 private float $expansionFactor;
24 private bool $brackets;
25 private bool $parseHTML;
26 /**
27 * @var string[]
28 */
29 private array $localizableHTMLAttributes;
30 /**
31 * Available options:
32 * * accents:
33 * type: boolean
34 * default: true
35 * description: replace ASCII characters of the translated string with accented versions or similar characters
36 * example: if true, "foo" => "ƒöö".
37 *
38 * * expansion_factor:
39 * type: float
40 * default: 1
41 * validation: it must be greater than or equal to 1
42 * description: expand the translated string by the given factor with spaces and tildes
43 * example: if 2, "foo" => "~foo ~"
44 *
45 * * brackets:
46 * type: boolean
47 * default: true
48 * description: wrap the translated string with brackets
49 * example: if true, "foo" => "[foo]"
50 *
51 * * parse_html:
52 * type: boolean
53 * default: false
54 * description: parse the translated string as HTML - looking for HTML tags has a performance impact but allows to preserve them from alterations - it also allows to compute the visible translated string length which is useful to correctly expand ot when it contains HTML
55 * warning: unclosed tags are unsupported, they will be fixed (closed) by the parser - eg, "foo <div>bar" => "foo <div>bar</div>"
56 *
57 * * localizable_html_attributes:
58 * type: string[]
59 * default: []
60 * description: the list of HTML attributes whose values can be altered - it is only useful when the "parse_html" option is set to true
61 * example: if ["title"], and with the "accents" option set to true, "<a href="#" title="Go to your profile">Profile</a>" => "<a href="#" title="Ĝö ţö ýöûŕ þŕöƒîļé">Þŕöƒîļé</a>" - if "title" was not in the "localizable_html_attributes" list, the title attribute data would be left unchanged.
62 */
63 public function __construct(TranslatorInterface $translator, array $options = [])
64 {
65 $this->translator = $translator;
66 $this->accents = $options['accents'] ?? \true;
67 if (1.0 > ($this->expansionFactor = $options['expansion_factor'] ?? 1.0)) {
68 throw new \InvalidArgumentException('The expansion factor must be greater than or equal to 1.');
69 }
70 $this->brackets = $options['brackets'] ?? \true;
71 $this->parseHTML = $options['parse_html'] ?? \false;
72 if ($this->parseHTML && !$this->accents && 1.0 === $this->expansionFactor) {
73 $this->parseHTML = \false;
74 }
75 $this->localizableHTMLAttributes = $options['localizable_html_attributes'] ?? [];
76 }
77 /**
78 * {@inheritdoc}
79 */
80 public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null) : string
81 {
82 $trans = '';
83 $visibleText = '';
84 foreach ($this->getParts($this->translator->trans($id, $parameters, $domain, $locale)) as [$visible, $localizable, $text]) {
85 if ($visible) {
86 $visibleText .= $text;
87 }
88 if (!$localizable) {
89 $trans .= $text;
90 continue;
91 }
92 $this->addAccents($trans, $text);
93 }
94 $this->expand($trans, $visibleText);
95 $this->addBrackets($trans);
96 return $trans;
97 }
98 public function getLocale() : string
99 {
100 return $this->translator->getLocale();
101 }
102 private function getParts(string $originalTrans) : array
103 {
104 if (!$this->parseHTML) {
105 return [[\true, \true, $originalTrans]];
106 }
107 $html = \mb_encode_numericentity($originalTrans, [0x80, 0xffff, 0, 0xffff], \mb_detect_encoding($originalTrans, null, \true) ?: 'UTF-8');
108 $useInternalErrors = \libxml_use_internal_errors(\true);
109 $dom = new \DOMDocument();
110 $dom->loadHTML('<trans>' . $html . '</trans>');
111 \libxml_clear_errors();
112 \libxml_use_internal_errors($useInternalErrors);
113 return $this->parseNode($dom->childNodes->item(1)->childNodes->item(0)->childNodes->item(0));
114 }
115 private function parseNode(\DOMNode $node) : array
116 {
117 $parts = [];
118 foreach ($node->childNodes as $childNode) {
119 if (!$childNode instanceof \DOMElement) {
120 $parts[] = [\true, \true, $childNode->nodeValue];
121 continue;
122 }
123 $parts[] = [\false, \false, '<' . $childNode->tagName];
124 /** @var \DOMAttr $attribute */
125 foreach ($childNode->attributes as $attribute) {
126 $parts[] = [\false, \false, ' ' . $attribute->nodeName . '="'];
127 $localizableAttribute = \in_array($attribute->nodeName, $this->localizableHTMLAttributes, \true);
128 foreach (\preg_split('/(&(?:amp|quot|#039|lt|gt);+)/', \htmlspecialchars($attribute->nodeValue, \ENT_QUOTES, 'UTF-8'), -1, \PREG_SPLIT_DELIM_CAPTURE) as $i => $match) {
129 if ('' === $match) {
130 continue;
131 }
132 $parts[] = [\false, $localizableAttribute && 0 === $i % 2, $match];
133 }
134 $parts[] = [\false, \false, '"'];
135 }
136 $parts[] = [\false, \false, '>'];
137 $parts = \array_merge($parts, $this->parseNode($childNode, $parts));
138 $parts[] = [\false, \false, '</' . $childNode->tagName . '>'];
139 }
140 return $parts;
141 }
142 private function addAccents(string &$trans, string $text) : void
143 {
144 $trans .= $this->accents ? \strtr($text, [' ' => ' ', '!' => '¡', '"' => '″', '#' => '♯', '$' => '€', '%' => '‰', '&' => '�
145 �', '\'' => '´', '(' => '{', ')' => '}', '*' => '⁎', '+' => '⁺', ',' => '،', '-' => '‐', '.' => '·', '/' => '⁄', '0' => '⓪', '1' => '①', '2' => '②', '3' => '③', '4' => '④', '5' => '⑤', '6' => '⑥', '7' => '⑦', '8' => '⑧', '9' => '⑨', ':' => '∶', ';' => '⁏', '<' => '≤', '=' => '≂', '>' => '≥', '?' => '¿', '@' => '՞', 'A' => '�
146 ', 'B' => 'Ɓ', 'C' => 'Ç', 'D' => 'Ð', 'E' => 'É', 'F' => 'Ƒ', 'G' => 'Ĝ', 'H' => 'Ĥ', 'I' => 'Î', 'J' => 'Ĵ', 'K' => 'Ķ', 'L' => 'Ļ', 'M' => 'Ṁ', 'N' => 'Ñ', 'O' => 'Ö', 'P' => 'Þ', 'Q' => 'Ǫ', 'R' => 'Ŕ', 'S' => 'Š', 'T' => 'Ţ', 'U' => 'Û', 'V' => 'Ṽ', 'W' => 'Ŵ', 'X' => 'Ẋ', 'Y' => 'Ý', 'Z' => 'Ž', '[' => '�
147 ', '\\' => '', ']' => '', '^' => '˄', '_' => '', '`' => '‵', 'a' => 'å', 'b' => 'ƀ', 'c' => 'ç', 'd' => 'ð', 'e' => 'é', 'f' => 'ƒ', 'g' => 'ĝ', 'h' => 'ĥ', 'i' => 'î', 'j' => 'ĵ', 'k' => 'ķ', 'l' => 'ļ', 'm' => 'ɱ', 'n' => 'ñ', 'o' => 'ö', 'p' => 'þ', 'q' => 'ǫ', 'r' => 'ŕ', 's' => 'š', 't' => 'ţ', 'u' => 'û', 'v' => 'ṽ', 'w' => 'ŵ', 'x' => 'ẋ', 'y' => 'ý', 'z' => 'ž', '{' => '(', '|' => '¦', '}' => ')', '~' => '˞']) : $text;
148 }
149 private function expand(string &$trans, string $visibleText) : void
150 {
151 if (1.0 >= $this->expansionFactor) {
152 return;
153 }
154 $visibleLength = $this->strlen($visibleText);
155 $missingLength = (int) \ceil($visibleLength * $this->expansionFactor) - $visibleLength;
156 if ($this->brackets) {
157 $missingLength -= 2;
158 }
159 if (0 >= $missingLength) {
160 return;
161 }
162 $words = [];
163 $wordsCount = 0;
164 foreach (\preg_split('/ +/', $visibleText, -1, \PREG_SPLIT_NO_EMPTY) as $word) {
165 $wordLength = $this->strlen($word);
166 if ($wordLength >= $missingLength) {
167 continue;
168 }
169 if (!isset($words[$wordLength])) {
170 $words[$wordLength] = 0;
171 }
172 ++$words[$wordLength];
173 ++$wordsCount;
174 }
175 if (!$words) {
176 $trans .= 1 === $missingLength ? self::EXPANSION_CHARACTER : ' ' . \str_repeat(self::EXPANSION_CHARACTER, $missingLength - 1);
177 return;
178 }
179 \arsort($words, \SORT_NUMERIC);
180 $longestWordLength = \max(\array_keys($words));
181 while (\true) {
182 $r = \mt_rand(1, $wordsCount);
183 foreach ($words as $length => $count) {
184 $r -= $count;
185 if ($r <= 0) {
186 break;
187 }
188 }
189 $trans .= ' ' . \str_repeat(self::EXPANSION_CHARACTER, $length);
190 $missingLength -= $length + 1;
191 if (0 === $missingLength) {
192 return;
193 }
194 while ($longestWordLength >= $missingLength) {
195 $wordsCount -= $words[$longestWordLength];
196 unset($words[$longestWordLength]);
197 if (!$words) {
198 $trans .= 1 === $missingLength ? self::EXPANSION_CHARACTER : ' ' . \str_repeat(self::EXPANSION_CHARACTER, $missingLength - 1);
199 return;
200 }
201 $longestWordLength = \max(\array_keys($words));
202 }
203 }
204 }
205 private function addBrackets(string &$trans) : void
206 {
207 if (!$this->brackets) {
208 return;
209 }
210 $trans = '[' . $trans . ']';
211 }
212 private function strlen(string $s) : int
213 {
214 return \false === ($encoding = \mb_detect_encoding($s, null, \true)) ? \strlen($s) : \mb_strlen($s, $encoding);
215 }
216 }
217