From 6673e90d1fe899e5f5f6b992ff8f67d5ef088e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Guibert?= Date: Mon, 25 Feb 2013 12:51:07 +0100 Subject: [PATCH 1/4] Fix route uri --- classes/multilang/route.php | 134 ++++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 12 deletions(-) diff --git a/classes/multilang/route.php b/classes/multilang/route.php index 3aa3f33..d94f483 100644 --- a/classes/multilang/route.php +++ b/classes/multilang/route.php @@ -28,7 +28,7 @@ class Multilang_Route extends Kohana_Route { $regex['lang'] = $lang; } } - + if($lang !== NULL) { $name = $lang.'.'.$name; @@ -108,10 +108,8 @@ class Multilang_Route extends Kohana_Route { return parent::__construct($uri, $regex); } - + /** - * Altered method to handle multilingual uris. - * * Generates a URI for the current route based on the parameters given. * * // Using the "default" route: "users/profile/10" @@ -121,8 +119,7 @@ class Multilang_Route extends Kohana_Route { * 'id' => '10' * )); * - * @param array URI parameters - * @param string $lang a language code + * @param array $params URI parameters * @return string * @throws Kohana_Exception * @uses Route::REGEX_Key @@ -133,17 +130,130 @@ class Multilang_Route extends Kohana_Route { if($this->lang !== NULL) { $params['lang'] = ($lang === NULL ? $this->lang : $lang); - } + } - $uri = parent::uri($params); - // If it's the default route, we add a trailing slash - if(Route::name($this) === 'default') + // Start with the routed URI + $uri = $this->_uri; + + if (strpos($uri, '<') === FALSE AND strpos($uri, '(') === FALSE) { - $uri .= '/'; + // This is a static route, no need to replace anything + + if ( ! $this->is_external()) + return $uri; + + // If the localhost setting does not have a protocol + if (strpos($this->_defaults['host'], '://') === FALSE) + { + // Use the default defined protocol + $params['host'] = Route::$default_protocol.$this->_defaults['host']; + } + else + { + // Use the supplied host with protocol + $params['host'] = $this->_defaults['host']; + } + + // Compile the final uri and return it + return rtrim($params['host'], '/').'/'.$uri; } + + // Keep track of whether an optional param was replaced + $provided_optional = FALSE; + + while (preg_match('#\([^()]++\)#', $uri, $match)) + { + + // Search for the matched value + $search = $match[0]; + + // Remove the parenthesis from the match as the replace + $replace = substr($match[0], 1, -1); + + while (preg_match('#'.Route::REGEX_KEY.'#', $replace, $match)) + { + list($key, $param) = $match; + + if (isset($params[$param]) AND $params[$param] !== Arr::get($this->_defaults, $param)) + { + // Future optional params should be required + $provided_optional = TRUE; + + // Replace the key with the parameter value + $replace = str_replace($key, $params[$param], $replace); + } + elseif ($provided_optional) + { + // Look for a default + if (isset($this->_defaults[$param])) + { + $replace = str_replace($key, $this->_defaults[$param], $replace); + } + else + { + // Ungrouped parameters are required + throw new Kohana_Exception('Required route parameter not passed: :param', array( + ':param' => $param, + )); + } + } + else + { + // This group has missing parameters + $replace = ''; + break; + } + } + + // Replace the group in the URI + $uri = str_replace($search, $replace, $uri); + } + + while (preg_match('#'.Route::REGEX_KEY.'#', $uri, $match)) + { + list($key, $param) = $match; + + if ( ! isset($params[$param])) + { + // Look for a default + if (isset($this->_defaults[$param])) + { + $params[$param] = $this->_defaults[$param]; + } + else + { + // Ungrouped parameters are required + throw new Kohana_Exception('Required route parameter not passed: :param', array( + ':param' => $param, + )); + } + } + + $uri = str_replace($key, $params[$param], $uri); + } + + // Trim all extra slashes from the URI + //$uri = preg_replace('#//+#', '/', rtrim($uri, '/')); + $uri = preg_replace('#//+#', '/', $uri); + + if ($this->is_external()) + { + // Need to add the host to the URI + $host = $this->_defaults['host']; + + if (strpos($host, '://') === FALSE) + { + // Use the default defined protocol + $host = Route::$default_protocol.$host; + } + + // Clean up the host and prepend it to the URI + $uri = rtrim($host, '/').'/'.$uri; + } + return $uri; } - + /** * Altered method to handle multilingual parameter * From 3e35b801a6a83e3c1697411eb16d16435bb3678e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Guibert?= Date: Mon, 25 Feb 2013 12:54:54 +0100 Subject: [PATCH 2/4] Fix case --- classes/Multilang.php | 9 + classes/Multilang/Core.php | 159 ++++++++++++++++ classes/Multilang/Request.php | 199 +++++++++++++++++++ classes/Multilang/Route.php | 346 ++++++++++++++++++++++++++++++++++ classes/Multilang/Routes.php | 77 ++++++++ classes/Multilang/URL.php | 22 +++ classes/Request.php | 8 + classes/Route.php | 8 + classes/Routes.php | 8 + classes/URL.php | 5 + 10 files changed, 841 insertions(+) create mode 100644 classes/Multilang.php create mode 100644 classes/Multilang/Core.php create mode 100644 classes/Multilang/Request.php create mode 100644 classes/Multilang/Route.php create mode 100644 classes/Multilang/Routes.php create mode 100644 classes/Multilang/URL.php create mode 100644 classes/Request.php create mode 100644 classes/Route.php create mode 100644 classes/Routes.php create mode 100644 classes/URL.php diff --git a/classes/Multilang.php b/classes/Multilang.php new file mode 100644 index 0000000..d15e454 --- /dev/null +++ b/classes/Multilang.php @@ -0,0 +1,9 @@ +load('multilang'); + + if($config->auto_detect) + { + // Get the list of supported languages + $languages = $config->languages; + $cookie = $config->cookie; + + // Look for language cookie first + if($lang = Cookie::get($cookie)) + { + // Valid language found in cookie + if(isset($languages[$lang])) + { + return $lang; + } + + // Delete cookie with unset language + Cookie::delete($cookie); + } + + // Parse HTTP Accept-Language headers + foreach(Request::accept_lang() as $lang => $quality) + { + // Return the first language found (the language with the highest quality) + if(isset($languages[$lang])) + { + return $lang; + } + } + } + // Return the hard-coded default language as final fallback + return $config->default; + } + + /** + * Initialize the config and cookies + */ + static public function init() + { + $config = Kohana::$config->load('multilang'); + + // Get the list of supported languages + $langs = $config->languages; + + // Set the language in I18n + I18n::lang($langs[Request::$lang]['i18n']); + + // Set locale + setlocale(LC_ALL, $langs[Request::$lang]['locale']); + + $cookie = $config->cookie; + // Update language cookie if needed + if(Cookie::get($cookie) !== Request::$lang) + { + Cookie::set($cookie, Request::$lang); + } + } + + /** + * Return a language selector menu + * @param boolean $current Display the current language or not + * @return View + */ + static public function selector($current = TRUE) + { + $config = Kohana::$config->load('multilang'); + + $languages = $config->languages; + + // Get the current route name + $current_route = Route::name(Request::initial()->route()); + + + $params = Request::initial()->param(); + + if($current_route !== 'default' && strpos($current_route, '.') !== FALSE) + { + // Split the route path + list($lang, $name) = explode('.', $current_route, 2); + } + else + { + $name = $current_route; + } + + // Create uris for each language + foreach($languages as $lang => &$language) + { + // If it's the current language + if($lang === Request::$lang) + { + // We only display it when required + if($current) + { + $selectors[$lang] = ''.$languages[$lang]['label'].''; + } + } + else + { + $route = NULL; + + // If it's the default route, it's unique and special (like you <3) + if($current_route === 'default') + { + // We juste need to change the language parameter + $route = Request::initial()->route(); + $params['lang'] = NULL; + if(!$config->hide_default || $config->default !== $lang) + { + $params['lang'] = $lang; + } + + + } + else + { + if(Arr::get(Route::all(), $lang.'.'.$name)) + { + $route = Route::get($name, $lang); + } + } + + if($route !== NULL) + { + $selectors[$lang] = HTML::anchor($route->uri($params), $languages[$lang]['label'], array('class' => 'multilang-selectable multilang-'.$lang, 'title' => $languages[$lang]['label'])); + } + } + } + + // We display the menu only if we can select another language for this page + if(count($selectors) > 1) + { + return View::factory('multilang/selector') + ->bind('selectors', $selectors); + } + return ''; + } +} \ No newline at end of file diff --git a/classes/Multilang/Request.php b/classes/Multilang/Request.php new file mode 100644 index 0000000..b85f29c --- /dev/null +++ b/classes/Multilang/Request.php @@ -0,0 +1,199 @@ +load('multilang'); + + // If we don't hide the default language, we must look for a language code for the root uri + if(Request::detect_uri() === '' AND $config->auto_detect AND $uri === TRUE) + { + $lang = Multilang::find_user_language(); + if(!$config->hide_default OR $lang != $config->default) + { + // Use the default server protocol + $protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'; + + // Redirect to the root URI, but with language prepended + header($protocol.' 302 Found'); + header('Location: '.URL::base(TRUE, TRUE).$lang.'/'); + exit; + } + } + + return parent::factory($uri, $client_params, $allow_external, $injected_routes); + } + + /** + * We don't want to remove the trailing slash from the uri + */ + public function __construct($uri, $client_params = array(), $allow_external = TRUE, $injected_routes = array()) + { + $client_params = is_array($client_params) ? $client_params : array(); + + // Initialise the header + $this->_header = new HTTP_Header(array()); + + // Assign injected routes + $this->_routes = $injected_routes; + + // Cleanse query parameters from URI (faster that parse_url()) + $split_uri = explode('?', $uri); + $uri = array_shift($split_uri); + + // Initial request has global $_GET already applied + if (Request::$initial !== NULL) + { + if ($split_uri) + { + parse_str($split_uri[0], $this->_get); + } + } + + // Detect protocol (if present) + // $allow_external = FALSE prevents the default index.php from + // being able to proxy external pages. + if ( ! $allow_external OR strpos($uri, '://') === FALSE) + { + // Remove trailing slashes from the URI (We don't want that) + //$this->_uri = trim($uri, '/'); + $this->_uri = ltrim($uri, '/'); + //$this->_route = new Route($uri); + // Apply the client + $this->_client = new Request_Client_Internal($client_params); + } + else + { + // Create a route + $this->_route = new Route($uri); + + // Store the URI + $this->_uri = $uri; + + // Set the security setting if required + if (strpos($uri, 'https://') === 0) + { + $this->secure(TRUE); + } + + // Set external state + $this->_external = TRUE; + + // Setup the client + $this->_client = Request_Client_External::factory($client_params); + } + } + + /** + * Altered to detect the language in the uri + * + * @return Response + * @throws Request_Exception + * @throws HTTP_Exception_404 + * @uses [Kohana::$profiling] + * @uses [Profiler] + */ + public function execute() + { + if ( ! $this->_external) + { + $processed = Request::process($this, $this->_routes); + + if ($processed) + { + // Store the matching route + $this->_route = $processed['route']; + $params = $processed['params']; + + // Is this route external? + $this->_external = $this->_route->is_external(); + + if (isset($params['directory'])) + { + // Controllers are in a sub-directory + $this->_directory = $params['directory']; + } + + // Store the controller + $this->_controller = $params['controller']; + + // Store the action + $this->_action = (isset($params['action'])) + ? $params['action'] + : Route::$default_action; + + // These are accessible as public vars and can be overloaded + unset($params['controller'], $params['action'], $params['directory']); + + // Params cannot be changed once matched + $this->_params = $params; + } + } + + if ( ! $this->_route instanceof Route) + { + return HTTP_Exception::factory(404, 'Unable to find a route to match the URI: :uri', array( + ':uri' => $this->_uri, + ))->request($this) + ->get_response(); + } + + if ( ! $this->_client instanceof Request_Client) + { + throw new Request_Exception('Unable to execute :uri without a Kohana_Request_Client', array( + ':uri' => $this->_uri, + )); + } + + // Multilang part + if(Request::$lang === NULL) + { + Request::$lang = $this->_route->lang; + } + + $config = Kohana::$config->load('multilang'); + if($config->hide_default AND $this->param('lang') === NULL OR $this->_route->lang === NULL AND $this->param('lang') === NULL) + { + Request::$lang = $config->default; + } + else + { + Request::$lang = $this->param('lang'); + } + Multilang::init(); + + return $this->_client->execute($this); + } + + +} \ No newline at end of file diff --git a/classes/Multilang/Route.php b/classes/Multilang/Route.php new file mode 100644 index 0000000..d94f483 --- /dev/null +++ b/classes/Multilang/Route.php @@ -0,0 +1,346 @@ +load('multilang'); + + if(!$config->hide_default || $config->default != $lang) + { + if($lang !== NULL) + { + $uri_callback = '/'.$uri_callback; + $regex['lang'] = $lang; + } + } + + if($lang !== NULL) + { + $name = $lang.'.'.$name; + } + + return Route::$_routes[$name] = new Route($uri_callback, $regex, $lang); + } + + + /** + * Retrieves a named route. + * + * $route = Route::get('default'); + * + * @param string route name + * @return Route + * @throws Kohana_Exception + */ + static public function get($name, $lang = NULL) + { + // We use the current language if none given + if($lang === NULL) + { + $lang = Request::$lang; + } + + // We first look for a "given_language.name" route. + if(isset(Route::$_routes[$lang.'.'.$name])) + { + $name = $lang.'.'.$name; + + } // then the default language + elseif(isset(Route::$_routes[Kohana::$config->load('multilang')->default.'.'.$name])) { + $name = $config->default.'.'.$name; + } + // And if we don't have any for this language, it means that route is neither defined nor multilingual + return parent::get($name); + } + + /** + * Altered constructor to handle multilingual routes + * + * Creates a new route. Sets the URI and regular expressions for keys. + * Routes should always be created with [Route::set] or they will not + * be properly stored. + * + * $route = new Route($uri, $regex); + * + * The $uri parameter can either be a string for basic regex matching or it + * can be a valid callback or anonymous function (php 5.3+). If you use a + * callback or anonymous function, your method should return an array + * containing the proper keys for the route. If you want the route to be + * "reversable", you need to return a 'uri' key in the standard syntax. + * + * $route = new Route(function($uri) + * { + * if (list($controller, $action, $param) = explode('/', $uri) AND $controller == 'foo' AND $action == 'bar') + * { + * return array( + * 'controller' => 'foobar', + * 'action' => $action, + * 'id' => $param, + * 'uri' => 'foo/bar/.html + * ); + * } + * }); + * + * @param mixed route URI pattern or lambda/callback function + * @param array key patterns + * @param + * @return void + * @uses Route::_compile + */ + public function __construct($uri = NULL, array $regex = NULL, $lang = NULL) + { + $this->lang = $lang; + return parent::__construct($uri, $regex); + } + + + /** + * Generates a URI for the current route based on the parameters given. + * + * // Using the "default" route: "users/profile/10" + * $route->uri(array( + * 'controller' => 'users', + * 'action' => 'profile', + * 'id' => '10' + * )); + * + * @param array $params URI parameters + * @return string + * @throws Kohana_Exception + * @uses Route::REGEX_Key + */ + public function uri(array $params = NULL, $lang = NULL) + { + // We define the language if required + if($this->lang !== NULL) + { + $params['lang'] = ($lang === NULL ? $this->lang : $lang); + } + + // Start with the routed URI + $uri = $this->_uri; + + if (strpos($uri, '<') === FALSE AND strpos($uri, '(') === FALSE) + { + // This is a static route, no need to replace anything + + if ( ! $this->is_external()) + return $uri; + + // If the localhost setting does not have a protocol + if (strpos($this->_defaults['host'], '://') === FALSE) + { + // Use the default defined protocol + $params['host'] = Route::$default_protocol.$this->_defaults['host']; + } + else + { + // Use the supplied host with protocol + $params['host'] = $this->_defaults['host']; + } + + // Compile the final uri and return it + return rtrim($params['host'], '/').'/'.$uri; + } + + // Keep track of whether an optional param was replaced + $provided_optional = FALSE; + + while (preg_match('#\([^()]++\)#', $uri, $match)) + { + + // Search for the matched value + $search = $match[0]; + + // Remove the parenthesis from the match as the replace + $replace = substr($match[0], 1, -1); + + while (preg_match('#'.Route::REGEX_KEY.'#', $replace, $match)) + { + list($key, $param) = $match; + + if (isset($params[$param]) AND $params[$param] !== Arr::get($this->_defaults, $param)) + { + // Future optional params should be required + $provided_optional = TRUE; + + // Replace the key with the parameter value + $replace = str_replace($key, $params[$param], $replace); + } + elseif ($provided_optional) + { + // Look for a default + if (isset($this->_defaults[$param])) + { + $replace = str_replace($key, $this->_defaults[$param], $replace); + } + else + { + // Ungrouped parameters are required + throw new Kohana_Exception('Required route parameter not passed: :param', array( + ':param' => $param, + )); + } + } + else + { + // This group has missing parameters + $replace = ''; + break; + } + } + + // Replace the group in the URI + $uri = str_replace($search, $replace, $uri); + } + + while (preg_match('#'.Route::REGEX_KEY.'#', $uri, $match)) + { + list($key, $param) = $match; + + if ( ! isset($params[$param])) + { + // Look for a default + if (isset($this->_defaults[$param])) + { + $params[$param] = $this->_defaults[$param]; + } + else + { + // Ungrouped parameters are required + throw new Kohana_Exception('Required route parameter not passed: :param', array( + ':param' => $param, + )); + } + } + + $uri = str_replace($key, $params[$param], $uri); + } + + // Trim all extra slashes from the URI + //$uri = preg_replace('#//+#', '/', rtrim($uri, '/')); + $uri = preg_replace('#//+#', '/', $uri); + + if ($this->is_external()) + { + // Need to add the host to the URI + $host = $this->_defaults['host']; + + if (strpos($host, '://') === FALSE) + { + // Use the default defined protocol + $host = Route::$default_protocol.$host; + } + + // Clean up the host and prepend it to the URI + $uri = rtrim($host, '/').'/'.$uri; + } + + return $uri; + } + + /** + * Altered method to handle multilingual parameter + * + * Create a URL from a route name. This is a shortcut for: + * + * echo URL::site(Route::get($name)->uri($params), $protocol); + * + * @param string route name + * @param array URI parameters + * @param mixed protocol string or boolean, adds protocol and domain + * @return string + * @since 3.0.7 + * @uses URL::site + */ + static public function url($name, array $params = NULL, $protocol = NULL, $lang = NULL) + { + // Create a URI with the route and convert it to a URL + return URL::site(Route::get($name, $lang)->uri($params), $protocol); + } + + /** + * We don't want to remove the trailing slash. + */ + public function matches(Request $request) + { + // Get the URI from the Request + //$uri = trim($request->uri(), '/'); + $uri = ltrim($request->uri(), '/'); + + if ( ! preg_match($this->_route_regex, $uri, $matches)) + return FALSE; + + $params = array(); + foreach ($matches as $key => $value) + { + if (is_int($key)) + { + // Skip all unnamed keys + continue; + } + + // Set the value for all matched keys + $params[$key] = $value; + } + + foreach ($this->_defaults as $key => $value) + { + if ( ! isset($params[$key]) OR $params[$key] === '') + { + // Set default values for any key that was not matched + $params[$key] = $value; + } + } + + if ( ! empty($params['controller'])) + { + // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore + $params['controller'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['controller']))); + } + + if ( ! empty($params['directory'])) + { + // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore + $params['directory'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['directory']))); + } + + if ($this->_filters) + { + foreach ($this->_filters as $callback) + { + // Execute the filter giving it the route, params, and request + $return = call_user_func($callback, $this, $params, $request); + + if ($return === FALSE) + { + // Filter has aborted the match + return FALSE; + } + elseif (is_array($return)) + { + // Filter has modified the parameters + $params = $return; + } + } + } + + return $params; + } + +} \ No newline at end of file diff --git a/classes/Multilang/Routes.php b/classes/Multilang/Routes.php new file mode 100644 index 0000000..4be4498 --- /dev/null +++ b/classes/Multilang/Routes.php @@ -0,0 +1,77 @@ + 'home', + * 'fr' => 'accueil', + * ))->defaults(array( + * 'controller' => 'homepage', + * 'action' => 'index', + * )); + * + * @param string route name + * @param array URI patterns (array of "language code" => "uri") + * @param array regex patterns for route keys + * @return Routes + */ + static public function set($name, $uris = array(), $regex = NULL) + { + $config = Kohana::$config->load('multilang'); + $routes = new Routes(); + + // We add the routes for each language and set their names to lang.name (en.homepage for example). + // The segment is also added on the uri if it's not hidden + + $default_lang = $config->default; + $languages = $config->languages; + + // We first look for the default language uri which is obviously compulsory + $default_uri = Arr::get($uris, $default_lang); + if($default_uri === NULL) + { + throw new Kohana_Exception('The default language route uri is required for the route: :route', array(':route' => $name)); + } + else + { + $routes->_routes[$default_lang.'.'.$name] = Route::set($name, $default_uri, $regex, $default_lang); + } + unset($languages[$default_lang]); + + // Then we add the routes for all the other languages + foreach($languages as $lang => $settings) + { + $uri = (Arr::get($uris, $lang) ? $uris[$lang] : $uris[$default_lang]); + + // For the uri, we use the one given or the default one + $routes->_routes[$lang.'.'.$name] = Route::set($name, $uri, $regex, $lang); + } + return $routes; + } + + + /** + * Set the defaults values for each route + * @param array $defaults + * @return Multilang_Routes + */ + public function defaults(array $defaults = NULL) + { + foreach($this->_routes as $route) + { + $route->defaults($defaults); + } + return $this; + } + + +} \ No newline at end of file diff --git a/classes/Multilang/URL.php b/classes/Multilang/URL.php new file mode 100644 index 0000000..570f754 --- /dev/null +++ b/classes/Multilang/URL.php @@ -0,0 +1,22 @@ + Date: Mon, 25 Feb 2013 13:04:06 +0100 Subject: [PATCH 3/4] Fix --- classes/Multilang.php | 9 - classes/Multilang/Core.php | 159 ---------------- classes/Multilang/Request.php | 199 ------------------- classes/Multilang/Route.php | 346 ---------------------------------- classes/Multilang/Routes.php | 77 -------- classes/Multilang/URL.php | 22 --- classes/Request.php | 8 - classes/Route.php | 8 - classes/Routes.php | 8 - classes/URL.php | 5 - classes/multilang.php | 9 - classes/multilang/core.php | 159 ---------------- classes/multilang/request.php | 199 ------------------- classes/multilang/route.php | 346 ---------------------------------- classes/multilang/routes.php | 77 -------- classes/multilang/url.php | 22 --- classes/request.php | 8 - classes/route.php | 8 - classes/routes.php | 8 - classes/url.php | 5 - 20 files changed, 1682 deletions(-) delete mode 100644 classes/Multilang.php delete mode 100644 classes/Multilang/Core.php delete mode 100644 classes/Multilang/Request.php delete mode 100644 classes/Multilang/Route.php delete mode 100644 classes/Multilang/Routes.php delete mode 100644 classes/Multilang/URL.php delete mode 100644 classes/Request.php delete mode 100644 classes/Route.php delete mode 100644 classes/Routes.php delete mode 100644 classes/URL.php delete mode 100644 classes/multilang.php delete mode 100644 classes/multilang/core.php delete mode 100644 classes/multilang/request.php delete mode 100644 classes/multilang/route.php delete mode 100644 classes/multilang/routes.php delete mode 100644 classes/multilang/url.php delete mode 100644 classes/request.php delete mode 100644 classes/route.php delete mode 100644 classes/routes.php delete mode 100644 classes/url.php diff --git a/classes/Multilang.php b/classes/Multilang.php deleted file mode 100644 index d15e454..0000000 --- a/classes/Multilang.php +++ /dev/null @@ -1,9 +0,0 @@ -load('multilang'); - - if($config->auto_detect) - { - // Get the list of supported languages - $languages = $config->languages; - $cookie = $config->cookie; - - // Look for language cookie first - if($lang = Cookie::get($cookie)) - { - // Valid language found in cookie - if(isset($languages[$lang])) - { - return $lang; - } - - // Delete cookie with unset language - Cookie::delete($cookie); - } - - // Parse HTTP Accept-Language headers - foreach(Request::accept_lang() as $lang => $quality) - { - // Return the first language found (the language with the highest quality) - if(isset($languages[$lang])) - { - return $lang; - } - } - } - // Return the hard-coded default language as final fallback - return $config->default; - } - - /** - * Initialize the config and cookies - */ - static public function init() - { - $config = Kohana::$config->load('multilang'); - - // Get the list of supported languages - $langs = $config->languages; - - // Set the language in I18n - I18n::lang($langs[Request::$lang]['i18n']); - - // Set locale - setlocale(LC_ALL, $langs[Request::$lang]['locale']); - - $cookie = $config->cookie; - // Update language cookie if needed - if(Cookie::get($cookie) !== Request::$lang) - { - Cookie::set($cookie, Request::$lang); - } - } - - /** - * Return a language selector menu - * @param boolean $current Display the current language or not - * @return View - */ - static public function selector($current = TRUE) - { - $config = Kohana::$config->load('multilang'); - - $languages = $config->languages; - - // Get the current route name - $current_route = Route::name(Request::initial()->route()); - - - $params = Request::initial()->param(); - - if($current_route !== 'default' && strpos($current_route, '.') !== FALSE) - { - // Split the route path - list($lang, $name) = explode('.', $current_route, 2); - } - else - { - $name = $current_route; - } - - // Create uris for each language - foreach($languages as $lang => &$language) - { - // If it's the current language - if($lang === Request::$lang) - { - // We only display it when required - if($current) - { - $selectors[$lang] = ''.$languages[$lang]['label'].''; - } - } - else - { - $route = NULL; - - // If it's the default route, it's unique and special (like you <3) - if($current_route === 'default') - { - // We juste need to change the language parameter - $route = Request::initial()->route(); - $params['lang'] = NULL; - if(!$config->hide_default || $config->default !== $lang) - { - $params['lang'] = $lang; - } - - - } - else - { - if(Arr::get(Route::all(), $lang.'.'.$name)) - { - $route = Route::get($name, $lang); - } - } - - if($route !== NULL) - { - $selectors[$lang] = HTML::anchor($route->uri($params), $languages[$lang]['label'], array('class' => 'multilang-selectable multilang-'.$lang, 'title' => $languages[$lang]['label'])); - } - } - } - - // We display the menu only if we can select another language for this page - if(count($selectors) > 1) - { - return View::factory('multilang/selector') - ->bind('selectors', $selectors); - } - return ''; - } -} \ No newline at end of file diff --git a/classes/Multilang/Request.php b/classes/Multilang/Request.php deleted file mode 100644 index b85f29c..0000000 --- a/classes/Multilang/Request.php +++ /dev/null @@ -1,199 +0,0 @@ -load('multilang'); - - // If we don't hide the default language, we must look for a language code for the root uri - if(Request::detect_uri() === '' AND $config->auto_detect AND $uri === TRUE) - { - $lang = Multilang::find_user_language(); - if(!$config->hide_default OR $lang != $config->default) - { - // Use the default server protocol - $protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'; - - // Redirect to the root URI, but with language prepended - header($protocol.' 302 Found'); - header('Location: '.URL::base(TRUE, TRUE).$lang.'/'); - exit; - } - } - - return parent::factory($uri, $client_params, $allow_external, $injected_routes); - } - - /** - * We don't want to remove the trailing slash from the uri - */ - public function __construct($uri, $client_params = array(), $allow_external = TRUE, $injected_routes = array()) - { - $client_params = is_array($client_params) ? $client_params : array(); - - // Initialise the header - $this->_header = new HTTP_Header(array()); - - // Assign injected routes - $this->_routes = $injected_routes; - - // Cleanse query parameters from URI (faster that parse_url()) - $split_uri = explode('?', $uri); - $uri = array_shift($split_uri); - - // Initial request has global $_GET already applied - if (Request::$initial !== NULL) - { - if ($split_uri) - { - parse_str($split_uri[0], $this->_get); - } - } - - // Detect protocol (if present) - // $allow_external = FALSE prevents the default index.php from - // being able to proxy external pages. - if ( ! $allow_external OR strpos($uri, '://') === FALSE) - { - // Remove trailing slashes from the URI (We don't want that) - //$this->_uri = trim($uri, '/'); - $this->_uri = ltrim($uri, '/'); - //$this->_route = new Route($uri); - // Apply the client - $this->_client = new Request_Client_Internal($client_params); - } - else - { - // Create a route - $this->_route = new Route($uri); - - // Store the URI - $this->_uri = $uri; - - // Set the security setting if required - if (strpos($uri, 'https://') === 0) - { - $this->secure(TRUE); - } - - // Set external state - $this->_external = TRUE; - - // Setup the client - $this->_client = Request_Client_External::factory($client_params); - } - } - - /** - * Altered to detect the language in the uri - * - * @return Response - * @throws Request_Exception - * @throws HTTP_Exception_404 - * @uses [Kohana::$profiling] - * @uses [Profiler] - */ - public function execute() - { - if ( ! $this->_external) - { - $processed = Request::process($this, $this->_routes); - - if ($processed) - { - // Store the matching route - $this->_route = $processed['route']; - $params = $processed['params']; - - // Is this route external? - $this->_external = $this->_route->is_external(); - - if (isset($params['directory'])) - { - // Controllers are in a sub-directory - $this->_directory = $params['directory']; - } - - // Store the controller - $this->_controller = $params['controller']; - - // Store the action - $this->_action = (isset($params['action'])) - ? $params['action'] - : Route::$default_action; - - // These are accessible as public vars and can be overloaded - unset($params['controller'], $params['action'], $params['directory']); - - // Params cannot be changed once matched - $this->_params = $params; - } - } - - if ( ! $this->_route instanceof Route) - { - return HTTP_Exception::factory(404, 'Unable to find a route to match the URI: :uri', array( - ':uri' => $this->_uri, - ))->request($this) - ->get_response(); - } - - if ( ! $this->_client instanceof Request_Client) - { - throw new Request_Exception('Unable to execute :uri without a Kohana_Request_Client', array( - ':uri' => $this->_uri, - )); - } - - // Multilang part - if(Request::$lang === NULL) - { - Request::$lang = $this->_route->lang; - } - - $config = Kohana::$config->load('multilang'); - if($config->hide_default AND $this->param('lang') === NULL OR $this->_route->lang === NULL AND $this->param('lang') === NULL) - { - Request::$lang = $config->default; - } - else - { - Request::$lang = $this->param('lang'); - } - Multilang::init(); - - return $this->_client->execute($this); - } - - -} \ No newline at end of file diff --git a/classes/Multilang/Route.php b/classes/Multilang/Route.php deleted file mode 100644 index d94f483..0000000 --- a/classes/Multilang/Route.php +++ /dev/null @@ -1,346 +0,0 @@ -load('multilang'); - - if(!$config->hide_default || $config->default != $lang) - { - if($lang !== NULL) - { - $uri_callback = '/'.$uri_callback; - $regex['lang'] = $lang; - } - } - - if($lang !== NULL) - { - $name = $lang.'.'.$name; - } - - return Route::$_routes[$name] = new Route($uri_callback, $regex, $lang); - } - - - /** - * Retrieves a named route. - * - * $route = Route::get('default'); - * - * @param string route name - * @return Route - * @throws Kohana_Exception - */ - static public function get($name, $lang = NULL) - { - // We use the current language if none given - if($lang === NULL) - { - $lang = Request::$lang; - } - - // We first look for a "given_language.name" route. - if(isset(Route::$_routes[$lang.'.'.$name])) - { - $name = $lang.'.'.$name; - - } // then the default language - elseif(isset(Route::$_routes[Kohana::$config->load('multilang')->default.'.'.$name])) { - $name = $config->default.'.'.$name; - } - // And if we don't have any for this language, it means that route is neither defined nor multilingual - return parent::get($name); - } - - /** - * Altered constructor to handle multilingual routes - * - * Creates a new route. Sets the URI and regular expressions for keys. - * Routes should always be created with [Route::set] or they will not - * be properly stored. - * - * $route = new Route($uri, $regex); - * - * The $uri parameter can either be a string for basic regex matching or it - * can be a valid callback or anonymous function (php 5.3+). If you use a - * callback or anonymous function, your method should return an array - * containing the proper keys for the route. If you want the route to be - * "reversable", you need to return a 'uri' key in the standard syntax. - * - * $route = new Route(function($uri) - * { - * if (list($controller, $action, $param) = explode('/', $uri) AND $controller == 'foo' AND $action == 'bar') - * { - * return array( - * 'controller' => 'foobar', - * 'action' => $action, - * 'id' => $param, - * 'uri' => 'foo/bar/.html - * ); - * } - * }); - * - * @param mixed route URI pattern or lambda/callback function - * @param array key patterns - * @param - * @return void - * @uses Route::_compile - */ - public function __construct($uri = NULL, array $regex = NULL, $lang = NULL) - { - $this->lang = $lang; - return parent::__construct($uri, $regex); - } - - - /** - * Generates a URI for the current route based on the parameters given. - * - * // Using the "default" route: "users/profile/10" - * $route->uri(array( - * 'controller' => 'users', - * 'action' => 'profile', - * 'id' => '10' - * )); - * - * @param array $params URI parameters - * @return string - * @throws Kohana_Exception - * @uses Route::REGEX_Key - */ - public function uri(array $params = NULL, $lang = NULL) - { - // We define the language if required - if($this->lang !== NULL) - { - $params['lang'] = ($lang === NULL ? $this->lang : $lang); - } - - // Start with the routed URI - $uri = $this->_uri; - - if (strpos($uri, '<') === FALSE AND strpos($uri, '(') === FALSE) - { - // This is a static route, no need to replace anything - - if ( ! $this->is_external()) - return $uri; - - // If the localhost setting does not have a protocol - if (strpos($this->_defaults['host'], '://') === FALSE) - { - // Use the default defined protocol - $params['host'] = Route::$default_protocol.$this->_defaults['host']; - } - else - { - // Use the supplied host with protocol - $params['host'] = $this->_defaults['host']; - } - - // Compile the final uri and return it - return rtrim($params['host'], '/').'/'.$uri; - } - - // Keep track of whether an optional param was replaced - $provided_optional = FALSE; - - while (preg_match('#\([^()]++\)#', $uri, $match)) - { - - // Search for the matched value - $search = $match[0]; - - // Remove the parenthesis from the match as the replace - $replace = substr($match[0], 1, -1); - - while (preg_match('#'.Route::REGEX_KEY.'#', $replace, $match)) - { - list($key, $param) = $match; - - if (isset($params[$param]) AND $params[$param] !== Arr::get($this->_defaults, $param)) - { - // Future optional params should be required - $provided_optional = TRUE; - - // Replace the key with the parameter value - $replace = str_replace($key, $params[$param], $replace); - } - elseif ($provided_optional) - { - // Look for a default - if (isset($this->_defaults[$param])) - { - $replace = str_replace($key, $this->_defaults[$param], $replace); - } - else - { - // Ungrouped parameters are required - throw new Kohana_Exception('Required route parameter not passed: :param', array( - ':param' => $param, - )); - } - } - else - { - // This group has missing parameters - $replace = ''; - break; - } - } - - // Replace the group in the URI - $uri = str_replace($search, $replace, $uri); - } - - while (preg_match('#'.Route::REGEX_KEY.'#', $uri, $match)) - { - list($key, $param) = $match; - - if ( ! isset($params[$param])) - { - // Look for a default - if (isset($this->_defaults[$param])) - { - $params[$param] = $this->_defaults[$param]; - } - else - { - // Ungrouped parameters are required - throw new Kohana_Exception('Required route parameter not passed: :param', array( - ':param' => $param, - )); - } - } - - $uri = str_replace($key, $params[$param], $uri); - } - - // Trim all extra slashes from the URI - //$uri = preg_replace('#//+#', '/', rtrim($uri, '/')); - $uri = preg_replace('#//+#', '/', $uri); - - if ($this->is_external()) - { - // Need to add the host to the URI - $host = $this->_defaults['host']; - - if (strpos($host, '://') === FALSE) - { - // Use the default defined protocol - $host = Route::$default_protocol.$host; - } - - // Clean up the host and prepend it to the URI - $uri = rtrim($host, '/').'/'.$uri; - } - - return $uri; - } - - /** - * Altered method to handle multilingual parameter - * - * Create a URL from a route name. This is a shortcut for: - * - * echo URL::site(Route::get($name)->uri($params), $protocol); - * - * @param string route name - * @param array URI parameters - * @param mixed protocol string or boolean, adds protocol and domain - * @return string - * @since 3.0.7 - * @uses URL::site - */ - static public function url($name, array $params = NULL, $protocol = NULL, $lang = NULL) - { - // Create a URI with the route and convert it to a URL - return URL::site(Route::get($name, $lang)->uri($params), $protocol); - } - - /** - * We don't want to remove the trailing slash. - */ - public function matches(Request $request) - { - // Get the URI from the Request - //$uri = trim($request->uri(), '/'); - $uri = ltrim($request->uri(), '/'); - - if ( ! preg_match($this->_route_regex, $uri, $matches)) - return FALSE; - - $params = array(); - foreach ($matches as $key => $value) - { - if (is_int($key)) - { - // Skip all unnamed keys - continue; - } - - // Set the value for all matched keys - $params[$key] = $value; - } - - foreach ($this->_defaults as $key => $value) - { - if ( ! isset($params[$key]) OR $params[$key] === '') - { - // Set default values for any key that was not matched - $params[$key] = $value; - } - } - - if ( ! empty($params['controller'])) - { - // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore - $params['controller'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['controller']))); - } - - if ( ! empty($params['directory'])) - { - // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore - $params['directory'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['directory']))); - } - - if ($this->_filters) - { - foreach ($this->_filters as $callback) - { - // Execute the filter giving it the route, params, and request - $return = call_user_func($callback, $this, $params, $request); - - if ($return === FALSE) - { - // Filter has aborted the match - return FALSE; - } - elseif (is_array($return)) - { - // Filter has modified the parameters - $params = $return; - } - } - } - - return $params; - } - -} \ No newline at end of file diff --git a/classes/Multilang/Routes.php b/classes/Multilang/Routes.php deleted file mode 100644 index 4be4498..0000000 --- a/classes/Multilang/Routes.php +++ /dev/null @@ -1,77 +0,0 @@ - 'home', - * 'fr' => 'accueil', - * ))->defaults(array( - * 'controller' => 'homepage', - * 'action' => 'index', - * )); - * - * @param string route name - * @param array URI patterns (array of "language code" => "uri") - * @param array regex patterns for route keys - * @return Routes - */ - static public function set($name, $uris = array(), $regex = NULL) - { - $config = Kohana::$config->load('multilang'); - $routes = new Routes(); - - // We add the routes for each language and set their names to lang.name (en.homepage for example). - // The segment is also added on the uri if it's not hidden - - $default_lang = $config->default; - $languages = $config->languages; - - // We first look for the default language uri which is obviously compulsory - $default_uri = Arr::get($uris, $default_lang); - if($default_uri === NULL) - { - throw new Kohana_Exception('The default language route uri is required for the route: :route', array(':route' => $name)); - } - else - { - $routes->_routes[$default_lang.'.'.$name] = Route::set($name, $default_uri, $regex, $default_lang); - } - unset($languages[$default_lang]); - - // Then we add the routes for all the other languages - foreach($languages as $lang => $settings) - { - $uri = (Arr::get($uris, $lang) ? $uris[$lang] : $uris[$default_lang]); - - // For the uri, we use the one given or the default one - $routes->_routes[$lang.'.'.$name] = Route::set($name, $uri, $regex, $lang); - } - return $routes; - } - - - /** - * Set the defaults values for each route - * @param array $defaults - * @return Multilang_Routes - */ - public function defaults(array $defaults = NULL) - { - foreach($this->_routes as $route) - { - $route->defaults($defaults); - } - return $this; - } - - -} \ No newline at end of file diff --git a/classes/Multilang/URL.php b/classes/Multilang/URL.php deleted file mode 100644 index 570f754..0000000 --- a/classes/Multilang/URL.php +++ /dev/null @@ -1,22 +0,0 @@ -load('multilang'); - - if($config->auto_detect) - { - // Get the list of supported languages - $languages = $config->languages; - $cookie = $config->cookie; - - // Look for language cookie first - if($lang = Cookie::get($cookie)) - { - // Valid language found in cookie - if(isset($languages[$lang])) - { - return $lang; - } - - // Delete cookie with unset language - Cookie::delete($cookie); - } - - // Parse HTTP Accept-Language headers - foreach(Request::accept_lang() as $lang => $quality) - { - // Return the first language found (the language with the highest quality) - if(isset($languages[$lang])) - { - return $lang; - } - } - } - // Return the hard-coded default language as final fallback - return $config->default; - } - - /** - * Initialize the config and cookies - */ - static public function init() - { - $config = Kohana::$config->load('multilang'); - - // Get the list of supported languages - $langs = $config->languages; - - // Set the language in I18n - I18n::lang($langs[Request::$lang]['i18n']); - - // Set locale - setlocale(LC_ALL, $langs[Request::$lang]['locale']); - - $cookie = $config->cookie; - // Update language cookie if needed - if(Cookie::get($cookie) !== Request::$lang) - { - Cookie::set($cookie, Request::$lang); - } - } - - /** - * Return a language selector menu - * @param boolean $current Display the current language or not - * @return View - */ - static public function selector($current = TRUE) - { - $config = Kohana::$config->load('multilang'); - - $languages = $config->languages; - - // Get the current route name - $current_route = Route::name(Request::initial()->route()); - - - $params = Request::initial()->param(); - - if($current_route !== 'default' && strpos($current_route, '.') !== FALSE) - { - // Split the route path - list($lang, $name) = explode('.', $current_route, 2); - } - else - { - $name = $current_route; - } - - // Create uris for each language - foreach($languages as $lang => &$language) - { - // If it's the current language - if($lang === Request::$lang) - { - // We only display it when required - if($current) - { - $selectors[$lang] = ''.$languages[$lang]['label'].''; - } - } - else - { - $route = NULL; - - // If it's the default route, it's unique and special (like you <3) - if($current_route === 'default') - { - // We juste need to change the language parameter - $route = Request::initial()->route(); - $params['lang'] = NULL; - if(!$config->hide_default || $config->default !== $lang) - { - $params['lang'] = $lang; - } - - - } - else - { - if(Arr::get(Route::all(), $lang.'.'.$name)) - { - $route = Route::get($name, $lang); - } - } - - if($route !== NULL) - { - $selectors[$lang] = HTML::anchor($route->uri($params), $languages[$lang]['label'], array('class' => 'multilang-selectable multilang-'.$lang, 'title' => $languages[$lang]['label'])); - } - } - } - - // We display the menu only if we can select another language for this page - if(count($selectors) > 1) - { - return View::factory('multilang/selector') - ->bind('selectors', $selectors); - } - return ''; - } -} \ No newline at end of file diff --git a/classes/multilang/request.php b/classes/multilang/request.php deleted file mode 100644 index b85f29c..0000000 --- a/classes/multilang/request.php +++ /dev/null @@ -1,199 +0,0 @@ -load('multilang'); - - // If we don't hide the default language, we must look for a language code for the root uri - if(Request::detect_uri() === '' AND $config->auto_detect AND $uri === TRUE) - { - $lang = Multilang::find_user_language(); - if(!$config->hide_default OR $lang != $config->default) - { - // Use the default server protocol - $protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'; - - // Redirect to the root URI, but with language prepended - header($protocol.' 302 Found'); - header('Location: '.URL::base(TRUE, TRUE).$lang.'/'); - exit; - } - } - - return parent::factory($uri, $client_params, $allow_external, $injected_routes); - } - - /** - * We don't want to remove the trailing slash from the uri - */ - public function __construct($uri, $client_params = array(), $allow_external = TRUE, $injected_routes = array()) - { - $client_params = is_array($client_params) ? $client_params : array(); - - // Initialise the header - $this->_header = new HTTP_Header(array()); - - // Assign injected routes - $this->_routes = $injected_routes; - - // Cleanse query parameters from URI (faster that parse_url()) - $split_uri = explode('?', $uri); - $uri = array_shift($split_uri); - - // Initial request has global $_GET already applied - if (Request::$initial !== NULL) - { - if ($split_uri) - { - parse_str($split_uri[0], $this->_get); - } - } - - // Detect protocol (if present) - // $allow_external = FALSE prevents the default index.php from - // being able to proxy external pages. - if ( ! $allow_external OR strpos($uri, '://') === FALSE) - { - // Remove trailing slashes from the URI (We don't want that) - //$this->_uri = trim($uri, '/'); - $this->_uri = ltrim($uri, '/'); - //$this->_route = new Route($uri); - // Apply the client - $this->_client = new Request_Client_Internal($client_params); - } - else - { - // Create a route - $this->_route = new Route($uri); - - // Store the URI - $this->_uri = $uri; - - // Set the security setting if required - if (strpos($uri, 'https://') === 0) - { - $this->secure(TRUE); - } - - // Set external state - $this->_external = TRUE; - - // Setup the client - $this->_client = Request_Client_External::factory($client_params); - } - } - - /** - * Altered to detect the language in the uri - * - * @return Response - * @throws Request_Exception - * @throws HTTP_Exception_404 - * @uses [Kohana::$profiling] - * @uses [Profiler] - */ - public function execute() - { - if ( ! $this->_external) - { - $processed = Request::process($this, $this->_routes); - - if ($processed) - { - // Store the matching route - $this->_route = $processed['route']; - $params = $processed['params']; - - // Is this route external? - $this->_external = $this->_route->is_external(); - - if (isset($params['directory'])) - { - // Controllers are in a sub-directory - $this->_directory = $params['directory']; - } - - // Store the controller - $this->_controller = $params['controller']; - - // Store the action - $this->_action = (isset($params['action'])) - ? $params['action'] - : Route::$default_action; - - // These are accessible as public vars and can be overloaded - unset($params['controller'], $params['action'], $params['directory']); - - // Params cannot be changed once matched - $this->_params = $params; - } - } - - if ( ! $this->_route instanceof Route) - { - return HTTP_Exception::factory(404, 'Unable to find a route to match the URI: :uri', array( - ':uri' => $this->_uri, - ))->request($this) - ->get_response(); - } - - if ( ! $this->_client instanceof Request_Client) - { - throw new Request_Exception('Unable to execute :uri without a Kohana_Request_Client', array( - ':uri' => $this->_uri, - )); - } - - // Multilang part - if(Request::$lang === NULL) - { - Request::$lang = $this->_route->lang; - } - - $config = Kohana::$config->load('multilang'); - if($config->hide_default AND $this->param('lang') === NULL OR $this->_route->lang === NULL AND $this->param('lang') === NULL) - { - Request::$lang = $config->default; - } - else - { - Request::$lang = $this->param('lang'); - } - Multilang::init(); - - return $this->_client->execute($this); - } - - -} \ No newline at end of file diff --git a/classes/multilang/route.php b/classes/multilang/route.php deleted file mode 100644 index d94f483..0000000 --- a/classes/multilang/route.php +++ /dev/null @@ -1,346 +0,0 @@ -load('multilang'); - - if(!$config->hide_default || $config->default != $lang) - { - if($lang !== NULL) - { - $uri_callback = '/'.$uri_callback; - $regex['lang'] = $lang; - } - } - - if($lang !== NULL) - { - $name = $lang.'.'.$name; - } - - return Route::$_routes[$name] = new Route($uri_callback, $regex, $lang); - } - - - /** - * Retrieves a named route. - * - * $route = Route::get('default'); - * - * @param string route name - * @return Route - * @throws Kohana_Exception - */ - static public function get($name, $lang = NULL) - { - // We use the current language if none given - if($lang === NULL) - { - $lang = Request::$lang; - } - - // We first look for a "given_language.name" route. - if(isset(Route::$_routes[$lang.'.'.$name])) - { - $name = $lang.'.'.$name; - - } // then the default language - elseif(isset(Route::$_routes[Kohana::$config->load('multilang')->default.'.'.$name])) { - $name = $config->default.'.'.$name; - } - // And if we don't have any for this language, it means that route is neither defined nor multilingual - return parent::get($name); - } - - /** - * Altered constructor to handle multilingual routes - * - * Creates a new route. Sets the URI and regular expressions for keys. - * Routes should always be created with [Route::set] or they will not - * be properly stored. - * - * $route = new Route($uri, $regex); - * - * The $uri parameter can either be a string for basic regex matching or it - * can be a valid callback or anonymous function (php 5.3+). If you use a - * callback or anonymous function, your method should return an array - * containing the proper keys for the route. If you want the route to be - * "reversable", you need to return a 'uri' key in the standard syntax. - * - * $route = new Route(function($uri) - * { - * if (list($controller, $action, $param) = explode('/', $uri) AND $controller == 'foo' AND $action == 'bar') - * { - * return array( - * 'controller' => 'foobar', - * 'action' => $action, - * 'id' => $param, - * 'uri' => 'foo/bar/.html - * ); - * } - * }); - * - * @param mixed route URI pattern or lambda/callback function - * @param array key patterns - * @param - * @return void - * @uses Route::_compile - */ - public function __construct($uri = NULL, array $regex = NULL, $lang = NULL) - { - $this->lang = $lang; - return parent::__construct($uri, $regex); - } - - - /** - * Generates a URI for the current route based on the parameters given. - * - * // Using the "default" route: "users/profile/10" - * $route->uri(array( - * 'controller' => 'users', - * 'action' => 'profile', - * 'id' => '10' - * )); - * - * @param array $params URI parameters - * @return string - * @throws Kohana_Exception - * @uses Route::REGEX_Key - */ - public function uri(array $params = NULL, $lang = NULL) - { - // We define the language if required - if($this->lang !== NULL) - { - $params['lang'] = ($lang === NULL ? $this->lang : $lang); - } - - // Start with the routed URI - $uri = $this->_uri; - - if (strpos($uri, '<') === FALSE AND strpos($uri, '(') === FALSE) - { - // This is a static route, no need to replace anything - - if ( ! $this->is_external()) - return $uri; - - // If the localhost setting does not have a protocol - if (strpos($this->_defaults['host'], '://') === FALSE) - { - // Use the default defined protocol - $params['host'] = Route::$default_protocol.$this->_defaults['host']; - } - else - { - // Use the supplied host with protocol - $params['host'] = $this->_defaults['host']; - } - - // Compile the final uri and return it - return rtrim($params['host'], '/').'/'.$uri; - } - - // Keep track of whether an optional param was replaced - $provided_optional = FALSE; - - while (preg_match('#\([^()]++\)#', $uri, $match)) - { - - // Search for the matched value - $search = $match[0]; - - // Remove the parenthesis from the match as the replace - $replace = substr($match[0], 1, -1); - - while (preg_match('#'.Route::REGEX_KEY.'#', $replace, $match)) - { - list($key, $param) = $match; - - if (isset($params[$param]) AND $params[$param] !== Arr::get($this->_defaults, $param)) - { - // Future optional params should be required - $provided_optional = TRUE; - - // Replace the key with the parameter value - $replace = str_replace($key, $params[$param], $replace); - } - elseif ($provided_optional) - { - // Look for a default - if (isset($this->_defaults[$param])) - { - $replace = str_replace($key, $this->_defaults[$param], $replace); - } - else - { - // Ungrouped parameters are required - throw new Kohana_Exception('Required route parameter not passed: :param', array( - ':param' => $param, - )); - } - } - else - { - // This group has missing parameters - $replace = ''; - break; - } - } - - // Replace the group in the URI - $uri = str_replace($search, $replace, $uri); - } - - while (preg_match('#'.Route::REGEX_KEY.'#', $uri, $match)) - { - list($key, $param) = $match; - - if ( ! isset($params[$param])) - { - // Look for a default - if (isset($this->_defaults[$param])) - { - $params[$param] = $this->_defaults[$param]; - } - else - { - // Ungrouped parameters are required - throw new Kohana_Exception('Required route parameter not passed: :param', array( - ':param' => $param, - )); - } - } - - $uri = str_replace($key, $params[$param], $uri); - } - - // Trim all extra slashes from the URI - //$uri = preg_replace('#//+#', '/', rtrim($uri, '/')); - $uri = preg_replace('#//+#', '/', $uri); - - if ($this->is_external()) - { - // Need to add the host to the URI - $host = $this->_defaults['host']; - - if (strpos($host, '://') === FALSE) - { - // Use the default defined protocol - $host = Route::$default_protocol.$host; - } - - // Clean up the host and prepend it to the URI - $uri = rtrim($host, '/').'/'.$uri; - } - - return $uri; - } - - /** - * Altered method to handle multilingual parameter - * - * Create a URL from a route name. This is a shortcut for: - * - * echo URL::site(Route::get($name)->uri($params), $protocol); - * - * @param string route name - * @param array URI parameters - * @param mixed protocol string or boolean, adds protocol and domain - * @return string - * @since 3.0.7 - * @uses URL::site - */ - static public function url($name, array $params = NULL, $protocol = NULL, $lang = NULL) - { - // Create a URI with the route and convert it to a URL - return URL::site(Route::get($name, $lang)->uri($params), $protocol); - } - - /** - * We don't want to remove the trailing slash. - */ - public function matches(Request $request) - { - // Get the URI from the Request - //$uri = trim($request->uri(), '/'); - $uri = ltrim($request->uri(), '/'); - - if ( ! preg_match($this->_route_regex, $uri, $matches)) - return FALSE; - - $params = array(); - foreach ($matches as $key => $value) - { - if (is_int($key)) - { - // Skip all unnamed keys - continue; - } - - // Set the value for all matched keys - $params[$key] = $value; - } - - foreach ($this->_defaults as $key => $value) - { - if ( ! isset($params[$key]) OR $params[$key] === '') - { - // Set default values for any key that was not matched - $params[$key] = $value; - } - } - - if ( ! empty($params['controller'])) - { - // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore - $params['controller'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['controller']))); - } - - if ( ! empty($params['directory'])) - { - // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore - $params['directory'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['directory']))); - } - - if ($this->_filters) - { - foreach ($this->_filters as $callback) - { - // Execute the filter giving it the route, params, and request - $return = call_user_func($callback, $this, $params, $request); - - if ($return === FALSE) - { - // Filter has aborted the match - return FALSE; - } - elseif (is_array($return)) - { - // Filter has modified the parameters - $params = $return; - } - } - } - - return $params; - } - -} \ No newline at end of file diff --git a/classes/multilang/routes.php b/classes/multilang/routes.php deleted file mode 100644 index 4be4498..0000000 --- a/classes/multilang/routes.php +++ /dev/null @@ -1,77 +0,0 @@ - 'home', - * 'fr' => 'accueil', - * ))->defaults(array( - * 'controller' => 'homepage', - * 'action' => 'index', - * )); - * - * @param string route name - * @param array URI patterns (array of "language code" => "uri") - * @param array regex patterns for route keys - * @return Routes - */ - static public function set($name, $uris = array(), $regex = NULL) - { - $config = Kohana::$config->load('multilang'); - $routes = new Routes(); - - // We add the routes for each language and set their names to lang.name (en.homepage for example). - // The segment is also added on the uri if it's not hidden - - $default_lang = $config->default; - $languages = $config->languages; - - // We first look for the default language uri which is obviously compulsory - $default_uri = Arr::get($uris, $default_lang); - if($default_uri === NULL) - { - throw new Kohana_Exception('The default language route uri is required for the route: :route', array(':route' => $name)); - } - else - { - $routes->_routes[$default_lang.'.'.$name] = Route::set($name, $default_uri, $regex, $default_lang); - } - unset($languages[$default_lang]); - - // Then we add the routes for all the other languages - foreach($languages as $lang => $settings) - { - $uri = (Arr::get($uris, $lang) ? $uris[$lang] : $uris[$default_lang]); - - // For the uri, we use the one given or the default one - $routes->_routes[$lang.'.'.$name] = Route::set($name, $uri, $regex, $lang); - } - return $routes; - } - - - /** - * Set the defaults values for each route - * @param array $defaults - * @return Multilang_Routes - */ - public function defaults(array $defaults = NULL) - { - foreach($this->_routes as $route) - { - $route->defaults($defaults); - } - return $this; - } - - -} \ No newline at end of file diff --git a/classes/multilang/url.php b/classes/multilang/url.php deleted file mode 100644 index 570f754..0000000 --- a/classes/multilang/url.php +++ /dev/null @@ -1,22 +0,0 @@ - Date: Mon, 25 Feb 2013 13:05:17 +0100 Subject: [PATCH 4/4] Fix case --- classes/Multilang.php | 9 + classes/Multilang/Core.php | 159 ++++++++++++++++ classes/Multilang/Request.php | 199 +++++++++++++++++++ classes/Multilang/Route.php | 346 ++++++++++++++++++++++++++++++++++ classes/Multilang/Routes.php | 77 ++++++++ classes/Multilang/URL.php | 22 +++ classes/Request.php | 8 + classes/Route.php | 8 + classes/Routes.php | 8 + classes/URL.php | 5 + 10 files changed, 841 insertions(+) create mode 100644 classes/Multilang.php create mode 100644 classes/Multilang/Core.php create mode 100644 classes/Multilang/Request.php create mode 100644 classes/Multilang/Route.php create mode 100644 classes/Multilang/Routes.php create mode 100644 classes/Multilang/URL.php create mode 100644 classes/Request.php create mode 100644 classes/Route.php create mode 100644 classes/Routes.php create mode 100644 classes/URL.php diff --git a/classes/Multilang.php b/classes/Multilang.php new file mode 100644 index 0000000..d15e454 --- /dev/null +++ b/classes/Multilang.php @@ -0,0 +1,9 @@ +load('multilang'); + + if($config->auto_detect) + { + // Get the list of supported languages + $languages = $config->languages; + $cookie = $config->cookie; + + // Look for language cookie first + if($lang = Cookie::get($cookie)) + { + // Valid language found in cookie + if(isset($languages[$lang])) + { + return $lang; + } + + // Delete cookie with unset language + Cookie::delete($cookie); + } + + // Parse HTTP Accept-Language headers + foreach(Request::accept_lang() as $lang => $quality) + { + // Return the first language found (the language with the highest quality) + if(isset($languages[$lang])) + { + return $lang; + } + } + } + // Return the hard-coded default language as final fallback + return $config->default; + } + + /** + * Initialize the config and cookies + */ + static public function init() + { + $config = Kohana::$config->load('multilang'); + + // Get the list of supported languages + $langs = $config->languages; + + // Set the language in I18n + I18n::lang($langs[Request::$lang]['i18n']); + + // Set locale + setlocale(LC_ALL, $langs[Request::$lang]['locale']); + + $cookie = $config->cookie; + // Update language cookie if needed + if(Cookie::get($cookie) !== Request::$lang) + { + Cookie::set($cookie, Request::$lang); + } + } + + /** + * Return a language selector menu + * @param boolean $current Display the current language or not + * @return View + */ + static public function selector($current = TRUE) + { + $config = Kohana::$config->load('multilang'); + + $languages = $config->languages; + + // Get the current route name + $current_route = Route::name(Request::initial()->route()); + + + $params = Request::initial()->param(); + + if($current_route !== 'default' && strpos($current_route, '.') !== FALSE) + { + // Split the route path + list($lang, $name) = explode('.', $current_route, 2); + } + else + { + $name = $current_route; + } + + // Create uris for each language + foreach($languages as $lang => &$language) + { + // If it's the current language + if($lang === Request::$lang) + { + // We only display it when required + if($current) + { + $selectors[$lang] = ''.$languages[$lang]['label'].''; + } + } + else + { + $route = NULL; + + // If it's the default route, it's unique and special (like you <3) + if($current_route === 'default') + { + // We juste need to change the language parameter + $route = Request::initial()->route(); + $params['lang'] = NULL; + if(!$config->hide_default || $config->default !== $lang) + { + $params['lang'] = $lang; + } + + + } + else + { + if(Arr::get(Route::all(), $lang.'.'.$name)) + { + $route = Route::get($name, $lang); + } + } + + if($route !== NULL) + { + $selectors[$lang] = HTML::anchor($route->uri($params), $languages[$lang]['label'], array('class' => 'multilang-selectable multilang-'.$lang, 'title' => $languages[$lang]['label'])); + } + } + } + + // We display the menu only if we can select another language for this page + if(count($selectors) > 1) + { + return View::factory('multilang/selector') + ->bind('selectors', $selectors); + } + return ''; + } +} \ No newline at end of file diff --git a/classes/Multilang/Request.php b/classes/Multilang/Request.php new file mode 100644 index 0000000..b85f29c --- /dev/null +++ b/classes/Multilang/Request.php @@ -0,0 +1,199 @@ +load('multilang'); + + // If we don't hide the default language, we must look for a language code for the root uri + if(Request::detect_uri() === '' AND $config->auto_detect AND $uri === TRUE) + { + $lang = Multilang::find_user_language(); + if(!$config->hide_default OR $lang != $config->default) + { + // Use the default server protocol + $protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'; + + // Redirect to the root URI, but with language prepended + header($protocol.' 302 Found'); + header('Location: '.URL::base(TRUE, TRUE).$lang.'/'); + exit; + } + } + + return parent::factory($uri, $client_params, $allow_external, $injected_routes); + } + + /** + * We don't want to remove the trailing slash from the uri + */ + public function __construct($uri, $client_params = array(), $allow_external = TRUE, $injected_routes = array()) + { + $client_params = is_array($client_params) ? $client_params : array(); + + // Initialise the header + $this->_header = new HTTP_Header(array()); + + // Assign injected routes + $this->_routes = $injected_routes; + + // Cleanse query parameters from URI (faster that parse_url()) + $split_uri = explode('?', $uri); + $uri = array_shift($split_uri); + + // Initial request has global $_GET already applied + if (Request::$initial !== NULL) + { + if ($split_uri) + { + parse_str($split_uri[0], $this->_get); + } + } + + // Detect protocol (if present) + // $allow_external = FALSE prevents the default index.php from + // being able to proxy external pages. + if ( ! $allow_external OR strpos($uri, '://') === FALSE) + { + // Remove trailing slashes from the URI (We don't want that) + //$this->_uri = trim($uri, '/'); + $this->_uri = ltrim($uri, '/'); + //$this->_route = new Route($uri); + // Apply the client + $this->_client = new Request_Client_Internal($client_params); + } + else + { + // Create a route + $this->_route = new Route($uri); + + // Store the URI + $this->_uri = $uri; + + // Set the security setting if required + if (strpos($uri, 'https://') === 0) + { + $this->secure(TRUE); + } + + // Set external state + $this->_external = TRUE; + + // Setup the client + $this->_client = Request_Client_External::factory($client_params); + } + } + + /** + * Altered to detect the language in the uri + * + * @return Response + * @throws Request_Exception + * @throws HTTP_Exception_404 + * @uses [Kohana::$profiling] + * @uses [Profiler] + */ + public function execute() + { + if ( ! $this->_external) + { + $processed = Request::process($this, $this->_routes); + + if ($processed) + { + // Store the matching route + $this->_route = $processed['route']; + $params = $processed['params']; + + // Is this route external? + $this->_external = $this->_route->is_external(); + + if (isset($params['directory'])) + { + // Controllers are in a sub-directory + $this->_directory = $params['directory']; + } + + // Store the controller + $this->_controller = $params['controller']; + + // Store the action + $this->_action = (isset($params['action'])) + ? $params['action'] + : Route::$default_action; + + // These are accessible as public vars and can be overloaded + unset($params['controller'], $params['action'], $params['directory']); + + // Params cannot be changed once matched + $this->_params = $params; + } + } + + if ( ! $this->_route instanceof Route) + { + return HTTP_Exception::factory(404, 'Unable to find a route to match the URI: :uri', array( + ':uri' => $this->_uri, + ))->request($this) + ->get_response(); + } + + if ( ! $this->_client instanceof Request_Client) + { + throw new Request_Exception('Unable to execute :uri without a Kohana_Request_Client', array( + ':uri' => $this->_uri, + )); + } + + // Multilang part + if(Request::$lang === NULL) + { + Request::$lang = $this->_route->lang; + } + + $config = Kohana::$config->load('multilang'); + if($config->hide_default AND $this->param('lang') === NULL OR $this->_route->lang === NULL AND $this->param('lang') === NULL) + { + Request::$lang = $config->default; + } + else + { + Request::$lang = $this->param('lang'); + } + Multilang::init(); + + return $this->_client->execute($this); + } + + +} \ No newline at end of file diff --git a/classes/Multilang/Route.php b/classes/Multilang/Route.php new file mode 100644 index 0000000..d94f483 --- /dev/null +++ b/classes/Multilang/Route.php @@ -0,0 +1,346 @@ +load('multilang'); + + if(!$config->hide_default || $config->default != $lang) + { + if($lang !== NULL) + { + $uri_callback = '/'.$uri_callback; + $regex['lang'] = $lang; + } + } + + if($lang !== NULL) + { + $name = $lang.'.'.$name; + } + + return Route::$_routes[$name] = new Route($uri_callback, $regex, $lang); + } + + + /** + * Retrieves a named route. + * + * $route = Route::get('default'); + * + * @param string route name + * @return Route + * @throws Kohana_Exception + */ + static public function get($name, $lang = NULL) + { + // We use the current language if none given + if($lang === NULL) + { + $lang = Request::$lang; + } + + // We first look for a "given_language.name" route. + if(isset(Route::$_routes[$lang.'.'.$name])) + { + $name = $lang.'.'.$name; + + } // then the default language + elseif(isset(Route::$_routes[Kohana::$config->load('multilang')->default.'.'.$name])) { + $name = $config->default.'.'.$name; + } + // And if we don't have any for this language, it means that route is neither defined nor multilingual + return parent::get($name); + } + + /** + * Altered constructor to handle multilingual routes + * + * Creates a new route. Sets the URI and regular expressions for keys. + * Routes should always be created with [Route::set] or they will not + * be properly stored. + * + * $route = new Route($uri, $regex); + * + * The $uri parameter can either be a string for basic regex matching or it + * can be a valid callback or anonymous function (php 5.3+). If you use a + * callback or anonymous function, your method should return an array + * containing the proper keys for the route. If you want the route to be + * "reversable", you need to return a 'uri' key in the standard syntax. + * + * $route = new Route(function($uri) + * { + * if (list($controller, $action, $param) = explode('/', $uri) AND $controller == 'foo' AND $action == 'bar') + * { + * return array( + * 'controller' => 'foobar', + * 'action' => $action, + * 'id' => $param, + * 'uri' => 'foo/bar/.html + * ); + * } + * }); + * + * @param mixed route URI pattern or lambda/callback function + * @param array key patterns + * @param + * @return void + * @uses Route::_compile + */ + public function __construct($uri = NULL, array $regex = NULL, $lang = NULL) + { + $this->lang = $lang; + return parent::__construct($uri, $regex); + } + + + /** + * Generates a URI for the current route based on the parameters given. + * + * // Using the "default" route: "users/profile/10" + * $route->uri(array( + * 'controller' => 'users', + * 'action' => 'profile', + * 'id' => '10' + * )); + * + * @param array $params URI parameters + * @return string + * @throws Kohana_Exception + * @uses Route::REGEX_Key + */ + public function uri(array $params = NULL, $lang = NULL) + { + // We define the language if required + if($this->lang !== NULL) + { + $params['lang'] = ($lang === NULL ? $this->lang : $lang); + } + + // Start with the routed URI + $uri = $this->_uri; + + if (strpos($uri, '<') === FALSE AND strpos($uri, '(') === FALSE) + { + // This is a static route, no need to replace anything + + if ( ! $this->is_external()) + return $uri; + + // If the localhost setting does not have a protocol + if (strpos($this->_defaults['host'], '://') === FALSE) + { + // Use the default defined protocol + $params['host'] = Route::$default_protocol.$this->_defaults['host']; + } + else + { + // Use the supplied host with protocol + $params['host'] = $this->_defaults['host']; + } + + // Compile the final uri and return it + return rtrim($params['host'], '/').'/'.$uri; + } + + // Keep track of whether an optional param was replaced + $provided_optional = FALSE; + + while (preg_match('#\([^()]++\)#', $uri, $match)) + { + + // Search for the matched value + $search = $match[0]; + + // Remove the parenthesis from the match as the replace + $replace = substr($match[0], 1, -1); + + while (preg_match('#'.Route::REGEX_KEY.'#', $replace, $match)) + { + list($key, $param) = $match; + + if (isset($params[$param]) AND $params[$param] !== Arr::get($this->_defaults, $param)) + { + // Future optional params should be required + $provided_optional = TRUE; + + // Replace the key with the parameter value + $replace = str_replace($key, $params[$param], $replace); + } + elseif ($provided_optional) + { + // Look for a default + if (isset($this->_defaults[$param])) + { + $replace = str_replace($key, $this->_defaults[$param], $replace); + } + else + { + // Ungrouped parameters are required + throw new Kohana_Exception('Required route parameter not passed: :param', array( + ':param' => $param, + )); + } + } + else + { + // This group has missing parameters + $replace = ''; + break; + } + } + + // Replace the group in the URI + $uri = str_replace($search, $replace, $uri); + } + + while (preg_match('#'.Route::REGEX_KEY.'#', $uri, $match)) + { + list($key, $param) = $match; + + if ( ! isset($params[$param])) + { + // Look for a default + if (isset($this->_defaults[$param])) + { + $params[$param] = $this->_defaults[$param]; + } + else + { + // Ungrouped parameters are required + throw new Kohana_Exception('Required route parameter not passed: :param', array( + ':param' => $param, + )); + } + } + + $uri = str_replace($key, $params[$param], $uri); + } + + // Trim all extra slashes from the URI + //$uri = preg_replace('#//+#', '/', rtrim($uri, '/')); + $uri = preg_replace('#//+#', '/', $uri); + + if ($this->is_external()) + { + // Need to add the host to the URI + $host = $this->_defaults['host']; + + if (strpos($host, '://') === FALSE) + { + // Use the default defined protocol + $host = Route::$default_protocol.$host; + } + + // Clean up the host and prepend it to the URI + $uri = rtrim($host, '/').'/'.$uri; + } + + return $uri; + } + + /** + * Altered method to handle multilingual parameter + * + * Create a URL from a route name. This is a shortcut for: + * + * echo URL::site(Route::get($name)->uri($params), $protocol); + * + * @param string route name + * @param array URI parameters + * @param mixed protocol string or boolean, adds protocol and domain + * @return string + * @since 3.0.7 + * @uses URL::site + */ + static public function url($name, array $params = NULL, $protocol = NULL, $lang = NULL) + { + // Create a URI with the route and convert it to a URL + return URL::site(Route::get($name, $lang)->uri($params), $protocol); + } + + /** + * We don't want to remove the trailing slash. + */ + public function matches(Request $request) + { + // Get the URI from the Request + //$uri = trim($request->uri(), '/'); + $uri = ltrim($request->uri(), '/'); + + if ( ! preg_match($this->_route_regex, $uri, $matches)) + return FALSE; + + $params = array(); + foreach ($matches as $key => $value) + { + if (is_int($key)) + { + // Skip all unnamed keys + continue; + } + + // Set the value for all matched keys + $params[$key] = $value; + } + + foreach ($this->_defaults as $key => $value) + { + if ( ! isset($params[$key]) OR $params[$key] === '') + { + // Set default values for any key that was not matched + $params[$key] = $value; + } + } + + if ( ! empty($params['controller'])) + { + // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore + $params['controller'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['controller']))); + } + + if ( ! empty($params['directory'])) + { + // PSR-0: Replace underscores with spaces, run ucwords, then replace underscore + $params['directory'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $params['directory']))); + } + + if ($this->_filters) + { + foreach ($this->_filters as $callback) + { + // Execute the filter giving it the route, params, and request + $return = call_user_func($callback, $this, $params, $request); + + if ($return === FALSE) + { + // Filter has aborted the match + return FALSE; + } + elseif (is_array($return)) + { + // Filter has modified the parameters + $params = $return; + } + } + } + + return $params; + } + +} \ No newline at end of file diff --git a/classes/Multilang/Routes.php b/classes/Multilang/Routes.php new file mode 100644 index 0000000..4be4498 --- /dev/null +++ b/classes/Multilang/Routes.php @@ -0,0 +1,77 @@ + 'home', + * 'fr' => 'accueil', + * ))->defaults(array( + * 'controller' => 'homepage', + * 'action' => 'index', + * )); + * + * @param string route name + * @param array URI patterns (array of "language code" => "uri") + * @param array regex patterns for route keys + * @return Routes + */ + static public function set($name, $uris = array(), $regex = NULL) + { + $config = Kohana::$config->load('multilang'); + $routes = new Routes(); + + // We add the routes for each language and set their names to lang.name (en.homepage for example). + // The segment is also added on the uri if it's not hidden + + $default_lang = $config->default; + $languages = $config->languages; + + // We first look for the default language uri which is obviously compulsory + $default_uri = Arr::get($uris, $default_lang); + if($default_uri === NULL) + { + throw new Kohana_Exception('The default language route uri is required for the route: :route', array(':route' => $name)); + } + else + { + $routes->_routes[$default_lang.'.'.$name] = Route::set($name, $default_uri, $regex, $default_lang); + } + unset($languages[$default_lang]); + + // Then we add the routes for all the other languages + foreach($languages as $lang => $settings) + { + $uri = (Arr::get($uris, $lang) ? $uris[$lang] : $uris[$default_lang]); + + // For the uri, we use the one given or the default one + $routes->_routes[$lang.'.'.$name] = Route::set($name, $uri, $regex, $lang); + } + return $routes; + } + + + /** + * Set the defaults values for each route + * @param array $defaults + * @return Multilang_Routes + */ + public function defaults(array $defaults = NULL) + { + foreach($this->_routes as $route) + { + $route->defaults($defaults); + } + return $this; + } + + +} \ No newline at end of file diff --git a/classes/Multilang/URL.php b/classes/Multilang/URL.php new file mode 100644 index 0000000..570f754 --- /dev/null +++ b/classes/Multilang/URL.php @@ -0,0 +1,22 @@ +