cvs: pear /I18N/Messages Translate.php
| From: | Wolfram Kriesing | Date: | Wed, 15 Jan 2003 14:51:41 +0000 |
| Subject: | cvs: pear /I18N/Messages Translate.php | ||
| Groups: | php.pear.cvs | ||
| Request: | Send a blank email to pear-cvs+get-8274@lists.php.net to get a copy of this message | ||
cain Wed Jan 15 09:51:41 2003 EDT
Modified files:
/pear/I18N/Messages Translate.php
Log:
- added option 'caseSensitive'
- enhance the possibleDelimiters
Index: pear/I18N/Messages/Translate.php diff -u pear/I18N/Messages/Translate.php:1.11 pear/I18N/Messages/Translate.php:1.12 --- pear/I18N/Messages/Translate.php:1.11 Sat Jan 4 06:55:28 2003 +++ pear/I18N/Messages/Translate.php Wed Jan 15 09:51:41 2003 @@ -16,7 +16,7 @@ // | Authors: Wolfram Kriesing <wolfram@kriesing.de> | // +----------------------------------------------------------------------+ // -// $Id: Translate.php,v 1.11 2003/01/04 11:55:28 mj Exp $ +// $Id: Translate.php,v 1.12 2003/01/15 14:51:41 cain Exp $ // we have to move this to some more common place in PEAR // this is just a quick hack here :-) @@ -33,16 +33,20 @@ class I18N_Messages_Translate extends Tree_OptionsDB { - var $options = array( 'tablePrefix' => 'translate_', // the DB-table name prefix, at the end we add the lang-string passed to the method - 'sourceLanguage'=> 'en', // the source language, the language used to retrieve the strings to translate from + var $options = array( 'tablePrefix' => 'translate_' // the DB-table name prefix, at the end we add the lang-string passed to the method + ,'sourceLanguage'=> 'en' // the source language, the language used to retrieve the strings to translate from // its also the table which is used to retreive the source string - 'translatorUrl' => '' // the url to a translator tool, only used if given + + // be case senstivie by default since not all languages write nouns and verbs etc. + // in lower case translating from german might fail if the case is not considered + ,'caseSensitive'=> true + + ,'translatorUrl' => '' // the url to a translator tool, only used if given ); /** - * those are the delimiters that are used to look for text to translate inside - * only text within those delimiters is translated - * this way we prevent from translating each HTML-tag, which definetly wouldnt work :-) + * Those are the delimiters surrounding translatable text. + * This way we prevent from translating each HTML-tag, which definetly wouldnt work :-) * those delimiters might also work on any other markup language, like xml - but not tested * * NOTE: if you have php inside such a tag then you have to use an extra filter @@ -56,25 +60,42 @@ */ var $possibleMarkUpDelimiters = array( // cant use this - // '>[^<]*' => '[^>]*<', // this mostly applies, that a text is inbetween '>' and '<' - // because it would translate 'class="..."' to off we have 'as' to be translated :-( + // '>[^<]*' ,'[^>]*<', // this mostly applies, that a text is inbetween '>' and '<' + // because it would translate 'class="..."' too, if we have the word 'as' to be translated :-( // but this also means we have to handle stuff like of others specials chars, that dont start // and end with a < or > somehow ... i dont know how yet :-( - + // this mostly applies, that a text is inbetween '>' and '<' - '>\s*' => '\s*<' + array('>\s*', '\s*<') - // same as above, + // same as above, // only that this leaves before and after the text outside html-tags as they are ... - // + // // actually we need a more common thing here, which also takes care of other chars which // we dont want to bother the translation with - ,'>[\s* ]*' => '[\s* ]*<' - + // ,array('>[\s* ]*', '[\s* ]*<') + //the above is not really secure, since [] means any char inside + // so '>nbsp translate this<' would be translated too + + + // this is for input button's values +//FIXXXME this fails if the order of type and value attrbs is switched :-( + ,array('<input type=["\']?(submit|button)["\']? [^>]*value=["\']?\s*' , '\s*["\']?[^>]*>' , 1) +// ,array('<\s*input .*type=submit .*value=["\']?\s*','\s*["\']?.*>') +// array('<\s*input.*type=[\'"]?(button|submit)[\'"]?.*value=["\']?\s*','\s*["\']?.*>',1) +// ,array('<\s*input.*value=["\']?\s*','\s*["\']?.*>') + +// all the reg-exps here are limited, the ones below would work perfect on: +// <a title="translate this" ...> or <img alt="translate this" ....> +// but with the following they would have problems: +// <a href="< ?php echo §foor ? >" title="translate this"> +// since there is a < before the title-attribute, and if we build the regexp +// with .* instead of [^>]* before the attribute it might return ambigious results - // this is for input button's values - ,'<\s*input .*value=["\']?\s*' => '\s*["\']?.*>' +// SOLUTION for now: put the attrbutes you want translated first inside the tag, like in the example above + ,array('<img [^>]*alt=["\']?\s*' , '\s*["\']?.*>') + ,array('<a [^>]*title=["\']?\s*' , '\s*["\']?.*>') ); /** @@ -276,6 +297,8 @@ } $this->getAll( $lang ); // get all the possible strings from the DB + + $addModifier = $this->getOption('caseSensitive') ? '' : 'i'; // FIXXME replace all spaces by something like this: (\s*|<br>|<br/>|<font.*>|</font>|<i>|</i>|<b>|</b>| ) // simply all those formatting tags which dont really cancel the phrase that should be translated @@ -291,13 +314,13 @@ if(is_array($this->_translated['strings']) && sizeof($this->_translated['strings'])) foreach( $this->_translated['strings'] as $aString ) // search for each single string and try to translate it { - $lastSubpattern = '$2'; + $lastSubpattern = 2; // we use 2 strings that we search for, one is the real text as from the db // the second $htmlSourceString is the source string but with all non html characters // translated using htmlentities, in case someone has been programming proper html :-) // shall the translated string be converted to HTML, or does it may be contain HTML? - if( $aString['convertToHtml'] ) + if( $aString['convertToHtml'] ) $translated = htmlentities($aString['translated']); else $translated = $aString['translated']; @@ -310,31 +333,31 @@ $sourceString = $aString['string']; $htmlSourceString = htmlentities($aString['string']);// we should not preg_quote the string - $lastSubpattern = '$'.( 2 + $aString['numSubPattern'] ); // set $lastSubpattern properly + $lastSubpattern = 2 + $aString['numSubPattern']; // set $lastSubpattern properly - // in the DB the spaceholders start with $1, but here we need it - // to start with $2, that's what the following does - preg_match_all ( '/\$(\d)/' , $translated , $res ); - $res[0] = array_reverse($res[0]); // reverse the arrays, since we replace $1 by $2 and then $2 by $3 ... - $res[1] = array_reverse($res[1]); // ... if we wouldnt reverse all would become $<lastNumber> - foreach( $res[0] as $index=>$aRes ) - { - $aRes = preg_quote($aRes); - $translated = preg_replace( '/'.$aRes.'/' , '\$'.($res[1][$index]+1) , $translated ); + // in the DB the spaceholders start with $1, but here we need it + // to start with $2, that's what the following does + preg_match_all ( '/\$(\d)/' , $translated , $res ); + $res[0] = array_reverse($res[0]); // reverse the arrays, since we replace $1 by $2 and then $2 by $3 ... + $res[1] = array_reverse($res[1]); // ... if we wouldnt reverse all would become $<lastNumber> + foreach( $res[0] as $index=>$aRes ) + { + $aRes = preg_quote($aRes); + $translated = preg_replace( '/'.$aRes.'/' , '\$'.($res[1][$index]+1) , $translated ); } } else { - // in none regExp's source strings we better quote the chars which could be - // mistakenly seen as regExp chars - $sourceString = preg_quote(trim($aString['string'])); - $htmlSourceString = preg_quote(htmlentities(trim($aString['string']))); - // escape all slashes, since preg_quote doenst do that :-( - $sourceString = str_replace('/','\/',$sourceString); - $htmlSourceString = str_replace('/','\/',$htmlSourceString); + // in none regExp's source strings we better quote the chars which could be + // mistakenly seen as regExp chars + $sourceString = preg_quote(trim($aString['string'])); + $htmlSourceString = preg_quote(htmlentities(trim($aString['string']))); + // escape all slashes, since preg_quote doenst do that :-( + $sourceString = str_replace('/','\/',$sourceString); + $htmlSourceString = str_replace('/','\/',$htmlSourceString); } - foreach( $this->possibleMarkUpDelimiters as $begin=>$end ) // go thru all the delimiters and try to translate the strings + foreach( $this->possibleMarkUpDelimiters as $delimiters ) // go thru all the delimiters and try to translate the strings { // FIXXME there might be a major problem: // <td @@ -345,27 +368,34 @@ // class="naviItem" // nowrap> // -// +// + $numSubPatterns = array(0,0); + $begin = $delimiters[0]; + $end = $delimiters[1]; + if( $delimiters[2] ) $numSubPatterns[0] = $delimiters[2]; + if( $delimiters[3] ) $numSubPatterns[1] = $delimiters[3]; + // replace all spaces in the source string by \s* so that there can be spaces // as many as one wants // and even newlines (the modifier s in the preg_replace takes care of that) $sourceString = preg_replace('/\s+/','\\s*',$sourceString); $htmlSourceString = preg_replace('/\s+/s','\\s*',$htmlSourceString); - $_hashCode = md5($input); - $input = preg_replace( '/('.$begin.')'.$sourceString.'('.$end.')/s' , - '$1'.$translated."$lastSubpattern" , + $_hashCode = md5($input); + + $input = preg_replace( '/('.$begin.')'.$sourceString.'('.$end.')/sU'.$addModifier , + '$1'.$translated.'$'.($lastSubpattern+$numSubPatterns[0]) , $input ); // if the regExp above didnt have no effect try this one with all html characters translated - // if we wouldnt check this i had the effect that something was translated twice ... + // if we wouldnt check this i had the effect that something was translated twice ... // dont know exactly why but it did :-) if( $_hashCode == md5($input) ) { // try also to translate the string with all non-HTML-characters translated using htmlentities // may be someone was creating proper html :-) - $input = preg_replace( '/('.$begin.')'.$htmlSourceString.'('.$end.')/i' , - '$1'.$translated."$lastSubpattern" , + $input = preg_replace( '/('.$begin.')'.$htmlSourceString.'('.$end.')/sU'.$addModifier , + '$1'.$translated.'$'.($lastSubpattern+$numSubPatterns[0]) , $input ); }
Index: pear/I18N/Messages/Translate.php diff -u pear/I18N/Messages/Translate.php:1.11 pear/I18N/Messages/Translate.php:1.12 --- pear/I18N/Messages/Translate.php:1.11 Sat Jan 4 06:55:28 2003 +++ pear/I18N/Messages/Translate.php Wed Jan 15 09:51:41 2003 @@ -16,7 +16,7 @@ // | Authors: Wolfram Kriesing <wolfram@kriesing.de> | // +----------------------------------------------------------------------+ // -// $Id: Translate.php,v 1.11 2003/01/04 11:55:28 mj Exp $ +// $Id: Translate.php,v 1.12 2003/01/15 14:51:41 cain Exp $ // we have to move this to some more common place in PEAR // this is just a quick hack here :-) @@ -33,16 +33,20 @@ class I18N_Messages_Translate extends Tree_OptionsDB { - var $options = array( 'tablePrefix' => 'translate_', // the DB-table name prefix, at the end we add the lang-string passed to the method - 'sourceLanguage'=> 'en', // the source language, the language used to retrieve the strings to translate from + var $options = array( 'tablePrefix' => 'translate_' // the DB-table name prefix, at the end we add the lang-string passed to the method + ,'sourceLanguage'=> 'en' // the source language, the language used to retrieve the strings to translate from // its also the table which is used to retreive the source string - 'translatorUrl' => '' // the url to a translator tool, only used if given + + // be case senstivie by default since not all languages write nouns and verbs etc. + // in lower case translating from german might fail if the case is not considered + ,'caseSensitive'=> true + + ,'translatorUrl' => '' // the url to a translator tool, only used if given ); /** - * those are the delimiters that are used to look for text to translate inside - * only text within those delimiters is translated - * this way we prevent from translating each HTML-tag, which definetly wouldnt work :-) + * Those are the delimiters surrounding translatable text. + * This way we prevent from translating each HTML-tag, which definetly wouldnt work :-) * those delimiters might also work on any other markup language, like xml - but not tested * * NOTE: if you have php inside such a tag then you have to use an extra filter @@ -56,25 +60,42 @@ */ var $possibleMarkUpDelimiters = array( // cant use this - // '>[^<]*' => '[^>]*<', // this mostly applies, that a text is inbetween '>' and '<' - // because it would translate 'class="..."' to off we have 'as' to be translated :-( + // '>[^<]*' ,'[^>]*<', // this mostly applies, that a text is inbetween '>' and '<' + // because it would translate 'class="..."' too, if we have the word 'as' to be translated :-( // but this also means we have to handle stuff like of others specials chars, that dont start // and end with a < or > somehow ... i dont know how yet :-( - + // this mostly applies, that a text is inbetween '>' and '<' - '>\s*' => '\s*<' + array('>\s*', '\s*<') - // same as above, + // same as above, // only that this leaves before and after the text outside html-tags as they are ... - // + // // actually we need a more common thing here, which also takes care of other chars which // we dont want to bother the translation with - ,'>[\s* ]*' => '[\s* ]*<' - + // ,array('>[\s* ]*', '[\s* ]*<') + //the above is not really secure, since [] means any char inside + // so '>nbsp translate this<' would be translated too + + + // this is for input button's values +//FIXXXME this fails if the order of type and value attrbs is switched :-( + ,array('<input type=["\']?(submit|button)["\']? [^>]*value=["\']?\s*' , '\s*["\']?[^>]*>' , 1) +// ,array('<\s*input .*type=submit .*value=["\']?\s*','\s*["\']?.*>') +// array('<\s*input.*type=[\'"]?(button|submit)[\'"]?.*value=["\']?\s*','\s*["\']?.*>',1) +// ,array('<\s*input.*value=["\']?\s*','\s*["\']?.*>') + +// all the reg-exps here are limited, the ones below would work perfect on: +// <a title="translate this" ...> or <img alt="translate this" ....> +// but with the following they would have problems: +// <a href="< ?php echo §foor ? >" title="translate this"> +// since there is a < before the title-attribute, and if we build the regexp +// with .* instead of [^>]* before the attribute it might return ambigious results - // this is for input button's values - ,'<\s*input .*value=["\']?\s*' => '\s*["\']?.*>' +// SOLUTION for now: put the attrbutes you want translated first inside the tag, like in the example above + ,array('<img [^>]*alt=["\']?\s*' , '\s*["\']?.*>') + ,array('<a [^>]*title=["\']?\s*' , '\s*["\']?.*>') ); /** @@ -276,6 +297,8 @@ } $this->getAll( $lang ); // get all the possible strings from the DB + + $addModifier = $this->getOption('caseSensitive') ? '' : 'i'; // FIXXME replace all spaces by something like this: (\s*|<br>|<br/>|<font.*>|</font>|<i>|</i>|<b>|</b>| ) // simply all those formatting tags which dont really cancel the phrase that should be translated @@ -291,13 +314,13 @@ if(is_array($this->_translated['strings']) && sizeof($this->_translated['strings'])) foreach( $this->_translated['strings'] as $aString ) // search for each single string and try to translate it { - $lastSubpattern = '$2'; + $lastSubpattern = 2; // we use 2 strings that we search for, one is the real text as from the db // the second $htmlSourceString is the source string but with all non html characters // translated using htmlentities, in case someone has been programming proper html :-) // shall the translated string be converted to HTML, or does it may be contain HTML? - if( $aString['convertToHtml'] ) + if( $aString['convertToHtml'] ) $translated = htmlentities($aString['translated']); else $translated = $aString['translated']; @@ -310,31 +333,31 @@ $sourceString = $aString['string']; $htmlSourceString = htmlentities($aString['string']);// we should not preg_quote the string - $lastSubpattern = '$'.( 2 + $aString['numSubPattern'] ); // set $lastSubpattern properly + $lastSubpattern = 2 + $aString['numSubPattern']; // set $lastSubpattern properly - // in the DB the spaceholders start with $1, but here we need it - // to start with $2, that's what the following does - preg_match_all ( '/\$(\d)/' , $translated , $res ); - $res[0] = array_reverse($res[0]); // reverse the arrays, since we replace $1 by $2 and then $2 by $3 ... - $res[1] = array_reverse($res[1]); // ... if we wouldnt reverse all would become $<lastNumber> - foreach( $res[0] as $index=>$aRes ) - { - $aRes = preg_quote($aRes); - $translated = preg_replace( '/'.$aRes.'/' , '\$'.($res[1][$index]+1) , $translated ); + // in the DB the spaceholders start with $1, but here we need it + // to start with $2, that's what the following does + preg_match_all ( '/\$(\d)/' , $translated , $res ); + $res[0] = array_reverse($res[0]); // reverse the arrays, since we replace $1 by $2 and then $2 by $3 ... + $res[1] = array_reverse($res[1]); // ... if we wouldnt reverse all would become $<lastNumber> + foreach( $res[0] as $index=>$aRes ) + { + $aRes = preg_quote($aRes); + $translated = preg_replace( '/'.$aRes.'/' , '\$'.($res[1][$index]+1) , $translated ); } } else { - // in none regExp's source strings we better quote the chars which could be - // mistakenly seen as regExp chars - $sourceString = preg_quote(trim($aString['string'])); - $htmlSourceString = preg_quote(htmlentities(trim($aString['string']))); - // escape all slashes, since preg_quote doenst do that :-( - $sourceString = str_replace('/','\/',$sourceString); - $htmlSourceString = str_replace('/','\/',$htmlSourceString); + // in none regExp's source strings we better quote the chars which could be + // mistakenly seen as regExp chars + $sourceString = preg_quote(trim($aString['string'])); + $htmlSourceString = preg_quote(htmlentities(trim($aString['string']))); + // escape all slashes, since preg_quote doenst do that :-( + $sourceString = str_replace('/','\/',$sourceString); + $htmlSourceString = str_replace('/','\/',$htmlSourceString); } - foreach( $this->possibleMarkUpDelimiters as $begin=>$end ) // go thru all the delimiters and try to translate the strings + foreach( $this->possibleMarkUpDelimiters as $delimiters ) // go thru all the delimiters and try to translate the strings { // FIXXME there might be a major problem: // <td @@ -345,27 +368,34 @@ // class="naviItem" // nowrap> // -// +// + $numSubPatterns = array(0,0); + $begin = $delimiters[0]; + $end = $delimiters[1]; + if( $delimiters[2] ) $numSubPatterns[0] = $delimiters[2]; + if( $delimiters[3] ) $numSubPatterns[1] = $delimiters[3]; + // replace all spaces in the source string by \s* so that there can be spaces // as many as one wants // and even newlines (the modifier s in the preg_replace takes care of that) $sourceString = preg_replace('/\s+/','\\s*',$sourceString); $htmlSourceString = preg_replace('/\s+/s','\\s*',$htmlSourceString); - $_hashCode = md5($input); - $input = preg_replace( '/('.$begin.')'.$sourceString.'('.$end.')/s' , - '$1'.$translated."$lastSubpattern" , + $_hashCode = md5($input); + + $input = preg_replace( '/('.$begin.')'.$sourceString.'('.$end.')/sU'.$addModifier , + '$1'.$translated.'$'.($lastSubpattern+$numSubPatterns[0]) , $input ); // if the regExp above didnt have no effect try this one with all html characters translated - // if we wouldnt check this i had the effect that something was translated twice ... + // if we wouldnt check this i had the effect that something was translated twice ... // dont know exactly why but it did :-) if( $_hashCode == md5($input) ) { // try also to translate the string with all non-HTML-characters translated using htmlentities // may be someone was creating proper html :-) - $input = preg_replace( '/('.$begin.')'.$htmlSourceString.'('.$end.')/i' , - '$1'.$translated."$lastSubpattern" , + $input = preg_replace( '/('.$begin.')'.$htmlSourceString.'('.$end.')/sU'.$addModifier , + '$1'.$translated.'$'.($lastSubpattern+$numSubPatterns[0]) , $input ); }