I18nData.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <?php
  2. class I18nData {
  3. const REFERENCE_LANGUAGE = 'en';
  4. private $data = array();
  5. private $ignore = array();
  6. public function __construct($data, $ignore) {
  7. $this->data = $data;
  8. $this->ignore = $ignore;
  9. $this->synchonizeKeys();
  10. }
  11. public function getData() {
  12. $output = array();
  13. $reference = $this->getReferenceLanguage();
  14. $languages = $this->getNonReferenceLanguages();
  15. foreach ($reference as $file => $values) {
  16. foreach ($values as $key => $value) {
  17. $output[static::REFERENCE_LANGUAGE][$file][$key] = $value;
  18. foreach ($languages as $language) {
  19. if ($this->data[$language][$file][$key] !== $value) {
  20. // This value is translated, there is no need to flag it.
  21. $output[$language][$file][$key] = $this->data[$language][$file][$key];
  22. } elseif (array_key_exists($language, $this->ignore) && in_array($key, $this->ignore[$language])) {
  23. // This value is ignored, there is no need to flag it.
  24. $output[$language][$file][$key] = $this->data[$language][$file][$key];
  25. } else {
  26. // This value is not translated nor ignored, it must be flagged.
  27. $output[$language][$file][$key] = "{$value} -> todo";
  28. }
  29. }
  30. }
  31. }
  32. return $output;
  33. }
  34. public function getIgnore() {
  35. $ignore = array();
  36. foreach ($this->ignore as $language => $keys) {
  37. sort($keys);
  38. $ignore[$language] = $keys;
  39. }
  40. return $ignore;
  41. }
  42. private function synchonizeKeys() {
  43. $this->addMissingKeysFromReference();
  44. $this->removeExtraKeysFromOtherLanguages();
  45. $this->removeUnknownIgnoreKeys();
  46. }
  47. private function addMissingKeysFromReference() {
  48. $reference = $this->getReferenceLanguage();
  49. $languages = $this->getNonReferenceLanguages();
  50. foreach ($reference as $file => $values) {
  51. foreach ($values as $key => $value) {
  52. foreach ($languages as $language) {
  53. if (!array_key_exists($key, $this->data[$language][$file])) {
  54. $this->data[$language][$file][$key] = $value;
  55. }
  56. }
  57. }
  58. }
  59. }
  60. private function removeExtraKeysFromOtherLanguages() {
  61. $reference = $this->getReferenceLanguage();
  62. foreach ($this->getNonReferenceLanguages() as $language) {
  63. foreach ($this->getLanguage($language) as $file => $values) {
  64. foreach ($values as $key => $value) {
  65. if (!array_key_exists($key, $reference[$file])) {
  66. unset($this->data[$language][$file][$key]);
  67. }
  68. }
  69. }
  70. }
  71. }
  72. private function removeUnknownIgnoreKeys() {
  73. $reference = $this->getReferenceLanguage();
  74. foreach ($this->ignore as $language => $keys) {
  75. foreach ($keys as $index => $key) {
  76. if (!array_key_exists($this->getFilenamePrefix($key), $reference) || !array_key_exists($key, $reference[$this->getFilenamePrefix($key)])) {
  77. unset($this->ignore[$language][$index]);
  78. }
  79. }
  80. }
  81. }
  82. /**
  83. * Return the available languages
  84. *
  85. * @return array
  86. */
  87. public function getAvailableLanguages() {
  88. $languages = array_keys($this->data);
  89. sort($languages);
  90. return $languages;
  91. }
  92. /**
  93. * Return all available languages without the reference language
  94. *
  95. * @return array
  96. */
  97. public function getNonReferenceLanguages() {
  98. return array_filter(array_keys($this->data), function ($value) {
  99. return static::REFERENCE_LANGUAGE !== $value;
  100. });
  101. }
  102. /**
  103. * Add a new language. It's a copy of the reference language.
  104. *
  105. * @param string $language
  106. * @param string $reference
  107. * @throws Exception
  108. */
  109. public function addLanguage($language, $reference = null) {
  110. if (array_key_exists($language, $this->data)) {
  111. throw new Exception('The selected language already exist.');
  112. }
  113. if (!is_string($reference) && !array_key_exists($reference, $this->data)) {
  114. $reference = static::REFERENCE_LANGUAGE;
  115. }
  116. $this->data[$language] = $this->data[$reference];
  117. }
  118. /**
  119. * Check if the key is known.
  120. *
  121. * @param string $key
  122. * @return bool
  123. */
  124. public function isKnown($key) {
  125. return array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) &&
  126. array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)]);
  127. }
  128. /**
  129. * Add a new key to all languages.
  130. *
  131. * @param string $key
  132. * @param string $value
  133. * @throws Exception
  134. */
  135. public function addKey($key, $value) {
  136. if ($this->isKnown($key)) {
  137. throw new Exception('The selected key already exist.');
  138. }
  139. foreach ($this->getAvailableLanguages() as $language) {
  140. if (!array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) {
  141. $this->data[$language][$this->getFilenamePrefix($key)][$key] = $value;
  142. }
  143. }
  144. }
  145. /**
  146. * Add a value for a key for the selected language.
  147. *
  148. * @param string $key
  149. * @param string $value
  150. * @param string $language
  151. * @throws Exception
  152. */
  153. public function addValue($key, $value, $language) {
  154. if (!in_array($language, $this->getAvailableLanguages())) {
  155. throw new Exception('The selected language does not exist.');
  156. }
  157. if (!array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) ||
  158. !array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
  159. throw new Exception('The selected key does not exist for the selected language.');
  160. }
  161. if (static::REFERENCE_LANGUAGE === $language) {
  162. $previousValue = $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key];
  163. foreach ($this->getAvailableLanguages() as $lang) {
  164. if ($this->data[$lang][$this->getFilenamePrefix($key)][$key] === $previousValue) {
  165. $this->data[$lang][$this->getFilenamePrefix($key)][$key] = $value;
  166. }
  167. }
  168. } else {
  169. $this->data[$language][$this->getFilenamePrefix($key)][$key] = $value;
  170. }
  171. }
  172. /**
  173. * Remove a key in all languages
  174. *
  175. * @param string $key
  176. * @throws Exception
  177. */
  178. public function removeKey($key) {
  179. if (!$this->isKnown($key)) {
  180. throw new Exception('The selected key does not exist.');
  181. }
  182. foreach ($this->getAvailableLanguages() as $language) {
  183. if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) {
  184. unset($this->data[$language][$this->getFilenamePrefix($key)][$key]);
  185. }
  186. if (array_key_exists($language, $this->ignore) && $position = array_search($key, $this->ignore[$language])) {
  187. unset($this->ignore[$language][$position]);
  188. }
  189. }
  190. }
  191. /**
  192. * Ignore a key from a language, or reverse it.
  193. *
  194. * @param string $key
  195. * @param string $language
  196. * @param boolean $reverse
  197. */
  198. public function ignore($key, $language, $reverse = false) {
  199. if (!array_key_exists($language, $this->ignore)) {
  200. $this->ignore[$language] = array();
  201. }
  202. $index = array_search($key, $this->ignore[$language]);
  203. if (false !== $index && $reverse) {
  204. unset($this->ignore[$language][$index]);
  205. return;
  206. }
  207. if (false !== $index && !$reverse) {
  208. return;
  209. }
  210. $this->ignore[$language][] = $key;
  211. }
  212. /**
  213. *Ignore all unmodified keys from a language, or reverse it.
  214. *
  215. * @param string $language
  216. * @param boolean $reverse
  217. */
  218. public function ignore_unmodified($language, $reverse = false) {
  219. $my_language = $this->getLanguage($language);
  220. foreach ($this->getReferenceLanguage() as $file => $ref_language) {
  221. foreach ($ref_language as $key => $ref_value) {
  222. if (array_key_exists($key, $my_language[$file])) {
  223. if($ref_value == $my_language[$file][$key]) {
  224. $this->ignore($key, $language, $reverse);
  225. }
  226. }
  227. }
  228. }
  229. }
  230. public function getLanguage($language) {
  231. return $this->data[$language];
  232. }
  233. public function getReferenceLanguage() {
  234. return $this->getLanguage(static::REFERENCE_LANGUAGE);
  235. }
  236. /**
  237. * @param string $key
  238. * @return string
  239. */
  240. private function getFilenamePrefix($key) {
  241. return preg_replace('/\..*/', '.php', $key);
  242. }
  243. }