IcuResFileDumper.php 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Translation\Dumper;
  11. use Symfony\Component\Translation\MessageCatalogue;
  12. /**
  13. * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
  14. *
  15. * @author Stealth35
  16. */
  17. class IcuResFileDumper extends FileDumper
  18. {
  19. protected $relativePathTemplate = '%domain%/%locale%.%extension%';
  20. public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
  21. {
  22. $data = $indexes = $resources = '';
  23. foreach ($messages->all($domain) as $source => $target) {
  24. $indexes .= pack('v', \strlen($data) + 28);
  25. $data .= $source."\0";
  26. }
  27. $data .= $this->writePadding($data);
  28. $keyTop = $this->getPosition($data);
  29. foreach ($messages->all($domain) as $source => $target) {
  30. $resources .= pack('V', $this->getPosition($data));
  31. $data .= pack('V', \strlen($target))
  32. .mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
  33. .$this->writePadding($data)
  34. ;
  35. }
  36. $resOffset = $this->getPosition($data);
  37. $data .= pack('v', \count($messages->all($domain)))
  38. .$indexes
  39. .$this->writePadding($data)
  40. .$resources
  41. ;
  42. $bundleTop = $this->getPosition($data);
  43. $root = pack('V7',
  44. $resOffset + (2 << 28), // Resource Offset + Resource Type
  45. 6, // Index length
  46. $keyTop, // Index keys top
  47. $bundleTop, // Index resources top
  48. $bundleTop, // Index bundle top
  49. \count($messages->all($domain)), // Index max table length
  50. 0 // Index attributes
  51. );
  52. $header = pack('vC2v4C12@32',
  53. 32, // Header size
  54. 0xDA, 0x27, // Magic number 1 and 2
  55. 20, 0, 0, 2, // Rest of the header, ..., Size of a char
  56. 0x52, 0x65, 0x73, 0x42, // Data format identifier
  57. 1, 2, 0, 0, // Data version
  58. 1, 4, 0, 0 // Unicode version
  59. );
  60. return $header.$root.$data;
  61. }
  62. private function writePadding(string $data): ?string
  63. {
  64. $padding = \strlen($data) % 4;
  65. return $padding ? str_repeat("\xAA", 4 - $padding) : null;
  66. }
  67. private function getPosition(string $data): float|int
  68. {
  69. return (\strlen($data) + 28) / 4;
  70. }
  71. protected function getExtension(): string
  72. {
  73. return 'res';
  74. }
  75. }