X-Cart: shopping cart software

X-Cart forums (https://forum.x-cart.com/index.php)
-   Dev Questions (X-Cart 5) (https://forum.x-cart.com/forumdisplay.php?f=56)
-   -   x5 - Subdirectories for languages using htaccess rewrite (https://forum.x-cart.com/showthread.php?t=72460)

xgarb 07-20-2015 06:36 AM

x5 - Subdirectories for languages using htaccess rewrite
 
On a previous x4 site I had something like the following set up with each language subdirectory using the files from the root of domain.com. ie just one install of X-cart for the 4 languages.

domain.com/en
domain.com/es
domain.com/it
domain.com/fr

I want to do the same with the new x5 site.

If I add the following to the .htaccess file

RewriteRule ^es/(.*) /$1
RewriteRule ^fr/(.*) /$1
RewriteRule ^it/(.*) /$1

I can access any pages from the root directory from the language subdirectories, for example domain.com/toys is available from domain.com/fr/toys and domain.com/es/toys, but the links themselves on the page are missing the language subdirectory.

Where should I look to correct this?

qualiteam 07-21-2015 05:13 AM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
I believe that almost all places that render links in X-Cart 5 call the \XLite\Core\Handler::buildURL() method in the end.

So, you should somehow program your custom module to insert the current language into the URL here (or in other methods that call this method).

xgarb 07-21-2015 06:34 AM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
In the end I found I had to go to the top and in var/run/classes/XLiteAbstract.php

edit getShopURL

Code:

public function getShopURL($url = '', $isSecure = null, array $params = array())
    { 
        $url = 'es/'.$url ;
        return \XLite\Core\URLManager::getShopURL($url, $isSecure, $params);
    }


to get the subdirectory to appear in links. This is just a test! I now have to incorporate the code here x5 set language from browser and make it into a module.

There is one thing that doesn't work though.. when there's more than one category in the url (ie domain.com/es/toys/rc-toys) gives a page not found.

xgarb 07-22-2015 06:41 AM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
I've got further with this.

Code:

getShopURL now looks like this:

    public function getShopURL($url = '', $isSecure = null, array $params = array())
    {
   
            //find current country code in URL
        $_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $segments = explode('/', substr($_SERVER['REQUEST_URI_PATH'], 1));
        $lang_dir = $segments[0];
        $store_language = $lang_dir; //code from url
        if (in_array($store_language, array('es','it','fr','de'))){
        $url = $store_language.'/'.$url;
        }

        return \XLite\Core\URLManager::getShopURL($url, $isSecure, $params);
    }


and the relevant part of the htaccess file...

Code:

  RewriteEngine on

  RewriteRule ^es/(.*) /$1
  RewriteRule ^fr/(.*) /$1
  RewriteRule ^de/(.*) /$1
  RewriteRule ^it/(.*) /$1

  # #BUG-772 Add HTTP_AUTHORIZATION header for fastCGI (need for XC\Qiwi)
  RewriteCond %{HTTP:Authorization} ^(.*)
  RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

  RewriteRule (^|/)\. - [F]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^sitemap.xml(\?.+)?$ cart.php?target=sitemap [NC,L,QSA]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !^/../
  RewriteRule ^((([/_a-z0-9-]+)/)?([_a-z0-9-]+)/)?([_a-z0-9-]+)(/?)(\.([_a-z0-9-]+))?$ cart.php?url=$5&last=$4&rest=$3&ext=$7 [NC,L,QSA]
 
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} ^/../
  RewriteRule ^../((([/_a-z0-9-]+)/)?([_a-z0-9-]+)/)?([_a-z0-9-]+)(/?)(\.([_a-z0-9-]+))?$ cart.php?url=$5&last=$4&rest=$3&ext=$7 [NC,L,QSA] 

  RewriteBase /


I realised that getShopURL is used by everything to build the path so the above isn't very efficient in that the method is not just making the links have the correct path but making all the page contents have the wrong path which is then corrected by the first part of the htaccess file.

Without the second part of the htaccess there was a problem with deeper directories.

I need the have English in the root to match the current site.

Any ideas or input welcome!

xgarb 07-27-2015 08:33 AM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
I now have this working as a module with the following functionality

One install of X-cart
English at the root of the domain (ie domain.com)
Four other languages in subdirectories (ie domain.com/fr domain.com/de etc)
Language displayed based on URL (better for SEO and linking in general)
Override selection of language via normal x-cart language selector
Cookie set to remember user's preference if they use the language selector.
I've removed the detection based on user's browsers language

The files are as follows:

In htaccess:

Code:

<IfModule mod_rewrite.c>
  RewriteEngine on
 
  RewriteRule ^es/(.*) /$1
  RewriteRule ^fr/(.*) /$1
  RewriteRule ^de/(.*) /$1
  RewriteRule ^it/(.*) /$1

  RewriteCond %{HTTP:Authorization} ^(.*)
  RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

  RewriteRule (^|/)\. - [F]
 
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !^/../
  RewriteRule ^((([/_a-z0-9-]+)/)?([_a-z0-9-]+)/)?([_a-z0-9-]+)(/?)(\.([_a-z0-9-]+))?$ cart.php?url=$5&last=$4&rest=$3&ext=$7 [NC,L,QSA]
 
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} ^/../
  RewriteRule ^../((([/_a-z0-9-]+)/)?([_a-z0-9-]+)/)?([_a-z0-9-]+)(/?)(\.([_a-z0-9-]+))?$ cart.php?url=$5&last=$4&rest=$3&ext=$7 [NC,L,QSA] 

  #RewriteBase ____WEB_DIR____
</IfModule>



SetLanguageFromDir.php (sets the language based on URL but redirects if the cookie value differs)

Code:

abstract class SetLanguageFromDir extends \XLite\Core\Session implements \XLite\Base\IDecorator


    /**
    * Get language
    *
    * @return \XLite\Model\Language
    */
    public function getLanguage()
    {
           
                if (!isset($this->language)){
               
                      $current_language = 'en'; // default in case no language set
               
                        $_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
                        $segments = explode('/', substr($_SERVER['REQUEST_URI_PATH'], 1));
                        $url_lang = $segments[0];
               
                        if (in_array($url_lang, array('es','it','fr','de'))){
                                $current_language = $url_lang;
                        }
               
                        $this->language = \XLite\Core\Database::getRepo('XLite\Model\Language')
                        ->findOneByCode($current_language);
                }     

                return $this->language;
        }
       
       
           
    /**
    * language cooookies!
    *
    */   
    public function getLanguageCookie()
    {     
            $store_language_codes = array('en','es','fr','de','it') ;
                $cookieLanguageCode = NULL;

        // -- If cookie is set
        if ( in_array(strtolower($_COOKIE[store_language]), $store_language_codes) ) {
                        $cookieLanguageCode = strtolower($_COOKIE[store_language]) ;
        }

        return  $cookieLanguageCode;
    }
   
    /**
    * Create session
    *
    * @return void
    */
    protected function createSession()
    {
   
        $_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
                $segments = explode('/', substr($_SERVER['REQUEST_URI_PATH'], 1));
                $url_lang = $segments[0];
                $http_or_https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://' ; //basic check
                $lang_cookie  = $this->getLanguageCookie();

                if (strlen($url_lang) == 2 && !empty($lang_cookie)){ // a language is set in the URL and cookie
                    if ($lang_cookie != $url_lang){ // the user's cookie is different from the language in the URL
                                $reuse_uri = $_SERVER['REQUEST_URI'];
                                $reuse_uri = substr($reuse_uri,3); // remove current character code
                                if ($lang_cookie != 'en'){
                                        $redirect_to = $http_or_https.$_SERVER['SERVER_NAME']."/".$lang_cookie.$reuse_uri;
                                        header("Location: ".$redirect_to,TRUE,307); //redirect to url with a language code
                                        exit;
                                }
                                if ($lang_cookie == 'en'){
                                        $redirect_to = $http_or_https.$_SERVER['SERVER_NAME'].$reuse_uri;
                                        header("Location: ".$redirect_to,TRUE,307); //redirect to url without a language code
                                        exit;
                                }       
                        }
               
        }
       
        if (strlen($url_lang) != 2 && !empty($lang_cookie) && $lang_cookie != 'en'){ // no language is set in the URL but a non-English cookie is set
                        $reuse_uri = $_SERVER['REQUEST_URI'];
                        $redirect_to = $http_or_https.$_SERVER['SERVER_NAME']."/".$lang_cookie."/".$reuse_uri;
                              header("Location: ".$redirect_to,TRUE,307); //redirect to url with a language code
                                exit;             
        }       
   
   
        if ($this->useDumpSession()) {
            $this->session = new \XLite\Model\SessionDump();

        } else {
            $this->session = new \XLite\Model\Session();
            $this->session->updateExpiry();
            $this->session->setSid(\XLite\Core\Database::getRepo('XLite\Model\Session')->generatePublicSessionId());

            \XLite\Core\Database::getEM()->persist($this->session);
            \XLite\Core\Database::getEM()->flush();
        }
    }

}



SetLanguageFromSelector.php (sets cookies and redirects)

Code:

abstract class SetLanguageFromSelector extends \XLite\Controller\AController implements \XLite\Base\IDecorator

    /**
    * Change current language
    *
    * @return void
    */
    protected function doActionChangeLanguage()
    {
        $code = strval(\XLite\Core\Request::getInstance()->language);

        if (!empty($code)) {
            $language = \XLite\Core\Database::getRepo('\XLite\Model\Language')->findOneByCode($code);
           
            setcookie('store_language', $code, time()+31536000,"/"); // new line
                    $_COOKIE['store_language'] = $code; // new line

            if (isset($language) && $language->getEnabled()) {
                \XLite\Core\Session::getInstance()->setLanguage($language->getCode());
                if (\XLite\Core\Auth::getInstance()->isLogged()) {
                    \XLite\Core\Auth::getInstance()->getProfile()->setLanguage($language->getCode());
                    \XLite\Core\Database::getEM()->flush();
                }
            }
        }
               

                // finding and redoing current URL to add/remove language code
              $_SERVER['REQUEST_URI_PATH'] = parse_url($this->getReferrerURL(), PHP_URL_PATH);
                $segments = explode('/', substr($_SERVER['REQUEST_URI_PATH'], 1));
                $url_lang = $segments[0];
                $http_or_https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://' ; //basic check

        if (strlen($url_lang) == 2){ // a language is set in the URL
                        $reuse_uri = parse_url($this->getReferrerURL(), PHP_URL_PATH);
                                $reuse_uri = substr($reuse_uri,3); // remove current character code
                                if ($code != 'en'){
                                        $new_url = $http_or_https.$_SERVER['SERVER_NAME']."/".$code.$reuse_uri;
                                }
                                if ($code == 'en'){
                                        $new_url = $http_or_https.$_SERVER['SERVER_NAME'].$reuse_uri;
                                }
        }
               
                if (strlen($url_lang) != 2){ // no language is set in the URL
                        $reuse_uri = parse_url($this->getReferrerURL(), PHP_URL_PATH);
                        if ($code != 'en'){
                        $new_url = $http_or_https.$_SERVER['SERVER_NAME']."/".$code.$reuse_uri;
                        }
                        if ($code == 'en'){
                        $new_url = $http_or_https.$_SERVER['SERVER_NAME'].$reuse_uri;
                                }
        }


        $this->setReturnURL($new_url);
    }
       
}


AddLanguageDirToLinks.php

Code:

abstract class AddLanguageDirToLinks extends \XLite  implements \XLite\Base\IDecorator
{
    public function getShopURL($url = '', $isSecure = null, array $params = array())
    {
       
                $_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
                $segments = explode('/', substr($_SERVER['REQUEST_URI_PATH'], 1));
                $lang_dir = $segments[0];
                $url_language = $lang_dir; //code from url       
       
                if (in_array($url_language, array('es','it','fr','de'))){
                $url = $url_language .'/'.$url;
                }


    return \XLite\Core\URLManager::getShopURL($url, $isSecure, $params);
    }
}



If anyone spots anything that can be replace with X-cart functions or constants let me know. I don't really like the http stuff I've used.

qualiteam 07-27-2015 09:34 PM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
I believe this will be a very useful module!

However, I'm not sure about the following things:

1. "return \XLite\Core\URLManager::getShopURL($url, $isSecure, $params);"

I think you should use parent::getShopURL() there.

2. Changes to .htaccess

I believe modules can't alter .htaccess, so the changes should be explained somewhere in the module description or documentation.

xgarb 11-12-2018 06:41 AM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
Looks like most of this is in the core now. Just edit this line in config.php

Code:

[clean_urls]
; Is use urls like domain.com/LG for languages
; possible values "Y", "N"
; Changing this setting requires to re-deploy your store
use_language_url = "Y"


qualiteam 11-14-2018 04:05 AM

Re: x5 - Subdirectories for languages using htaccess rewrite
 
Quote:

Originally Posted by xgarb
Looks like most of this is in the core now. Just edit this line in config.php

Code:

[clean_urls]
; Is use urls like domain.com/LG for languages
; possible values "Y", "N"
; Changing this setting requires to re-deploy your store
use_language_url = "Y"




That is correct, this is in the core now.


All times are GMT -8. The time now is 04:05 AM.

Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.