Теперь я ищу рамки для многоязычных веб-приложений. На данный момент мне кажется, что лучший выбор - Spring MVC. Но я столкнулся с тем, что все руководящие принципы для разработчиков предлагают переключать языки с помощью LocaleChangeInterceptor таким образом:
http://www.somesite.com/action/?locale=en
К сожалению, существует ряд причин, почему я бы хотел этого избежать. Как я могу сделать код языка неотъемлемой частью URL? Например:
http://www.somesite.com/en/action
Спасибо.
UPD: Я нашел следующее решение. Он еще не завершен, но работает. Решение состоит из двух частей: фильтр сервлетов и релятор локали bean. Это выглядит немного хаки, но я не вижу другого способа решить эту проблему.
public class LocaleFilter implements Filter
{
...
private static final String DEFAULT_LOCALE = "en";
private static final String[] AVAILABLE_LOCALES = new String[] {"en", "ru"};
public LocaleFilter() {}
private List<String> getSevletRequestParts(ServletRequest request)
{
String[] splitedParts = ((HttpServletRequest) request).getServletPath().split("/");
List<String> result = new ArrayList<String>();
for (String sp : splitedParts)
{
if (sp.trim().length() > 0)
result.add(sp);
}
return result;
}
private Locale getLocaleFromRequestParts(List<String> parts)
{
if (parts.size() > 0)
{
for (String lang : AVAILABLE_LOCALES)
{
if (lang.equals(parts.get(0)))
{
return new Locale(lang);
}
}
}
return null;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
List<String> requestParts = this.getSevletRequestParts(request);
Locale locale = this.getLocaleFromRequestParts(requestParts);
if (locale != null)
{
request.setAttribute(LocaleFilter.class.getName() + ".LOCALE", locale);
StringBuilder sb = new StringBuilder();
for (int i = 1; i < requestParts.size(); i++)
{
sb.append('/');
sb.append((String) requestParts.get(i));
}
RequestDispatcher dispatcher = request.getRequestDispatcher(sb.toString());
dispatcher.forward(request, response);
}
else
{
request.setAttribute(LocaleFilter.class.getName() + ".LOCALE", new Locale(DEFAULT_LOCALE));
chain.doFilter(request, response);
}
}
...
}
public class FilterLocaleResolver implements LocaleResolver
{
private Locale DEFAULT_LOCALE = new Locale("en");
@Override
public Locale resolveLocale(HttpServletRequest request)
{
Locale locale = (Locale) request.getAttribute(LocaleFilter.class.getName() + ".LOCALE");
return (locale != null ? locale : DEFAULT_LOCALE);
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale)
{
request.setAttribute(LocaleFilter.class.getName() + ".LOCALE", locale);
}
}
Таким образом, нет необходимости отображать локаль в каждом действии в контроллерах. Следующий пример будет работать нормально:
@Controller
@RequestMapping("/test")
public class TestController
{
@RequestMapping("action")
public ModelAndView action(HttpServletRequest request, HttpServletResponse response)
{
ModelAndView mav = new ModelAndView("test/action");
...
return mav;
}
}