Cody Potter - Posted on March 31, 2024
The Hellscape of Multi-Language Angular
Ok, so you want to add multi-lingual features to your angular app -- an admirable task. I have recently gone down this path, and I'd like to share my experience with you.
Simply put, there are no good options. No matter what you do, you will need to make a compromise in order to provide multi-lingual features in your Angular app.
If you want to check all of these boxes, you're going to be disappointed:
- Cheap, static web hosting
- Simple, fast build system
- Easy to read/organize/update translations
- Dynamic (runtime) translations
- Clean, focused, performant application code
First of all, none of these requirements are crazy or outlandish. But here's the harsh reality -- achieving all these goals simultaneously is not easily attainable by any means I have found. Aside: If you have a super slick way to do this and it checks all the boxes, please let me know what it is! You can share your solutions and ideas in the comments or contact me.
Why? A decision tree
Ok, lets talk about the current options. At the bottom of the flowchart are the two big players in the localization game, Angular Internationalization (i18n) and ngx-translate, are the only options I'm discussing today.
Your options
Let's discuss both, including how they work and what they look like in your project.
Angular Internationalization (i18n)
First of all, I could (and should) have a whole blog post about abbreviations that use this pattern. i18n is unclear and confusing because the abbreviation itself is complex, un-pronouncable, and easy to mis-type for newbies. Can you spot the difference -> i18n vs il8n.
Angular i18n, is the Angular-prescribed method for adding multi-language features to your application.
How it appears in your code
Markup Translation: Angular i18n primarily involves marking up text in your templates and components for translation using special Angular syntax. For example, you can use the i18n attribute on HTML elements to mark them for translation.
<p i18n>Hello, world!</p>
Translation Files: Angular generates translation files (.xlf or .xlf2 format) during the build process, which contain the translatable strings marked in your code. These files can be provided to translators for localization into different languages.
Translation Placeholder: Angular i18n uses placeholder elements (<ng-container>
and <ng-template>
) to represent translatable content in the generated translation files. Translators can then replace these placeholders with the corresponding translations.
How it is Hosted/Served
Build Process: During the Angular build process (ng build), Angular CLI compiles your application and generates separate bundles for each supported language. It also creates translation files for each language, which contain the translated text.
Serving Translations: When serving your Angular application, you can configure your server to serve the appropriate language bundle and translation files based on the user's locale. This can be done using server-side routing or by embedding the language in the URL.
Dynamic Loading: Alternatively, you can dynamically load translations at runtime using Angular's TranslateService. This allows you to fetch translations asynchronously from a server or storage service, providing flexibility in managing translations. Note: this service isn't like google translate, your content must already have translations provided somewhere, or fetchable from a service.
What's the problem?
- It takes a lot of work to set everything up, and working with the translation files can be a pain without the software you need.
- Say you need to add ONE translation, a very common use case in iterative development, the cli tools make you regenerate your entire translation file, and then its up to you to manually add the xlf translations you need. Its a big headache, and it is confusing for newbies.
- Its a pain to iterate locally. You need to stop your dev server, extract translations, merge everything together.
- You can't translate libraries unless they add support for i18n.
ngx-translate (the third-party option)
ngx-translate is a popular third-party library for internationalization (i18n) in Angular applications. It provides methods to manage translations and localize content dynamically at runtime.
🚨🚨🚨
Big asterisk! Long-term support for ngx-translate is questionable. It posted a maintance mode notice, and this GitHub issue regarding the future of the library is a little bleak. As of Feb 26, 2024, it is still open and there are discussions regarding a lack of worthy maintainers. As of this writing, there is no support for the most recent Angular version, 17, as there should be.
🚨🚨🚨
How it appears in your code
Setup: To use ngx-translate in your Angular application, you first need to install the library via npm and import the necessary modules into your Angular application module.
Translation Files: ngx-translate typically uses JSON files to store translations for different languages. These translation files contain key-value pairs, where keys represent the original text in the application, and values represent the translated text.
Translation Service: ngx-translate provides a TranslateService that allows you to load translation files, switch between languages, and translate text dynamically in your components and services.
Markup Translation: In your Angular templates, you can use the translate pipe provided by ngx-translate to translate text dynamically based on the current language.
<p>{{ 'HELLO_WORLD' | translate }}</p>
How it is Hosted/Served
Hosting and serving an Angular application that uses ngx-translate is no different from hosting any other Angular application. You can serve it statically or deploy it to a server, CDN, or cloud platform like AWS, Firebase, or Azure.
Static Hosting: You can build your Angular application with ngx-translate (ng build) and deploy the generated static files to any static hosting provider, such as GitHub Pages, Netlify, Vercel, or AWS S3. The translation files (JSON) are included in the build output and served alongside other static assets.
Server-side Rendering (SSR): If you're using Angular Universal for server-side rendering (SSR), ngx-translate can still be used in a similar manner. Translation files are preloaded on the server, and translated content is rendered dynamically before being sent to the client.
Dynamic Loading: ngx-translate also supports dynamic loading of translation files at runtime, allowing you to fetch translations asynchronously from a server or storage service. This can be useful for applications with a large number of translations or when translations are updated frequently. Again, these translations have to live somewhere -- its not Google translate.
What's the problem?
You might be thinking, "What's the problem Cody?". This looks fine. Here's an example where ngx-translate gets a little out of hand.
Let's look at this template:
<p>{{ 'HELLO_WORLD' | translate }}</p>
Pretty simple right? In ngx-translate, the syntax for template interpolation is the same as with Angular i18n. However, there are additional complexities introduced in managing the translation service and handling translation logic in the application code.
Managing the TranslateService: In EVERY Angular component that uses translations, you need to inject and use the TranslateService to load translations and handle translation logic. This involves additional setup and management compared to Angular i18n, where translation handling is built-in.
Translation File Loading: With ngx-translate, you need to load translation files dynamically at runtime using the TranslateService. This involves additional asynchronous logic to fetch translation files from a server or storage service.
Handling Translation Logic: In your application code, you may need to handle translation logic manually, such as switching between languages, updating translations dynamically, and handling fallbacks for missing translations. This requires additional code compared to Angular i18n, where translation handling is handled by the framework.
Testing Considerations: When testing components that use the TranslateService, additional setup is required to provide mocks or stubs for the service. This can add complexity to unit tests and may require mocking HTTP requests or translation methods.
Bindings: Since ngx-translate uses bindings (either a pipe or directive), the translations are found at runtime, which results in a flassh of content effect (FOC) while the translations are loaded. There is a performance overhead as well.
Splitting translations: This is buggy and just straight up doesn't work right.
JSON Format: If you want to offload your translation work to a third party, you will run into a problem where third parties do not use the same format as ngx-translate. JSON is non-standard.
No text shows up: If it breaks, you get no text.
AOT: No ahead-of-time compilation optimizations are available.
Ok so now what?
Generally speaking, ngx-translate offers more flexibility and additional features compared to Angular i18n. However, it also introduces additional complexity in managing the translation service and handling translation logic in your application code. This is a trade-off you'll have to weigh for your project.
I don't recommend using Angular i18n in its current state. It is an immediate no-go if you're using a hosting service like AWS S3, Firebase on a free/spark plan, Vercel, GitHub Pages, or Netlify. The build system makes bespoke builds, per translation, that can make your deployment process much more complicated.
What's on the horizon?
Nothing really exciting.
Angular is continually evolving. In fact there have been some recent enhancements, providing much better support for runtime i18n. However, it is still undocumented (laugh out loud).
The Angular team has proven that i18n is clearly not a priority for the framework. The maintainer of ngx-translate has actually been working on Angular i18n, improving it and hoping folks will stop using ngx-translate. His alternative suggestion is to put ngx-translate behind a paywall. To be fair, if ngx-translate could be improved to solve the litany of problems it has, it woud be extremely valuable.
If you're interested in helping out ngx-translate
, they are open-source and they are in need qualified maintainers. The future of the project is unclear.
This part sucks to hear
If you're hosting your site statically, you're SOL, out of luck. ngx-translate
has questionable support, and the official angular i18n tools do not document any support. Your best bet is to try to explor a path toward @angular/ssr
or an nginx
or apache
web server solution.