1<?php 2 3namespace Gettext\Utils; 4 5use Exception; 6use Gettext\Translations; 7 8abstract class FunctionsScanner 9{ 10 /** 11 * Scan and returns the functions and the arguments. 12 * 13 * @param array $constants Constants used in the code to replace 14 * 15 * @return array 16 */ 17 abstract public function getFunctions(array $constants = []); 18 19 /** 20 * Search for specific functions and create translations. 21 * 22 * You can pass multiple translation with different domains and value found will be sorted respectively. 23 * 24 * @param Translations|Translations[] $translations Multiple domain translations instances where to save the values 25 * @param array $options The extractor options 26 * @throws Exception 27 */ 28 public function saveGettextFunctions($translations, array $options) 29 { 30 $translations = is_array($translations) ? $translations : [$translations]; 31 32 /** @var Translations[] $translationByDomain [domain => translations, ..] */ 33 $translationByDomain = array_reduce($translations, function ($carry, Translations $translations) { 34 $carry[$translations->getDomain()] = $translations; 35 return $carry; 36 }, []); 37 38 $functions = $options['functions']; 39 $file = $options['file']; 40 41 foreach ($this->getFunctions($options['constants']) as $function) { 42 list($name, $line, $args) = $function; 43 44 if (isset($options['lineOffset'])) { 45 $line += $options['lineOffset']; 46 } 47 48 if (!isset($functions[$name])) { 49 continue; 50 } 51 52 $deconstructed = $this->deconstructArgs($functions[$name], $args); 53 54 if (!$deconstructed) { 55 continue; 56 } 57 58 list($domain, $context, $original, $plural) = $deconstructed; 59 60 if ((string)$original === '') { 61 continue; 62 } 63 64 $isDefaultDomain = $domain === null; 65 66 $domainTranslations = isset($translationByDomain[$domain]) ? $translationByDomain[$domain] : false; 67 68 if (!empty($options['domainOnly']) && $isDefaultDomain) { 69 // If we want to find translations for a specific domain, skip default domain messages 70 continue; 71 } 72 73 if (!$domainTranslations) { 74 continue; 75 } 76 77 $translation = $domainTranslations->insert($context, $original, $plural); 78 $translation->addReference($file, $line); 79 80 if (isset($function[3])) { 81 foreach ($function[3] as $extractedComment) { 82 $translation->addExtractedComment($extractedComment); 83 } 84 } 85 } 86 } 87 88 /** 89 * Deconstruct arguments to translation values 90 * 91 * @param $function 92 * @param $args 93 * @return array|null 94 * @throws Exception 95 */ 96 protected function deconstructArgs($function, $args) 97 { 98 $domain = null; 99 $context = null; 100 $original = null; 101 $plural = null; 102 103 switch ($function) { 104 case 'noop': 105 case 'gettext': 106 if (!isset($args[0])) { 107 return null; 108 } 109 110 $original = $args[0]; 111 break; 112 case 'ngettext': 113 if (!isset($args[1])) { 114 return null; 115 } 116 117 list($original, $plural) = $args; 118 break; 119 case 'pgettext': 120 if (!isset($args[1])) { 121 return null; 122 } 123 124 list($context, $original) = $args; 125 break; 126 case 'dgettext': 127 if (!isset($args[1])) { 128 return null; 129 } 130 131 list($domain, $original) = $args; 132 break; 133 case 'dpgettext': 134 if (!isset($args[2])) { 135 return null; 136 } 137 138 list($domain, $context, $original) = $args; 139 break; 140 case 'npgettext': 141 if (!isset($args[2])) { 142 return null; 143 } 144 145 list($context, $original, $plural) = $args; 146 break; 147 case 'dnpgettext': 148 if (!isset($args[3])) { 149 return null; 150 } 151 152 list($domain, $context, $original, $plural) = $args; 153 break; 154 case 'dngettext': 155 if (!isset($args[2])) { 156 return null; 157 } 158 159 list($domain, $original, $plural) = $args; 160 break; 161 default: 162 throw new Exception(sprintf('Not valid function %s', $function)); 163 } 164 165 return [$domain, $context, $original, $plural]; 166 } 167} 168