/laradock/vendor/illuminate/translation/Translator.php

https://gitlab.com/hoangduys4k5/laravelproject · PHP · 434 lines · 173 code · 55 blank · 206 comment · 10 complexity · 1894d5c51d2a1383a24069bf1823720e MD5 · raw file

  1. <?php
  2. namespace Illuminate\Translation;
  3. use Illuminate\Contracts\Translation\Loader;
  4. use Illuminate\Contracts\Translation\Translator as TranslatorContract;
  5. use Illuminate\Support\Arr;
  6. use Illuminate\Support\NamespacedItemResolver;
  7. use Illuminate\Support\Str;
  8. use Illuminate\Support\Traits\Macroable;
  9. use InvalidArgumentException;
  10. class Translator extends NamespacedItemResolver implements TranslatorContract
  11. {
  12. use Macroable;
  13. /**
  14. * The loader implementation.
  15. *
  16. * @var \Illuminate\Contracts\Translation\Loader
  17. */
  18. protected $loader;
  19. /**
  20. * The default locale being used by the translator.
  21. *
  22. * @var string
  23. */
  24. protected $locale;
  25. /**
  26. * The fallback locale used by the translator.
  27. *
  28. * @var string
  29. */
  30. protected $fallback;
  31. /**
  32. * The array of loaded translation groups.
  33. *
  34. * @var array
  35. */
  36. protected $loaded = [];
  37. /**
  38. * The message selector.
  39. *
  40. * @var \Illuminate\Translation\MessageSelector
  41. */
  42. protected $selector;
  43. /**
  44. * Create a new translator instance.
  45. *
  46. * @param \Illuminate\Contracts\Translation\Loader $loader
  47. * @param string $locale
  48. * @return void
  49. */
  50. public function __construct(Loader $loader, $locale)
  51. {
  52. $this->loader = $loader;
  53. $this->setLocale($locale);
  54. }
  55. /**
  56. * Determine if a translation exists for a given locale.
  57. *
  58. * @param string $key
  59. * @param string|null $locale
  60. * @return bool
  61. */
  62. public function hasForLocale($key, $locale = null)
  63. {
  64. return $this->has($key, $locale, false);
  65. }
  66. /**
  67. * Determine if a translation exists.
  68. *
  69. * @param string $key
  70. * @param string|null $locale
  71. * @param bool $fallback
  72. * @return bool
  73. */
  74. public function has($key, $locale = null, $fallback = true)
  75. {
  76. return $this->get($key, [], $locale, $fallback) !== $key;
  77. }
  78. /**
  79. * Get the translation for the given key.
  80. *
  81. * @param string $key
  82. * @param array $replace
  83. * @param string|null $locale
  84. * @param bool $fallback
  85. * @return string|array
  86. */
  87. public function get($key, array $replace = [], $locale = null, $fallback = true)
  88. {
  89. $locale = $locale ?: $this->locale;
  90. // For JSON translations, there is only one file per locale, so we will simply load
  91. // that file and then we will be ready to check the array for the key. These are
  92. // only one level deep so we do not need to do any fancy searching through it.
  93. $this->load('*', '*', $locale);
  94. $line = $this->loaded['*']['*'][$locale][$key] ?? null;
  95. // If we can't find a translation for the JSON key, we will attempt to translate it
  96. // using the typical translation file. This way developers can always just use a
  97. // helper such as __ instead of having to pick between trans or __ with views.
  98. if (! isset($line)) {
  99. [$namespace, $group, $item] = $this->parseKey($key);
  100. // Here we will get the locale that should be used for the language line. If one
  101. // was not passed, we will use the default locales which was given to us when
  102. // the translator was instantiated. Then, we can load the lines and return.
  103. $locales = $fallback ? $this->localeArray($locale) : [$locale];
  104. foreach ($locales as $locale) {
  105. if (! is_null($line = $this->getLine(
  106. $namespace, $group, $locale, $item, $replace
  107. ))) {
  108. return $line;
  109. }
  110. }
  111. }
  112. // If the line doesn't exist, we will return back the key which was requested as
  113. // that will be quick to spot in the UI if language keys are wrong or missing
  114. // from the application's language files. Otherwise we can return the line.
  115. return $this->makeReplacements($line ?: $key, $replace);
  116. }
  117. /**
  118. * Get a translation according to an integer value.
  119. *
  120. * @param string $key
  121. * @param \Countable|int|array $number
  122. * @param array $replace
  123. * @param string|null $locale
  124. * @return string
  125. */
  126. public function choice($key, $number, array $replace = [], $locale = null)
  127. {
  128. $line = $this->get(
  129. $key, $replace, $locale = $this->localeForChoice($locale)
  130. );
  131. // If the given "number" is actually an array or countable we will simply count the
  132. // number of elements in an instance. This allows developers to pass an array of
  133. // items without having to count it on their end first which gives bad syntax.
  134. if (is_countable($number)) {
  135. $number = count($number);
  136. }
  137. $replace['count'] = $number;
  138. return $this->makeReplacements(
  139. $this->getSelector()->choose($line, $number, $locale), $replace
  140. );
  141. }
  142. /**
  143. * Get the proper locale for a choice operation.
  144. *
  145. * @param string|null $locale
  146. * @return string
  147. */
  148. protected function localeForChoice($locale)
  149. {
  150. return $locale ?: $this->locale ?: $this->fallback;
  151. }
  152. /**
  153. * Retrieve a language line out the loaded array.
  154. *
  155. * @param string $namespace
  156. * @param string $group
  157. * @param string $locale
  158. * @param string $item
  159. * @param array $replace
  160. * @return string|array|null
  161. */
  162. protected function getLine($namespace, $group, $locale, $item, array $replace)
  163. {
  164. $this->load($namespace, $group, $locale);
  165. $line = Arr::get($this->loaded[$namespace][$group][$locale], $item);
  166. if (is_string($line)) {
  167. return $this->makeReplacements($line, $replace);
  168. } elseif (is_array($line) && count($line) > 0) {
  169. foreach ($line as $key => $value) {
  170. $line[$key] = $this->makeReplacements($value, $replace);
  171. }
  172. return $line;
  173. }
  174. }
  175. /**
  176. * Make the place-holder replacements on a line.
  177. *
  178. * @param string $line
  179. * @param array $replace
  180. * @return string
  181. */
  182. protected function makeReplacements($line, array $replace)
  183. {
  184. if (empty($replace)) {
  185. return $line;
  186. }
  187. $shouldReplace = [];
  188. foreach ($replace as $key => $value) {
  189. $shouldReplace[':'.Str::ucfirst($key)] = Str::ucfirst($value);
  190. $shouldReplace[':'.Str::upper($key)] = Str::upper($value);
  191. $shouldReplace[':'.$key] = $value;
  192. }
  193. return strtr($line, $shouldReplace);
  194. }
  195. /**
  196. * Add translation lines to the given locale.
  197. *
  198. * @param array $lines
  199. * @param string $locale
  200. * @param string $namespace
  201. * @return void
  202. */
  203. public function addLines(array $lines, $locale, $namespace = '*')
  204. {
  205. foreach ($lines as $key => $value) {
  206. [$group, $item] = explode('.', $key, 2);
  207. Arr::set($this->loaded, "$namespace.$group.$locale.$item", $value);
  208. }
  209. }
  210. /**
  211. * Load the specified language group.
  212. *
  213. * @param string $namespace
  214. * @param string $group
  215. * @param string $locale
  216. * @return void
  217. */
  218. public function load($namespace, $group, $locale)
  219. {
  220. if ($this->isLoaded($namespace, $group, $locale)) {
  221. return;
  222. }
  223. // The loader is responsible for returning the array of language lines for the
  224. // given namespace, group, and locale. We'll set the lines in this array of
  225. // lines that have already been loaded so that we can easily access them.
  226. $lines = $this->loader->load($locale, $group, $namespace);
  227. $this->loaded[$namespace][$group][$locale] = $lines;
  228. }
  229. /**
  230. * Determine if the given group has been loaded.
  231. *
  232. * @param string $namespace
  233. * @param string $group
  234. * @param string $locale
  235. * @return bool
  236. */
  237. protected function isLoaded($namespace, $group, $locale)
  238. {
  239. return isset($this->loaded[$namespace][$group][$locale]);
  240. }
  241. /**
  242. * Add a new namespace to the loader.
  243. *
  244. * @param string $namespace
  245. * @param string $hint
  246. * @return void
  247. */
  248. public function addNamespace($namespace, $hint)
  249. {
  250. $this->loader->addNamespace($namespace, $hint);
  251. }
  252. /**
  253. * Add a new JSON path to the loader.
  254. *
  255. * @param string $path
  256. * @return void
  257. */
  258. public function addJsonPath($path)
  259. {
  260. $this->loader->addJsonPath($path);
  261. }
  262. /**
  263. * Parse a key into namespace, group, and item.
  264. *
  265. * @param string $key
  266. * @return array
  267. */
  268. public function parseKey($key)
  269. {
  270. $segments = parent::parseKey($key);
  271. if (is_null($segments[0])) {
  272. $segments[0] = '*';
  273. }
  274. return $segments;
  275. }
  276. /**
  277. * Get the array of locales to be checked.
  278. *
  279. * @param string|null $locale
  280. * @return array
  281. */
  282. protected function localeArray($locale)
  283. {
  284. return array_filter([$locale ?: $this->locale, $this->fallback]);
  285. }
  286. /**
  287. * Get the message selector instance.
  288. *
  289. * @return \Illuminate\Translation\MessageSelector
  290. */
  291. public function getSelector()
  292. {
  293. if (! isset($this->selector)) {
  294. $this->selector = new MessageSelector;
  295. }
  296. return $this->selector;
  297. }
  298. /**
  299. * Set the message selector instance.
  300. *
  301. * @param \Illuminate\Translation\MessageSelector $selector
  302. * @return void
  303. */
  304. public function setSelector(MessageSelector $selector)
  305. {
  306. $this->selector = $selector;
  307. }
  308. /**
  309. * Get the language line loader implementation.
  310. *
  311. * @return \Illuminate\Contracts\Translation\Loader
  312. */
  313. public function getLoader()
  314. {
  315. return $this->loader;
  316. }
  317. /**
  318. * Get the default locale being used.
  319. *
  320. * @return string
  321. */
  322. public function locale()
  323. {
  324. return $this->getLocale();
  325. }
  326. /**
  327. * Get the default locale being used.
  328. *
  329. * @return string
  330. */
  331. public function getLocale()
  332. {
  333. return $this->locale;
  334. }
  335. /**
  336. * Set the default locale.
  337. *
  338. * @param string $locale
  339. * @return void
  340. *
  341. * @throws \InvalidArgumentException
  342. */
  343. public function setLocale($locale)
  344. {
  345. if (Str::contains($locale, ['/', '\\'])) {
  346. throw new InvalidArgumentException('Invalid characters present in locale.');
  347. }
  348. $this->locale = $locale;
  349. }
  350. /**
  351. * Get the fallback locale being used.
  352. *
  353. * @return string
  354. */
  355. public function getFallback()
  356. {
  357. return $this->fallback;
  358. }
  359. /**
  360. * Set the fallback locale being used.
  361. *
  362. * @param string $fallback
  363. * @return void
  364. */
  365. public function setFallback($fallback)
  366. {
  367. $this->fallback = $fallback;
  368. }
  369. /**
  370. * Set the loaded translation groups.
  371. *
  372. * @param array $loaded
  373. * @return void
  374. */
  375. public function setLoaded(array $loaded)
  376. {
  377. $this->loaded = $loaded;
  378. }
  379. }