Issues (9)

src/Loaders/FileLoader.php (1 issue)

Severity
1
<?php
2
declare(strict_types=1);
3
4
namespace Nexendrie\Translation\Loaders;
5
6
use Nette\Utils\Finder;
7
use Nette\Utils\Strings;
8
use Nexendrie\Translation\ILocaleResolver;
9
use Nexendrie\Translation\Resolvers\ManualLocaleResolver;
10
use Nexendrie\Translation\ISettableLocaleResolver;
11
use Nexendrie\Translation\InvalidFolderException;
12
use Nexendrie\Translation\FolderNotSetException;
13
use Nette\Utils\Arrays;
14
use Nexendrie\Translation\IFileLoader;
15
16
/**
17
 * Generic file translations loader
18
 * Loads texts from {$this->extension} files
19
 * You need to define method parseFile() which processes individual file
20
 *
21
 * @author Jakub Konečný
22
 * @property string $lang
23
 * @property-read array $texts
24
 * @property string[] $folders
25
 * @property-read array $resources
26
 * @method void onLanguageChange(FileLoader $loader, string $oldLang, string $newLang)
27
 * @method void onFoldersChange(FileLoader $loader, string[] $folders)
28
 * @method void onLoad(FileLoader $loader, string $lang)
29
 */
30
abstract class FileLoader implements IFileLoader {
31
  use \Nette\SmartObject;
32
33
  protected const DOMAIN_MASK = "%domain%";
34
  protected const LANGUAGE_MASK = "%language%";
35
36
  public string $defaultLang = "en";
37
  protected ?string $loadedLang = null;
38
  protected array $texts = [];
39
  /** @var string[] */
40
  protected array $folders = [];
41
  protected ILocaleResolver $resolver;
42
  protected array $resources = [];
43
  protected string $extension;
44
  /** @var callable[] */
45
  public array $onLanguageChange = [];
46
  /** @var callable[] */
47
  public array $onFoldersChange = [];
48
  /** @var callable[] */
49
  public array $onLoad = [];
50
  
51
  /**
52
   * @param string[] $folders
53
   */
54
  public function __construct(ILocaleResolver $resolver = null, array $folders = []) {
55 1
    $this->setFolders($folders);
56 1
    $this->resolver = $resolver ?? new ManualLocaleResolver();
57 1
  }
58
59
  /**
60
   * @deprecated Access the property directly
61
   */
62
  public function getLang(): string {
63 1
    return $this->resolver->resolve() ?? $this->defaultLang;
64
  }
65
66
  /**
67
   * @deprecated Access the property directly
68
   */
69
  public function setLang(string $lang): void {
70 1
    if(is_a($this->resolver, ISettableLocaleResolver::class)) {
71 1
      $oldLang = $this->lang;
72 1
      $this->resolver->setLang($lang);
73 1
      $this->onLanguageChange($this, $oldLang, $lang);
74
    }
75 1
  }
76
77
  /**
78
   * @deprecated Access the property directly
79
   */
80
  public function getDefaultLang(): string {
81 1
    return $this->defaultLang;
82
  }
83
84
  /**
85
   * @deprecated Access the property directly
86
   */
87
  public function setDefaultLang(string $defaultLang): void {
88 1
    $this->defaultLang = $defaultLang;
89 1
  }
90
  
91
  /**
92
   * @return string[]
93
   * @deprecated Access the property directly
94
   */
95
  public function getFolders(): array {
96 1
    return $this->folders;
97
  }
98
  
99
  /**
100
   * @param string[] $folders
101
   * @throws InvalidFolderException
102
   * @deprecated Access the property directly
103
   */
104
  public function setFolders(array $folders): void {
105 1
    foreach($folders as $folder) {
106 1
      if(!is_dir($folder)) {
107 1
        throw new InvalidFolderException("Folder $folder does not exist.");
108
      }
109 1
      $this->folders[] = $folder;
110
    }
111 1
    $this->onFoldersChange($this, $folders);
112 1
  }
113
  
114
  protected function addResource(string $filename, string $domain): void {
115 1
    if(!isset($this->resources[$domain]) || !in_array($filename, $this->resources[$domain], true)) {
116 1
      $this->resources[$domain][] = $filename;
117
    }
118 1
  }
119
120
  /**
121
   * @deprecated Access the property directly
122
   */
123
  public function getResources(): array {
124 1
    return $this->resources;
125
  }
126
  
127
  /**
128
   * Parse individual file
129
   */
130
  abstract protected function parseFile(string $filename): array;
131
  
132
  /**
133
   * Load texts from one text domain
134
   */
135
  protected function loadDomain(string $name): array {
136 1
    $return = [];
137 1
    $defaultLang = $this->defaultLang;
138 1
    $defaultFilename = $this->getLanguageFilenameMask();
139 1
    $defaultFilename = str_replace([static::DOMAIN_MASK, static::LANGUAGE_MASK, ], [$name, $defaultLang, ], $defaultFilename);
0 ignored issues
show
Line exceeds 120 characters; contains 126 characters
Loading history...
140 1
    $files = Finder::findFiles($defaultFilename)
141 1
      ->from(...$this->folders);
142
    /** @var \SplFileInfo $file */
143 1
    foreach($files as $file) {
144 1
      $default = $this->parseFile($file->getPathname());
145 1
      $this->addResource($file->getPathname(), $name);
146 1
      $lang = [];
147 1
      $filename = str_replace($defaultLang, $this->lang, $defaultFilename);
148 1
      $filename = str_replace($defaultFilename, $filename, $file->getPathname());
149 1
      if($this->lang !== $defaultLang && is_file($filename)) {
150 1
        $lang = $this->parseFile($filename);
151 1
        $this->addResource($filename, $name);
152
      }
153 1
      $return = Arrays::mergeTree($return, Arrays::mergeTree($lang, $default));
154
    }
155 1
    return $return;
156
  }
157
  
158
  /**
159
   * Load all texts
160
   *
161
   * @throws FolderNotSetException
162
   */
163
  protected function loadTexts(): void {
164 1
    if($this->lang === $this->loadedLang) {
165 1
      return;
166
    }
167 1
    if(count($this->folders) === 0) {
168 1
      throw new FolderNotSetException("Folder for translations was not set.");
169
    }
170 1
    $default = $this->defaultLang;
171 1
    $this->resources = $texts = [];
172 1
    $mask = $this->getLanguageFilenameMask();
173 1
    $mask = str_replace([static::DOMAIN_MASK, static::LANGUAGE_MASK, ], ["*", $default, ], $mask);
174 1
    $files = Finder::findFiles($mask)
175 1
      ->from(...$this->folders);
176
    /** @var \SplFileInfo $file */
177 1
    foreach($files as $file) {
178 1
      $domain = $file->getBasename((string) Strings::after($mask, "*"));
179 1
      $texts[$domain] = $this->loadDomain($domain);
180
    }
181 1
    $this->texts = $texts;
182 1
    $this->loadedLang = $this->lang;
183 1
    $this->onLoad($this, $this->lang);
184 1
  }
185
186
  /**
187
   * @deprecated Access the property directly
188
   */
189
  public function getTexts(): array {
190 1
    $this->loadTexts();
191 1
    return $this->texts;
192
  }
193
  
194
  public function getResolverName(): string {
195 1
    $class = get_class($this->resolver);
196 1
    return (string) Strings::after($class, '\\', -1);
197
  }
198
199
  protected function getLanguageFilenameMask(): string {
200 1
    return static::DOMAIN_MASK . "." . static::LANGUAGE_MASK . "." . $this->extension;
201
  }
202
  
203
  /**
204
   * @return string[]
205
   * @throws FolderNotSetException
206
   */
207
  public function getAvailableLanguages(): array {
208 1
    if(count($this->folders) === 0) {
209 1
      throw new FolderNotSetException("Folder for translations was not set.");
210
    }
211 1
    $languages = [];
212 1
    $extension = $this->extension;
213 1
    $mask = $this->getLanguageFilenameMask();
214 1
    $mask = str_replace([static::DOMAIN_MASK, static::LANGUAGE_MASK, ], "*", $mask);
215 1
    $files = Finder::findFiles($mask)
216 1
      ->from(...$this->folders);
217
    /** @var \SplFileInfo $file */
218 1
    foreach($files as $file) {
219 1
      $filename = $file->getBasename(".$extension");
220 1
      $lang = (string) Strings::after($filename, ".");
221 1
      if(!in_array($lang, $languages, true)) {
222 1
        $languages[] = $lang;
223
      }
224
    }
225 1
    return $languages;
226
  }
227
}
228
?>