/Translation/src/translation.php

https://github.com/F5/zetacomponents · PHP · 214 lines · 69 code · 6 blank · 139 comment · 8 complexity · b903ffd10948dcfbece16a2885f10d40 MD5 · raw file

  1. <?php
  2. /**
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one
  5. * or more contributor license agreements. See the NOTICE file
  6. * distributed with this work for additional information
  7. * regarding copyright ownership. The ASF licenses this file
  8. * to you under the Apache License, Version 2.0 (the
  9. * "License"); you may not use this file except in compliance
  10. * with the License. You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing,
  15. * software distributed under the License is distributed on an
  16. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17. * KIND, either express or implied. See the License for the
  18. * specific language governing permissions and limitations
  19. * under the License.
  20. *
  21. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  22. * @version //autogentag//
  23. * @filesource
  24. * @package Translation
  25. */
  26. /**
  27. * ezcTranslation is a container that holds the translated strings for a
  28. * specific context.
  29. *
  30. * ezcTranslation objects are returned by the ezcTranslationManager for every
  31. * requested context.
  32. *
  33. * For an example see {@link ezcTranslationManager}.
  34. *
  35. * @package Translation
  36. * @version //autogentag//
  37. * @mainclass
  38. */
  39. class ezcTranslation
  40. {
  41. /**
  42. * Contains an array where the key is the original string (often
  43. * English) and the element is an object of the class
  44. * ezcTranslationData (a struct).
  45. *
  46. * @var array(string=>ezcTranslationData)
  47. */
  48. private $translationMap;
  49. /**
  50. * Constructs the ezcTranslation object.
  51. *
  52. * The constructor receives an array containing the translation elements,
  53. * and builds up an internal map between the original string and the
  54. * accompanying translation data.
  55. *
  56. * @param array(ezcTranslationData) $data
  57. */
  58. function __construct( array $data )
  59. {
  60. $this->translationMap = array();
  61. foreach ( $data as $translationElement )
  62. {
  63. $this->translationMap[$translationElement->original] = $translationElement;
  64. }
  65. }
  66. /**
  67. * Returns the replacement for the key $key from the parameters $params.
  68. *
  69. * The params array is an associative array in the form array('key'=>'value').
  70. *
  71. * This is a callback function used by the getTranslation() method for each
  72. * matched parameter in the translated string.
  73. *
  74. * @param string $key
  75. * @param array $params
  76. * @return string
  77. */
  78. private function parameterCallback( $key, array $params )
  79. {
  80. if ( !isset( $params[strtolower( $key )] ) )
  81. {
  82. throw new ezcTranslationParameterMissingException( $key );
  83. }
  84. $string = $params[strtolower( $key )];
  85. // We use ctype_upper() here to check if the first character of the key
  86. // is an uppercase letter. If it is then we make the first character of
  87. // the returned translation also an upper case character. With this
  88. // mechanism we can correctly upper case translated strings if word
  89. // order changes. See
  90. // {@link ezcTranslationTest::testGetStringWithParameters} for an
  91. // example of this.
  92. if ( ctype_upper( $key[0] ) )
  93. {
  94. $string = ucfirst( $string );
  95. }
  96. return $string;
  97. }
  98. /**
  99. * Returns the translated version of the original string $key.
  100. *
  101. * This method returns a translated string and substitutes the parameters $param
  102. * in the localized string.
  103. *
  104. * @throws ezcTranslationKeyNotAvailableException when the key is not
  105. * available in the translation definitions
  106. * @throws ezcTranslationParameterMissingException when not enough
  107. * parameters are passed for a parameterized string
  108. * @param string $key
  109. * @param array(string=>string) $params
  110. * @return string
  111. */
  112. public function getTranslation( $key, array $params = array() )
  113. {
  114. if ( !isset( $this->translationMap[$key] ) )
  115. {
  116. throw new ezcTranslationKeyNotAvailableException( $key );
  117. }
  118. $translatedString = $this->translationMap[$key]->translation;
  119. // Little optimization to prevent preg if not needed, it bails out too
  120. // if there is just a percent sign in the string without a valid
  121. // parameter-identifier, but we can live with that.
  122. if ( strstr( $translatedString, '%' ) === false )
  123. {
  124. return $translatedString;
  125. }
  126. // So we do have a possibility of a parameterized string, replace those
  127. // with the parameters. The callback function can actually throw an
  128. // exception to tell that there was a missing parameter.
  129. return (string) preg_replace( '@%(([A-Za-z][a-z_]*[a-z])|[1-9])@e', '$this->parameterCallback("\\1", $params)', $translatedString );
  130. }
  131. /**
  132. * Returns the replacement for the key $key from the parameters $params.
  133. *
  134. * The params array is an associative array in the form array('key'=>'value').
  135. *
  136. * This is a callback function used by the compileTranslation() method for each
  137. * matched parameter in the translated string.
  138. *
  139. * @param string $key
  140. * @param array $params
  141. * @return string
  142. */
  143. private function parameterCallbackCompile( $key, array $params )
  144. {
  145. if ( !isset( $params[strtolower( $key )] ) )
  146. {
  147. throw new ezcTranslationParameterMissingException( $key );
  148. }
  149. // We use ctype_upper() here to check if the first character of the key
  150. // is an uppercase letter. If it is then we make the first character of
  151. // the returned translation also an upper case character. With this
  152. // mechanism we can correctly upper case translated strings if word
  153. // order changes. See
  154. // {@link ezcTranslationTest::testGetStringWithParameters} for an
  155. // example of this.
  156. if ( ctype_upper( $key[0] ) )
  157. {
  158. $string = "' . ucfirst(". $params[strtolower( $key )] . ") . '";
  159. }
  160. else
  161. {
  162. $string = "' . ". $params[strtolower( $key )] . " . '";
  163. }
  164. return $string;
  165. }
  166. /**
  167. * Returns the translated version of the original string $key.
  168. *
  169. * This method returns a translated string and substitutes the parameters $param
  170. * in the localized string with PHP code to place the variable data into
  171. * the string at a later moment. Instead of the values for each of the
  172. * parameters, an expression to get to the data should be sumbitted into
  173. * the $params array.
  174. *
  175. * <code>
  176. * echo $translation->compileTranslation( "Hello #%nr", array( "nr" => '$this->send->nr' ) );
  177. * </code>
  178. *
  179. * Will return something like:
  180. * <code>
  181. * 'Hallo #' . $this->send->nr . ''
  182. * </code>
  183. *
  184. * @param string $key
  185. * @param array(string=>string) $params
  186. * @return string
  187. */
  188. public function compileTranslation( $key, array $params = array() )
  189. {
  190. if ( !isset( $this->translationMap[$key] ) )
  191. {
  192. throw new ezcTranslationKeyNotAvailableException( $key );
  193. }
  194. $translatedString = var_export( $this->translationMap[$key]->translation, true );
  195. // Little optimization to prevent preg if not needed, it bails out too
  196. // if there is just a percent sign in the string without a valid
  197. // parameter-identifier, but we can live with that.
  198. if ( strstr( $translatedString, '%' ) === false )
  199. {
  200. return $translatedString;
  201. }
  202. // So we do have a possibility of a parameterized string, replace those
  203. // with the parameters. The callback function can actually throw an
  204. // exception to tell that there was a missing parameter.
  205. return (string) preg_replace( '@%(([A-Za-z][a-z_]*[a-z])|[1-9])@e', '$this->parameterCallbackCompile("\\1", $params)', $translatedString );
  206. }
  207. }
  208. ?>