mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 16:26:59 +02:00
Updates for issue processwire/processwire-issues#215 to better support locale settings on front-end, plus add $languages->setLocale() and $languages->getLocale() methods, and freshen up code and docs in related classes.
This commit is contained in:
@@ -391,6 +391,7 @@ class Selectors extends WireArray {
|
||||
$operator = $op;
|
||||
$not = true;
|
||||
} else {
|
||||
if(is_array($value)) $value = implode('|', $value);
|
||||
$debug = $this->wire('config')->debug ? "field='$field', value='$value', selector: '$this->selectorStr'" : "";
|
||||
throw new WireException("Unknown Selector operator: '$operator' -- was your selector value properly escaped? $debug");
|
||||
}
|
||||
@@ -434,7 +435,7 @@ class Selectors extends WireArray {
|
||||
}
|
||||
}
|
||||
|
||||
if($field || strlen("$value")) {
|
||||
if($field || $value || strlen("$value")) {
|
||||
$selector = $this->create($field, $operator, $value);
|
||||
if(!is_null($group)) $selector->group = $group;
|
||||
if($quote) $selector->quote = $quote;
|
||||
|
@@ -182,8 +182,8 @@ class LanguageSupport extends WireData implements Module, ConfigurableModule {
|
||||
}
|
||||
|
||||
$this->wire('config')->dateFormat = $this->_('Y-m-d H:i:s'); // Sortable date format used in the admin
|
||||
$locale = $this->_('C'); // Value to pass to PHP's setlocale(LC_ALL, 'value') function when initializing this language // Default is 'C'. Specify '0' to skip the setlocale() call (and carry on system default).
|
||||
if($locale != '0') setlocale(LC_ALL, $locale);
|
||||
$locale = $this->_('C'); // Value to pass to PHP's setlocale(LC_ALL, 'value') function when initializing this language // Default is 'C'. Specify '0' to skip the setlocale() call (and carry on system default). Specify CSV string of locales to try multiple locales in order.
|
||||
if($locale != '0') $languages->setLocale(LC_ALL, $locale);
|
||||
|
||||
// setup our hooks handled by this class
|
||||
$this->addHookBefore('Inputfield::render', $this, 'hookInputfieldBeforeRender');
|
||||
|
@@ -3,8 +3,12 @@
|
||||
/**
|
||||
* Multi-language support page names module
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2017 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @property int $moduleVersion
|
||||
* @property int $inheritInactive
|
||||
* @property int $useHomeSegment
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -129,7 +133,10 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
// verify that page path doesn't have mixed languages where it shouldn't
|
||||
$redirectURL = $this->verifyPath($this->requestPath);
|
||||
if($redirectURL) return $this->wire('session')->redirect($redirectURL);
|
||||
if($redirectURL) {
|
||||
$this->wire('session')->redirect($redirectURL);
|
||||
return;
|
||||
}
|
||||
|
||||
$page = $this->wire('page');
|
||||
|
||||
@@ -178,6 +185,9 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
* 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
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function updatePath($path) {
|
||||
@@ -269,7 +279,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
// set the language
|
||||
if(!$setLanguage) $setLanguage = $languages->get('default');
|
||||
$user->language = $setLanguage;
|
||||
$this->setLanguage = $setLanguage;
|
||||
$this->setLanguage = $setLanguage;
|
||||
$languages->setLocale();
|
||||
|
||||
// if $page is the 404 page, exit out now
|
||||
if($page->id == $config->http404PageID) return '';
|
||||
@@ -360,10 +371,14 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook in before ProcesssPageView::execute to capture and modify $_GET[it] as needed
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookProcessPageViewExecute(HookEvent $event) {
|
||||
$event->object->setDelayRedirects(true);
|
||||
/** @var ProcessPageView $process */
|
||||
$process = $event->object;
|
||||
$process->setDelayRedirects(true);
|
||||
// save now, since ProcessPageView removes $_GET['it'] when it executes
|
||||
$it = isset($_GET['it']) ? $_GET['it'] : '';
|
||||
$this->requestPath = $it;
|
||||
@@ -377,9 +392,13 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook in before ProcesssPageView::render to throw 404 when appropriate
|
||||
*
|
||||
* @param HookEvent $event
|
||||
* @throws WireException
|
||||
*
|
||||
*/
|
||||
public function hookPageRender(HookEvent $event) {
|
||||
if($event) {}
|
||||
if($this->force404) {
|
||||
$this->force404 = false; // prevent another 404 on the 404 page
|
||||
throw new Wire404Exception();
|
||||
@@ -390,12 +409,16 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
* Hook in after ProcesssPageView::viewable account for specific language versions
|
||||
*
|
||||
* May be passed a Language name or page to check viewable for that language
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageViewable(HookEvent $event) {
|
||||
if(!$event->return) return;
|
||||
/** @var Page $page */
|
||||
$page = $event->object;
|
||||
// if(wire('user')->isSuperuser() || $page->editable()) return;
|
||||
/** @var Language $language */
|
||||
$language = $event->arguments(0);
|
||||
if(!$language) return;
|
||||
if(is_string($language)) $language = $this->wire('languages')->get($this->wire('sanitizer')->pageNameUTF8($language));
|
||||
@@ -407,10 +430,14 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook into WirePageEditor (i.e. ProcessPageEdit) to remove the non-applicable default home name of 'home'
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookWirePageEditorExecute(HookEvent $event) {
|
||||
$page = $event->object->getPage();
|
||||
/** @var WirePageEditor $editor */
|
||||
$editor = $event->object;
|
||||
$page = $editor->getPage();
|
||||
if($page && $page->id == 1) {
|
||||
if($page->name == Pages::defaultRootName) $page->name = '';
|
||||
}
|
||||
@@ -420,6 +447,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
* Hook into the page name render for when in ProcessPageEdit
|
||||
*
|
||||
* Adds additional inputs for each language
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookInputfieldPageNameRenderAfter(HookEvent $event) {
|
||||
@@ -489,13 +518,19 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
* Process the input data from hookInputfieldPageNameRender
|
||||
*
|
||||
* @todo Just move this to the InputfieldPageName module rather than using hooks
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookInputfieldPageNameProcess(HookEvent $event) {
|
||||
|
||||
/** @var InputfieldPageName $inputfield */
|
||||
$inputfield = $event->object;
|
||||
//$page = $this->process == 'ProcessPageEdit' ? $this->process->getPage() : new NullPage();
|
||||
$page = $this->process->getPage();
|
||||
/** @var WirePageEditor $process */
|
||||
$process = $this->process;
|
||||
/** @var Page $page */
|
||||
$page = $process instanceof WirePageEditor ? $process->getPage() : new NullPage();
|
||||
if($page->id && !$page->editable('name', false)) return; // name is not editable
|
||||
$input = $event->arguments[0];
|
||||
/** @var Languages $languages */
|
||||
@@ -533,10 +568,13 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook into PageFinder::getQuery to add language status check
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageFinderGetQuery(HookEvent $event) {
|
||||
$query = $event->return;
|
||||
/** @var PageFinder $pageFinder */
|
||||
$pageFinder = $event->object;
|
||||
$options = $pageFinder->getOptions();
|
||||
|
||||
@@ -555,9 +593,12 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook into Page::path to localize path for current language
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPagePath(HookEvent $event) {
|
||||
/** @var Page $page */
|
||||
$page = $event->object;
|
||||
if($page->template == 'admin') return;
|
||||
$language = $this->wire('user')->get('language');
|
||||
@@ -570,6 +611,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* event param Language|string|int Optional language
|
||||
* event return string Localized language name or blank if not set
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageLocalName(HookEvent $event) {
|
||||
@@ -586,9 +629,12 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* event param Language|string|int Optional language
|
||||
* event return string Localized language path
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageLocalPath(HookEvent $event) {
|
||||
/** @var Page $page */
|
||||
$page = $event->object;
|
||||
$language = $this->getLanguage($event->arguments(0));
|
||||
$event->return = $this->getPagePath($page, $language);
|
||||
@@ -599,9 +645,12 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* event param Language|string|int Optional language
|
||||
* event return string Localized language URL
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageLocalUrl(HookEvent $event) {
|
||||
/** @var Page $page */
|
||||
$page = $event->object;
|
||||
$language = $this->getLanguage($event->arguments(0));
|
||||
$event->return = $this->wire('config')->urls->root . ltrim($this->getPagePath($page, $language), '/');
|
||||
@@ -612,6 +661,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* event param Language|string|int Optional language
|
||||
* event return string Localized language name or blank if not set
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageLocalHttpUrl(HookEvent $event) {
|
||||
@@ -649,6 +700,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Update pages table for new column when a language is added
|
||||
*
|
||||
* @param Language|Page $language
|
||||
*
|
||||
*/
|
||||
public function languageAdded(Page $language) {
|
||||
@@ -668,6 +721,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook called when language is added
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookLanguageAdded(HookEvent $event) {
|
||||
@@ -677,6 +732,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Update pages table to remove column when a language is deleted
|
||||
*
|
||||
* @param Language|Page $language
|
||||
*
|
||||
*/
|
||||
protected function languageDeleted(Page $language) {
|
||||
@@ -695,6 +752,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Hook called when language is deleted
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookLanguageDeleted(HookEvent $event) {
|
||||
@@ -707,6 +766,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* Here we make use of the 'extraData' return property of the saveReady hook
|
||||
* to bundle in the language name fields into the query.
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageSaveReady(HookEvent $event) {
|
||||
@@ -781,7 +842,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
*/
|
||||
public function hookPageSetupNew(HookEvent $event) {
|
||||
|
||||
|
||||
/** @var Page $page */
|
||||
$page = $event->arguments[0];
|
||||
|
||||
// if page already has a name, then no need to continue
|
||||
@@ -821,6 +883,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
/**
|
||||
* Hook called immediately after a page is saved
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookPageSaved(HookEvent $event) {
|
||||
// The setLanguage may get lost upon some page save events, so this restores that
|
||||
@@ -925,6 +989,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Check to make sure that the status table exists and creates it if not
|
||||
*
|
||||
* @param bool $force
|
||||
*
|
||||
*/
|
||||
public function checkModuleVersion($force = false) {
|
||||
@@ -961,6 +1027,9 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
|
||||
/**
|
||||
* Module interactive configuration fields
|
||||
*
|
||||
* @param array $data
|
||||
* @return InputfieldWrapper
|
||||
*
|
||||
*/
|
||||
public function getModuleConfigInputfields(array $data) {
|
||||
|
@@ -29,6 +29,7 @@
|
||||
* @method added(Page $language) Hook called when Language is added #pw-hooker
|
||||
* @method deleted(Page $language) Hook called when Language is deleted #pw-hooker
|
||||
* @method updated(Page $language, $what) Hook called when Language is added or deleted #pw-hooker
|
||||
* @method languageChanged($fromLanguage, $toLanguage) Hook called when User language is changed #pw-hooker
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -36,6 +37,8 @@ class Languages extends PagesType {
|
||||
|
||||
/**
|
||||
* Reference to LanguageTranslator instance
|
||||
*
|
||||
* @var LanguageTranslator
|
||||
*
|
||||
*/
|
||||
protected $translator = null;
|
||||
@@ -93,7 +96,15 @@ class Languages extends PagesType {
|
||||
*
|
||||
*/
|
||||
protected $editableCache = array();
|
||||
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param ProcessWire $wire
|
||||
* @param array $templates
|
||||
* @param array $parents
|
||||
*
|
||||
*/
|
||||
public function __construct(ProcessWire $wire, $templates = array(), $parents = array()) {
|
||||
parent::__construct($wire, $templates, $parents);
|
||||
$this->wire('database')->addHookAfter('unknownColumnError', $this, 'hookUnknownColumnError');
|
||||
@@ -107,9 +118,15 @@ class Languages extends PagesType {
|
||||
*
|
||||
*/
|
||||
public function translator(Language $language) {
|
||||
if(is_null($this->translator)) $this->translator = $this->wire(new LanguageTranslator($language));
|
||||
else $this->translator->setCurrentLanguage($language);
|
||||
return $this->translator;
|
||||
/** @var LanguageTranslator $translator */
|
||||
$translator = $this->translator;
|
||||
if(is_null($translator)) {
|
||||
$translator = $this->wire(new LanguageTranslator($language));
|
||||
$this->translator = $translator;
|
||||
} else {
|
||||
$translator->setCurrentLanguage($language);
|
||||
}
|
||||
return $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,6 +365,110 @@ class Languages extends PagesType {
|
||||
$user->language = $this->savedLanguage2;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current locale
|
||||
*
|
||||
* This function behaves exactly the same way as [PHP setlocale](http://php.net/manual/en/function.setlocale.php) except
|
||||
* for the following:
|
||||
*
|
||||
* - If the $locale argument is omitted, it uses the locale setting translated for the current user language.
|
||||
* - You can optionally specify a CSV string of locales to try for the $locale argument.
|
||||
* - You can optionally or a “category=locale;category=locale;category=locale” string for the $locale argument.
|
||||
* When this type of string is used, the $category argument is ignored.
|
||||
* - This method does not accept more than the 2 indicated arguments.
|
||||
*
|
||||
* See the PHP setlocale link above for a list of constants that can be used for the `$category` argument.
|
||||
*
|
||||
* ~~~~~
|
||||
* // Set locale to whatever settings defined for current $user language
|
||||
* $languages->setLocale();
|
||||
*
|
||||
* // Set all locale categories
|
||||
* $languages->setLocale(LC_ALL, 'en_US.UTF-8');
|
||||
*
|
||||
* // Set locale for specific category (CTYPE)
|
||||
* $langauges->setLocale(LC_CTYPE, 'en_US.UTF-8');
|
||||
*
|
||||
* // Try multiple locales till one works (in order) using array
|
||||
* $languages->setLocale(LC_ALL, [ 'en_US.UTF-8', 'en_US', 'en' ]);
|
||||
*
|
||||
* // Same as above, except using CSV string
|
||||
* $languages->setLocale(LC_ALL, 'en_US.UTF-8, en_US, en');
|
||||
*
|
||||
* // Set multiple categories and locales (first argument ignored)
|
||||
* $languages->setLocale(null, 'LC_CTYPE=en_US;LC_NUMERIC=de_DE;LC_TIME=es_ES');
|
||||
* ~~~~~
|
||||
*
|
||||
* @param int $category Specify a PHP “LC_” constant or omit (or null) for default (LC_ALL).
|
||||
* @param string|array|null $locale Specify string, array or CSV string of locale name(s), or omit (null) for default language locale.
|
||||
* @return string|bool Returns the locale that was set or boolean false if requested locale cannot be set.
|
||||
* @see Languages::getLocale()
|
||||
*
|
||||
*/
|
||||
public function setLocale($category = LC_ALL, $locale = null) {
|
||||
|
||||
$setLocale = ''; // return value
|
||||
if($category === null) $category = LC_ALL;
|
||||
|
||||
if($locale === null) {
|
||||
// argument omitted means set according to language settings
|
||||
$locale = __('C', 'wire--modules--languagesupport--languagesupport-module');
|
||||
}
|
||||
|
||||
if(is_string($locale)) {
|
||||
|
||||
if(strpos($locale, ',') !== false) {
|
||||
// convert CSV string to array of locales
|
||||
$locale = explode(',', $locale);
|
||||
foreach($locale as $key => $value) {
|
||||
$locale[$key] = trim($value);
|
||||
}
|
||||
|
||||
} else if(strpos($locale, ';') !== false) {
|
||||
// multi-category and locale string, i.e. LC_CTYPE=en_US.UTF-8;LC_NUMERIC=C;LC_TIME=C
|
||||
foreach(explode(';', $locale) as $s) {
|
||||
// call setLocale() for each locale item present in the string
|
||||
if(strpos($s, '=') === false) continue;
|
||||
list($cats, $loc) = explode('=', $s);
|
||||
$cat = constant($cats);
|
||||
if($cat !== null) {
|
||||
$loc = $this->setLocale($cat, $loc);
|
||||
if($loc !== false) $setLocale .= trim($cats) . '=' . trim($loc) . ";";
|
||||
}
|
||||
}
|
||||
$setLocale = rtrim($setLocale, ';');
|
||||
if(empty($setLocale)) $setLocale = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($setLocale === '') {
|
||||
if($locale === '0' || $locale === 0) {
|
||||
// get locale (to be consistent with behavior of PHP setlocale)
|
||||
$setLocale = $this->getLocale($category);
|
||||
} else {
|
||||
// set the locale
|
||||
$setLocale = setlocale($category, $locale);
|
||||
}
|
||||
}
|
||||
|
||||
return $setLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current locale setting
|
||||
*
|
||||
* If using LC_ALL category and locales change by category, the returned string will be in
|
||||
* the format: “category=locale;category=locale”, and so on.
|
||||
*
|
||||
* @param int $category Optionally specify a PHP LC constant (default=LC_ALL)
|
||||
* @return string|bool Locale(s) string or boolean false if not supported by the system.
|
||||
* @see Languages::setLocale()
|
||||
*
|
||||
*/
|
||||
public function getLocale($category = LC_ALL) {
|
||||
return setlocale($category, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a language is deleted
|
||||
|
Reference in New Issue
Block a user