PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/loco-translate/src/gettext/Data.php

https://gitlab.com/najomie/fit-hippie
PHP | 255 lines | 144 code | 41 blank | 70 comment | 16 complexity | f56128f9432e1c711c43cc7ae1efda31 MD5 | raw file
  1. <?php
  2. loco_require_lib('compiled/gettext.php');
  3. /**
  4. * Wrapper for array forms of parsed PO data
  5. */
  6. class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
  7. /**
  8. * @return Loco_gettext_Data
  9. */
  10. public static function load( Loco_fs_File $file ){
  11. $type = strtoupper( $file->extension() );
  12. // parse PO
  13. if( 'PO' === $type || 'POT' === $type ){
  14. $po = self::fromSource( $file->getContents() );
  15. }
  16. // parse MO
  17. else if( 'MO' === $type ){
  18. $po = self::fromBinary( $file->getContents() );
  19. }
  20. // else file type not parsable. not currently sniffing file header - use the right file extension.
  21. else {
  22. // translators: Error thrown when attemping to parse a file that is not PO, POT or MO
  23. throw new Loco_error_Exception( sprintf( __('%s is not a Gettext file'), $file->basename() ) );
  24. }
  25. return $po;
  26. }
  27. /**
  28. * @param string assumed PO source
  29. * @return Loco_gettext_Data
  30. */
  31. public static function fromSource( $src ){
  32. return new Loco_gettext_Data( loco_parse_po($src) );
  33. }
  34. /**
  35. * @param string assumed MO bytes
  36. * @return Loco_gettext_Data
  37. */
  38. public static function fromBinary( $bin ){
  39. return new Loco_gettext_Data( loco_parse_mo($bin) );
  40. }
  41. /**
  42. * Create a dummy/empty instance
  43. * @return Loco_gettext_Data
  44. */
  45. public static function dummy(){
  46. return new Loco_gettext_Data( array( array('source'=>'','target'=>'') ) );
  47. }
  48. /**
  49. * Compile messages to binary MO format
  50. * @return string MO file source
  51. */
  52. public function msgfmt(){
  53. $mo = new LocoMo( $this, $this->getHeaders() );
  54. $opts = Loco_data_Settings::get();
  55. if( $opts->gen_hash ){
  56. $mo->enableHash();
  57. }
  58. if( $opts->use_fuzzy ){
  59. $mo->useFuzzy();
  60. }
  61. return $mo->compile();
  62. }
  63. /**
  64. * @return array
  65. */
  66. public function jsonSerialize(){
  67. $po = $this->getArrayCopy();
  68. // exporting headers non-scalar so js doesn't have to parse them
  69. try {
  70. $headers = $this->getHeaders();
  71. $po[0]['target'] = $headers->getArrayCopy();
  72. }
  73. // suppress header errors when serializing
  74. // @codeCoverageIgnoreStart
  75. catch( Exception $e ){ }
  76. // @codeCoverageIgnoreEnd
  77. return $po;
  78. }
  79. /**
  80. * Export to JSON for JavaScript editor
  81. * @return string
  82. */
  83. public function exportJson(){
  84. return json_encode( $this->jsonSerialize() );
  85. }
  86. /**
  87. * Create a signature for use in comparing source strings between documents
  88. * @return string
  89. */
  90. public function getSourceDigest(){
  91. $data = $this->getHashes();
  92. return md5( implode("\1",$data) );
  93. }
  94. /**
  95. * @return Loco_gettext_Data
  96. */
  97. public function localize( Loco_Locale $locale, array $custom = null ){
  98. $date = gmdate('Y-m-d H:i').'+0000'; // <- forcing UCT
  99. $headers = $this->getHeaders();
  100. // headers that must always be set if absent
  101. $defaults = array (
  102. 'Project-Id-Version' => '',
  103. 'Report-Msgid-Bugs-To' => '',
  104. 'POT-Creation-Date' => $date,
  105. );
  106. // Project-Id-Version permitted to
  107. // headers that must always override when localizing
  108. $required = array (
  109. 'PO-Revision-Date' => $date,
  110. 'Last-Translator' => '',
  111. 'Language-Team' => $locale->getName(),
  112. 'Language' => (string) $locale,
  113. 'Plural-Forms' => $locale->getPluralFormsHeader(),
  114. 'MIME-Version' => '1.0',
  115. 'Content-Type' => 'text/plain; charset=UTF-8',
  116. 'Content-Transfer-Encoding' => '8bit',
  117. 'X-Generator' => 'Loco https://localise.biz/',
  118. //'X-WordPress' => sprintf('Loco Translate %s, WP %s', loco_plugin_version(), $GLOBALS['wp_version'] ),
  119. );
  120. // set actual last translator from WordPress login when possible
  121. if( function_exists('get_current_user_id') && get_current_user_id() ){
  122. $user = wp_get_current_user();
  123. $name = $user->get('display_name') or $name = 'nobody';
  124. $email = $user->get('user_email') or $email = 'nobody@localhost';
  125. // set user's preferred last translator credit if configured
  126. $prefs = Loco_data_Preferences::get();
  127. $credit = $prefs->credit;
  128. if( ! $credit ){
  129. $credit = sprintf('%s <%s>', $name, $email );
  130. }
  131. $required['Last-Translator'] = apply_filters( 'loco_current_translator', $credit, $name, $email );
  132. }
  133. // only set absent or empty headers from default list
  134. foreach( $defaults as $key => $value ){
  135. if( ! $headers[$key] ){
  136. $headers[$key] = $value;
  137. }
  138. }
  139. // add required headers with custom ones overriding
  140. if( is_array($custom) ){
  141. $required = array_merge( $required, $custom );
  142. }
  143. foreach( $required as $key => $value ){
  144. $headers[$key] = $value;
  145. }
  146. // avoid non-empty POT placeholders that won't have been set from $defaults
  147. if( 'PACKAGE VERSION' === $headers['Project-Id-Version'] ){
  148. $headers['Project-Id-Version'] = '';
  149. }
  150. // header message must be un-fuzzied if it was formerly a POT file
  151. return $this->initPo();
  152. }
  153. /**
  154. * @return Loco_gettext_Data
  155. */
  156. public function templatize(){
  157. $date = gmdate('Y-m-d H:i').'+0000'; // <- forcing UCT
  158. $headers = $this->getHeaders();
  159. $required = array (
  160. 'Project-Id-Version' => 'PACKAGE VERSION',
  161. 'Report-Msgid-Bugs-To' => '',
  162. 'POT-Creation-Date' => $date,
  163. 'PO-Revision-Date' => 'YEAR-MO-DA HO:MI+ZONE',
  164. 'Last-Translator' => 'FULL NAME <EMAIL@ADDRESS>',
  165. 'Language-Team' => '',
  166. 'Language' => '',
  167. 'Plural-Forms' => 'nplurals=INTEGER; plural=EXPRESSION;',
  168. 'MIME-Version' => '1.0',
  169. 'Content-Type' => 'text/plain; charset=UTF-8',
  170. 'Content-Transfer-Encoding' => '8bit',
  171. 'X-Generator' => 'Loco https://localise.biz/',
  172. );
  173. foreach( $required as $key => $value ){
  174. $headers[$key] = $value;
  175. }
  176. return $this->initPot();
  177. }
  178. /**
  179. * Remap proprietary base path when PO file is moving to another location.
  180. *
  181. * @param Loco_fs_File the file that was originally extracted to (POT)
  182. * @param Loco_fs_File the file that must now target references relative to itself
  183. * @param string vendor name used in header keys
  184. * @return bool whether base header was alterered
  185. */
  186. public function rebaseHeader( Loco_fs_File $origin, Loco_fs_File $target, $vendor ){
  187. $base = $target->getParent();
  188. $head = $this->getHeaders();
  189. $key = 'X-'.$vendor.'-Basepath';
  190. if( $key = $head->normalize($key) ){
  191. $oldRelBase = $head[$key];
  192. $oldAbsBase = new Loco_fs_Directory($oldRelBase);
  193. $oldAbsBase->normalize( $origin->getParent() );
  194. $newRelBase = $oldAbsBase->getRelativePath($base);
  195. // new base path is relative to $target location
  196. $head[$key] = $newRelBase;
  197. return true;
  198. }
  199. return false;
  200. }
  201. /**
  202. * @param string date format as Gettext states "YEAR-MO-DA HO:MI+ZONE"
  203. * @return int
  204. */
  205. public static function parseDate( $podate ){
  206. if( method_exists('DateTime', 'createFromFormat') ){
  207. $objdate = DateTime::createFromFormat('Y-m-d H:iO', $podate);
  208. if( $objdate instanceof DateTime ){
  209. return $objdate->getTimestamp();
  210. }
  211. }
  212. return strtotime($podate);
  213. }
  214. }