Jump to content

Search in multilanguage site with multilang fields


seddass
 Share

Recommended Posts

Hi all,

Hope that there is a quick tip that someone already know...

Is it possible to search in multilanguage fields only in the current language values without to search in the default language as fallback? See the quote below.

We will assume that the current user's language is Dutch and that this is a language installed in the system. We will also assume that the field "body" is a multi-language textarea field. Because the user's current language is Dutch, the following API call matches any pages that contain the phrase "welkom vrienden" (welcome friends) in the Dutch body field OR the default body field. If there are other languages installed, it does not attempt to search them.

In other words.. I would like to search only in the current language (Dutch), no matter if some of the Dutch language values are empty. Is it possible?

Thanks

Link to comment
Share on other sites

Not technically a supported feature at present, but I think you can get the result you want. You'd take a query like this:

$pages->find("body*=something");

and convert it to this:

$pages->find("body.data{$user->language}*=something"); 

That should return just the pages that match the current user's language, rather than including the default language.

  • Like 3
Link to comment
Share on other sites

  • 5 months later...

Not technically a supported feature at present, but I think you can get the result you want. You'd take a query like this:

$pages->find("body*=something");

and convert it to this:

$pages->find("body.data{$user->language}*=something"); 

That should return just the pages that match the current user's language, rather than including the default language.

Sorry to dig this up, but I've followed these instructions, changing:

$matches = $pages->find("title|body|sidebar*=$q, limit=50, id!=1"); 

to

$matches = $pages->find("body.data{$user->language}*=$q, limit=50, id!=1"); 

and the following error shows up:

Error Exception: Unknown column 'field_body.data1029' in 'field list' (in /home/v3maran/public_html/wire/core/Database.php line 118)

Any clue why this is happening? I am using the built in multilanguage module. Thank you.

Link to comment
Share on other sites

(Edit: This just got deprecated ;), but I'll still leave it here - see "Part 2").

Go and see Setup -> Fields -> body. What's the type of the field?

I'm guessing it's "Textarea" as there doesn't seem to be fields for different languages in the database. That kind of selector would work only for fields of type *Language, "TextareaLanguage" in this case most likely.

You can change the type safely, but still after that for the selector to work in a reasonable way you'd have to input some content in the very language you're using in your search. But that was actually what you must have been trying to do anyway. :)

(..a few hours later..)

Part 2

Had another idea a bit later and while the earlier explanation could have been right, there's another possibility as well. And I think this is much more probable than the first one as I can't understand why you'd be using a selector like that if you didn't already have actual multilingual data in there - stupid me.

So now I'm thinking 1029 is the id of you default language (see Setup -> Languages -> default - what's the value of id parameter?). That special kind of selector would only work for languages other than the default one as its field is named just "data", not "data1029" for instance. So when the language is set to default ($user->language->name == 'default'), you'd have to use a regular selector without the ".data{$user->language}" part (or just ".data" without the id, I think).

Next part will follow in the morning - hope not.

Edited by nik
  • Like 2
Link to comment
Share on other sites

Nik is right about this. You probably want to change your selector to something like this:

$field = $user->language->isDefault() ? "body" : "body.data" . $user->language; 
$matches = $pages->find("$field*=$q"); 

That will force it to not consider the default language in the matches at all.

However, most of the time you should just do this, which already takes languages into account:

$matches = $pages->find("body*=$q"); 

So whether the user searches for "Beer" or "Cerveza" they will still get to the right page. If you exclude the default language, then that fallback never happens.

  • Like 5
Link to comment
Share on other sites

Thanks for both answers. My content fields are all multilanguage and work perfectly with everything else.

I implemented the changes Ryan pointed out and the error is gone. However, now the language resets always to the default one. I type the string, hit the button and the language changes back and displays results on that specific language.

You can check it here: http://maran.pt/

Try searching in portuguese (default) for "armario" and then, in english for "locker".

Link to comment
Share on other sites

I have that set in the header, it should load properly. However, I may have another loophole when I build the search form:

<form id='search_form' action='<?php echo $config->urls->root?>pesquisa/' method='get'>

The 'pesquisa' is the name of the search page. I believe this should change in order to get the /pt/ or /en/ after it, right?

Link to comment
Share on other sites

I think this will just depend on how and where you are setting the language. You'll want to make sure you are setting $user->language somewhere before your search (and before any output).

I now realized that part. Search.php treats things differently, so I would need to set the language before the output construction. However I am still unaware on how to achieve this since I tried to use the head.inc language related code lines, and nothing resulted from that. Here's what I have:

$lang = $user->language;
$langname = $lang->name == 'default' ? 'pt' : $lang->name;

I make no sense of this because I don't think it is setting anything (just storing the current languag in variables for further use), but everything else works. How can that be? I am confused now... ???

Link to comment
Share on other sites

When switching to language en, the search form is not changing it's action url.

<form id='search_form' action='/pesquisa/' method='get'>
 <input type='text' name='q' id='search_query' value='' />
 <button type='submit' id='search_submit'>Search</button>
</form>

When I manually enter http://maran.pt/en/search/?q=locker it seems to work.

  • Like 1
Link to comment
Share on other sites

Yes, Soma, I agree with you on that. I believe I have to place the language alias before. And about that, I have a question that is connected to this problem. When I want to link to a page, instead of typing the URL with the normal name, I would like to get the URL depending on the language I am at. Here's what I do, but I think this solution is not vert elegant...

$homepage = $pages->get("/");
$children = $homepage->children->find("name=pagename");
$child = $children->first();

Then I use $child->url for the url's link. Is there a easier way?

Link to comment
Share on other sites

  • 1 year later...

1.

$field = $user->language->isDefault() ? "body" : "body.data" . $user->language; 
$matches = $pages->find("$field*=$q"); 
2.
$matches = $pages->find("body*=$q");

WOW! The first one just made my day..thank you!!  :)

The second one is not working for name field is that correct?

Couldn't get it working $pages->get("name*=$q") it's only getting default language (find-> wasn't working for me neither)?

Link to comment
Share on other sites

  • 4 years later...
On 9/30/2012 at 6:00 PM, ryan said:

Nik is right about this. You probably want to change your selector to something like this:


$field = $user->language->isDefault() ? "body" : "body.data" . $user->language; 
$matches = $pages->find("$field*=$q"); 
 

That will force it to not consider the default language in the matches at all.

However, most of the time you should just do this, which already takes languages into account:


$matches = $pages->find("body*=$q"); 
 

So whether the user searches for "Beer" or "Cerveza" they will still get to the right page. If you exclude the default language, then that fallback never happens.

Hey,

I just wanted to say that this kind of functionality is super important for many websites. I just spend three hours looking for a solution until I stumbled on this. Seriously consider adding it to the documentation.

Now I can easily show only news item that actually has content in the relevant language.

  • Like 2
Link to comment
Share on other sites

  • 1 year later...

Maybe it is worth rethinking this implementation? When checking is a field is empty or not, for example, fallback to default is a bug. The hack solution is kinda ugly and unintuitive.
And one of PW's strongest points is multi-language support. What do you think,  @ryan?

P.S. I just tried it out one more time. It seems that if you check if the field is empty using just the field name, it checks only the default language. So if the field has text in user lang but not in default, the check is falsely false. So might be a real bug here.

Link to comment
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
 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By ErikMH
      So, if I do this right at the top of a template PHP file:
      <?php namespace ProcessWire; function myFunction() { global $config; echo $config->dateFormat; }; ?> I, predictably, get this in my front end (once I figured out about the necessary global $config; line):
      Y-m-d H:i:s Happy camper. But if I try to access $session variables in the same way:
      <?php namespace ProcessWire; function myFunction() { global $session; echo $session->future; }; ?> I’m told there is no $session object; it responds exactly as if I hadn’t included the global $session statement:
      PHP Notice: Trying to get property 'future' of non-object in .../public/site/templates/home.php:5 I thought the problem might conceivably have to do with my private variables, so I tried the provided hasCookie() method:
      <?php namespace ProcessWire; function myFunction() { global $session; print_r($session->hasCookie()); }; ?> With essentially the same result:
      Error Call to a member function hasCookie() on null $session variables and methods are fully accessible and work exactly as expected if placed immediately outside of myFunction().
      I am rapidly running out of hair. Is this intentional? Or a bug? Can anyone confirm that they see this behavior? Can anyone think of a workaround? Thanks!
      ProcessWire: 3.0.179
      PHP: 7.4.19
       
    • By prestoav
      Hi all,
      I could have sworn I used to be able to use the site generic 'title' field as a sub field of a repeater field. However I've tried to do this on two 3.0.165 sites recently and, while it will add the title field in the repeater field setup, it wont save the repeater title sub field's content when the repeater is used in a page template and edited.
      It;'s not a big issue but I wondered if this was a known restriction?
    • By spercy16
      I was previously using individual fields to capture and output multiple cards onto my web page but after recently learning about repeaters would prefer to use this field type, as it will be a lot more user friendly for end users to create new cards. I tried to modify my code to grab the fields from the new Repeater field(s) but am getting this error message on the page:
      Here is the code I'm currently trying to use for the cards:
      <?php // https://processwire.com/api/arrays/ // check if the array of images has items foreach($page->tall_card as $card) { $count = 0; $count++; $options = array( 'quality' => 70 ); $image = $card->image; $img = $card->image->size(550, 400, $options); $cardHeading = $card->title; $cardBody = $card->plain_paragraph; $raised = $card->raised_amount; $goal = $card->goal_amount; $link = $card->link; if ($raised == 0 ) : $percent = 0; else: $percent = $raised_amount / $goal_amount * 100; endif; if ($percent <= 5) : $percent = 0; endif; ?> <span id="card<?php echo $count?>" class="card"> <img class="cardThumb" src="<?php echo $img->url; ?>" alt="<?php echo $image->description; ?> Thumbnail" /> <div class="cardBody"> <div class="cardText"> <h2><?php echo $cardHeading; ?></h2> <?php echo $cardBody; ?> </div> <div class="progressBarSection"> <progress class="progressBar" id="progressbar<?php echo $count; ?>" value="<?php echo $percent; ?>" max="100"></progress> <span class="raisedAmount"> $<?php echo $raised; ?> usd </span> <span class="goalAmount"> $<?php echo $goal; ?> usd </span> </div> <div class="primaryBtn"> <a href="https://www.paypal.com/donate?hosted_button_id= <?php echo $link; ?> &source=url"> <button> <i class="fas fa-donate"></i> Donate </button> </a> </div> </div> </span> <?php } ?> Thanks in advance for any help!
    • By spercy16
      Coming from Perch (CMS) to Processwire, the one major downside I've found is that every place I want to insert content into my pages requires a single field (be that an image, integer, string, etc.). This can be a real pain to setup and manage if you have a lot of pages, many of them with dozens of unique fields. For example, on the Projects page of a site I'm working on right now I have to have fields for donate_amount (1-15, meaning fifteen unique fields that I have to duplicate manually), goal_amount(1-15), card_body(1-15), etc. After using Perch for a while, the way their system works is simply easier. You instead create your fields in a single PHP template (for every unique section, like a card) and their CMS imports those fields into the CMS when you choose to use that card, then you just fill in the values. You can also choose to reuse that card multiple times and each one you add gives you the several fields you need to fill in. So you can easily add your 15 cards, each with a picture, title, paragraph, and link, etc. and each one is basically given a unique ID that you can reference in your CSS files. If there's any way to make fields and templates work more like that, it would be a truly outstanding and efficient CMS. The great advantage of the way Perch is setup is that I can make a card with 10 fields, if need be, and easily duplicate that card out 40 times if I need 40 cards on the page and wouldn't need 10 fields for 40 cards (meaning in PW I would need 400 fields). If there's an easier way to do this in PW I would love to know, but as of right now, from what little I do know about the CMS 400 fields would be the only way to set that up, and that would be much more time consuming than if I could create one card (in PHP) with 10 fields that automatically added a number to the end of each field for each card (if that makes sense).
    • By donatas
      Hello,
      how would I do a multi-language website search with just a selector?
      I have many multi-lang fields and I want to do a search through all of them at once and through all of their language values.
      Is there a "selector way" of doing this? Maybe something like `title|title:de|title:it`? It seems I have seen this somewhere a long time ago but can't find in any documentation or forum search...
      Or the only way of doing it is by running separate searches for each language with output formatting off and then consolidating it all in one single results array?
      Because I still want to give users a result, even if it is in another language than current $user. Visitors mostly will be searching for specific terms that are very similar in all languages, but might be not used in one language version of a single page, for example. Or the user might not have switched language tohis prefered and did the search first, etc.. (many use cases in my situation)
      Example:
      $pages->find('title~='.$q) - maybe different operator is needed? /en/search/?q=visit = 1 results /it/search/?q=visit = 0 results Thanks for any advice!
×
×
  • Create New...