mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 08:17:12 +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,9 +3,13 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
class LanguageSupportPageNames extends WireData implements Module, ConfigurableModule {
|
||||
@@ -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');
|
||||
|
||||
@@ -179,6 +186,9 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* It extracts the language segment and uses that to later set the language
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function updatePath($path) {
|
||||
if($path === '/' || !strlen($path)) return $path;
|
||||
@@ -270,6 +280,7 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
if(!$setLanguage) $setLanguage = $languages->get('default');
|
||||
$user->language = $setLanguage;
|
||||
$this->setLanguage = $setLanguage;
|
||||
$languages->setLocale();
|
||||
|
||||
// if $page is the 404 page, exit out now
|
||||
if($page->id == $config->http404PageID) return '';
|
||||
@@ -361,9 +372,13 @@ 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;
|
||||
@@ -378,8 +393,12 @@ 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();
|
||||
@@ -391,11 +410,15 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* 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));
|
||||
@@ -408,9 +431,13 @@ 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 = '';
|
||||
}
|
||||
@@ -421,6 +448,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* Adds additional inputs for each language
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookInputfieldPageNameRenderAfter(HookEvent $event) {
|
||||
|
||||
@@ -490,12 +519,18 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
*
|
||||
* @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 */
|
||||
@@ -534,9 +569,12 @@ 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();
|
||||
|
||||
@@ -556,8 +594,11 @@ 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');
|
||||
@@ -571,6 +612,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) {
|
||||
$page = $event->object;
|
||||
@@ -587,8 +630,11 @@ 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);
|
||||
@@ -600,8 +646,11 @@ 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), '/');
|
||||
@@ -613,6 +662,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) {
|
||||
$this->hookPageLocalUrl($event);
|
||||
@@ -650,6 +701,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) {
|
||||
if(!$language->id || $language->name == 'default') return;
|
||||
@@ -669,6 +722,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
/**
|
||||
* Hook called when language is added
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookLanguageAdded(HookEvent $event) {
|
||||
$language = $event->arguments[0];
|
||||
@@ -678,6 +733,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) {
|
||||
if(!$language->id || $language->name == 'default') return;
|
||||
@@ -696,6 +753,8 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
|
||||
/**
|
||||
* Hook called when language is deleted
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
*/
|
||||
public function hookLanguageDeleted(HookEvent $event) {
|
||||
$language = $event->arguments[0];
|
||||
@@ -708,6 +767,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) {
|
||||
|
||||
@@ -782,6 +843,7 @@ 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
|
||||
@@ -926,6 +990,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) {
|
||||
|
||||
@@ -962,6 +1028,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
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -37,6 +38,8 @@ class Languages extends PagesType {
|
||||
/**
|
||||
* Reference to LanguageTranslator instance
|
||||
*
|
||||
* @var LanguageTranslator
|
||||
*
|
||||
*/
|
||||
protected $translator = null;
|
||||
|
||||
@@ -94,6 +97,14 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,6 +366,110 @@ class Languages extends PagesType {
|
||||
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