private $extMapper = NULL;
/**
- * @var CRM_Utils_Cache_Interface
+ * @var CRM_Core_Resources_Strings
*/
- private $cache = NULL;
+ private $strings = NULL;
/**
* @var array free-form data tree
*/
public function __construct($extMapper, $cache, $cacheCodeKey = NULL) {
$this->extMapper = $extMapper;
- $this->cache = $cache;
+ $this->strings = new CRM_Core_Resources_Strings($cache);
$this->cacheCodeKey = $cacheCodeKey;
if ($cacheCodeKey !== NULL) {
$this->cacheCode = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, $cacheCodeKey);
*/
public function addScriptFile($ext, $file, $weight = self::DEFAULT_WEIGHT, $region = self::DEFAULT_REGION, $translate = TRUE) {
if ($translate) {
- $this->translateScript($ext, $file);
+ // For each extension, maintain one cache record which
+ // includes parsed (translatable) strings for all its files.
+ $this->addString($this->strings->get($ext, $this->getPath($ext, $file), 'text/javascript'));
}
// Look for non-minified version if we are in debug mode
if (CRM_Core_Config::singleton()->debug && strpos($file, '.min.js') !== FALSE) {
* @return CRM_Core_Resources
*/
public function flushStrings() {
- $this->cache->flush();
+ $this->strings->flush();
return $this;
}
/**
- * Translate strings in a javascript file
- *
- * @param string $ext
- * extension name.
- * @param string $file
- * file path.
- * @return void
- */
- private function translateScript($ext, $file) {
- // For each extension, maintain one cache record which
- // includes parsed (translatable) strings for all its JS files.
- $stringsByFile = $this->cache->get($ext); // array($file => array(...strings...))
- if (!$stringsByFile) {
- $stringsByFile = array();
- }
- if (!isset($stringsByFile[$file])) {
- $filePath = $this->getPath($ext, $file);
- if ($filePath && is_readable($filePath)) {
- $stringsByFile[$file] = CRM_Utils_JS::parseStrings(file_get_contents($filePath));
- }
- else {
- $stringsByFile[$file] = array();
- }
- $this->cache->set($ext, $stringsByFile);
- }
- $this->addString($stringsByFile[$file]);
+ * @return CRM_Core_Resources_Strings
+ */
+ public function getStrings() {
+ return $this->strings;
}
/**
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.6 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+*/
+
+/**
+ * Manage translatable strings on behalf of resource files.
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2014
+ * $Id$
+ */
+class CRM_Core_Resources_Strings {
+
+ /**
+ * @var CRM_Utils_Cache_Interface|NULL
+ */
+ private $cache = NULL;
+
+ /**
+ * @param CRM_Utils_Cache_Interface $cache
+ * Localization cache.
+ */
+ public function __construct($cache) {
+ $this->cache = $cache;
+ }
+
+ /**
+ * Flush the cache of translated strings.
+ */
+ public function flush() {
+ $this->cache->flush();
+ }
+
+ /**
+ * Get the strings from a file, using a cache if available.
+ *
+ * @param string $bucket
+ * The name of a cache-row which includes strings for this file.
+ * @param string $file
+ * File path.
+ * @param string $format
+ * Type of file (e.g. 'text/javascript', 'text/html').
+ * @return array
+ * List of translatable strings.
+ */
+ public function get($bucket, $file, $format) {
+ $stringsByFile = $this->cache->get($bucket); // array($file => array(...strings...))
+ if (!$stringsByFile) {
+ $stringsByFile = array();
+ }
+ if (!isset($stringsByFile[$file])) {
+ if ($file && is_readable($file)) {
+ $stringsByFile[$file] = $this->extract($file, $format);
+ }
+ else {
+ $stringsByFile[$file] = array();
+ }
+ $this->cache->set($bucket, $stringsByFile);
+ }
+ return $stringsByFile[$file];
+ }
+
+ /**
+ * Extract a list of strings from a file.
+ *
+ * @param string $file
+ * File path.
+ * @param string $format
+ * Type of file (e.g. 'text/javascript', 'text/html').
+ * @return array
+ * List of translatable strings.
+ * @throws Exception
+ */
+ public function extract($file, $format) {
+ switch ($format) {
+ case 'text/javascript':
+ return CRM_Utils_JS::parseStrings(file_get_contents($file));
+
+ case 'text/html':
+ // Magic! The JS parser works with HTML! See CRM_Utils_HTMLTest.
+ return CRM_Utils_JS::parseStrings(file_get_contents($file));
+
+ default:
+ throw new Exception("Cannot extract strings: Unrecognized file type.");
+ }
+ }
+}
--- /dev/null
+<?php
+/*
++--------------------------------------------------------------------+
+| CiviCRM version 4.6 |
++--------------------------------------------------------------------+
+| Copyright CiviCRM LLC (c) 2004-2014 |
++--------------------------------------------------------------------+
+| This file is a part of CiviCRM. |
+| |
+| CiviCRM is free software; you can copy, modify, and distribute it |
+| under the terms of the GNU Affero General Public License |
+| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+| |
+| CiviCRM is distributed in the hope that it will be useful, but |
+| WITHOUT ANY WARRANTY; without even the implied warranty of |
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+| See the GNU Affero General Public License for more details. |
+| |
+| You should have received a copy of the GNU Affero General Public |
+| License and the CiviCRM Licensing Exception along |
+| with this program; if not, contact CiviCRM LLC |
+| at info[AT]civicrm[DOT]org. If you have questions about the |
+| GNU Affero General Public License or the licensing of CiviCRM, |
+| see the CiviCRM license FAQ at http://civicrm.org/licensing |
++--------------------------------------------------------------------+
+*/
+
+require_once 'CiviTest/CiviUnitTestCase.php';
+
+/**
+ * Tests for parsing translatable strings in HTML content.
+ */
+class CRM_Core_Resources_StringsTest extends CiviUnitTestCase {
+
+ /**
+ * Get strings from files.
+ */
+ public function testGet() {
+ $basedir = $this->createExamples();
+ $strings = new CRM_Core_Resources_Strings(
+ new CRM_Utils_Cache_Arraycache(NULL)
+ );
+ $this->assertEquals(
+ array('Hello from Javascript'),
+ $strings->get('example', "$basedir/hello.js", "text/javascript")
+ );
+ $this->assertEquals(
+ array('Hello from HTML'),
+ $strings->get('example', "$basedir/hello.html", "text/html")
+ );
+ }
+
+ /**
+ * @return string
+ * Path to the example dir.
+ */
+ public function createExamples() {
+ $basedir = rtrim($this->createTempDir('ext-'), '/');
+ file_put_contents("$basedir/hello.js", "alert(ts('Hello from Javascript'));");
+ file_put_contents("$basedir/hello.html", "<div>{{ts('Hello from HTML')}}</div>");
+ return $basedir;
+ }
+}
--- /dev/null
+<?php
+/*
++--------------------------------------------------------------------+
+| CiviCRM version 4.6 |
++--------------------------------------------------------------------+
+| Copyright CiviCRM LLC (c) 2004-2014 |
++--------------------------------------------------------------------+
+| This file is a part of CiviCRM. |
+| |
+| CiviCRM is free software; you can copy, modify, and distribute it |
+| under the terms of the GNU Affero General Public License |
+| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+| |
+| CiviCRM is distributed in the hope that it will be useful, but |
+| WITHOUT ANY WARRANTY; without even the implied warranty of |
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+| See the GNU Affero General Public License for more details. |
+| |
+| You should have received a copy of the GNU Affero General Public |
+| License and the CiviCRM Licensing Exception along |
+| with this program; if not, contact CiviCRM LLC |
+| at info[AT]civicrm[DOT]org. If you have questions about the |
+| GNU Affero General Public License or the licensing of CiviCRM, |
+| see the CiviCRM license FAQ at http://civicrm.org/licensing |
++--------------------------------------------------------------------+
+*/
+
+require_once 'CiviTest/CiviUnitTestCase.php';
+
+/**
+ * Tests for parsing translatable strings in HTML content.
+ */
+class CRM_Utils_HTMLTest extends CiviUnitTestCase {
+ /**
+ * @return array
+ */
+ public function translateExamples() {
+ $cases = array();
+ $cases[] = array(
+ '',
+ array(),
+ );
+ $cases[] = array(// missing ts
+ '<div>Hello world</div>',
+ array(),
+ );
+ $cases[] = array(// text, no arg
+ '<div>{{ts("Hello world")}}</div>',
+ array('Hello world'),
+ );
+ $cases[] = array(// text, no arg, alternate text
+ '<div>{{ts("Good morning, Dave")}}</div>',
+ array('Good morning, Dave'),
+ );
+ $cases[] = array(// text, with arg
+ '<div>{{ts("Hello world", {1: "whiz"})}}</div>',
+ array('Hello world'),
+ );
+ $cases[] = array(// text, not really ts(), no arg
+ '<div>{{clients("Hello world")}}</div>',
+ array(),
+ );
+ $cases[] = array(// text, not really ts(), with arg
+ '<div>{{clients("Hello world", {1: "whiz"})}}</div>',
+ array(),
+ );
+ $cases[] = array(// two strings, duplicate
+ '<div>{{ts("Hello world")}}</div> <p>{{ts("Hello world")}}</p>',
+ array('Hello world'),
+ );
+ $cases[] = array(// two strings, addition
+ '<div>{{ts("Hello world") + "-" + ts("How do you do?")}}</p>',
+ array('Hello world', 'How do you do?'),
+ );
+ $cases[] = array(// two strings, separate calls
+ '<div>{{ts("Hello world")}}</div> <p>{{ts("How do you do?")}}</p>',
+ array('Hello world', 'How do you do?'),
+ );
+ $cases[] = array(// single quoted
+ '<div>{{ts(\'Hello world\')}}</div>',
+ array('Hello world'),
+ );
+ $cases[] = array(// unclear string
+ '<div>{{ts(message)}}</div>',
+ array(),
+ );
+ $cases[] = array(// ts() within a string
+ '<div>{{ts("Does the ts(\'example\') notation work?")}}</div>',
+ array('Does the ts(\'example\') notation work?'),
+ );
+ $cases[] = array(// attribute, no arg
+ '<div crm-title="ts("Hello world")"></div>',
+ array('Hello world'),
+ );
+ $cases[] = array(// attribute, with arg
+ '<div crm-title="ts("Hello world", {1: "whiz"})"></div>',
+ array('Hello world'),
+ );
+ $cases[] = array(// attribute, two strings, with arg
+ '<div crm-title="ts("Hello world", {1: "whiz"}) + ts("How do you do, %1?", {2: "funky"})"></div>',
+ array('Hello world', 'How do you do, %1?'),
+ );
+ $cases[] = array(// trick question! Not used on Smarty templates.
+ '<div>{ts}Hello world{/ts}</div>',
+ array(),
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @param string $html
+ * Example HTML input.
+ * @param array $expectedStrings
+ * List of expected strings.
+ * @dataProvider translateExamples
+ */
+ public function testParseStrings($html, $expectedStrings) {
+ // Magic! The JS parser works with HTML!
+ $actualStrings = CRM_Utils_JS::parseStrings($html);
+ sort($expectedStrings);
+ sort($actualStrings);
+ $this->assertEquals($expectedStrings, $actualStrings);
+ }
+}