Jump to content

How to do a language switcher without the module LanguageSupportPageNames installed?


Pixrael
 Share

Recommended Posts

I want to make a language switcher for my site header but I don't want to use the LanguageSupportPageNames module, in this website case I prefer using path siterootpath/services for English and siterootpath/es/services for Spanish, but I can't print the path without $page->localurl() and that function seems to be only available in the LanguageSupportPageNames module .. too if I put siterootpath/es/ in the browser this causes me a 404 error.. How to do this, please?

Link to comment
Share on other sites

Yes, I test that site profile before, but I decided to build my site from scratch with the blank profile and using a template system. I try to reuse the language switcher found in that profile. but it makes use of functions (localHttpUrl, localUrl) that (I think) are only available when you install the LanguageSupportPageNames module, and will not really use it.

I already install the base Language Support module and the Language Support Fields module. I understood that the use of Language Support Page Names module was optional to support multiple languages :-( It's simple, I only need the current page url for each language available

Link to comment
Share on other sites

While LanguageSupportPageNames is in fact optional, rolling your own language handling under the hood needs a bit of coding. Basically, you have to implement by yourself what LanguageSupportPageNames does in hookProcessPageViewExecute(), isAssetPath() and updatePath(), that is, intercept the request and, if there's a language prefix in the URL and it's not a request for an asset file, extract the path and language, set the user's language and update $_GET["it"] (the requested URL) with the non-prefixed URL.

Link to comment
Share on other sites

A cheap rip-off of LanguageSupportPageNames that adds support for prefixed urls, localUrl and localHttpUrl:

<?php

/**
 * Adds simple support for URL paths prefixed by language name.
 *
 * Proof-of-concept.
 *
 * Most of the actual code is stolen from LanguageSupportPageNames.
 * Adds the same localUrl and localHttpUrl methods to page objects.
 *
 */
class LanguageSupportPath extends Wire implements Module {
	public static function getModuleInfo() {
		return array(
			"title"			=>	__("Support for Language Path"),
			"summary"		=>	__("Adds simple support for URL paths prefixed by language name"),
			"version"		=>	"0.0.3",
			"autoload"		=>	true,
			"requires"		=>	array(
				"LanguageSupport"
			)
		);
	}
	
	public function init() {
		$this->addHookBefore("ProcessPageView::execute", $this, "hookProcessPageViewExecute");
	}
	
	public function ready() {
		$this->addHook('Page::localUrl', $this, 'hookPageLocalUrl');
		$this->addHook('Page::localHttpUrl', $this, 'hookPageLocalHttpUrl'); 
	}
	
	/**
	 * Hook in before ProcesssPageView::execute to capture and modify $_GET[it] as needed
	 *
	 */
	public function hookProcessPageViewExecute(HookEvent $event) {
		$event->object->setDelayRedirects(true); 
		// save now, since ProcessPageView removes $_GET['it'] when it executes
		$it = isset($_GET['it']) ? $_GET['it'] : '';
		if(!$this->isAssetPath($it)) {
			if(strpos($it, "processwire/") !== 0) $this->log->message("Original path: $it");
			$it = $this->updatePath($it);
			if(strpos($it, "processwire/") !== 0) $this->log->message("Updated path: $it");
			$_GET['it'] = $it;
		}
	}

	/**
	 * Is the given path a site assets path? (i.e. /site/)
	 * 
	 * Determines whether this is a path we should attempt to perform any language processing on.
	 * 
	 * @param string $path
	 * @return bool
	 *
	 */
	protected function isAssetPath($path) {
		$config = $this->wire('config');
		// determine if this is a asset request, for compatibility with pagefileSecure
		$segments = explode('/', trim($config->urls->assets, '/')); // start with [subdir]/site/assets
		array_pop($segments); // pop off /assets, reduce to [subdir]/site
		$sitePath = '/' . implode('/', $segments) . '/'; // combine to [/subdir]/site/
		$sitePath = str_replace($config->urls->root, '', $sitePath); // remove possible subdir, reduce to: site/
		// if it is a request to assets, then don't attempt to modify it
		return strpos($path, $sitePath) === 0;
	}

	/**
	 * Given a page path, return an updated version that lacks the language segment
	 *
	 * It extracts the language segment and uses that to later set the language
	 *
	 */
	public function updatePath($path) {
		if($path === '/' || !strlen($path)) {
			$this->user->language = $this->wire('languages')->getDefault();
			return $path;
		}
		$trailingSlash = substr($path, -1) == '/';
		$testPath = trim($path, '/') . '/';
		$home = $this->wire('pages')->get(1);
		$found = false;
		foreach($this->wire('languages') as $language) {
			if($language->isDefault()) continue;
			$name = $language->name . "/"; 
			if(strpos($testPath, $name) === 0) {
				$found = true;
				$this->user->language = $language; 
				$path = substr($testPath, strlen($name)); 
				break;
			}
		}
		if(!$found) $this->user->language = $this->wire('languages')->getDefault();
		if(!$trailingSlash && $path != '/') $path = rtrim($path, '/'); 
		return $path; 
	}
	
	public function hookPageLocalUrl(HookEvent $event) {
		$lang = $this->getLanguage($event->arguments(0));
		$event->return = $this->wire('config')->urls->root . ltrim(($lang->isDefault() ? "" : $lang->name) . $event->object->path, "/"); 
	}

	public function hookPageLocalHttpUrl(HookEvent $event) {
		$this->hookPageLocalUrl($event); 
		$url = $event->return;
		$event->return = $this->wire('input')->scheme() . "://" . $this->wire('config')->httpHost . $url;
	}

	/**
	 * Given an object, integer or string, return the Language object instance
	 *
	 * @param int|string|Language
	 * @return Language
	 *
	 */
	protected function getLanguage($language) {

		if(is_object($language)) {
			if($language instanceof Language) return $language; 
			$language = '';
		}

		if($language && (is_string($language) || is_int($language))) {
			if(ctype_digit("$language")) $language = (int) $language; 
				else $language = $this->wire('sanitizer')->pageNameUTF8($language); 
			$language = $this->wire("languages")->get($language); 
		}

		if(!$language || !$language->id || !$language instanceof Language) {
			$language = $this->wire('languages')->get('default'); 
		}

		return $language; 
	}

	public function ___install() {
		if($this->modules->isInstalled("LanguageSupportPageNames")) {
			throw new WireException($this->_("LanguageSupportPath and LanguageSupportPageNames cannot be active at the same time"));
		}
	}
}

This way, of course, the page paths after the prefix are identical for all languages, which might not be desired for SEO reasons. The module also may have side effects from setting the language that I didn't consider, so use at your own risk ;)

 

  • Like 3
Link to comment
Share on other sites

Great! BitPoet thank you very much, for your time and your effort, this is an incredible community! I'm so glad I found this place. I'm a graphic designer with a lot experience making Web/UI/UX designs, but always associated with programmers who build the business and data access layer, I just make the design and layout with html, css and some javascript, mainly jquery. But finding Processwire and see the ease of use, at least for small business marketing sites, gave me the courage to make complete projects for myself, and although I fully understand the whole concept of working with Processwire, in these initial steps I stuck a little on small details and decision making in which is the best way to go, for example: using some templates system or not, etc. But I'm motivated to continue (sorry for my programmers hehe) now I'm starting to prepare an starting site profile with everything prepared for this kind of webs, that help me to start new projects quickly from it.. bye wp!
So again thank you very much for your help and everyone here.

  • Like 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...