summaryrefslogtreecommitdiff
path: root/lib/phptal/PHPTAL/Php/Attribute/I18N
diff options
context:
space:
mode:
Diffstat (limited to 'lib/phptal/PHPTAL/Php/Attribute/I18N')
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Attributes.php118
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Data.php36
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Domain.php50
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Name.php47
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Source.php48
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Target.php43
-rw-r--r--lib/phptal/PHPTAL/Php/Attribute/I18N/Translate.php130
7 files changed, 472 insertions, 0 deletions
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Attributes.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Attributes.php
new file mode 100644
index 0000000..5eb3fac
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Attributes.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+/**
+ * i18n:attributes
+ *
+ * This attribute will allow us to translate attributes of HTML tags, such
+ * as the alt attribute in the img tag. The i18n:attributes attribute
+ * specifies a list of attributes to be translated with optional message
+ * IDs? for each; if multiple attribute names are given, they must be
+ * separated by semi-colons. Message IDs? used in this context must not
+ * include whitespace.
+ *
+ * Note that the value of the particular attributes come either from the
+ * HTML attribute value itself or from the data inserted by tal:attributes.
+ *
+ * If an attibute is to be both computed using tal:attributes and translated,
+ * the translation service is passed the result of the TALES expression for
+ * that attribute.
+ *
+ * An example:
+ *
+ * <img src="http://foo.com/logo" alt="Visit us"
+ * tal:attributes="alt here/greeting"
+ * i18n:attributes="alt"
+ * />
+ *
+ *
+ * In this example, let tal:attributes set the value of the alt attribute to
+ * the text "Stop by for a visit!". This text will be passed to the
+ * translation service, which uses the result of language negotiation to
+ * translate "Stop by for a visit!" into the requested language. The example
+ * text in the template, "Visit us", will simply be discarded.
+ *
+ * Another example, with explicit message IDs:
+ *
+ * <img src="../icons/uparrow.png" alt="Up"
+ * i18n:attributes="src up-arrow-icon; alt up-arrow-alttext"
+ * >
+ *
+ * Here, the message ID up-arrow-icon will be used to generate the link to
+ * an icon image file, and the message ID up-arrow-alttext will be used for
+ * the "alt" text.
+ *
+ *
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Attributes extends PHPTAL_Php_Attribute
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ // split attributes to translate
+ foreach ($codewriter->splitExpression($this->expression) as $exp) {
+ list($qname, $key) = $this->parseSetExpression($exp);
+
+ // if the translation key is specified and not empty (but may be '0')
+ if (strlen($key)) {
+ // we use it and replace the tag attribute with the result of the translation
+ $code = $this->_getTranslationCode($codewriter, $key);
+ } else {
+ $attr = $this->phpelement->getAttributeNode($qname);
+ if (!$attr) throw new PHPTAL_TemplateException("Unable to translate attribute $qname, because there is no translation key specified",
+ $this->phpelement->getSourceFile(), $this->phpelement->getSourceLine());
+
+ if ($attr->getReplacedState() === PHPTAL_Dom_Attr::NOT_REPLACED) {
+ $code = $this->_getTranslationCode($codewriter, $attr->getValue());
+ } elseif ($attr->getReplacedState() === PHPTAL_Dom_Attr::VALUE_REPLACED && $attr->getOverwrittenVariableName()) {
+ // sadly variables won't be interpolated in this translation
+ $code = 'echo '.$codewriter->escapeCode($codewriter->getTranslatorReference(). '->translate('.$attr->getOverwrittenVariableName().', false)');
+ } else {
+ throw new PHPTAL_TemplateException("Unable to translate attribute $qname, because other TAL attributes are using it",
+ $this->phpelement->getSourceFile(), $this->phpelement->getSourceLine());
+ }
+ }
+ $this->phpelement->getOrCreateAttributeNode($qname)->overwriteValueWithCode($code);
+ }
+ }
+
+ public function after(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ }
+
+ /**
+ * @param key - unescaped string (not PHP code) for the key
+ */
+ private function _getTranslationCode(PHPTAL_Php_CodeWriter $codewriter, $key)
+ {
+ $code = '';
+ if (preg_match_all('/\$\{(.*?)\}/', $key, $m)) {
+ array_shift($m);
+ $m = array_shift($m);
+ foreach ($m as $name) {
+ $code .= "\n".$codewriter->getTranslatorReference(). '->setVar('.$codewriter->str($name).','.PHPTAL_Php_TalesInternal::compileToPHPExpression($name).');'; // allow more complex TAL expressions
+ }
+ $code .= "\n";
+ }
+
+ // notice the false boolean which indicate that the html is escaped
+ // elsewhere looks like an hack doesn't it ? :)
+ $code .= 'echo '.$codewriter->escapeCode($codewriter->getTranslatorReference().'->translate('.$codewriter->str($key).', false)');
+ return $code;
+ }
+}
+
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Data.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Data.php
new file mode 100644
index 0000000..bad310f
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Data.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+/**
+ * i18n:data
+ *
+ * Since TAL always returns strings, we need a way in ZPT to translate
+ * objects, the most obvious case being DateTime objects. The data attribute
+ * will allow us to specify such an object, and i18n:translate will provide
+ * us with a legal format string for that object. If data is used,
+ * i18n:translate must be used to give an explicit message ID, rather than
+ * relying on a message ID computed from the content.
+ *
+ *
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Data extends PHPTAL_Php_Attribute
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter){}
+ public function after(PHPTAL_Php_CodeWriter $codewriter){}
+}
+
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Domain.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Domain.php
new file mode 100644
index 0000000..92ece11
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Domain.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+/**
+ * i18n:domain
+ *
+ * The i18n:domain attribute is used to specify the domain to be used to get
+ * the translation. If not specified, the translation services will use a
+ * default domain. The value of the attribute is used directly; it is not
+ * a TALES expression.
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Domain extends PHPTAL_Php_Attribute
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ // ensure a domain stack exists or create it
+ $codewriter->doIf('!isset($_i18n_domains)');
+ $codewriter->pushCode('$_i18n_domains = array()');
+ $codewriter->doEnd('if');
+
+ $expression = $codewriter->interpolateTalesVarsInString($this->expression);
+
+ // push current domain and use new domain
+ $code = '$_i18n_domains[] = '.$codewriter->getTranslatorReference().'->useDomain('.$expression.')';
+ $codewriter->pushCode($code);
+ }
+
+ public function after(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ // restore domain
+ $code = $codewriter->getTranslatorReference().'->useDomain(array_pop($_i18n_domains))';
+ $codewriter->pushCode($code);
+ }
+}
+
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Name.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Name.php
new file mode 100644
index 0000000..8a8f4e7
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Name.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+/** i18n:name
+ *
+ * Name the content of the current element for use in interpolation within
+ * translated content. This allows a replaceable component in content to be
+ * re-ordered by translation. For example:
+ *
+ * <span i18n:translate=''>
+ * <span tal:replace='here/name' i18n:name='name' /> was born in
+ * <span tal:replace='here/country_of_birth' i18n:name='country' />.
+ * </span>
+ *
+ * would cause this text to be passed to the translation service:
+ *
+ * "${name} was born in ${country}."
+ *
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Name extends PHPTAL_Php_Attribute
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ $codewriter->pushCode('ob_start()');
+ }
+
+ public function after(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ $codewriter->pushCode($codewriter->getTranslatorReference().'->setVar('.$codewriter->str($this->expression).', ob_get_clean())');
+ }
+}
+
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Source.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Source.php
new file mode 100644
index 0000000..9575fae
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Source.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+
+/**
+ * i18n:source
+ *
+ * The i18n:source attribute specifies the language of the text to be
+ * translated. The default is "nothing", which means we don't provide
+ * this information to the translation services.
+ *
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Source extends PHPTAL_Php_Attribute
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ // ensure that a sources stack exists or create it
+ $codewriter->doIf('!isset($_i18n_sources)');
+ $codewriter->pushCode('$_i18n_sources = array()');
+ $codewriter->end();
+
+ // push current source and use new one
+ $codewriter->pushCode('$_i18n_sources[] = ' . $codewriter->getTranslatorReference(). '->setSource('.$codewriter->str($this->expression).')');
+ }
+
+ public function after(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ // restore source
+ $code = $codewriter->getTranslatorReference().'->setSource(array_pop($_i18n_sources))';
+ $codewriter->pushCode($code);
+ }
+}
+
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Target.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Target.php
new file mode 100644
index 0000000..9cf2a67
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Target.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+/**
+ * i18n:target
+ *
+ * The i18n:target attribute specifies the language of the translation we
+ * want to get. If the value is "default", the language negotiation services
+ * will be used to choose the destination language. If the value is
+ * "nothing", no translation will be performed; this can be used to suppress
+ * translation within a larger translated unit. Any other value must be a
+ * language code.
+ *
+ * The attribute value is a TALES expression; the result of evaluating the
+ * expression is the language code or one of the reserved values.
+ *
+ * Note that i18n:target is primarily used for hints to text extraction
+ * tools and translation teams. If you had some text that should only be
+ * translated to e.g. German, then it probably shouldn't be wrapped in an
+ * i18n:translate span.
+ *
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Target extends PHPTAL_Php_Attribute
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter){}
+ public function after(PHPTAL_Php_CodeWriter $codewriter){}
+}
+
diff --git a/lib/phptal/PHPTAL/Php/Attribute/I18N/Translate.php b/lib/phptal/PHPTAL/Php/Attribute/I18N/Translate.php
new file mode 100644
index 0000000..a0e26c2
--- /dev/null
+++ b/lib/phptal/PHPTAL/Php/Attribute/I18N/Translate.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * PHPTAL templating engine
+ *
+ * PHP Version 5
+ *
+ * @category HTML
+ * @package PHPTAL
+ * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
+ * @author Kornel Lesiński <kornel@aardvarkmedia.co.uk>
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
+ * @version SVN: $Id$
+ * @link http://phptal.org/
+ */
+
+/**
+ * ZPTInternationalizationSupport
+ *
+ * i18n:translate
+ *
+ * This attribute is used to mark units of text for translation. If this
+ * attribute is specified with an empty string as the value, the message ID
+ * is computed from the content of the element bearing this attribute.
+ * Otherwise, the value of the element gives the message ID.
+ *
+ *
+ * @package PHPTAL
+ * @subpackage Php.attribute.i18n
+ */
+class PHPTAL_Php_Attribute_I18N_Translate extends PHPTAL_Php_Attribute_TAL_Content
+{
+ public function before(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ $escape = true;
+ $this->_echoType = PHPTAL_Php_Attribute::ECHO_TEXT;
+ if (preg_match('/^(text|structure)(?:\s+(.*)|\s*$)/', $this->expression, $m)) {
+ if ($m[1]=='structure') { $escape=false; $this->_echoType = PHPTAL_Php_Attribute::ECHO_STRUCTURE; }
+ $this->expression = isset($m[2])?$m[2]:'';
+ }
+
+ $this->_prepareNames($codewriter, $this->phpelement);
+
+ // if no expression is given, the content of the node is used as
+ // a translation key
+ if (strlen(trim($this->expression)) == 0) {
+ $key = $this->_getTranslationKey($this->phpelement, !$escape, $codewriter->getEncoding());
+ $key = trim(preg_replace('/\s+/sm'.($codewriter->getEncoding()=='UTF-8'?'u':''), ' ', $key));
+ if ('' === trim($key)) {
+ throw new PHPTAL_TemplateException("Empty translation key",
+ $this->phpelement->getSourceFile(), $this->phpelement->getSourceLine());
+ }
+ $code = $codewriter->str($key);
+ } else {
+ $code = $codewriter->evaluateExpression($this->expression);
+ if (is_array($code))
+ return $this->generateChainedContent($codewriter, $code);
+
+ $code = $codewriter->evaluateExpression($this->expression);
+ }
+
+ $codewriter->pushCode('echo '.$codewriter->getTranslatorReference().'->translate('.$code.','.($escape ? 'true':'false').');');
+ }
+
+ public function after(PHPTAL_Php_CodeWriter $codewriter)
+ {
+ }
+
+ public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
+ {
+ $codewriter = $executor->getCodeWriter();
+
+ $escape = !($this->_echoType == PHPTAL_Php_Attribute::ECHO_STRUCTURE);
+ $exp = $codewriter->getTranslatorReference()."->translate($exp, " . ($escape ? 'true':'false') . ')';
+ if (!$islast) {
+ $var = $codewriter->createTempVariable();
+ $executor->doIf('!phptal_isempty('.$var.' = '.$exp.')');
+ $codewriter->pushCode("echo $var");
+ $codewriter->recycleTempVariable($var);
+ } else {
+ $executor->doElse();
+ $codewriter->pushCode("echo $exp");
+ }
+ }
+
+ private function _getTranslationKey(PHPTAL_Dom_Node $tag, $preserve_tags, $encoding)
+ {
+ $result = '';
+ foreach ($tag->childNodes as $child) {
+ if ($child instanceof PHPTAL_Dom_Text) {
+ if ($preserve_tags) {
+ $result .= $child->getValueEscaped();
+ } else {
+ $result .= $child->getValue($encoding);
+ }
+ } elseif ($child instanceof PHPTAL_Dom_Element) {
+ if ($attr = $child->getAttributeNodeNS('http://xml.zope.org/namespaces/i18n', 'name')) {
+ $result .= '${' . $attr->getValue() . '}';
+ } else {
+
+ if ($preserve_tags) {
+ $result .= '<'.$child->getQualifiedName();
+ foreach ($child->getAttributeNodes() as $attr) {
+ if ($attr->getReplacedState() === PHPTAL_Dom_Attr::HIDDEN) continue;
+
+ $result .= ' '.$attr->getQualifiedName().'="'.$attr->getValueEscaped().'"';
+ }
+ $result .= '>'.$this->_getTranslationKey($child, $preserve_tags, $encoding) . '</'.$child->getQualifiedName().'>';
+ } else {
+ $result .= $this->_getTranslationKey($child, $preserve_tags, $encoding);
+ }
+ }
+ }
+ }
+ return $result;
+ }
+
+ private function _prepareNames(PHPTAL_Php_CodeWriter $codewriter, PHPTAL_Dom_Node $tag)
+ {
+ foreach ($tag->childNodes as $child) {
+ if ($child instanceof PHPTAL_Dom_Element) {
+ if ($child->hasAttributeNS('http://xml.zope.org/namespaces/i18n', 'name')) {
+ $child->generateCode($codewriter);
+ } else {
+ $this->_prepareNames($codewriter, $child);
+ }
+ }
+ }
+ }
+}
+