xfra35 / f3-multilang

Create multilingual apps with this localization plugin for the PHP Fat-Free Framework
GNU General Public License v3.0
48 stars 13 forks source link

Ignoring folder on global #2

Closed planetahuevo closed 9 years ago

planetahuevo commented 9 years ago

How can I ignore a whole folder on the global config?

I would like to keep all the routes under /api/* without using the language reroute.

Thanks

xfra35 commented 9 years ago

At the moment, the only way to do it is to give a name to each api route and add it to the global list:

[MULTILANG]
global = api_route1, api_route2, api_route3

That's not very convenient though. What do you think of allowing URL prefixes in this global variable?

[MULTILANG]
global = /api
rafatrace commented 9 years ago

What that would do is, when facing a route that starts by /api, like /api/list_users, the multilang will ignore?

If thats so, its seems good to me. I can't think of any problems that may appear with that solution.

planetahuevo commented 9 years ago

Sounds good. My problem really is that I have a lot or routes and I do not use aliases on them at the moment, so using url prefixes (or regex) seems like an easier solution. I like it.

xfra35 commented 9 years ago

Hi guys, I need to think more about it. The solution I've suggested actually raises issues:

Do you need this urgently?

In the meanwhile, a quick solution consists in splitting routes declaration in two, declaring global routes after calling the plugin:

$f3->config('etc/routes1.ini');
Multilang::instance();
$f3->config('etc/routes2.ini');

(routes contained in routes2.ini will not be rewritten)

rafatrace commented 9 years ago

That quick solution sounds good, unfortunately that will make me change my route structure. I don't need this urgently but I'll be glad to see a solution without changing my route structure.

Nice job thought, I'll glafly help on what you need. Cheers

xfra35 commented 9 years ago

Thanks. I'm open to suggestions. My concern is to not degrade the framework router performance with that check for global folders.

planetahuevo commented 9 years ago

Hi, That quick solution seems perfect for us. We are in a hurry but we are rerouting the app completely to add the aliases for the multilang, so create another .ini is much faster than create an alias for each global url. So for me that solution is perfect and we do not need anything else.

We will test it and see how it works. Thanks!

planetahuevo commented 9 years ago

Hi, I have another problem related to this. We are using the api for sending emails to the users.

We want to send the email on the language the page was loaded, but somehow the ml is loaded again when executing the email function and it is empty (because the api is language independent) so the api does not know which language should use.

We are trying to fix it using a global variable that load the value of "ml" and only changes when we are using a route outside of the api, but we were not able to make this work.

Any ideas?

Thanks

xfra35 commented 9 years ago

I'm not sure to follow you. What is the relation between the email function, the api and the current page?

planetahuevo commented 9 years ago

Yeah, I can imagine. It is difficult for me to follow myself. :D I will try to make it easier. Is there any way to execute a function on index.php only when some routes are used? I need to create an "IF" that only happens when I am not using the routes included on the routes2.ini if we use the example above. I am still debugging the problem, so I will comeback with more detailes later.

Thanks!

xfra35 commented 9 years ago

Are you trying to guess the current route before $f3->run()? Well... that's precisely the role of $f3->run() to find it for you ;) so there's something wrong in your logic.

But you wrote previously:

We want to send the email on the language the page was loaded

The "language the page was loaded" means that we're on a multilingual page and that the language has been determined by Multilang, right? So at which step do you lose it?

planetahuevo commented 9 years ago

No, I know the route. Let me put an example. I have one route that is on multilang, loaded on routes1.ini so it can be loaded as domain.com/en/comments or domain.com/es/comments I can access it and on the first one everything is in english and on the second everything on the page is in spanish. So far so good everything is working. I have a box on that page that send a comment by email (to other people not important). The function that send the email is accesed by an API which use another route located on routes2.ini so that route is independent from language.

The api get the info from the webpage and send the email but the language is lost. I need the language to send the content of the email (subject) on the language the user was on the page.

Still not sure where I am loosing it. This is what I am trying to debug. :)

xfra35 commented 9 years ago

Now I understand, you're posting a Spanish form to a language-independant route:

GET /es/comments => POST /api/email

But why making the api language-independant if it is dependant?

Anyway you can fix the problem by embedding the framework's LANGUAGE in your form:

<input type="hidden" name="LANGUAGE" value="{{@LANGUAGE}}"/>

and then in your api, just before sending your e-mail:

$f3->LANGUAGE=$_POST['LANGUAGE'];
planetahuevo commented 9 years ago

"But why making the api language-independant if it is dependant?" That is a good question. :) We miss that when we develop the app, so some api calls are language independant and they shouldn´t, but now, that we have implemented the multilang, we want to find a way to "fix" this problem meanwhile we work on rewriting the new api calls.

I will try your solution, but sometimes we do not have a form (we send emails based on actions made by the user, like buying something or clicking a button on the web) so sometimes we do not have a POST data.

I am going to investigate that and let you know.

Thank you very much!

xfra35 commented 9 years ago

I'm tempted to say: move the api route to routes1.ini... but there's probably some constraint preventing you from doing it. Then why not embedding the language in the query string (/api/email?lang=es)? And then $f3->LANGUAGE=$_GET['lang'];

planetahuevo commented 9 years ago

You are right, I cannot move them into routes1.ini because it will rewrite the urls adding the /en/ to them. Doing more testing, what happened is that when calling to the api route, multilang loads the english by default, which is strange. I am going to open a new issue right now as this is a different problem. :) I will come back to the topic after that.

planetahuevo commented 9 years ago

So, returning to my problem. Sending the language on the call to the API was the best solution but we are talking about 50-60 functions that will need to be rewriten because of this, so we are trying to avoid that. And because we have the language already on a variable ($ml) it looks like it shouldnt be that difficult to use that global language.

Let me explain the problem again. When the page loads {{$ml->current}} on the template returns the correct language value from the "url". /en or es in my case. {{$LANGUAGE}} is also with the good one and the page render the correct dictionary on the texts.

I write the comment or make the actions I want and the api is called and an email is written. The email is sent but when I use the {{$ml->current}} on the email template, it returns the english one, which is not the default but the browser autodetected language. I suppose this happen because the routes2.ini are considered global.

What we need is to have a "non language routes" that does not alter the value of {{$LANGUAGE}} and {{$ml->current}} from the same session.

We need to be able to define routes that are completely independant from the multilang plugin.

What we are trying so far: We were trying to store the value of the LANGUAGE on a custom variable only on pages from routes1.ini when index.php load. So, when I load the routes2.ini (/api/) the custom variable wont get overwrite on index.php and we can use that to restore the language modified by multilang before the run. If you know how to create an "IF" that only loads on non "/api/" routes I could try this.

So far nothing worked. :/

Thanks!

xfra35 commented 9 years ago

What we need is to have a "non language routes" that does not alter the value of {{$LANGUAGE}} and {{$ml->current}} from the same session.

The Multilang plugin doesn't rely on sessions, but on URL. So:

What should we do on "nothing"? Either we fall back on the primary language or we guess the best language from the client headers. I've chosen the latter approach. However after #1 and #5 will be fixed, the two approaches will be available.

Anyway, your problem is different: you're using global routes where you should be using multilingual routes. So:

  1. either you add a querystring to "hint" the language ('?lang='.$ml->current)
  2. or you store the current language in session, in order to remember it on global routes

Concerning solution 1, you don't need to rewrite 50-60 functions. Just place this code in your index.php (right after the call to Multilang):

if (isset($_GET['lang']) && $ml->auto)
  $f3->LANGUAGE=$_GET['lang'];

Concerning solution 2, place this code in your index.php (also right after the call to Multilang):

if (!$ml->auto)
  $f3->copy('LANGUAGE','SESSION.lang');
elseif ($f3->exists('SESSION.lang',$lang))
  $f3->LANGUAGE=$lang;

NB: $ml->auto is TRUE if the language has been auto-detected (i.e could not be detected from the URL)

planetahuevo commented 9 years ago

Hi, Thank you for the two suggestions.

Anyway, your problem is different: you're using global routes where you should be using multilingual routes. Not completely true. Multilingual routes on your plugin rewrite the url allways and I do not want the url to be rewrite.

What should we do on "nothing"?

You suggest there are two options, and I suggest a third, which is my case. a) fall back on the primary language. Ok. b) autodetect. Ok. c) use the session language and do not change language in any case.

I can see the points on a) and b), a lot of projects will use that but in my case, I would need c) and I am sure other projects in the future could need it too.

On solutions. 1.- sounds good but I still need to change the way the 50-60 functions are called (adding the hint to them) all around the app. If I decided to go 1.- I will rather add the language to the API call and fix it properly. This is something we will do on the future for sure. But thank you for the easy suggestion on how to capture the language.

2.- that IF is what we needed!! :) Going to test it right now. One commet I am testing your solution directly and I get this: Undefined variable: ml This is my code on index.php

$f3->set('ml',Multilang::instance()); //multilang
if (!$ml->auto)
  $f3->copy('LANGUAGE','SESSION.lang');
elseif ($f3->exists('SESSION.lang',$lang))
  $f3->LANGUAGE=$lang;

If I use this:

$f3->set('ml',Multilang::instance()); //multilang
$ml = \Multilang::instance();
if (!$ml->auto)
  $f3->copy('LANGUAGE','SESSION.lang');
elseif ($f3->exists('SESSION.lang',$lang))
  $f3->LANGUAGE=$lang;

I get Undefined variable: lang I know I can declare them to avoid the error, I am wandering if the error is ok as your suggestion does not declare the "lang" variable.

Thank you again. You are helping me a lot. :)

xfra35 commented 9 years ago

You've guessed it right: $ml referred to the Multilang instance. Concerning the 2nd error, it should be working.. see the docs.

$f3->exists('SESSION.lang',$lang);

is a shortcut for:

if ($f3->exists('SESSION.lang'))
  $lang=$f3->get('SESSION.lang');

Maybe you're running an old version of the framework? Anyway, you can just work it around like this:

if (!$ml->auto)
  $f3->copy('LANGUAGE','SESSION.lang');
elseif ($f3->exists('SESSION.lang'))
  $f3->LANGUAGE=$f3->get('SESSION.lang');
planetahuevo commented 9 years ago

Last version was installed and now the code works fine (not sure why it didn´t the first time, maybe a typo). We created another variable to store the value of $ml and now everything works as expected, ignoring the autodetect and using the last session language on the API.

Thank you very much!

planetahuevo commented 9 years ago

Offtopic but related to last comments: Why you suggest

$f3->set('ml',Multilang::instance()); //multilang
if (!$ml->auto) 

And it didn´t work and I need to use:

$f3->set('ml',Multilang::instance()); //multilang
$ml = \Multilang::instance();
if (!$ml->auto)
xfra35 commented 9 years ago

Look above: I didn't suggest $f3->set('ml',Multilang::instance()) ;) I just assumed that $ml was defined somehow so you were right to add that extra line. But you could as well use the instance defined above:

$f3->set('ml',Multilang::instance()); //multilang
if (!$f3->ml->auto)
planetahuevo commented 9 years ago

You are completely right. My bad. :+1:

xfra35 commented 9 years ago

Hi there, I'm really sorry for the delay but now it's all good. You can include prefixes in MULTILANG.global:

[MULTILANG]
global = /api, /admin, /path/to/folder

Hope it helps!

planetahuevo commented 9 years ago

Hi, Thank you! Great to hear it has been fixed!