This can be done in 3 main steps.
1. Get the site subdirectories working
First just get the /en/
and /es/
subdirectory working:
- Create
en/
and es/
subfolders in your webroot
- Each subfolder should have its own
index.php
file and .htaccess
file (if using Apache).
Assuming you used the craftcms/craft project as a starting point, update the define('CRAFT_BASE_PATH'...
line in each of the index.php
files to:
define('CRAFT_BASE_PATH', dirname(__DIR__, 2));
Update your English site’s Base URL to include the /en/
.
At this point, if you point your browser directly to /en/
, the English site should work as expected.
2. Create a redirect script in the webroot’s index.php
Create an index.php
file in your webroot (alongside the en/
and es/
subfolders). This script will be responsible for redirecting the request to the correct subfolder, based on the requested URI and language.
<?php
// Bootstrap Craft -------------------------------------------------------------
// Set path constants
define('CRAFT_BASE_PATH', dirname(__DIR__));
define('CRAFT_VENDOR_PATH', CRAFT_BASE_PATH.'/vendor');
// Load Composer's autoloader
require_once CRAFT_VENDOR_PATH.'/autoload.php';
// Load dotenv?
if (file_exists(CRAFT_BASE_PATH.'/.env')) {
(new Dotenv\Dotenv(CRAFT_BASE_PATH))->load();
}
// Load Craft (but don't run)
define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
/** @var \craft\web\Application $app */
$app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';
// Custom Logic ----------------------------------------------------------------
// find a site language that matches the browser's requested language
$siteLanguages = $app->i18n->getSiteLocaleIds();
$language = $app->request->getPreferredLanguage($siteLanguages);
// find the first site that uses that language
foreach ($app->sites->getAllSites() as $site) {
if ($site->language === $language) {
// found it
break;
}
}
// figure out where to redirect this request now
$url = (function() use ($app, $site) {
$uri = $app->request->getPathInfo();
// see if we have an exact URI/language match
if ($element = $app->elements->getElementByUri($uri, $site->id, true)) {
return $element->getUrl();
}
// see if we have an exact URI match in any other site
foreach ($app->sites->getAllSites() as $otherSite) {
if ($otherSite !== $site) {
if ($otherSiteElement = $app->elements->getElementByUri($uri, $otherSite->id, true)) {
// found one! now see if the element is also available in the requested site
if ($element = $otherSiteElement::find()->id($otherSiteElement->id)->siteId($site->id)->one()) {
return $element->getUrl();
}
// otherwise we'll just ignore the browser language
return $otherSiteElement->getUrl();
}
}
}
// no element matches. we'll just redirect to the same URI in the requested site.
return \craft\helpers\UrlHelper::siteUrl($uri, null, null, $site->id);
})();
// redirect to the URL
$app->response->redirect($url)->send();
With that in place, you should be able to start testing the redirects by pointing your browser to /index.php?p=some/uri
.
3. Redirect nonlocalized requests to the webroot’s index.php
Finally, we want to get all requests that don’t start with en/
or es/
to be routed to an index.php
file in your web root. If you’re using Apache, you can do that with mod_rewrite
:
# Send requests missing en/ or es/ to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(en|es) [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
Now everything should work!
.htaccess
orindex.php
into whatever folderhttp://localhost:8888
is configured to serve with your redirect logic in it, no? – Brad Bell Feb 5 '18 at 20:08mysite.com
and all it's sections intomysite.com/en
andmysite.com/es
. Just like microsoft.com is doing; you can never browsemicrosoft.com/section
but instead you get redirected tomicrosoft.com/en-US/section
. I got this to work only when I create a third Craft site: - default (.htaccess and index.php are under public/) - English (.htaccess and index.php are under public/en) - Spanish (they are under public/es) – Rosana Ruiz Feb 5 '18 at 21:08