multi-language url rewiting. Is it possible?

Splash Forums PrettyFaces Users multi-language url rewiting. Is it possible?

This topic contains 18 replies, has 3 voices, and was last updated by  Anonymous 3 years, 5 months ago.

Viewing 15 posts - 1 through 15 (of 19 total)
  • Author
    Posts
  • #19544

    Anonymous

    Hi,

    I’m looking for a solution for the following problem and I don’t know if pretty-faces can help without side effects of any kind:

    My JSF2 application handle multi-language support, so at the moment the same page is rendered in english or italian according to the browser locale. I heard a way to handle internationalization for SEO is to have different ulr’s for different languages, so instead of:

    http://www.mydomain.com/fixed-unuseful-path/welcome.xhtml

    I could have:

    http://www.mydomain.com/en/welcome.xhtml

    http://www.mydomain.com/it/welcome.xhtml

    I already have the locale stored in a session bean, I was thinking DynaView could fit this pattern as described in the documentation, but then I read the caution: “Automatic out-bound URL-rewriting will not function on pages with dynamic view-ID’s.”

    What does that mean?

    Second question: is this pattern the best way to handle internationalization in jsf2 for SEO purposes?

    Thanks in advance.

    #23421

    Sure, you can embed the language code into the URL. I would try something like this:

    <url-mapping id="base">
    <pattern value="/#{localeBean.currentLang}" />
    </url-mapping>

    <url-mapping id="welcome" parentId="base">
    <pattern value="/welcome" />
    <view-id value="/faces/welcome.xhtml" />
    </url-mapping>

    This way you will get an URL like http://someserver/en/welcome which will automatically set the language code in your bean responsible for the language.

    The localeBean in this example IMHO shouldn’t have session scope but request scope, because the language is embedded in each URL and therefore it is automatically set on each request.

    #23422

    Anonymous

    Thanks for the reply, and the useful tips. Please would you clarify the caution message I’ve found in the documentation, it is still unclear to me.

    Thanks

    #23423

    Sure, see this example:

    <url-mapping id="welcome">
    <pattern value="/welcome" />
    <view-id value="/faces/welcome.xhtml" />
    </url-mapping>

    If the user enters /welcome into the address bar, PrettyFaces intercepts the request and forwards it, so that for JSF it looks like /faces/welcome.xhtml was requested. This is called “inbound rewriting”. But now JSF renders the result page. Each time JSF tries to render /faces/welcome.xhtml to the resulting page, PrettyFaces intercepts this, and changes it back to /welcome. This is called “outbound rewriting”. This is important for example for <h:form>, because it ensures that submitted forms post back to the pretty URL and not to the plain JSF URL.

    Now have a look a this example:

    <url-mapping id="welcome">
    <pattern value="/welcome" />
    <view-id value="#{someBean.calculateViewId}" />
    </url-mapping>

    In this case PrettyFaces calls the dynaview method during inbound rewriting to determine to which URL the request should be forwarded. But outbound rewriting won’t work here because PrettyFaces doesn’t know hat your dynaview methods can return and how to rewrite URLs rendered to the page.

    So you CAN use dynaview, but then URLs may turn ugly after postbacks. That’s the reason why I for myself don’t use dynaview at all. It may be useful in some special cases, but typically going with plain mappings is better.

    I hope this helps. :)

    Christian

    #23424

    Anonymous

    Thank you, very clear now. The next question comes up, in order to follow your suggestion about the multi-language pattern,

    <url-mapping id="base">
    <pattern value="/#{localeBean.currentLang}" />
    </url-mapping>
    <url-mapping id="welcome" parentId="base">
    <pattern value="/welcome" />
    <view-id value="/faces/welcome.xhtml" />
    </url-mapping>

    (I guess this is a dynaview example, right?) I cannot use fixed mapping as far as I understand so how can I prevent the outbound issue?

    #23425

    Do, this example is not using dynaview. You are using dynaview, if you are using a EL expression as the viewId.

    This example you posted should work fine.

    #23426

    Anonymous

    I’ve installed pretty-faces very quickly, that’s very nice.

    I’ve just used this configuration for my project and I experienced behaviours I was not expected.

    I’m trying with my eclipse project which adds the context “mtc” which will not be there on production (where the web app is on root of jetty server).

    This is the configuration:

    <pretty-config xmlns="http://ocpsoft.org/prettyfaces/3.3.3"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://ocpsoft.org/prettyfaces/3.3.3
    http://ocpsoft.org/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.3.xsd">

    <url-mapping id="base">
    <pattern value="/#{localeChanger.languageCode}/main" />
    </url-mapping>
    <url-mapping id="welcome" parentId="base">
    <pattern value="/welcome" />
    <view-id value="/pages/main/welcome.jsf" />
    </url-mapping>

    </pretty-config>

    In the web.xml:

    <welcome-file-list>
    <welcome-file>pages/main/welcome.jsf</welcome-file>
    </welcome-file-list>

    and the pretty-faces filter is the first one configured as in the documentation.

    Here is the behaviour:

    1) when I enter http://localhost:8080/mtc/ the browser displays the default page

    http://localhost:8080/mtc/pages/main/welcome.jsf (I expected http://localhost:8080/mtc/it/main/welcome instead, is there a way to fulfill my use case?)

    2) in this page there is a link to itself: the link (out-bound request, as far as I understand) navigates to tha same url

    http://localhost:8080/mtc/pages/main/welcome.jsf (I expected again http://localhost:8080/mtc/it/main/welcome. As I’m not using dynaview, why out-bound does not work? )

    3) when I enter http://localhost:8080/mtc/en/main/welcome the mapping works well and the page is displayed (in-bound request)

    4) in this situation the link to the same page returns

    http://localhost:8080/mtc/pages/main/welcome.jsf (instead of http://localhost:8080/mtc/en/main/welcome, why?)

    So, to be clearer, I would like to have the following behaviour:

    1) the user types

    1.a – http://localhost:8080/mtc/ (in my development environment) or

    1.b – http://www.mydomain.com/ (in production)

    and the rewritten url should be

    1.a – http://localhost:8080/mtc/it/main/welcome

    1.b – http://www.mydomain.com/it/main/welcome

    2) the link in welcome page , which internally is

    <h:outputLink value="../../pages/main/welcome.jsf">
    <h:outputText value="#{msgs.info}" />
    </h:outputLink>

    should show the url:

    1.a – http://localhost:8080/mtc/it/main/welcome

    1.b – http://www.mydomain.com/it/main/welcome

    Maybe there is still something missing somewhere, what is wrong?

    #23427

    Anonymous

    Sorry for the little mistake in my previous post,

    the web.xml is as follow:

    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    where index.html is

    <html>
    <head>
    <meta http-equiv="Refresh" content="0;url=pages/main/welcome.jsf">
    </head>
    </html>

    #23428

    If you are redirecting to the native URL pages/main/welcome.jsf in your index.html file, you are circumventing PrettyFaces, and you will likely not see what you expect.

    I’d suggest redirecting to a page that PrettyFaces knows about, like so:

    <html>
    <head>
    <meta http-equiv="Refresh" content="0;url=it/main/welcome">
    </head>
    </html>

    Outbound URL-rewriting isn’t active in plain HTML like the above page, so you need to use the pretty URL in the redirect manually.

    #23429

    Anonymous

    I tried but in this case a browser with english language would display the welcome page with italian content.

    Still I cannot figure out the solution of the multi-language problem, if the solution really exists using only pretty-faces as my initial guess.

    Furthermore the outputLink still does not work because from

    http://localhost:8080/mtc/it/main/welcome

    it leads to

    http://localhost:8080/mtc/pages/main/welcome.jsf.

    I wonder why….

    Thanks

    #23430

    To clarify the outbound rewriting stuff: It will only work if you are using exactly the correct view id (meaning /pages/main/welcome.jsf instead of something like ../../pages/main/welcome.jsf) and if you are using a JSF component to render the link. So it should work if you are using something like this:

    <h:link outcome="/pages/main/welcome.jsf">
    Click me
    </h:link>

    You will see that the rendered html contains a link to /en/main/welcome. IMHO you shouldn’t use <h:outputLink> here, because I’m not sure whether it calls the required Servlet API’s that are required for rewriting to work as it is usually used for external links. So you should use <h:link> or <pretty:link> instead.

    I tried but in this case a browser with english language would display the welcome page with italian content.

    This shouldn’t happen if you are doing it correctly. The general idea is to inject the language code from the URL into a bean that uses it to identify the correct locale and sets it for the view root. Something like this:

    <url-mapping id="base">
    <pattern value="/#{localeChanger.languageCode}/main" />
    </url-mapping>

    and:

    public class LocaleChanger {

    private String languageCode;

    /* getters / setters */

    public Locale getLocale() {
    return new Locale(languageCode);
    }

    }

    and:

    <f:view locale="#{localeChanger.locale}">
    ...
    </f:view>

    #23431

    Anonymous

    Thanks Christian, I’m just exploring pretty-faces in these days, I will try to change the outputLink as soon as possible. I got your clarification about the out-bound link.

    What I didn’t understand yet is your comment about the redirection in the index.html. As index.html is not jsf, following Lincoln’s suggestion, I had to insert the italian languageCode “it” in the meta refresh tag, a page pretty-faces knows about, so the espression #{localeChanger.languageCode} in the config file sets the languageCode value to “it” even if the user language is english.

    I have to say that LocaleChanger is still session scope because it is used also to permit the user to change the language using country flag buttons on top of the page.

    #23432

    Anonymous

    I played with both h:link and pretty:link,

    the beaviour is quite different:

    1. <h:link>

    I tried two links of this type, the one suggested by Christian:

    <h:link outcome="/pages/main/welcome.jsf">
    info1
    </h:link>

    and the following one:

    <h:link outcome="/pages/main/welcome.jsf" value="#{msgs.info}">
    <f:param value="#{localeChanger.languageCode}" />
    </h:link>

    the results are the same: the url becomes http://localhost:8080/mtc/pages/main/welcome.jsf, so the out-bound seems to misbehave.

    2. <h:link> with mapping-ID

    <h:link outcome="pretty:welcome" value="#{msgs.info}">
    <f:param value="#{localeChanger.languageCode}" />
    </h:link>

    here the url becomes http://localhost:8080/mtc/pages/main/welcome.jsf?com.ocpsoft.mappingId=welcome

    …still not working

    3. <pretty:link>

    <pretty:link mappingId="welcome">
    <f:param value="#{localeChanger.languageCode}" />
    info2
    </pretty:link>

    here the url becomes http://localhost:8080/mtc/it/main/welcome, so the out-bound works as expected.

    I used the configuration we discussed in the previous posts, why h:link doesn’t work as expected?

    Thanks in advance

    #23433

    If you want to use h:link, you will also have to used named parameters. See:

    http://ocpsoft.org/docs/prettyfaces/3.3.3/en-US/html/Configuration.html#config.pathparams

    So you will have to change the mapping to this:

    <url-mapping id="base">
    <pattern value="/#{ locale : localeChanger.languageCode }/main" />
    </url-mapping>

    And then add the name attribute to the <f:param> tags:

    <h:link outcome="/pages/main/welcome.jsf" value="#{msgs.info}">
    <f:param name="locale" value="#{localeChanger.languageCode}" />
    </h:link>

    See also:

    http://ocpsoft.org/docs/prettyfaces/3.3.3/en-US/html/components.html#components.jsf

    #23434

    Anonymous

    Thanks, the picture is getting clearer. I prefer to use the pretty:link and it work perfectly!

    Now I’m stuck on a commandLink, the one I used to change the language by clicking on a flag icon: when I ckick the flag, the url does not change the first time. It willl change if I click once more the flag or I navigate away from the page. Maybe this is a small issue but even adding ?faces-redirect=true the problem persists. Is there something related to pretty-faces?

    Here is the xhtml snippet:

    <h:commandLink immediate="true"
    action="#{localeChanger.changeLocale('en')}">
    <h:graphicImage library="images" name="flags/flag_eng.gif" />
    </h:commandLink>

    Here is the action:

    public String changeLocale(String lang) {
    languageCode = lang;
    FacesContext context = FacesContext.getCurrentInstance();
    context.getViewRoot().setLocale(new Locale(languageCode));
    String path = context.getExternalContext().getRequestServletPath();

    String rewrittenURL = context.getExternalContext()
    .encodeResourceURL(path+"?faces-redirect=true&lang="+languageCode);
    System.out.println("changeLocale:"+rewrittenURL);
    return rewrittenURL;
    }

    So rewrittenURL is correct (/mtc/en/main/welcome?faces-redirect=true) but the url in the address bar does not change.

    The commandLink is part of the template so it is on every pages, also on those pages where the url-rewriting is not necessary.

Viewing 15 posts - 1 through 15 (of 19 total)

You must be logged in to reply to this topic.

Comments are closed.