Concept
So Fluent supports localising via query string out of the box, but appending locales to the URL is reserved for pages driven by the CMS. With your example I'm able to see correct results via /search?l=en
and /search?l=mi
.
In order to allow locales in the URL for non-SiteTree routes, we can patch FluentDirectorExtension
, which is the class responsible for injecting Fluent's routing rules, and add support for explicit configuration of routes that should also be localisable. This can be achieved by adding Director rules that essentially do the same thing as above, but masking the /search?l=en
URL as /en/search
in the background.
My example configuration is something like this:
TractorCow\Fluent\Extension\FluentDirectorExtension:
static_routes: # Routes that should also allow URL segment based localisation
- 'search//'
This should match the rule key in your Director.rules
config.
We can then construct the new URL to allow support for, and tell Director to use the existing configured controller while also passing the l
argument for the locale transparently. We need to do this for each locale, and the rules need to be inserted before Fluent's default rules are. An example of what you could do:
diff --git a/src/Extension/FluentDirectorExtension.php b/src/Extension/FluentDirectorExtension.php
index 6ebf1d6..0cdd80b 100644
--- a/src/Extension/FluentDirectorExtension.php
+++ b/src/Extension/FluentDirectorExtension.php
@@ -116,7 +116,10 @@ class FluentDirectorExtension extends Extension
protected function getExplicitRoutes($originalRules)
{
$queryParam = static::config()->get('query_param');
+ $staticRoutes = static::config()->get('static_routes');
$rules = [];
+ $prependRules = []; // we push these into the $rules before default fluent rules
+
/** @var Locale $localeObj */
foreach (Locale::getCached() as $localeObj) {
$locale = $localeObj->getLocale();
@@ -138,8 +141,22 @@ class FluentDirectorExtension extends Extension
'Controller' => $controller,
$queryParam => $locale,
];
+
+ // Include opt-in static routes
+ foreach ($staticRoutes as $staticRoute) {
+ // Check for a matching rule in the Director configuration
+ if (!isset($originalRules[$staticRoute])) {
+ continue;
+ }
+
+ $prependRules[$url . '/' . $staticRoute] = [
+ 'Controller' => $originalRules[$staticRoute],
+ $queryParam => $locale,
+ ];
+ }
}
- return $rules;
+
+ return array_merge($prependRules, $rules);
}
/**
If you debug $rules
at the end of the updateRules()
method, you'll see that Fluent has now injected a new rule for that route in each locale:
'en/search//' =>
array (size=2)
'Controller' => string 'App\Controllers\SearchController' (length=42)
'l' => string 'en_NZ' (length=5)
'mi/search//' =>
array (size=2)
'Controller' => string 'App\Controllers\SearchController' (length=42)
'l' => string 'mi_NZ' (length=5)
Implementation
I'm going to formulate a pull request to the module for this change once I can back it up with some unit tests, but in the meantime, you can implement this by using an Injector override in your project code, and extend the protected getExplicitRoutes
method to implement the changes above:
SilverStripe\Core\Injector\Injector:
TractorCow\Fluent\Extension\FluentDirectorExtension:
class: MyFluentDirectorExtension
class MyFluentDirectorExtension extends FluentDirectorExtension
{
protected function getExplicitRoutes($originalRules)
{
$rules = parent::getExplicitRoutes($originalRules);
$staticRoutes = static::config()->get('static_routes');
$queryParam = static::config()->get('query_param');
$prependRules = [];
// Include opt-in static routes
foreach (Locale::getCached() as $localeObj) {
foreach ($staticRoutes as $staticRoute) {
$locale = $localeObj->getLocale();
$url = urlencode($localeObj->getURLSegment());
// Check for a matching rule in the Director configuration
if (!isset($originalRules[$staticRoute])) {
continue;
}
$prependRules[$url . '/' . $staticRoute] = [
'Controller' => $originalRules[$staticRoute],
$queryParam => $locale,
];
}
}
return array_merge($prependRules, $rules);
}
}