Alternate front-end usage examples
These are alternates to the multi-language URLs method. If possible, we recommend using that method. But if you can't for some reason, here are a few alternate examples that demonstrate how you might take advantage of multi-language fields on the front-end of your site.
Example 1: Displaying a different language based on URL segment
Please note that the method described in this example (1) is now deprecated. While it is still perfectly fine to use, you may find it better to use the multi-language URLs method, available in newer versions of ProcessWire.
Lets say that you have a page that lives at the URL /about/ and you have one or more fields on that page available in multiple languages. When someone accesses /about/ they get the page in the default language. When someone accesses the page with /about/spanish/ you want it to display the Spanish version of that page. You'd want to have some code at the top of your template file (or better yet, a shared header include file) that does something like this:
if($input->urlSegment1 == 'spanish') {
$user->language = $languages->get("spanish");
}
Now when the page displays, it will be the /about/ page, but in Spanish, and living at it's own URL. Note that to use URL segments, you must have the "allow URL segments" option enabled in your template's settings.
To take this example further, you might also want to automatically link to the Spanish-versions of other pages in your site. So when you output your navigation, you may want to append "/spanish/" to the end of URLs you output, but only for pages where you are supporting it.
if($user->language->name != 'default') $segment = $user->language->name;
else $segment = '';
foreach($page->children as $child) {
echo "<li><a href='{$child->url}$segment'>{$child->title}</a></li>";
}
Example 2: Display a different language based on subdomain
Lets say that you have domain.com for your site, and you want your site to display in Spanish when accessed at the subdomain: spanish.domain.com. You would configure spanish.domain.com to point to your site in the same way as domain.com so that you can access your site from either. Once you've got that in place, you'd want to add the following code to the top of your header include file used by your templates (or any common included file that you use before creating output).
if($config->httpHost == 'spanish.domain.com') {
$user->language = $languages->get("spanish");
}
Now whenever your site is accessed at spanish.domain.com, the language is assumed to be Spanish and the site will output the Spanish-language fields where applicable. This same technique would apply to other hostnames or even other domain names you point at your server.
Note that unlike Example 1, it's not necessary for us to modify the output of our navigation as the current hostname is usually assumed by ProcessWire API functions that return URLs. This makes things simpler.
Example 3: Display a different language based on URL pre-segment
Please note that the method described in this example (3) is now deprecated. While it is still perfectly fine to use, you may find it better to use the multi-language URLs method, available in newer versions of ProcessWire.
This example is very similar to Example 1, except that we're dealing with a pre-segment rather an a post-segment. Meaning, we'd be looking for a URL like /spanish/about/ rather than /about/spanish/. Many prefer this as the language is the first segment identified in the URL.
To proceed, we will need to create top-level pages in your site to represent each language. The pages will have to use a special template we'll create, and the pages will have to use names consistent with the language names in our site. For the sake of simplicity, we'll continue our Spanish example and just assume that's the only other language we are supporting.
Create a new template called "language-gateway" (or something else if you prefer). In the templates "URL" settings, ensure that "URL Segments" are enabled. Save. Now create the corresponding file for this template, called /site/templates/language-gateway.php and place the following code in it:
$user->language = $languages->get($page->name);
$path = '/';
foreach($input->urlSegments as $segment) {
$path .= $segment . '/';
}
$mypage = $pages->get($path);
if(!$mypage->id || !$mypage->viewable()) throw new Wire404Exception();
echo $mypage->render();
Next you'd create a top-level page called "/spanish/" and make it use the language-gateway template. You don't need to create any pages below it. Now when someone accesses /spanish/about/ or /spanish/portfolio/abc/ (or any valid URL in your site), it will set the user's language to Spanish, load the page, and output it in Spanish.
This example has a similar problem to Example 1 in that you have to determine how best to adjust your site's navigation for the language. You would do this in the same manner as in Example 1. However, another approach you could use here would be to capture the $mypage->render() output to a variable and perform a string replacement, inserting the current language into any URLs present in the output:
$out = $mypage->render();
$regex = '{(<a [^>]*href=["\']/)(["\']';
$topnav = $page->parent->children();
foreach($topnav as $p) $regex .= "|" . $p->name;
$regex .= ")}";
$out = preg_replace($regex, '$1' . $page->name . '/$2', $out);
echo $out;
The above example uses a regular expression to match any <a> tags linking to pages that have a URL starting with one of the site's top level pages, and then prepends the language name to the beginning of those links. We use a regex to ensure that we aren't modifying any links that might be pointing to things outside of ProcessWire pages. If you implement this technique, please post about your experience in the forum and we'll also be happy to help you customize it to your needs.
Example 4: Setting the language in the $session
This example is one of the simplest (second only to using subdomains), but it's also one to avoid if search accessibility is important to your site. It determines the language from a user's session variable rather than from the URL, so it can cause problems with how your site is indexed by 3rd party search engines. However, if your multi-language needs are for an application, intranet, mobile app or something else that doesn't rely on search engine indexing, then this is definitely a good approach to consider.
The approach works like this: the user is presented with links that let them choose what language they want to view your site in. These can be present on every page, or at some gateway page. The links would point to the current page's URL with a GET variable setting the language:
<a href='./?language=dutch'>Dutch</a>
<a href='./?language=spanish'>Spanish</a>
<a href='./?language=default'>English</a>
You would then setup a common template (like a header include) to detect when the language is set, and assign it to a session variable. In the same place, you'd also set the current language based on the session variable.
if($input->get->language) {
// user clicked on a link to set the language
$name = $sanitizer->pageName($input->get->language);
$language = $languages->get($name);
if($language) $session->language = $language->name;
}
if($session->language) {
// language is defined in user's session
$user->language = $languages->get($session->language);
}
That's all that you need to do. Anything that follows that will be outputting in the proper language where available.