ryan

Multi-language page names / URLs

Recommended Posts

Ryan, you just have to look at what you take from my PR, because I think you modified some of the files at the same time. Also you may have to check if the code really makes sense and maybe something missing an isset() or alike. I just done it real quick and only tested with multilanguage on.

No worries, that's pretty much what I already do. Unless a block of code is instantly understandable to me, I generally recode anything that goes into the core so that I can fully understand and comment it. That's why it sometimes takes me awhile to bring in PRs. But since I've got to support the code in the future, I figure I need to go through the process. 

  • Like 2

Share this post


Link to post
Share on other sites

BUG? I tried to change the default language to french (fr), which I set first to german (de) in the admin. What I did: I went to admin -> setup -> languages and changed entries for name and title and saved it. When I tried to edit other pages the names (pathes) didn't change.

After looking in the database the entries for the homepage (id=1) in the fields "name" and "name1234" in the table "pages" retain the original value.

Share this post


Link to post
Share on other sites
BUG? I tried to change the default language to french (fr), which I set first to german (de) in the admin. What I did: I went to admin -> setup -> languages and changed entries for name and title and saved it. When I tried to edit other pages the names (pathes) didn't change.

I'm confused because you can't change the default language per-se. You can change what you consider to be the default language, but it still has to have the name "default". In fact, ProcessWire doesn't (or isn't supposed to) let you change the name of the default language at all. 

Share this post


Link to post
Share on other sites

Sorry for confusing ??? and wasting your time. Finally it was a cache problem. What I have meant wasn't the name of the language but rather the name of the rootpage in the default language (here: fr for default).

  • Like 1

Share this post


Link to post
Share on other sites

I'm trying to find pages by name. I can't get a page by using it's alternative page name.

Assume it's the same page:

$p = $pages->find("name=namefor_default"); // this works as normal

$p = $pages->find("name=namefor_german"); // this doesn't

Doesn't matter what language the user is viewing. Also trying to do something like "name$langID=blabla" just throws error that name1013 isn't a field.

I tried all different things but no chance. This makes it kinda hard to build multilanguage page structures that would require to find pages using the path or name i.e. using urlSegments etc.

Edit: Only chance seems to use "path=/de/full/path/to/namefor_german/".

Share this post


Link to post
Share on other sites

Think the problem lies here: core > fields.php
function isNativeName() checks if field is an item of array $nativeNames.
Found it searching for other stuff a few time ago.
 

class Fields extends WireSaveableItems {

    /**
     * Instance of FieldsArray
     *
     */

    /**
     * Field names that are native/permanent to the system and thus treated differently in several instances.
     * For example, a Field can't be given one of these names.
     * @TODO This really doesn't belong here. This check can be performed from a Page without needing to maintain this silly list.
     */
    static protected $nativeNames = array(
      //NOT INCLUDED HERE: 'name1234' or what ever language id
    );

 


Have a look here too:

http://processwire.com/talk/topic/4780-database-structure/

Share this post


Link to post
Share on other sites

Thanks for the PR Soma!  I will pull this in within the next day or two and make any necessary updates to the CKEditor plugin as well. 

I would be very happy to have this included any time soon if you can manage it, because currently we have some multilanguage projects going that is kinda pointless without being able to link to a page int he language the field is being edited. 

Thanks

Share this post


Link to post
Share on other sites
I would be very happy to have this included any time soon if you can manage it, because currently we have some multilanguage projects going that is kinda pointless without being able to link to a page int he language the field is being edited. 

I'll try to get this one in later today. 

I'm trying to find pages by name. I can't get a page by using it's alternative page name.
Assume it's the same page:
$p = $pages->find("name=namefor_default"); // this works as normal
$p = $pages->find("name=namefor_german"); // this doesn't

This is actually the intended behavior because names specified in each language may not be unique. For example the spelling of Chocolate is the same between English and Spanish. But there are many examples, and it's very common to have the same page names across languages. As a result, "name" in a selector refers to the actual page's name, and not it's name in another language. While names aren't unique for the same page across languages, paths are unique (otherwise PW has no way to determine the language) so that's why your retrieval of the path worked but the name didn't. 

Doesn't matter what language the user is viewing. Also trying to do something like "name$langID=blabla" just throws error that name1013 isn't a field.

This is one that we can feasibly get working without too much trouble, if there's a need for it. 

I tried all different things but no chance. This makes it kinda hard to build multilanguage page structures that would require to find pages using the path or name i.e. using urlSegments etc.

One way you could do it is to change your "name" selector to a path selector:

$p = $pages->find($page->parent->path . "namefor_german"); 
  • Like 1

Share this post


Link to post
Share on other sites

Doesn't matter what language the user is viewing. Also trying to do something like "name$langID=blabla" just throws error that name1013 isn't a field.

This is one that we can feasibly get working without too much trouble, if there's a need for it. 

One way you could do it is to change your "name" selector to a path selector:

$p = $pages->find($page->parent->path . "namefor_german"); 

Thanks! I was trying to do something similar to manage language-friendly permalinks to news articles:

$article_page = $pages->get('/site-articles')->child("categories.name=news, post_date>=$start_date, post_date<=$end_date, name{$user->language}|name=$input->urlSegment2");

Replaced it by:

$candidate_pages = $pages->find($pages->get('/site-articles')->path . $input->urlSegment2);
$article_page = $candidate_pages->get("categories.name=news, post_date>=$start_date, post_date<=$end_date");

And now it works. 

BTW, I'm in the (almost finished) process of porting an existing site to ProcessWire and the multi-language support in pw is just fantastic!

  • Like 1

Share this post


Link to post
Share on other sites
BTW, I'm in the (almost finished) process of porting an existing site to ProcessWire and the multi-language support in pw is just fantastic!

Thanks, glad you are enjoying it! I'm assuming you are running the latest PW (2.4, formerly dev branch) since you are using multi-language features, but just in case, make sure you are running 2.4 as the support of multi-language is much better in 2.4 than in 2.3. 

Share this post


Link to post
Share on other sites

Thanks, glad you are enjoying it! I'm assuming you are running the latest PW (2.4, formerly dev branch) since you are using multi-language features, but just in case, make sure you are running 2.4 as the support of multi-language is much better in 2.4 than in 2.3. 

Sure. As I was just starting with PW, I was luck enough to pick dev version 2.3.15 (which said "release candidate for 2.4") and upgraded to 2.4 yesterday.  :)

Share this post


Link to post
Share on other sites

I have a problem with $page->localUrl() throwing error at 404 page:

Fatal error: Exception: Method Page::localUrl does not exist or is not callable in this context (in /Users/Roope/Sites/demo/wire/core/Wire.php line 320) 
#0 /Users/Roope/Sites/demo/site/templates/inc/header.php(61): Wire->__call('localUrl', Array) 
#1 /Users/Roope/Sites/demo/site/templates/inc/header.php(61): Page->localUrl(Object(Language)) 
#2 /Users/Roope/Sites/demo/site/templates/basic.php(1): include('/Users/Roope/Si...') 
#3 /Users/Roope/Sites/demo/wire/core/TemplateFile.php(139): require('/Users/Roope/Si...') 
#4 [internal function]: TemplateFile->___render() 
#5 /Users/Roope/Sites/demo/wire/core/Wire.php(359): call_user_func_array(Array, Array) 
#6 /Users/Roope/Sites/demo/wire/core/Wire.php(317): Wire->runHooks('render', Array) 
#7 /Users/Roope/Sites/demo/wire/m in /Users/Roope/Sites/demo/index.php on line 214

In header.php around line 61 I have language switcher code borrowed from previous page:

<?php 
echo '<ul>';
	foreach($languages as $language) {
		if(!$page->viewable($language)) continue; // check if page not published for this language
		$class = "$language" == "$user->language" ? ' class="active"' : '';
		$url = $page->localUrl($language); 
		echo '<li'.$class.'><a href="'.$url.'">'.$language->title.'</a></li>';
	}
echo '</ul>';

I updated PW to latest dev but that didn't have any affect on this one. Besides 404 error, everything else runs smoothly. Any thoughts?

I have regularly similar errors here in my site with a language switcher in the shared header, and, after analyzing the site logs,  it turns out that these errors occur only when robots (googlebot, baidu…) are visiting the site and try to get non existing files. 

I finally succeeded to reproduce the error systematically by entering urls in the /site directory of he site, like for example /site/aaaaa.

So my (maybe naive) guess is that when PW tries to serve a real file and doesn't find it, the /http404/ page does not have the language url hooks installed, hence the exception.

For the record, the simple workaround that I implemented just consists in catching WireExceptions when rendering the language switcher, like this:

<ul class="dropdown-menu">
	<?php
		foreach ($languages as $language) 
		{
			// if this page isn't viewable (active) for the language, skip it
			if (!$page->viewable($language)) continue;

			// Add the language to the menu
			if ($user->language->id == $language->id)
				echo "<li class='disabled ticked'><a>{$language->title}</a></li>";
			else {
				try {
					echo "<li><a href='{$page->localUrl($language)}'>{$language->title}</a></li>";
				} catch(WireException $e) {}
			}
		}
	?>
</ul>

This has the advantage that it keeps the simplicity of the call to $page->localUrl($language), and it makes the robots happy by returning a 404 error as expected.

Share this post


Link to post
Share on other sites

This is known that on a 404 there's was or is problems with LanguagePageNames module that add localUrl etc to page.

THe 404 error on site/sdads is fixed just recently: https://github.com/ryancramerdesign/ProcessWire/issues/399

It's always best to report issues on github and not in the forum, as Ryan isn't always scanning the forum, but sees issue reports in github immedieately.

Share this post


Link to post
Share on other sites

Hello,

I'm new to this great system (PW), not a coder, and trying to make a multilingual website (Turkish and English, Turkish being the default) for The Graduate School where I've worked for 12 years.

I've installed the default multilingual site profile, changed the default language to Turkish, and now what I'm trying to do is to use country flags as language switcher instead of the default text links on the upper right corner of the page.

Thanks in advance.

Share this post


Link to post
Share on other sites

Hi Murat,

You can change the markup where the language navigation is defined, it's here: https://github.com/ryancramerdesign/ProcessWire/blob/master/site-languages/templates/_main.php#L45

Your flag images should have the same filename as the language name in ProcessWire (e.g. default.gif, en.gif). Then output an image instead of the language title.

Cheers

Share this post


Link to post
Share on other sites

@Wanze,

Thanks for the quick reply.

Actually I managed to get the flags by editing the main.php file as you recommended. Then, I got another problem which was when I click the second language's flag (English in my site) the page opens in that language but the flag images on top disappears as there is no img at http://localhost/fbe_pw/en/site/assets/images/tr.png. I was trying to solve this problem that is why I did not update my original question. In fact, I came across this problem and a solution for it somewhere when I was reading about PW, but now I cannot find it  :(

EDIT: I've solved the problem of flag images disappearing by defining them in main.php as absolute URLs :).  Probably this is not an optimal solution, but it works (until I will find the other solution somewhere again).

Share this post


Link to post
Share on other sites

You're welcome!

Could you post your code how you output the images when the problem happens? Thanks.

Share this post


Link to post
Share on other sites

@Wanze

the src of flag images was 

<img width='32px' src='site/assets/images/".$language->title.".png' />";

and when I used absolute path as 

<img width='32px' src='http://xxx.yyy.edu.tr/site/assets/images/".$language->title.".png' />";

the error of flag images disappearing in second language pages gone

The whole code for language switcher in main.php file is as follows (I updated the flags with two states, i.e. active flag is in color, the other flag is in grey).

<ul class='languages'>
	<?php
	$currentLanguage = $user->language; // remember language
	$flag = '';
	foreach($languages as $language) {
		if(!$page->viewable($language)) continue; // is page viewable in this language?
		$user->language = $language; 
		if($language->id == $currentLanguage->id) {
			//echo "<li class='current'>";
			$flag = "<img width='32px' src='http://fbe.ogu.edu.tr/site/assets/images/".$language->title.".png' />";

		} else {
			//echo "<li>";
			$flag = "<img width='32px' src='http://fbe.ogu.edu.tr/site/assets/images/".$language->title."_off.png' />";
		}
		//echo "<a href='$page->url'>$language->title</a></li>";
		echo "<a href='$page->url'>$flag</a>";
	}
	$user->language = $currentLanguage; // restore language
	?>
</ul>

And here are screenshots of final look

post-3282-0-10659400-1428671099_thumb.pn

post-3282-0-97324900-1428671109_thumb.pn

Share this post


Link to post
Share on other sites
<img width='32px' src='site/assets/images/".$language->title.".png' />";

The problem is that this path is relative. Use an absolute path (starting with a slash).

ProcessWire provides the correct paths and urls for you over the config API variable: https://processwire.com/api/variables/config/

This should work:

echo "<img width='32px' src='{$config->urls->assets}images/{$language->title}.png' />";

Share this post


Link to post
Share on other sites

@Wanze, thanks for the answer, worked like a charm. Now I've another question.

Here is my languages setup:

default ---> Turkish (Türkçe) / name ---> tr

-------------------------------------------------------------------

other ---> English (İngilizce) / name ---> en

-------------------------------------------------------------------

flags ---> tr.png / tr_off.png / en.png / en_off.png

-------------------------------------------------------------------

In my working code I setup the language names as two letter codes (tr and en), and this is not good for the content editor. However, if I setup the language names as normal (Türkçe and İngilizce, for Turkish and English, respectively) I cannot get the two letter code for images.

My question is how can I get two letter codes to put as flag image's sources when the language names are set as Turkish and English?

Thanks.

Share this post


Link to post
Share on other sites

@murat@pw

I'm not sure if I fully understand your question. Languages are ProcessWire pages with a language template. This means, the "name" field identifies the language, it's a unique identifier. For example, you can't change the name of the default language (which is "default") because ProcessWire identifies the correct default language over this attribute. However, you can change the title of those languages:

 name     | title
----------|---------
 default  | Türkçe
----------|---------
 en       | İngilizce

If your title field is a multilanguage field, you can set the titles for both languages.

For your flag images, you'd use the "name" property as image file name, e.g. default.png for turkish and en.png for english. Because the name is independent of the title and most likely won't change in the future. Does it make sense? :)

Share this post


Link to post
Share on other sites

I've pushed and update to the dev branch so that sorting should now work across languages. Previously, calls like these would still result in the returned pages being sorted by the default language field, regardless of the user's language: 

$pages->find("..., sort=name"); 
$pages->find("..., sort=title"); 
$pages->find("..., sort=pageref.name");
$pages->find("..., sort=pageref.title");
// and so on

To demonstrate the problem, lets say that you had these three pages:

  • /numbers/one/
  • /numbers/two/
  • /numbers/three/

In Spanish, those pages would be named:

  • /numeros/uno/
  • /numeros/dos/
  • /numeros/tres/ 

Lets say I executed this in English (my default language):

$pages->get('/numbers/')->children('sort=name');

The result would be alphabetical:

  • /numbers/one/
  • /numbers/three/
  • /numbers/two/ 

If I executed it in Spanish, the order would still be the same, sorted by the English spelling (which is clearly not correct):

  • /numeros/uno/
  • /numeros/tres/
  • /numeros/dos/

They should be sorted alphabetically by Spanish instead. With the latest commit to the dev branch, they should now sort correctly for the given language. Meaning the Spanish results would now be in this order: 

  • /numeros/dos/
  • /numeros/tres/
  • /numeros/uno/

The scope of those goes beyond page names. This also affects multi-language text fields. So if you've got a multi-language 'title' field for instance, you can sort by that, or any other multi-language field you are using, and the sorting should work properly now. It does not yet work with language-alternate fields, though I think it's probably unusual to use those fields as sorting keys anyways. 

Hola amigos :)

I just stumbled over exactly this issue, with tags not properly sorted, or better to say all sorted by default (english) language and not the one I'm currently on.

Tried to disable and enable language url again and again, even created a new tag, to see if it somehow works with newer pages, but no difference.

I'm on 2.6.9 and 2.6.1 both with the same issue.. :/

Am I forgetting anything?

No matter how I sort them, by sort=name selector or $a->sort() method..

Share this post


Link to post
Share on other sites

Marth, you have three posts, and none of them about ProcessWire. Plus, your picture is from a rather obscure actress that doesn't fit your name. I'm tempted to mark you as spammer right away, but will give you another chance. Care to explain?

Share this post


Link to post
Share on other sites

Hi all,

I'm so sorry but I'm not getting out of the wood with my static page navigation in a multilingual site.

- Language switcher is working fine on single pages.

- In a normal single language site to refer to a single page in the menu, I use for example:

<li><a href="<?php echo $config->urls->root; ?>bestuur-kfc-heist">Bestuur</a></li> 

Now, what must I do so that the links reflect the /fr/  /en/  once I navigate between menu items in a certain language?

Am I missing a statement in the head so that  $config->urls->root;  would include the   /fr/    /en/   /nl/  ? 

For hours I've been searching but I'm simply not getting it right. The live site sits in a subdir 'rubens' and I changed in my htaccess to:   RewriteBase /rubens/

I'd greatly appreciate your advice ..

Bernard

EDIT

PW is far too simple for silly nooby's like me looking far too far for things which are yet soo obvious   :(   :( I solved my own stupid problem and indeed it works -right out of the box-

If anyone nooby like me would try to walk with his head in the sand, here's the code which works for me:

<a href="<? echo $pages->get("/")->url; ?>"><? echo $pages->get("/")->title; ?></a>  //home page
<a href="<? echo $pages->get("/inlijstingen/")->url; ?>"><? echo $pages->get("/inlijstingen/")->title; ?></a> //some page

And for the children of a page:
<ul class="someclass"><?php $articles = $pages->get("/inlijstingen/")->children;
foreach ($articles as $child) { ?>
<li><a href="<?php echo $child->url; ?>"><?php echo $child->get("headline|title"); ?></a></li>
<? } ?> 
</ul>

Compared to Joomla, setting up a multilingual site is as simple as Bonjour!

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.