Deep Links With Angular Routing and i18n in Prod Mode
With Angular i18n the different directories for the language build need to be supported. This article shows how to support language-independent deep linking.
Join the DZone community and get the full member experience.
Join For FreeIn some use cases, it is necessary to provide deep links in an Angular application. Without support for multiple languages, it is simply the URL + the angular route. With Angular i18n the different directories for the language build need to be supported. This article shows how to support language-independent deep linking. The AngularAndSpring project will serve as an example. It is a Spring Boot application that provides the backend with the rest endpoints and serves the Angular frontend in the 'resources/static/' directory.
Frontend
The frontend contains these file and directories:
- 'resources/static/index.html' -> push the user to the frontend matching their browser language
- 'resources/static/en/' -> English Angular compiled frontend package
- 'resources/static/de/' -> german Angular compiled frontend package
The Angular application supports; for example, this route: '/details/bsdetail/btcusd'. To access it, the request 'https://somedomain.de/details/bsdetail/btcusd' needs to be forwarded to the matching 'index.html' of the Angular package. For example, 'https://somedomain.de/en/index.html'.
Backend
The backend uses the ForwardServletFilter to forward the requests to the language matching Angular frontend:
@WebFilter
@Component
public class ForwardServletFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(ForwardServletFilter.class);
public static final List<Locale> SUPPORTED_LOCALES =
List.of(Locale.ENGLISH, Locale.GERMAN);
public static final List<String> REST_PATHS =
List.of("/bitfinex", "/bitstamp", "/coinbase", "/itbit", "/myuser");
public static final List<String> LANGUAGE_PATHS = SUPPORTED_LOCALES
.stream().map(myLocale -> String.format("/%s/", myLocale.getLanguage()))
.collect(Collectors.toList());
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest myRequest = (HttpServletRequest) request;
if(REST_PATHS.stream()
.anyMatch(restEndPoint -> 0 == myRequest.getServletPath()
.indexOf(restEndPoint)) ||
(LANGUAGE_PATHS.stream().anyMatch(langPath ->
0 == myRequest.getServletPath().indexOf(langPath))
&& (myRequest.getServletPath().contains(".")
&& !myRequest.getServletPath().contains("?"))))
{
chain.doFilter(myRequest, response);
} else {
Iterable<Locale> iterable = () -> myRequest.getLocales().asIterator();
Locale userLocale = StreamSupport.stream(iterable.spliterator(), false)
.filter(myLocale -> SUPPORTED_LOCALES.contains(myLocale))
.findFirst().orElse(Locale.ENGLISH);
String forwardPath = String.format("/%s/index.html",
userLocale.getLanguage());
RequestDispatcher dispatcher = myRequest.getServletContext()
.getRequestDispatcher(forwardPath);
dispatcher.forward(myRequest, response);
return;
}
}
}
In lines 1-3, the ForwardServletFilter is defined as a Web filter Component that implements the Filter interface.
In lines, 5-6, the list of supported Locales is put in the SUPPORTED_LOCALES list. It has to contain all Angular language packages that are in the '/resources/static' directory.
In lines 7-8, the list of paths with rest endpoints is created. They are excluded from redirection.
In lines 9-11, the list of the language paths is created to be able to check if the redirection is needed.
In lines 13-15, the doFilter method is defined to perform any necessary redirects.
In lines 16, the ServletRequest is cast to a HttpServletRequest.
In the lines 17-19, it is checked if the 'HttpServletRequest.getServletPath()' contains a rest path that should not be redirected.
In lines 20-23, it is checked if the 'HttpServletRequest.getServletPath()' contains already one of the LANGUAGE_PATHS and a '.' without a Parameter('?'). Those are the files of the compiled Angular Packages that should not be redirected.
In line 25, the ServletRequest is passed to the other Servlet Filters.
In lines 26, and following the ServletRequests, they should be redirected are processed.
In lines 27-30, the user locale is matched to the SUPPORTED_LOCALES. If no match is found, English is set as default.
In lines 30-32, the forward path of the 'index.html' of the Angular language package is created.
In lines 33-35, a RequestDispatcher is created with the 'forwardPath', and the dispatcher forwards the request to the selected Angular language package.
Conclusion
The ForwardServletFilter Angular projects with i18n can support deep linking in Angular routes. The deep link does not have to know the language to link to and the user gets the requested route of the frontend. The filter works with Spring Boot but can be adapted to Jakarta EE. For other deployment environments, other implementations of the concept are needed.
Opinions expressed by DZone contributors are their own.
Comments