/src/Localization.php

https://github.com/ARCANEDEV/Localization · PHP · 506 lines · 211 code · 68 blank · 227 comment · 18 complexity · eaff04cf05908dd243c4fa4b916b7238 MD5 · raw file

  1. <?php
  2. declare(strict_types=1);
  3. namespace Arcanedev\Localization;
  4. use Arcanedev\Localization\Contracts\LocalesManager as LocalesManagerContract;
  5. use Arcanedev\Localization\Contracts\Localization as LocalizationContract;
  6. use Arcanedev\Localization\Contracts\RouteTranslator as RouteTranslatorContract;
  7. use Arcanedev\Localization\Exceptions\UnsupportedLocaleException;
  8. use Arcanedev\Localization\Utilities\Url;
  9. use Illuminate\Contracts\Foundation\Application as ApplicationContract;
  10. use Illuminate\Contracts\View\Factory as ViewFactoryContract;
  11. use Illuminate\Http\Request;
  12. /**
  13. * Class Localization
  14. *
  15. * @author ARCANEDEV <arcanedev.maroc@gmail.com>
  16. */
  17. class Localization implements LocalizationContract
  18. {
  19. /* -----------------------------------------------------------------
  20. | Properties
  21. | -----------------------------------------------------------------
  22. */
  23. /**
  24. * Base url.
  25. *
  26. * @var string
  27. */
  28. protected $baseUrl;
  29. /**
  30. * Laravel application instance.
  31. *
  32. * @var \Illuminate\Contracts\Foundation\Application
  33. */
  34. private $app;
  35. /**
  36. * The RouteTranslator instance.
  37. *
  38. * @var \Arcanedev\Localization\Contracts\RouteTranslator
  39. */
  40. protected $routeTranslator;
  41. /**
  42. * The LocalesManager instance.
  43. *
  44. * @var \Arcanedev\Localization\Contracts\LocalesManager
  45. */
  46. private $localesManager;
  47. /* -----------------------------------------------------------------
  48. | Constructor
  49. | -----------------------------------------------------------------
  50. */
  51. /**
  52. * Localization constructor.
  53. *
  54. * @param \Illuminate\Contracts\Foundation\Application $app
  55. * @param \Arcanedev\Localization\Contracts\RouteTranslator $routeTranslator
  56. * @param \Arcanedev\Localization\Contracts\LocalesManager $localesManager
  57. */
  58. public function __construct(
  59. ApplicationContract $app,
  60. RouteTranslatorContract $routeTranslator,
  61. LocalesManagerContract $localesManager
  62. ) {
  63. $this->app = $app;
  64. $this->routeTranslator = $routeTranslator;
  65. $this->localesManager = $localesManager;
  66. $this->localesManager->setDefaultLocale(
  67. $this->app['config']->get('app.locale')
  68. );
  69. }
  70. /* -----------------------------------------------------------------
  71. | Getters & Setters
  72. | -----------------------------------------------------------------
  73. */
  74. /**
  75. * Get Request instance.
  76. *
  77. * @return \Illuminate\Http\Request
  78. */
  79. private function request()
  80. {
  81. return $this->app['request'];
  82. }
  83. /**
  84. * Returns default locale.
  85. *
  86. * @return string
  87. */
  88. public function getDefaultLocale()
  89. {
  90. return $this->localesManager->getDefaultLocale();
  91. }
  92. /**
  93. * Return an array of all supported Locales.
  94. *
  95. * @return \Arcanedev\Localization\Entities\LocaleCollection
  96. */
  97. public function getSupportedLocales()
  98. {
  99. return $this->localesManager->getSupportedLocales();
  100. }
  101. /**
  102. * Set the supported locales.
  103. *
  104. * @param array $supportedLocales
  105. *
  106. * @return self
  107. */
  108. public function setSupportedLocales(array $supportedLocales)
  109. {
  110. $this->localesManager->setSupportedLocales($supportedLocales);
  111. return $this;
  112. }
  113. /**
  114. * Get supported locales keys.
  115. *
  116. * @return array
  117. */
  118. public function getSupportedLocalesKeys()
  119. {
  120. return $this->localesManager->getSupportedLocalesKeys();
  121. }
  122. /**
  123. * Returns current language.
  124. *
  125. * @return string
  126. */
  127. public function getCurrentLocale()
  128. {
  129. return $this->localesManager->getCurrentLocale();
  130. }
  131. /**
  132. * Returns current language.
  133. *
  134. * @return \Arcanedev\Localization\Entities\Locale
  135. */
  136. public function getCurrentLocaleEntity()
  137. {
  138. return $this->localesManager->getCurrentLocaleEntity();
  139. }
  140. /**
  141. * Returns current locale name.
  142. *
  143. * @return string
  144. */
  145. public function getCurrentLocaleName()
  146. {
  147. return $this->getCurrentLocaleEntity()->name();
  148. }
  149. /**
  150. * Returns current locale script.
  151. *
  152. * @return string
  153. */
  154. public function getCurrentLocaleScript()
  155. {
  156. return $this->getCurrentLocaleEntity()->script();
  157. }
  158. /**
  159. * Returns current locale direction.
  160. *
  161. * @return string
  162. */
  163. public function getCurrentLocaleDirection()
  164. {
  165. return $this->getCurrentLocaleEntity()->direction();
  166. }
  167. /**
  168. * Returns current locale native name.
  169. *
  170. * @return string
  171. */
  172. public function getCurrentLocaleNative()
  173. {
  174. return $this->getCurrentLocaleEntity()->native();
  175. }
  176. /**
  177. * Returns current locale regional.
  178. *
  179. * @return string
  180. */
  181. public function getCurrentLocaleRegional()
  182. {
  183. return $this->getCurrentLocaleEntity()->regional();
  184. }
  185. /**
  186. * Get all locales.
  187. *
  188. * @return \Arcanedev\Localization\Entities\LocaleCollection
  189. */
  190. public function getAllLocales()
  191. {
  192. return $this->localesManager->getAllLocales();
  193. }
  194. /**
  195. * Set and return current locale.
  196. *
  197. * @param string|null $locale
  198. *
  199. * @return string
  200. */
  201. public function setLocale($locale = null)
  202. {
  203. return $this->localesManager->setLocale($locale);
  204. }
  205. /**
  206. * Sets the base url for the site.
  207. *
  208. * @param string $url
  209. *
  210. * @return $this
  211. */
  212. public function setBaseUrl($url)
  213. {
  214. if (substr($url, -1) !== '/') $url .= '/';
  215. $this->baseUrl = $url;
  216. return $this;
  217. }
  218. /* -----------------------------------------------------------------
  219. | Main Methods
  220. | -----------------------------------------------------------------
  221. */
  222. /**
  223. * Translate routes and save them to the translated routes array (used in the localize route filter).
  224. *
  225. * @param string $routeName
  226. *
  227. * @return string
  228. */
  229. public function transRoute($routeName)
  230. {
  231. return $this->routeTranslator->trans($routeName);
  232. }
  233. /**
  234. * Returns an URL adapted to $locale or current locale.
  235. *
  236. * @param string|null $url
  237. * @param string|null $locale
  238. *
  239. * @return string
  240. */
  241. public function localizeURL($url = null, $locale = null)
  242. {
  243. return $this->getLocalizedURL($locale, $url);
  244. }
  245. /**
  246. * It returns an URL without locale (if it has it).
  247. *
  248. * @param string|null $url
  249. *
  250. * @return string
  251. */
  252. public function getNonLocalizedURL($url = null)
  253. {
  254. return $this->getLocalizedURL(false, $url);
  255. }
  256. /**
  257. * Returns an URL adapted to $locale or current locale.
  258. *
  259. * @param string|null $locale
  260. * @param string|null $url
  261. * @param array $attributes
  262. * @param bool|false $showHiddenLocale
  263. *
  264. * @return string|false
  265. */
  266. public function getLocalizedURL($locale = null, $url = null, array $attributes = [], $showHiddenLocale = false)
  267. {
  268. if (is_null($locale))
  269. $locale = $this->getCurrentLocale();
  270. $this->isLocaleSupportedOrFail($locale);
  271. if (empty($attributes))
  272. $attributes = Url::extractAttributes($url);
  273. if (empty($url)) {
  274. if ($this->routeTranslator->hasCurrentRoute()) {
  275. if (empty($attributes))
  276. $attributes = $this->request()->route()->parameters();
  277. return $this->getUrlFromRouteName(
  278. $locale,
  279. $this->routeTranslator->getCurrentRoute(),
  280. $attributes,
  281. $showHiddenLocale
  282. );
  283. }
  284. $url = $this->request()->fullUrl();
  285. }
  286. if (
  287. $locale &&
  288. $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->getCurrentLocale())
  289. ) {
  290. return $this->getUrlFromRouteName($locale, $translatedRoute, $attributes, $showHiddenLocale);
  291. }
  292. $baseUrl = $this->request()->getBaseUrl();
  293. $parsedUrl = parse_url($url);
  294. $translatedRoute = $this->routeTranslator->getTranslatedRoute(
  295. $baseUrl, $parsedUrl, $this->getDefaultLocale(), $this->getSupportedLocales()
  296. );
  297. if ($translatedRoute !== false)
  298. return $this->getUrlFromRouteName($locale, $translatedRoute, $attributes, $showHiddenLocale);
  299. if ( ! empty($locale)) {
  300. if ($locale !== $this->getDefaultLocale() || ! $this->isDefaultLocaleHiddenInUrl() || $showHiddenLocale) {
  301. $parsedUrl['path'] = $locale.'/'.ltrim($parsedUrl['path'], '/');
  302. }
  303. }
  304. $parsedUrl['path'] = ltrim(ltrim($baseUrl, '/') . '/' . $parsedUrl['path'], '/');
  305. $parsedUrl['path'] = rtrim($parsedUrl['path'], '/');
  306. $url = Url::unparse($parsedUrl);
  307. if (filter_var($url, FILTER_VALIDATE_URL)) return $url;
  308. return $this->createUrlFromUri(
  309. empty($url) ? $parsedUrl['path'] : $url
  310. );
  311. }
  312. /**
  313. * Create an url from the uri.
  314. *
  315. * @param string $uri
  316. *
  317. * @return string
  318. */
  319. public function createUrlFromUri($uri)
  320. {
  321. $uri = ltrim($uri, '/');
  322. return empty($this->baseUrl)
  323. ? $this->app[\Illuminate\Contracts\Routing\UrlGenerator::class]->to($uri)
  324. : $this->baseUrl.$uri;
  325. }
  326. /**
  327. * Get locales navigation bar.
  328. *
  329. * @return string
  330. */
  331. public function localesNavbar()
  332. {
  333. /** @var \Illuminate\Contracts\View\Factory $view */
  334. $view = $this->app[ViewFactoryContract::class];
  335. return $view->make('localization::navbar', ['supportedLocales' => $this->getSupportedLocales()])
  336. ->render();
  337. }
  338. /* -----------------------------------------------------------------
  339. | Translation Methods
  340. | -----------------------------------------------------------------
  341. */
  342. /**
  343. * Returns the translated route for an url and the attributes given and a locale
  344. *
  345. * @param string $url
  346. * @param array $attributes
  347. * @param string $locale
  348. *
  349. * @return string|false
  350. */
  351. private function findTranslatedRouteByUrl($url, $attributes, $locale)
  352. {
  353. if (empty($url))
  354. return false;
  355. // check if this url is a translated url
  356. foreach ($this->routeTranslator->getTranslatedRoutes() as $translatedRoute) {
  357. $translatedUrl = $this->getUrlFromRouteName($locale, $translatedRoute, $attributes);
  358. if ($this->getNonLocalizedURL($translatedUrl) === $this->getNonLocalizedURL($url))
  359. return $translatedRoute;
  360. }
  361. return false;
  362. }
  363. /**
  364. * Returns an URL adapted to the route name and the locale given.
  365. *
  366. * @param string|bool $locale
  367. * @param string $transKey
  368. * @param array $attributes
  369. * @param bool|false $showHiddenLocale
  370. *
  371. * @return string|false
  372. */
  373. public function getUrlFromRouteName($locale, $transKey, array $attributes = [], $showHiddenLocale = false)
  374. {
  375. $this->isLocaleSupportedOrFail($locale);
  376. $route = $this->routeTranslator->getUrlFromRouteName(
  377. $locale,
  378. $this->getDefaultLocale(),
  379. $transKey,
  380. $attributes,
  381. $this->isDefaultLocaleHiddenInUrl(),
  382. $showHiddenLocale
  383. );
  384. // This locale does not have any key for this route name
  385. if (empty($route)) return false;
  386. return rtrim($this->createUrlFromUri($route));
  387. }
  388. /**
  389. * Set route name from request.
  390. *
  391. * @param \Illuminate\Http\Request $request
  392. */
  393. public function setRouteNameFromRequest(Request $request)
  394. {
  395. $routeName = $this->routeTranslator->getRouteNameFromPath(
  396. $request->getUri(), $this->getCurrentLocale()
  397. );
  398. $this->routeTranslator->setCurrentRoute($routeName);
  399. }
  400. /* -----------------------------------------------------------------
  401. | Check Methods
  402. | -----------------------------------------------------------------
  403. */
  404. /**
  405. * Hide the default locale in URL ??
  406. *
  407. * @return bool
  408. */
  409. public function isDefaultLocaleHiddenInUrl()
  410. {
  411. return $this->localesManager->isDefaultLocaleHiddenInUrl();
  412. }
  413. /**
  414. * Check if Locale exists on the supported locales collection.
  415. *
  416. * @param string|bool $locale
  417. *
  418. * @return bool
  419. */
  420. public function isLocaleSupported($locale)
  421. {
  422. return ! ($locale !== false && ! $this->localesManager->isSupportedLocale($locale));
  423. }
  424. /**
  425. * Check if the locale is supported or fail if not.
  426. *
  427. * @param string $locale
  428. *
  429. * @throws \Arcanedev\Localization\Exceptions\UnsupportedLocaleException
  430. */
  431. private function isLocaleSupportedOrFail($locale): void
  432. {
  433. if ( ! $this->isLocaleSupported($locale))
  434. throw new UnsupportedLocaleException(
  435. "Locale '{$locale}' is not in the list of supported locales."
  436. );
  437. }
  438. }