Announcement Announcement Module
Collapse
No announcement yet.
Spring 3 MVC + RESTful url + Internationalization Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring 3 MVC + RESTful url + Internationalization

    Hello,

    I would like to know if it's possible using internationalization (with Resources messages Bundles) and RESTful url to make url like these :
    http://localhost:8080/en/index -> locale en
    and
    http://localhost:8080/fr/index -> locale fr
    and if possible
    http://localhost:8080/index -> default configured locale

    How to make the RequestMapping in my controllers ?
    How to change resources messages bundles with RESTful path variable ?

    Thanks in advance for your help.

  • #2
    I don't know much about internationalization... but I don't think putting the language in the path is the right choice. For one, you're going to want to eventually use namespaces, and it's going to get confusing if you also have languages in your path information. For example

    http://localhost:8080/admin/users
    http://localhost:8080/company/users

    rather than:

    http://localhost:8080/users

    This is very common when you need to have different perspectives to the same entity. The application I am working on now has a total of 5 namespaces - it's totally unavoidable for me.

    You are probably better off passing the language as a cookie or a session variable, and if those don't exist, then reading the default from the database for that user in an interceptor. You should only have one controller for all languages anyway. Don't clutter up your urls. If you must pass this information in the url, use a query string parameter. That is what they are there for.

    Also, in REST interfaces, you never refer to something as "index". It always just a "/" - the root:

    http://localhost:8080/users or http://localhost:8080/users/
    Last edited by egervari; Dec 9th, 2011, 05:13 AM.

    Comment


    • #3
      I have example (i don't know if it's Spring MVC behind) :
      http://battlelog.battlefield.com/fr/ -> content fr
      http://battlelog.battlefield.com/en/ -> content en
      All others actions are prefixed by the lang in the url... so it's possible !

      Problm with cookie/session language variable is how to easily change the locale ?

      Comment


      • #4
        I didn't say it wasn't possible, I just said it wasn't purely REST and that it wasn't desirable.

        The URL, in REST, should point to an actual resource. The language is not really resource - it's more like parameter.

        For example, I have many searches in my RESTful interfaces that look like this:

        http://localhost:8080/myapp/rest/help
        http://localhost:8080/myapp/rest/help?text=course

        Notice that I didn't do this:

        http://localhost:8080/myapp/rest/hel...ch?text=course

        The text parameter uses the same index action for the controller, but it's result is filtered. The language parameter would really be no different.

        Another example:

        Code:
        http://localhost:8080/myapp/rest/admin/user
        http://localhost:8080/myapp/rest/admin/user?firstName=&lastName=&username=&emailAddress=&director=true&_director=on&courseProvider=true&_courseProvider=on&instructor=true&_instructor=on&trainee=true&_trainee=on&submit=Search
        This is valid RESTful design.

        I highly doubt the Battlefield website is a fullblown enterprise application with over 50-150 entities in their system. They probably didn't have any need to consider namespaces. But if you're building an enterprise application with multiple user perspectives, I would advise against putting the language in your url path.

        You're better off doing:

        http://localhost:8080/myapp/rest/admin/user?lang=en

        And you can read the default lang from a cookie, session or from the database if it's not specified. This way that url ALWAYS points to the same resource. Doing it your way is actually making it harder on yourself.
        Last edited by egervari; Dec 9th, 2011, 05:44 AM.

        Comment


        • #5
          Originally posted by egervari View Post
          The URL, in REST, should point to an actual resource. The language is not really resource - it's more like parameter.

          For example, I have many searches in my RESTful interfaces that look like this:

          http://localhost:8080/myapp/rest/help
          http://localhost:8080/myapp/rest/help?text=course

          Notice that I didn't do this:

          http://localhost:8080/myapp/rest/hel...ch?text=course

          The text parameter uses the same index action for the controller, but it's result is filtered. The language parameter would really be no different.
          I don't understand why http://localhost:8080/myapp/rest/hel...ch?text=course is incorrect. You can make a RequestMapping on /rest/help/search ?

          When i say RESTful is more for @PathVariable feature (ex: /edit/{id})

          And using a request parameter like ?lang=en is not SEO !

          Comment


          • #6
            In REST, there is a convention that people follow. REST isn't just some technology - it is a form of conventions. All of your examples are not REST. You can still do it the way you want, but it wouldn't be REST.

            "/search" would be redundant. What is a search? A search is just a filter of what the index action is. The index action is usually a listing of all the entities. A search is just a filter of this listing, so you SHOULD use the same url for it. Here is an example of a /users action, which works for both non-searches and searches simultaneously:

            Code:
                @RequestMapping("/users")
                public ModelAndView index(@ModelAttribute UserAccountSearchForm form) {
                    ModelAndView modelAndView = new ModelAndView("users/index");
                    modelAndView.addObject("pagedResults", usersService.findAllUsers(form));
            
                    return modelAndView;
                }
            "/edit/{id}" is also incorrect. The id should be paired with the resource, not the action. The correct url for getting the edit form of a user would be:

            /users/{id}/edit

            This makes a great deal of sense because if you just want to see the view for a user (often called a show page), the url would be:

            /users/{id}

            Also, putting the ids after the entity makes even more sense when you chain them together:

            /users/{userId}/favourites/{favouriteId}

            This is a url that gets 1 favourite that is associated with a user. If you notice, this url design is hierarchical. You simply leave off the specifics to go up the chain. It acts as an implicit site-map. People usually chain 2 or 3 resources together. Any more than that is too complex to manage, but usually it is advantageous to do 2 or 3 chains.

            If you were to put the {id} after the action (such as "/users/{userId}/favourites/edit/{favouriteId}"), the chaining/nesting would not look so elegant.

            Common conventions

            GET /users - index action
            GET /users/create - create form action (sometimes omitted)
            POST /users - insert action
            GET /users/{id} - show action
            GET /users/{id}/edit - edit form action
            PUT /users/{id} - update action (you can also use POST since Spring is finicky with PUT)
            DELETE /users/{id} - delete action

            Of course, you can name your urls whatever you want, but the ones I listed are a good naming convention to follow. It works in all cases.

            I do have a lot of experience with this though, so if you don't want to run into url problems in the future, you might simply want to take my advice, even if you don't understand it. If you screw this up and do it "your own way", and then learn more later, you'll have a lot of rework to do.
            Last edited by egervari; Dec 9th, 2011, 06:49 AM.

            Comment


            • #7
              Thanks for your help, i now understand much better what is RESTful url !

              I've another question :
              In Spring Controller, it is better to group actions by same namespace ?
              For example :
              IndexController -> all actions from "/" (/search for example)
              UserController -> all actions from "/user"
              ...
              Or is it better to make Controller depend on Services (SearchService -> SearchController, ...) ?

              Comment


              • #8
                Yes, your controller class should group all of the 7 actions I specified earlier (sometimes you'll have less, sometimes more).

                I wouldn't have an Index controller. You should try and identify "resources" on your site, even if they don't translate to your domain objects in the back-end.

                You may want to create a "PagesController" for example, and the "/pages" would be your homepage, and "/pages/tour" should be Tour page, and so on. Then, you can setup your welcome page in your web.xml (usually index.jsp) to forward to "/pages" (make sure it's forward and NOT redirect).

                I would not use /search ever. Try and get away from that urge to do that. Only use "/pages/search" if it's a genuine search form that is distinctly different from the index action. More times than not, the index and search actions are actually the same action and they use almost the same view too. This is important, especially if you want to ajaxify your REST services. Dealing with different URLs that represent the same thing is confusing and makes for messy javascript code. Generifying your urls makes for easier ajax code.

                Sometimes you will have resources that don't translate to entities in your system. That's okay. For example, you could have /users/{id}/emailAddress to edit/save/verify a user's email address rather than putting everything on the basic "/user/{id}/edit" form.
                Last edited by egervari; Dec 9th, 2011, 09:42 AM.

                Comment


                • #9
                  Seo

                  This topic seems to have deviated from the original question IMHO.
                  I'm running into a similar problem, where I want the URLs to be

                  http://localhost:8080/myapp/fr/users
                  http://localhost:8080/myapp/de/users

                  for SEO puposes. As Aure77, earlier and rightly so mentioned - "And using a request parameter like ?lang=en is not SEO !"

                  So, what's the best way to accomplish this in Spring MVC 3?

                  I don't want to litter all my controllers with locale info, neither do I want to have to take care of locale whenever I have to generate URLs in the view. I can maybe, take care of the latter using (velocity)macros.

                  Comment


                  • #10
                    Originally posted by superpeer View Post
                    So, what's the best way to accomplish this in Spring MVC 3?

                    I don't want to litter all my controllers with locale info, neither do I want to have to take care of locale whenever I have to generate URLs in the view. I can maybe, take care of the latter using (velocity)macros.
                    I once built a spring application with this requirement. Mine was probably not the best approach, but at least it worked for me

                    Basically I wrote a ServletFilter intercepting all the application requests. In its doFilter() method, if the requested url follows the pattern, I remove its two-char locale identifier, pass them to the LocaleResolver and forward (via requestDispatcher) the original request without the language part.

                    For writing view urls without taking care of the locale, I wrap the HttpResponse in that same filter. The wrapper has its encodeUrl and encodeURL methods overriden, so they prepend the current locale code (if not already) to the url they're going to encode. Obviously this means you have to use <c:url> (or something which also calls encodeUrl) to generate your links.
                    Last edited by xcarlos; Jan 11th, 2012, 04:50 PM. Reason: Better explanation

                    Comment


                    • #11
                      Originally posted by superpeer View Post

                      for SEO puposes. As Aure77, earlier and rightly so mentioned - "And using a request parameter like ?lang=en is not SEO !"
                      Why do you believe this is so? You have some official documentation from search engines like Google that states that kind of URLs are desirable? The lang attribute seems to be able tell the search engine spider about the language of the page, so why wouldn't this be sufficient?
                      Last edited by MiB; Jan 12th, 2012, 05:00 AM.

                      Comment


                      • #12
                        SEO best practise

                        Please read the answer to this question:

                        http://stackoverflow.com/questions/1...e-optimization

                        Comment


                        • #13
                          Originally posted by superpeer View Post
                          Please read the answer to this question:

                          http://stackoverflow.com/questions/1...e-optimization
                          I read this very interesting post and the related articles, but my overall conclusion was that first best practice was different top domains if available and if not to use different subdomains for each country-language combo. Only after these did the subfolder solution you are aiming at come up.
                          I feel subdomains is a lot less messy than subfolders.

                          Thank you for bringing this up.

                          Comment


                          • #14
                            xcarlos your solution sounds really interesting. Can you post your solution?

                            Comment


                            • #15
                              Originally posted by hunziker View Post
                              xcarlos your solution sounds really interesting. Can you post your solution?
                              Yes I can, but I have not the code right here. Maybe in a couple of days.

                              Comment

                              Working...
                              X