Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
webbingbrasil/core-module / Services / Localization.php
Size: Mime:
<?php namespace Modules\Core\Services;

use Illuminate\Config\Repository;
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;
use Illuminate\Translation\Translator;
use Illuminate\View\Factory;
use Modules\Core\Exceptions\SupportedLocalesNotDefined;
use Modules\Core\Exceptions\UnsupportedLocaleException;

class Localization
{

    /**
     * Config repository.
     *
     * @var Repository
     */
    protected $configRepository;

    /**
     * Illuminate view Factory.
     *
     * @var Factory
     */
    protected $view;

    /**
     * Illuminate translator class.
     *
     * @var Translator
     */
    protected $translator;

    /**
     * Illuminate router class.
     *
     * @var Router
     */
    protected $router;

    /**
     * Illuminate request class.
     *
     * @var Request
     */
    protected $request;

    /**
     * Illuminate request class.
     *
     * @var Application
     */
    protected $app;

    /**
     * Illuminate request class.
     *
     * @var string
     */
    protected $baseUrl;

    /**
     * Default locale
     *
     * @var string
     */
    protected $defaultLocale;

    /**
     * Supported Locales
     *
     * @var array
     */
    protected $supportedLocales;

    /**
     * Current locale
     *
     * @var string
     */
    protected $currentLocale = false;

    /**
     * An array that contains all routes that should be translated
     *
     * @var array
     */
    protected $translatedRoutes = array();

    /**
     * Name of the translation key of the current route, it is used for url translations
     *
     * @var string
     */
    protected $routeName;

    /**
     * Creates new instance.
     * @throws UnsupportedLocaleException
     */
    public function __construct()
    {
        $this->app = app();

        $this->configRepository = $this->app['config'];
        $this->view = $this->app['view'];
        $this->translator = $this->app['translator'];
        $this->router = $this->app['router'];
        $this->request = $this->app['request'];

        // set default locale
        $this->defaultLocale = $this->configRepository->get('app.locale');
        $supportedLocales = $this->getSupportedLocales();

        if (empty($supportedLocales[$this->defaultLocale])) {
            throw new UnsupportedLocaleException("Laravel default locale is not in the supportedLocales array.");
        }
    }

    /**
     * Return an array of all supported Locales
     *
     * @throws SupportedLocalesNotDefined
     * @return array
     */
    public function getSupportedLocales()
    {
        if (!empty($this->supportedLocales)) {
            return $this->supportedLocales;
        }

        $locales = $this->configRepository->get('localization.supportedLocales');

        if (empty($locales) || !is_array($locales)) {
            throw new SupportedLocalesNotDefined();
        }

        $this->supportedLocales = $locales;

        return $locales;
    }

    /**
     * Set and return supported locales
     *
     * @param  array $locales Locales that the App supports
     */
    public function setSupportedLocales($locales)
    {
        $this->supportedLocales = $locales;
    }

    /**
     * Set and return current locale
     *
     * @param  string $locale Locale to set the App to (optional)
     *
     * @return string                    Returns locale (if route has any) or null (if route does not have a locale)
     */
    public function setLocale($locale = null)
    {
        if (empty($locale) || !is_string($locale)) {
            // If the locale has not been passed through the function
            // it tries to get it from the first segment of the url
            $locale = $this->request->segment(1);
        }

        $this->currentLocale = $locale;

        // if the first segment/locale passed is not valid
        // the system would ask which locale have to take
        // it could be taken by the browser
        // depending on your configuration
        if (empty($this->supportedLocales[$locale])) {
            // if we reached this point and hideDefaultLocaleInURL is true
            // we have to assume we are routing to a defaultLocale route.
            $locale = null;

            $this->currentLocale = $this->defaultLocale;
            // but if hideDefaultLocaleInURL is false, we have
            // to retrieve it from the browser...
            if (!$this->hideDefaultLocaleInURL()) {
                $this->currentLocale = $this->getCurrentLocale();
            }
        }

        $this->app->setLocale($this->currentLocale);

        // Regional locale such as de_DE, so formatLocalized works in Carbon
        $regional = $this->getCurrentLocaleRegional();
        if ($regional) {
            setlocale(LC_TIME, $regional . '.UTF-8');
            setlocale(LC_MONETARY, $regional . '.UTF-8');
        }

        return $locale;
    }

    /**
     * Returns the translation key for a given path
     *
     * @return boolean       Returns value of hideDefaultLocaleInURL in config.
     */
    public function hideDefaultLocaleInURL()
    {
        return $this->configRepository->get('localization.hideDefaultLocaleInURL');
    }

    /**
     * Returns current language
     *
     * @return string current language
     */
    public function getCurrentLocale()
    {
        if ($this->currentLocale) {
            return $this->currentLocale;
        }

        if ($this->useAcceptLanguageHeader()) {
            $negotiator = new LanguageNegotiator($this->defaultLocale, $this->getSupportedLocales(), $this->request);

            return $negotiator->negotiateLanguage();
        }

        // or get application default language
        return $this->configRepository->get('app.locale');
    }

    /**
     * Returns the translation key for a given path
     *
     * @return boolean       Returns value of useAcceptLanguageHeader in config.
     */
    protected function useAcceptLanguageHeader()
    {
        return $this->configRepository->get('localization.useAcceptLanguageHeader');
    }

    /**
     * Returns current regional
     * @return string current regional
     */
    public function getCurrentLocaleRegional()
    {
        // need to check if it exists, since 'regional' has been added
        // after version 1.0.11 and existing users will not have it
        if (isset($this->supportedLocales[$this->getCurrentLocale()]['regional'])) {
            return $this->supportedLocales[$this->getCurrentLocale()]['regional'];
        }

        return null;
    }

    /**
     * Returns an URL adapted to $locale or current locale
     *
     * @param  string $url URL to adapt. If not passed, the current url would be taken.
     * @param  string|boolean $locale Locale to adapt, false to remove locale
     *
     * @throws UnsupportedLocaleException
     *
     * @return string                       URL translated
     */
    public function localizeURL($url = null, $locale = null)
    {
        return $this->getLocalizedURL($locale, $url);
    }

    /**
     * Returns an URL adapted to $locale
     *
     * @throws SupportedLocalesNotDefined
     * @throws UnsupportedLocaleException
     *
     * @param  string|boolean $locale Locale to adapt, false to remove locale
     * @param  string|false $url URL to adapt in the current language. If not passed, the current url would be taken.
     * @param  array $attributes Attributes to add to the route, if empty, the system would try to extract them from the url.
     *
     *
     * @return string|false                URL translated, False if url does not exist
     */
    public function getLocalizedURL($locale = null, $url = null, $attributes = array())
    {
        if ($locale === null) {
            $locale = $this->getCurrentLocale();
        }

        if (!$this->checkLocaleInSupportedLocales($locale)) {
            throw new UnsupportedLocaleException('Locale \'' . $locale . '\' is not in the list of supported locales.');
        }

        if (empty($attributes)) {
            $attributes = $this->extractAttributes($url);
        }

        if (empty($url)) {
            if (!empty($this->routeName)) {
                return $this->getURLFromRouteNameTranslated($locale, $this->routeName, $attributes);
            }

            $url = $this->request->fullUrl();
        }

        if ($locale && $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->currentLocale)) {
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
        }

        $basePath = $this->request->getBaseUrl();
        $parsedUrl = parse_url($url);
        $urlLocale = $this->getDefaultLocale();
        $path = "";

        if ($parsedUrl || !empty($parsedUrl['path'])) {
            $parsedUrl['path'] = str_replace($basePath, '', '/' . ltrim($parsedUrl['path'], '/'));
            $path = $parsedUrl['path'];
            foreach (array_keys($this->getSupportedLocales()) as $localeCode) {
                $parsedUrl['path'] = preg_replace('%^/?' . $localeCode . '/%', '$1', $parsedUrl['path']);
                if ($parsedUrl['path'] !== $path) {
                    $urlLocale = $localeCode;
                    break;
                }

                $parsedUrl['path'] = preg_replace('%^/?' . $localeCode . '$%', '$1', $parsedUrl['path']);
                if ($parsedUrl['path'] !== $path) {
                    $urlLocale = $localeCode;
                    break;
                }
            }
        }

        $parsedUrl['path'] = ltrim($parsedUrl['path'], '/');

        if ($translatedRoute = $this->findTranslatedRouteByPath($parsedUrl['path'], $urlLocale)) {
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
        }

        if (!empty($locale) && ($locale != $this->defaultLocale || !$this->hideDefaultLocaleInURL())) {
            $parsedUrl['path'] = $locale . '/' . ltrim($parsedUrl['path'], '/');
        }

        //Make sure that the pass path is returned with a leading slash only if it come in with one.
        if (starts_with($path, '/') === true) {
            $parsedUrl['path'] = '/' . $parsedUrl['path'];
        }
        $parsedUrl['path'] = rtrim($parsedUrl['path'], '/');

        return $this->createUrlFromUri($parsedUrl['path']);
    }

    /**
     * Check if Locale exists on the supported locales array
     *
     * @param string|boolean $locale string|bool Locale to be checked
     * @throws SupportedLocalesNotDefined
     * @return boolean is the locale supported?
     */
    public function checkLocaleInSupportedLocales($locale)
    {
        $locales = $this->getSupportedLocales();
        if ($locale !== false && empty($locales[$locale])) {
            return false;
        }

        return true;
    }

    /**
     * Extract attributes for current url
     *
     * @param  string|null|false $url to extract attributes, if not present, the system will look for attributes in the current call
     *
     * @return array    Array with attributes
     *
     */
    protected function extractAttributes($url = false)
    {
        $attributes = [];

        if (empty($url)) {
            if (!$this->router->current()) {
                return [];
            }

            $attributes = $this->router->current()->parameters();
            $response = event('routes.translation', [$attributes]);

            if (!empty($response)) {
                $response = array_shift($response);
            }

            if (is_array($response)) {
                $attributes = array_merge($attributes, $response);
            }

            return $attributes;
        }

        $parse = parse_url($url);
        $parse = isset($parse['path']) ? explode("/", $parse['path']) : [];

        $url = [];
        foreach ($parse as $segment) {
            if (!empty($segment)) {
                $url[] = $segment;
            }
        }

        foreach ($this->router->getRoutes() as $route) {
            $path = $route->getUri();
            if (!preg_match("/{[\w]+}/", $path)) {
                continue;
            }

            $path = explode("/", $path);
            $i = 0;

            $match = true;
            foreach ($path as $j => $segment) {
                if (isset($url[$i])) {
                    if ($segment === $url[$i]) {
                        $i++;
                        continue;
                    }
                    if (preg_match("/{[\w]+}/", $segment)) {
                        // must-have parameters
                        $attributeName = preg_replace(["/}/", "/{/", "/\?/"], "", $segment);
                        $attributes[$attributeName] = $url[$i];
                        $i++;
                        continue;
                    }
                    if (preg_match("/{[\w]+\?}/", $segment)) {
                        // optional parameters
                        if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
                            // optional parameter taken
                            $attributeName = preg_replace(["/}/", "/{/", "/\?/"], "", $segment);
                            $attributes[$attributeName] = $url[$i];
                            $i++;
                            continue;
                        }
                    }
                } else if (!preg_match("/{[\w]+\?}/", $segment)) {
                    // no optional parameters but no more $url given
                    // this route does not match the url
                    $match = false;
                    break;
                }
            }

            if (isset($url[$i + 1])) {
                $match = false;
            }

            if ($match) {
                return $attributes;
            }
        }

        return [];
    }

    /**
     * Returns an URL adapted to the route name and the locale given
     *
     * @throws SupportedLocalesNotDefined
     * @throws UnsupportedLocaleException
     *
     * @param  string|boolean $locale Locale to adapt
     * @param  string $transKeyName Translation key name of the url to adapt
     * @param  array $attributes Attributes for the route (only needed if transKeyName needs them)
     *
     * @return string|false    URL translated
     */
    public function getURLFromRouteNameTranslated($locale, $transKeyName, $attributes = array())
    {
        if (!$this->checkLocaleInSupportedLocales($locale)) {
            throw new UnsupportedLocaleException('Locale \'' . $locale . '\' is not in the list of supported locales.');
        }

        if (!is_string($locale)) {
            $locale = $this->getDefaultLocale();
        }

        $route = "";

        if (!($locale === $this->defaultLocale && $this->hideDefaultLocaleInURL())) {
            $route = '/' . $locale;
        }
        if (is_string($locale) && $this->translator->has($transKeyName, $locale)) {
            $translation = $this->translator->trans($transKeyName, [], "", $locale);
            $route .= "/" . $translation;

            $route = $this->substituteAttributesInRoute($attributes, $route);
        }

        if (empty($route)) {
            // This locale does not have any key for this route name
            return false;
        }

        return rtrim($this->createUrlFromUri($route));


    }

    /**
     * Returns default locale
     *
     * @return string
     */
    public function getDefaultLocale()
    {
        return $this->defaultLocale;
    }

    /**
     * Change route attributes for the ones in the $attributes array
     *
     * @param $attributes array Array of attributes
     * @param string $route string route to substitute
     * @return string route with attributes changed
     */
    protected function substituteAttributesInRoute($attributes, $route)
    {
        foreach ($attributes as $key => $value) {
            $route = str_replace("{" . $key . "}", $value, $route);
            $route = str_replace("{" . $key . "?}", $value, $route);
        }

        // delete empty optional arguments that are not in the $attributes array
        $route = preg_replace('/\/{[^)]+\?}/', '', $route);

        return $route;
    }

    /**
     * Create an url from the uri
     * @param    string $uri Uri
     *
     * @return  string  Url for the given uri
     */
    public function createUrlFromUri($uri)
    {
        $uri = ltrim($uri, "/");

        if (empty($this->baseUrl)) {
            return app('url')->to($uri);
        }

        return $this->baseUrl . $uri;
    }

    /**
     * Returns the translated route for an url and the attributes given and a locale
     *
     * @throws SupportedLocalesNotDefined
     * @throws UnsupportedLocaleException
     *
     * @param  string|false|null $url Url to check if it is a translated route
     * @param  array $attributes Attributes to check if the url exists in the translated routes array
     * @param  string $locale Language to check if the url exists
     *
     * @return string|false                Key for translation, false if not exist
     */
    protected function findTranslatedRouteByUrl($url, $attributes, $locale)
    {
        if (empty($url)) {
            return false;
        }

        // check if this url is a translated url
        foreach ($this->translatedRoutes as $translatedRoute) {
            $routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);

            if ($this->getNonLocalizedURL($routeName) == $this->getNonLocalizedURL($url)) {
                return $translatedRoute;
            }
        }

        return false;
    }

    /**
     * It returns an URL without locale (if it has it)
     * Convenience function wrapping getLocalizedURL(false)
     *
     * @param  string|false $url URL to clean, if false, current url would be taken
     *
     * @return string           URL with no locale in path
     */
    public function getNonLocalizedURL($url = null)
    {
        return $this->getLocalizedURL(false, $url);
    }

    /**
     * Returns the translated route for the path and the url given
     *
     * @param  string $path Path to check if it is a translated route
     * @param  string $urlLocale Language to check if the path exists
     *
     * @return string|false            Key for translation, false if not exist
     */
    protected function findTranslatedRouteByPath($path, $urlLocale)
    {
        // check if this url is a translated url
        foreach ($this->translatedRoutes as $translatedRoute) {
            if ($this->translator->trans($translatedRoute, [], "", $urlLocale) == rawurldecode($path)) {
                return $translatedRoute;
            }
        }

        return false;
    }

    /**
     * Returns current locale name
     *
     * @return string current locale name
     */
    public function getCurrentLocaleName()
    {
        return $this->supportedLocales[$this->getCurrentLocale()]['name'];
    }

    /**
     * Returns current locale native name
     *
     * @return string current locale native name
     */
    public function getCurrentLocaleNative()
    {
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
    }

    /**
     * Returns current locale direction
     *
     * @return string current locale direction
     */
    public function getCurrentLocaleDirection()
    {

        if (!empty($this->supportedLocales[$this->getCurrentLocale()]['dir'])) {
            return $this->supportedLocales[$this->getCurrentLocale()]['dir'];
        }

        switch ($this->getCurrentLocaleScript()) {
            // Other (historic) RTL scripts exist, but this list contains the only ones in current use.
            case 'Arab':
            case 'Hebr':
            case 'Mong':
            case 'Tfng':
            case 'Thaa':
                return 'rtl';
            default:
                return 'ltr';
        }

    }

    /**
     * Returns current locale script
     *
     * @return string current locale script
     */
    public function getCurrentLocaleScript()
    {
        return $this->supportedLocales[$this->getCurrentLocale()]['script'];
    }

    /**
     * Returns current language's native reading
     *
     * @return string current language's native reading
     */
    public function getCurrentLocaleNativeReading()
    {
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
    }

    /**
     * Returns supported languages language key
     *
     * @return array    keys of supported languages
     */
    public function getSupportedLanguagesKeys()
    {
        return array_keys($this->supportedLocales);
    }

    /**
     * Set current route name
     * @param string $routeName current route name
     */
    public function setRouteName($routeName)
    {
        $this->routeName = $routeName;
    }

    /**
     * Translate routes and save them to the translated routes array (used in the localize route filter)
     *
     * @param  string $routeName Key of the translated string
     *
     * @return string                Translated string
     */
    public function transRoute($routeName)
    {
        if (!in_array($routeName, $this->translatedRoutes)) {
            $this->translatedRoutes[] = $routeName;
        }

        return $this->translator->trans($routeName);
    }

    /**
     * Returns the translation key for a given path
     *
     * @param  string $path Path to get the key translated
     *
     * @return string|false            Key for translation, false if not exist
     */
    public function getRouteNameFromAPath($path)
    {
        $attributes = $this->extractAttributes($path);

        $path = str_replace(url('/'), "", $path);
        if ($path[0] !== '/') {
            $path = '/' . $path;
        }
        $path = str_replace('/' . $this->currentLocale . '/', '', $path);
        $path = trim($path, "/");

        foreach ($this->translatedRoutes as $route) {
            if ($this->substituteAttributesInRoute($attributes, $this->translator->trans($route)) === $path) {
                return $route;
            }
        }

        return false;
    }

    /**
     * Returns the config repository for this instance
     *
     * @return Repository    Configuration repository
     *
     */
    public function getConfigRepository()
    {
        return $this->configRepository;
    }

    /**
     * Sets the base url for the site
     * @param string $url Base url for the site
     *
     */
    public function setBaseUrl($url)
    {
        if (substr($url, -1) != "/") {
            $url .= "/";
        }

        $this->baseUrl = $url;
    }

    /**
     * Returns translated routes
     *
     * @return array translated routes
     */
    protected function getTranslatedRoutes()
    {
        return $this->translatedRoutes;
    }

    /**
     * Returns true if the string given is a valid url
     *
     * @param  string $url String to check if it is a valid url
     *
     * @return boolean        Is the string given a valid url?
     */
    protected function checkUrl($url)
    {
        return filter_var($url, FILTER_VALIDATE_URL);
    }
}