diff --git a/packages/web/lib/fog/system.class.php b/packages/web/lib/fog/system.class.php index 0c254cc285..be592f526d 100644 --- a/packages/web/lib/fog/system.class.php +++ b/packages/web/lib/fog/system.class.php @@ -53,7 +53,7 @@ private static function _versionCompare() public function __construct() { self::_versionCompare(); - define('FOG_VERSION', '1.5.10.2294'); + define('FOG_VERSION', '1.5.10.2301'); define('FOG_SCHEMA', 282); define('FOG_BCACHE_VER', 143); define('FOG_CLIENT_VERSION', '0.13.0'); diff --git a/packages/web/lib/plugins/pushbullet/events/imagefail_pushbullet.event.php b/packages/web/lib/plugins/pushbullet/events/imagefail_pushbullet.event.php index 05c43875c9..02b51264c0 100755 --- a/packages/web/lib/plugins/pushbullet/events/imagefail_pushbullet.event.php +++ b/packages/web/lib/plugins/pushbullet/events/imagefail_pushbullet.event.php @@ -63,8 +63,32 @@ public function __construct() */ public function onEvent($event, $data) { - self::$message = 'This host has failed to image'; - self::$shortdesc = 'Failed'; + // TaskError sends the image and the reason FOS gave, and the reason is + // the only part of this an admin can act on -- "failed to image" says + // nothing the task list did not already show. Read defensively: a + // server whose web tree predates that change sends HostName alone, and + // reading a missing key would turn the notification into a PHP warning + // in an event that only fires when something has already gone wrong. + $image = (string) ($data['ImageName'] ?? ''); + if ('' === $image) { + $image = _('an unnamed image'); + } + $reason = (string) ($data['Reason'] ?? ''); + if ('' === $reason) { + $reason = _('no reason was reported'); + } + self::$shortdesc = _('Imaging Failed'); + // Composed here rather than handed to the base class as a bare + // literal, because the substitution has to happen AFTER translation: + // a msgid built at runtime matches no catalog entry and never + // translates. The base's _() then finds nothing and passes this + // through unchanged. Positional specifiers so a translator can + // reorder the sentence. + self::$message = sprintf( + _('This host failed imaging %1$s: %2$s'), + $image, + $reason + ); parent::onEvent($event, $data); } } diff --git a/packages/web/lib/plugins/slack/events/imagefail_slack.event.php b/packages/web/lib/plugins/slack/events/imagefail_slack.event.php index 1382cbb1b1..b8dbd886f6 100755 --- a/packages/web/lib/plugins/slack/events/imagefail_slack.event.php +++ b/packages/web/lib/plugins/slack/events/imagefail_slack.event.php @@ -62,15 +62,32 @@ public function __construct() */ public function onEvent($event, $data) { + // See the pushbullet listener: the reason is the actionable half of + // this notification, and every added key is read defensively so the + // plugin keeps working against a web tree that still sends HostName + // alone. + $image = (string) ($data['ImageName'] ?? ''); + if ('' === $image) { + $image = _('an unnamed image'); + } + $reason = (string) ($data['Reason'] ?? ''); + if ('' === $reason) { + $reason = _('no reason was reported'); + } foreach ((array)self::getClass('SlackManager') ->find() as &$Token ) { $args = array( 'channel' => $Token->get('name'), + // Whole sentence inside _() with positional specifiers: the + // old form put 'Host: %s ' outside the call and translated + // the tail on its own, which is not a sentence a translator + // can work with. 'text' => sprintf( - 'Host: %s %s', + _('Host %1$s failed imaging %2$s: %3$s'), $data['HostName'], - _('imaging failed.') + $image, + $reason ) ); $Token->call('chat.postMessage', $args); diff --git a/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po index a6a2f91898..7cfabdc255 100644 --- a/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po @@ -2536,6 +2536,10 @@ msgstr "Telefonnummer" msgid "Host" msgstr "Host" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + #, fuzzy msgid "Host AD Domain" msgstr "Host AD-Domäne" @@ -3075,6 +3079,10 @@ msgstr "Image Task vollständig" msgid "Imaging Duration" msgstr "Imaging Log" +#, fuzzy +msgid "Imaging Failed" +msgstr "Laden fehlgeschlagen: %s" + msgid "Imaging Log" msgstr "Imaging Log" @@ -6595,6 +6603,10 @@ msgstr "Diese Datei funktioniert nur auf Windows" msgid "This host already exists" msgstr "Dieser Host ist bereits vorhanden." +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "Dieser Host ist bereits vorhanden." + msgid "This installation process may take a few minutes" msgstr "Der Installationsprozess kann ein paar Minuten dauern, " @@ -7345,6 +7357,10 @@ msgstr "vor" msgid "all current storage nodes" msgstr "momentanen Speicherknoten löschen." +#, fuzzy +msgid "an unnamed image" +msgstr "Ungültiges Image" + msgid "and Mac OS X" msgstr "und Mac OS X" @@ -7696,10 +7712,6 @@ msgstr "Images" msgid "images to a storage group" msgstr "bildet ab zu einer Speichergruppe" -#, fuzzy -msgid "imaging failed." -msgstr "Laden fehlgeschlagen: %s" - msgid "in seconds" msgstr "in Sekunden" @@ -7845,6 +7857,9 @@ msgstr "nicht verfügbar" msgid "no login will appear" msgstr "wird kein Login erscheinen." +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "welcher Knoten die Images verteilt." diff --git a/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po index 23c8b0b3e7..4054d58a7d 100644 --- a/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po @@ -2538,6 +2538,10 @@ msgstr "Home Phone" msgid "Host" msgstr "Host" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + #, fuzzy msgid "Host AD Domain" msgstr "AD Domain" @@ -3076,6 +3080,10 @@ msgstr "after task completion" msgid "Imaging Duration" msgstr "Imaging Log" +#, fuzzy +msgid "Imaging Failed" +msgstr "Load failed: %s" + msgid "Imaging Log" msgstr "Imaging Log" @@ -6593,6 +6601,10 @@ msgstr "" msgid "This host already exists" msgstr "Printer already exists" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "Printer already exists" + msgid "This installation process may take a few minutes" msgstr "" @@ -7342,6 +7354,10 @@ msgstr " ago" msgid "all current storage nodes" msgstr "Invalid storage node" +#, fuzzy +msgid "an unnamed image" +msgstr "Invalid image" + msgid "and Mac OS X" msgstr "" @@ -7693,10 +7709,6 @@ msgstr "Images" msgid "images to a storage group" msgstr "Primary Storage Group" -#, fuzzy -msgid "imaging failed." -msgstr "Load failed: %s" - msgid "in seconds" msgstr "" @@ -7841,6 +7853,9 @@ msgstr "n/a" msgid "no login will appear" msgstr "" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "" diff --git a/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po index fd8f05f67d..11853b988d 100755 --- a/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po @@ -2530,6 +2530,10 @@ msgstr "" msgid "Host" msgstr "Equipo" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + #, fuzzy msgid "Host AD Domain" msgstr "Gestión de equipos" @@ -3097,6 +3101,10 @@ msgstr "Imagen" msgid "Imaging Duration" msgstr "Descripción" +#, fuzzy +msgid "Imaging Failed" +msgstr "Error al cargar" + msgid "Imaging Log" msgstr "" @@ -6578,6 +6586,10 @@ msgstr "" msgid "This host already exists" msgstr "Ya existe este equipo" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "Ya existe este equipo" + msgid "This installation process may take a few minutes" msgstr "" @@ -7294,6 +7306,10 @@ msgstr "" msgid "all current storage nodes" msgstr "todos los Nodos de Almacenamiento" +#, fuzzy +msgid "an unnamed image" +msgstr "Imagen inválida" + msgid "and Mac OS X" msgstr "" @@ -7645,10 +7661,6 @@ msgstr "Imágenes" msgid "images to a storage group" msgstr "Añadir grupo de almacenamiento" -#, fuzzy -msgid "imaging failed." -msgstr "Error al cargar" - msgid "in seconds" msgstr "" @@ -7789,6 +7801,9 @@ msgstr "" msgid "no login will appear" msgstr "Gestión de login" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "exportar imágenes" diff --git a/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po index 7c22664610..0a1d71eba2 100644 --- a/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po @@ -2247,6 +2247,10 @@ msgstr "Téléphone fixe" msgid "Host" msgstr "Machine" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + msgid "Host AD Domain" msgstr "Domaine AD machine" @@ -2722,6 +2726,10 @@ msgstr "Clonage terminé" msgid "Imaging Duration" msgstr "Durée du clonage" +#, fuzzy +msgid "Imaging Failed" +msgstr "La connexion a échoué" + msgid "Imaging Log" msgstr "Journal des clonages" @@ -5825,6 +5833,10 @@ msgstr "Ce fichier ne fonctionnera que sous Windows" msgid "This host already exists" msgstr "Cette machine existe déjà" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "Cette machine existe déjà" + msgid "This installation process may take a few minutes" msgstr "Ce processus d'installation peut prendre quelques minutes" @@ -6482,6 +6494,10 @@ msgstr "depuis" msgid "all current storage nodes" msgstr "tous les nœuds de stockage actuels" +#, fuzzy +msgid "an unnamed image" +msgstr "Image invalide" + msgid "and Mac OS X" msgstr "and MacOS X" @@ -6791,10 +6807,6 @@ msgstr "images" msgid "images to a storage group" msgstr "images vers un groupe de stockage" -#, fuzzy -msgid "imaging failed." -msgstr "La connexion a échoué" - msgid "in seconds" msgstr "en secondes" @@ -6922,6 +6934,9 @@ msgstr "n/a" msgid "no login will appear" msgstr "aucun login n'apparaîtra" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "nœud est le distributeur des images" diff --git a/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po index 18b698663b..91b21d0bf8 100644 --- a/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po @@ -2305,6 +2305,10 @@ msgstr "Telefono di casa" msgid "Host" msgstr "Host" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + msgid "Host AD Domain" msgstr "Host AD Dominio" @@ -2786,6 +2790,10 @@ msgstr "Attività di immagine completata" msgid "Imaging Duration" msgstr "Imaging Log" +#, fuzzy +msgid "Imaging Failed" +msgstr "Caricamento non riuscito" + msgid "Imaging Log" msgstr "Imaging Log" @@ -5947,6 +5955,10 @@ msgstr "Questo file funziona solo in Windows" msgid "This host already exists" msgstr "Questo host esiste già" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "Questo host esiste già" + msgid "This installation process may take a few minutes" msgstr "Questo processo di installazione impiegherà alcuni minuti" @@ -6617,6 +6629,10 @@ msgstr "fa" msgid "all current storage nodes" msgstr "tutti i nodi di archiviazione attivi" +#, fuzzy +msgid "an unnamed image" +msgstr "immagine non valido" + msgid "and Mac OS X" msgstr "e Mac OS X" @@ -6933,10 +6949,6 @@ msgstr "immagini" msgid "images to a storage group" msgstr "Immagini in un gruppo di archiviazione" -#, fuzzy -msgid "imaging failed." -msgstr "Caricamento non riuscito" - msgid "in seconds" msgstr "in secondi" @@ -7067,6 +7079,9 @@ msgstr "n/d" msgid "no login will appear" msgstr "nessun login appare" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "nodo è il distributore delle immagini" diff --git a/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po index 1e50fbdd95..4971d455a3 100644 --- a/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po @@ -2222,6 +2222,10 @@ msgstr "自宅電話番号" msgid "Host" msgstr "ホスト" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + msgid "Host AD Domain" msgstr "ホスト AD ドメイン" @@ -2695,6 +2699,10 @@ msgstr "イメージ処理が完了しました" msgid "Imaging Duration" msgstr "イメージ処理時間" +#, fuzzy +msgid "Imaging Failed" +msgstr "イメージ処理に失敗しました。" + msgid "Imaging Log" msgstr "イメージログ" @@ -5769,6 +5777,10 @@ msgstr "このファイルは Windows でのみ使用できます" msgid "This host already exists" msgstr "このホストは既に存在します" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "このホストは既に存在します" + msgid "This installation process may take a few minutes" msgstr "このインストール処理には数分かかる場合があります" @@ -6419,6 +6431,10 @@ msgstr "前" msgid "all current storage nodes" msgstr "現在のすべてのストレージノード" +#, fuzzy +msgid "an unnamed image" +msgstr "無効なイメージ" + msgid "and Mac OS X" msgstr "および Mac OS X" @@ -6725,9 +6741,6 @@ msgstr "イメージ" msgid "images to a storage group" msgstr "イメージをストレージグループへ" -msgid "imaging failed." -msgstr "イメージ処理に失敗しました。" - msgid "in seconds" msgstr "秒単位" @@ -6854,6 +6867,9 @@ msgstr "N/A" msgid "no login will appear" msgstr "ログイン画面は表示されません" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "ノードがイメージの配布元になります" diff --git a/packages/web/management/languages/messages.pot b/packages/web/management/languages/messages.pot index aff4c39b96..2f603d7665 100644 --- a/packages/web/management/languages/messages.pot +++ b/packages/web/management/languages/messages.pot @@ -2205,6 +2205,10 @@ msgstr "" msgid "Host" msgstr "" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + msgid "Host AD Domain" msgstr "" @@ -2675,6 +2679,9 @@ msgstr "" msgid "Imaging Duration" msgstr "" +msgid "Imaging Failed" +msgstr "" + msgid "Imaging Log" msgstr "" @@ -5739,6 +5746,10 @@ msgstr "" msgid "This host already exists" msgstr "" +#, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "" + msgid "This installation process may take a few minutes" msgstr "" @@ -6389,6 +6400,9 @@ msgstr "" msgid "all current storage nodes" msgstr "" +msgid "an unnamed image" +msgstr "" + msgid "and Mac OS X" msgstr "" @@ -6695,9 +6709,6 @@ msgstr "" msgid "images to a storage group" msgstr "" -msgid "imaging failed." -msgstr "" - msgid "in seconds" msgstr "" @@ -6824,6 +6835,9 @@ msgstr "" msgid "no login will appear" msgstr "" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "" diff --git a/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po index 751c4521a3..06d7858ec2 100644 --- a/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po @@ -2236,6 +2236,10 @@ msgstr "Telefone Residencial" msgid "Host" msgstr "Host" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + msgid "Host AD Domain" msgstr "Domínio AD do Host" @@ -2710,6 +2714,10 @@ msgstr "Criação de Imagem Concluída" msgid "Imaging Duration" msgstr "Duração da Criação de Imagem" +#, fuzzy +msgid "Imaging Failed" +msgstr "criação de imagem falhou." + msgid "Imaging Log" msgstr "Log de Criação de Imagem" @@ -5796,6 +5804,10 @@ msgstr "Este arquivo funcionará apenas no Windows" msgid "This host already exists" msgstr "Este host já existe" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "Este host já existe" + msgid "This installation process may take a few minutes" msgstr "Este processo de instalação pode levar alguns minutos" @@ -6447,6 +6459,10 @@ msgstr "atrás" msgid "all current storage nodes" msgstr "todos os nós de armazenamento atuais" +#, fuzzy +msgid "an unnamed image" +msgstr "Imagem inválida" + msgid "and Mac OS X" msgstr "e Mac OS X" @@ -6754,9 +6770,6 @@ msgstr "imagens" msgid "images to a storage group" msgstr "imagens para um grupo de armazenamento" -msgid "imaging failed." -msgstr "criação de imagem falhou." - msgid "in seconds" msgstr "em segundos" @@ -6883,6 +6896,9 @@ msgstr "n/d" msgid "no login will appear" msgstr "nenhum login aparecerá" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "nó é o distribuidor das imagens" diff --git a/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po index 12ed907735..83d69b761b 100644 --- a/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po @@ -2236,6 +2236,10 @@ msgstr "主页电话" msgid "Host" msgstr "主机" +#, php-format +msgid "Host %1$s failed imaging %2$s: %3$s" +msgstr "" + msgid "Host AD Domain" msgstr "主机AD域" @@ -2710,6 +2714,10 @@ msgstr "映像已完成" msgid "Imaging Duration" msgstr "映像期间" +#, fuzzy +msgid "Imaging Failed" +msgstr "映像失败" + msgid "Imaging Log" msgstr "映像日志" @@ -5796,6 +5804,10 @@ msgstr "这个文件只能在Windows上使用" msgid "This host already exists" msgstr "主机已经存在" +#, fuzzy, php-format +msgid "This host failed imaging %1$s: %2$s" +msgstr "主机已经存在" + msgid "This installation process may take a few minutes" msgstr "安装进程将持续几分钟" @@ -6447,6 +6459,10 @@ msgstr "前" msgid "all current storage nodes" msgstr "所有目前的存储节点" +#, fuzzy +msgid "an unnamed image" +msgstr "镜像无效" + msgid "and Mac OS X" msgstr "和MAC OS X" @@ -6753,9 +6769,6 @@ msgstr "镜像" msgid "images to a storage group" msgstr "存储组镜像" -msgid "imaging failed." -msgstr "映像失败" - msgid "in seconds" msgstr "几秒钟内" @@ -6882,6 +6895,9 @@ msgstr "N/A" msgid "no login will appear" msgstr "不会出现登录" +msgid "no reason was reported" +msgstr "" + msgid "node is the distributor of the images" msgstr "节点是镜像的分发器" diff --git a/tests/imaging-failure-reason.test.php b/tests/imaging-failure-reason.test.php new file mode 100644 index 0000000000..062ba41aaa --- /dev/null +++ b/tests/imaging-failure-reason.test.php @@ -0,0 +1,118 @@ + $root . '/pushbullet/events/imagefail_pushbullet.event.php', + 'slack' => $root . '/slack/events/imagefail_slack.event.php' +]; + +foreach ($files as $plugin => $file) { + if (!is_file($file)) { + $fails[] = "$plugin: imagefail listener is missing at $file"; + continue; + } + $src = file_get_contents($file); + // Comments stripped first, every time: the prose above each of these + // changes names the very thing being looked for and would satisfy the + // search on its own. + $code = preg_replace('#/\*.*?\*/#s', '', $src); + $code = preg_replace('#^\s*//.*$#m', '', $code); + + // Scoped to onEvent(), so a mention anywhere else in the file cannot + // stand in for the listener actually using it. + if (!preg_match('#function onEvent\(.*?\n \}#s', $code, $m)) { + $fails[] = "$plugin: could not read onEvent(), so nothing below is" + . ' actually checked'; + continue; + } + $fn = $m[0]; + + if (false === strpos($fn, "\$data['Reason']")) { + $fails[] = "$plugin: the failure notification never reads Reason, so" + . ' it says only that imaging failed and not why'; + } + if (false === strpos($fn, "\$data['ImageName']")) { + $fails[] = "$plugin: the failure notification never names the image"; + } + // Defensive reads. `?? ''` is the shape; a bare read is the bug. + foreach (['Reason', 'ImageName'] as $key) { + if (!preg_match( + "#\\\$data\['" . $key . "'\]\s*\?\?#", + $fn + )) { + $fails[] = "$plugin: \$data['$key'] is read without a default, so" + . ' a server that still sends only HostName turns this' + . ' notification into a PHP warning'; + } + } + // Both must have a fallback string, or an older server pushes a sentence + // with a hole in it ("failed imaging : "). + if (!preg_match('#\$reason\s*=\s*_\(#', $fn) + || !preg_match('#\$image\s*=\s*_\(#', $fn) + ) { + $fails[] = "$plugin: a missing key falls through without a translated" + . ' placeholder, so the message renders with an empty slot'; + } + // The substitution is outside _(). sprintf(_('...%1$s...'), $x) is right; + // _("...$x...") or _('...' . $x) is the bug this pins. + if (preg_match('#_\(\s*"[^"]*\$#', $fn) + || preg_match("#_\(\s*'[^']*'\s*\.#", $fn) + ) { + $fails[] = "$plugin: a variable is interpolated INSIDE _(), so the" + . ' msgid is built at runtime, matches no catalog entry and never' + . ' translates'; + } + if (!preg_match('#sprintf\(\s*\n?\s*_\(#', $fn)) { + $fails[] = "$plugin: the message is not composed with sprintf() around" + . ' a literal msgid, so the translated sentence cannot carry the' + . ' image and the reason'; + } + // Positional specifiers, so a translator can reorder. %s alone locks the + // sentence to English word order. + if (false === strpos($fn, '%1$s')) { + $fails[] = "$plugin: the msgid uses bare %s rather than positional" + . ' specifiers, so a translator cannot reorder the sentence'; + } +} + +if ($fails) { + echo 'FAIL: ' . count($fails) . " problem(s):\n"; + foreach ($fails as $f) { + echo " - $f\n"; + } + exit(1); +} +echo "ok: both failure notifications report the reason, defensively\n"; +exit(0);