1
0
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:
Ryan Cramer
2017-03-16 09:49:47 -04:00
parent e1928c9e3c
commit 9c92ce5305
4 changed files with 205 additions and 14 deletions

View File

@@ -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;

View File

@@ -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');

View File

@@ -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) {

View File

@@ -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
*