PageRenderTime 36ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Classes/TYPO3/FLOW3/I18n/Xliff/XliffModel.php

https://github.com/christianjul/FLOW3-Composer
PHP | 171 lines | 61 code | 21 blank | 89 comment | 9 complexity | 047cc987b0c0b3a070a1da46d4c8cd72 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  1. <?php
  2. namespace TYPO3\FLOW3\I18n\Xliff;
  3. /* *
  4. * This script belongs to the FLOW3 framework. *
  5. * *
  6. * It is free software; you can redistribute it and/or modify it under *
  7. * the terms of the GNU Lesser General Public License, either version 3 *
  8. * of the License, or (at your option) any later version. *
  9. * *
  10. * The TYPO3 project - inspiring people to share! *
  11. * */
  12. use \TYPO3\FLOW3\Annotations as FLOW3;
  13. /**
  14. * A model representing data from one XLIFF file.
  15. *
  16. * Please note that plural forms for particular translation unit are accessed
  17. * with integer index (and not string like 'zero', 'one', 'many' etc). This is
  18. * because they are indexed such way in XLIFF files in order to not break tools'
  19. * support.
  20. *
  21. * There are very few XLIFF editors, but they are nice Gettext's .po editors
  22. * available. Gettext supports plural forms, but it indexes them using integer
  23. * numbers. Leaving it this way in .xlf files, makes it possible to easily convert
  24. * them to .po (e.g. using xliff2po from Translation Toolkit), edit with Poedit,
  25. * and convert back to .xlf without any information loss (using po2xliff).
  26. *
  27. * @see http://docs.oasis-open.org/xliff/v1.2/xliff-profile-po/xliff-profile-po-1.2-cd02.html#s.detailed_mapping.tu
  28. */
  29. class XliffModel {
  30. /**
  31. * @var \TYPO3\FLOW3\Cache\Frontend\VariableFrontend
  32. */
  33. protected $cache;
  34. /**
  35. * Concrete XML parser which is set by more specific model extending this
  36. * class.
  37. *
  38. * @var \TYPO3\FLOW3\I18n\Xliff\XliffParser
  39. */
  40. protected $xmlParser;
  41. /**
  42. * Absolute path to the file which is represented by this class instance.
  43. *
  44. * @var string
  45. */
  46. protected $sourcePath;
  47. /**
  48. * @var \TYPO3\FLOW3\I18n\Locale
  49. */
  50. protected $locale;
  51. /**
  52. * @FLOW3\Inject
  53. * @var \TYPO3\FLOW3\Log\SystemLoggerInterface
  54. */
  55. protected $systemLogger;
  56. /**
  57. * Parsed data (structure depends on concrete model).
  58. *
  59. * @var array
  60. */
  61. protected $xmlParsedData;
  62. /**
  63. * @param string $sourcePath
  64. * @param \TYPO3\FLOW3\I18n\Locale $locale The locale represented by the file
  65. */
  66. public function __construct($sourcePath, \TYPO3\FLOW3\I18n\Locale $locale) {
  67. $this->sourcePath = $sourcePath;
  68. $this->locale = $locale;
  69. }
  70. /**
  71. * Injects the FLOW3_I18n_XmlModelCache cache
  72. *
  73. * @param \TYPO3\FLOW3\Cache\Frontend\VariableFrontend $cache
  74. * @return void
  75. */
  76. public function injectCache(\TYPO3\FLOW3\Cache\Frontend\VariableFrontend $cache) {
  77. $this->cache = $cache;
  78. }
  79. /**
  80. * @param \TYPO3\FLOW3\I18n\Xliff\XliffParser $parser
  81. * @return void
  82. */
  83. public function injectParser(\TYPO3\FLOW3\I18n\Xliff\XliffParser $parser) {
  84. $this->xmlParser = $parser;
  85. }
  86. /**
  87. * When it's called, XML file is parsed (using parser set in $xmlParser)
  88. * or cache is loaded, if available.
  89. *
  90. * @return void
  91. */
  92. public function initializeObject() {
  93. if ($this->cache->has(md5($this->sourcePath))) {
  94. $this->xmlParsedData = $this->cache->get(md5($this->sourcePath));
  95. } else {
  96. $this->xmlParsedData = $this->xmlParser->getParsedData($this->sourcePath);
  97. $this->cache->set(md5($this->sourcePath), $this->xmlParsedData);
  98. }
  99. }
  100. /**
  101. * Returns translated label ("target" tag in XLIFF) from source-target
  102. * pair where "source" tag equals to $source parameter.
  103. *
  104. * @param string $source Label in original language ("source" tag in XLIFF)
  105. * @param integer $pluralFormIndex Index of plural form to use (starts with 0)
  106. * @return mixed Translated label or FALSE on failure
  107. */
  108. public function getTargetBySource($source, $pluralFormIndex = 0) {
  109. foreach ($this->xmlParsedData['translationUnits'] as $translationUnit) {
  110. // $source is always singular (or only) form, so compare with index 0
  111. if (!isset($translationUnit[0]) || $translationUnit[0]['source'] !== $source) {
  112. continue;
  113. }
  114. if (count($translationUnit) <= $pluralFormIndex) {
  115. $this->systemLogger->log('The plural form index "' . $pluralFormIndex . '" for the source translation "' . $source . '" in ' . $this->sourcePath . ' is not available.', LOG_WARNING);
  116. return FALSE;
  117. }
  118. return $translationUnit[$pluralFormIndex]['target'] ?: FALSE;
  119. }
  120. return FALSE;
  121. }
  122. /**
  123. * Returns translated label ("target" tag in XLIFF) for the id given.
  124. * Id is compared with "id" attribute of "trans-unit" tag (see XLIFF
  125. * specification for details).
  126. *
  127. * @param string $transUnitId The "id" attribute of "trans-unit" tag in XLIFF
  128. * @param integer $pluralFormIndex Index of plural form to use (starts with 0)
  129. * @return mixed Translated label or FALSE on failure
  130. */
  131. public function getTargetByTransUnitId($transUnitId, $pluralFormIndex = 0) {
  132. if (!isset($this->xmlParsedData['translationUnits'][$transUnitId])) {
  133. $this->systemLogger->log('No trans-unit element with the id "' . $transUnitId . '" was found in ' . $this->sourcePath . '. Either this translation has been removed or the id in the code or template referring to the translation is wrong.', LOG_WARNING);
  134. return FALSE;
  135. }
  136. if (!isset($this->xmlParsedData['translationUnits'][$transUnitId][$pluralFormIndex])) {
  137. $this->systemLogger->log('The plural form index "' . $pluralFormIndex . '" for the trans-unit element with the id "' . $transUnitId . '" in ' . $this->sourcePath . ' is not available.', LOG_WARNING);
  138. return FALSE;
  139. }
  140. if ($this->xmlParsedData['translationUnits'][$transUnitId][$pluralFormIndex]['target']) {
  141. return $this->xmlParsedData['translationUnits'][$transUnitId][$pluralFormIndex]['target'];
  142. } elseif ($this->locale->getLanguage() === $this->xmlParsedData['sourceLocale']->getLanguage()) {
  143. return $this->xmlParsedData['translationUnits'][$transUnitId][$pluralFormIndex]['source'] ?: FALSE;
  144. } else {
  145. $this->systemLogger->log('The target translation was empty and the source translation language (' . $this->xmlParsedData['sourceLocale']->getLanguage() . ') does not match the current locale (' . $this->locale->getLanguage() . ') for the trans-unit element with the id "' . $transUnitId . '" in ' . $this->sourcePath, LOG_WARNING);
  146. return FALSE;
  147. }
  148. }
  149. }
  150. ?>