Discussion: future of the library

Hello everyone, I'd like to discuss about the future of this library and get your opinion on my plans.
(Long) history
You can skip that part if you don't care about how this library came to life
When I started this library 3 years ago, I wanted to learn Angular and I thought that working on an open source project would be the best way to do that. It had worked for me on AngularJS with my library ocLazyLoad that was a huge success (2600 stars) and whose core principles were finally integrated into the framework in v1.6.7.
At the time I was looking for a way to translate my Angular apps and found out that there was nothing in Angular to do that (i18n wasn't even existing in the framework). I asked my good friend Pascal Precht if he was interested in porting angular-translate from AngularJS to Angular but he wasn't and told me that I should do it.
My library quickly became popular for various reasons (no real alternative, I had a good reputation from my work on ocLazyLoad, my appearances in Angular Air and my talks at conferences). And I guess that the code was good enough and easy to start with.
It was also a time where the framework was still in beta, and there were no real guidelines for publishing libraries for Angular, it was so hard to do it that not a lot of people were trying and I didn't have any real competition on i18n for a long time.
Some time later, the library ecosystem started to settle and Angular was stable, they decided to drop the name Angular 2/4/... in favor of just "Angular". I decided to rename this library ngx-translate and to use npm scopes in order to deliver a modular experience. I rewrote the whole library and made it possible to replace some parts (loader, parser, compiler, ...).
It was still a side project for me, but I was using it at work because we had finally started using Angular in production and needed to translate the app in multiple locales.
The official i18n implementation was super complicated (and still is), it didn't support json, code translation, changing the locale without reloading the app, and you needed multiple app bundles (one per locale). My library was so popular that I wanted to work on it full time because I could see that it was a necessity for the Angular community. It solved a lot of use cases, and was simple enough to be usable in a few minutes.
I decided to quit my job and see if I could make a living out my open source work. I knew that it was possible because ag-grid had done it and they were very successful. It was in December 2016, I had 2 months left at work before I was free, and I went to the conference NG-BE where Igor Minar from the core team was present. I wanted to ask him some advices on how to turn this into a profitable OSS project, but before I could tell him about my plans, he told me: "Ah Olivier, I wanted to talk to you, you've got to stop working on your library [ngx-translate], Companies come to us and want to do i18n, but they only talk about your library, we want them to use our solution [Angular i18n] because it's more efficient".
I was a bit speechless, I was there about to tell him that I had quit my job and wanted to work full time on my lib, and he was asking me to stop working on it. So I did what anyone with a bit of common sense would have done, I told him that Angular i18n sucked, that it failed to deliver the promise of easy-to-use-yet-powerful that they wanted Angular to be.
I probably didn't use those words, but he agreed with me that it still needed some work, but they didn't have enough resources to work on it (Victor Savkin and Jeff Cross had just left the team to create Nrwl).
I jumped on the occasion and told him that I would love to work with them to improve Angular i18n.
He told me that he would consider it, and we left it at that.
A few weeks later, and recontacted me, and told me that they were ok to hire me as a contractor to work on i18n. It was like Christmas for me (actually it was around Christmas, so that might explain it) because working for Google is a once in a lifetime opportunity and a dream job. But working on open source, from home, for Angular, it was even better and I didn't even thought that it was possible for me to do that.
I joined the team in February 2017 (almost a year ago), and started working on i18n. There was a lot of work to do, but I was confident that I could make a difference. It was clear to me at the time that it would take a few months to make i18n easier to use for everyone, with the features that people wanted, and that I could deprecate my library after that.
It turns out that working on a framework like Angular is super complicated. The codebase is huge, not highly documented, with a lot of different packages. The development process is complicated (it doesn't even work on Windows yet), and whenever you make a change you have to be extra careful not to break anyone. We even write tests, like a lot of tests! It was a big shift for me, because I had always worked on projects that needed to ship fast, and tests were clearly not the priority, you fixed bugs instead. But working on a library like Angular is totally different. Millions of people depend on your code, when you make a mistake you can break applications that loose thousands or hundred of thousands of dollars because of you. The responsibility is overwhelming and that's why it is much more complicated to release new features. I also wasn't the one deciding the priorities for the framework. Any change that you want to make has to work with Google applications, and it's not like you can duplicate functionalities to make it work for everyone (who said forms and http?).
Anyway it was complicated to change the way i18n worked in Angular. I learned a lot and I feel like we're going in the right direction now. I understand the choices that they made for Angular i18n, it's the most efficient and stable way to translate applications. It works very well for huge companies like Google, but it just isn't what most developers need/want.
During this year, I haven't really worked on ngx-translate. The issues are pilling up, I've only merged a few PRs and some of them have been waiting there for a long time without any activity because of me. There are some long term issues that I haven't taken the time to fix (code splitting / lazy loading, testing, ICU expressions, bugs with ionic...).
But before we get to that, let's quickly compare my library with the native implementation.
Angular
In Angular, you translate your templates using an extraction tool that generates xmb or xliff files, which are well defined formats that have been battle-tested. Those files are translated using professional tools, by real translators. At the end you merge the translations at build time and get a translated bundle.
Advantages:

The translation process is well defined, it is easy to detect missing translations and you can integrate that in your plans before deploying your app (extract, send to translators, merge)
It scales well, you never look directly at the files since you use a software for that, you can translate in x languages, you just need to extract once and create the translation files for each locale (which your professional tool should do for you)
it's super efficient because the app is pre-translated when it bootstraps, there's no extra work to apply your translations and it works well with pre-rendering because of that
since you merge the translations at build time, it means that it can support directives, components and other html elements, you can move them around in the different languages, or even remove them if needed
you don't need to worry about lazy loading, your bundles are translated at build time, and that includes your lazy loaded modules

Issues:

it takes a lot of work to setup, you need to extract, send to translators, and then you can merge
you create one app bundle / locale, which means that you cannot change the locale at runtime, you need to reload a different bundle for that. And to do that you need to handle server side routing to deliver the correct locale bundle. Google doesn't feel like it's an issue because you're not supposed to change your locale frequently. And in fact most of your users will change it maybe only once, or not at all. But it still complicates the workflow a lot.
no code translations, only template are translated since that's all you can do at build time for now
harder to use in development because you need to stop your dev server, extract translations, merge them. And the setup is different between JIT and AOT...
you cannot translate libraries, and that's a real problem for components libraries (like material, ng bootstrap, ...)

ngx-translate
With ngx-translate you load the module and configure it, you then load the json files containing your translations. You need to manually define keys for your translations and to write them in your json files that you will probably translate yourself, or transform into other formats that you'll send to your translators. But it's ok because json is easy to manipulate and generate.
Advantages:

you can choose how you want to handle your translations (bundled, http-loaded, pre-cached using service workers or localstorage, etc...)
you can change the locale at any time
it works in your templates AND in your code
json (that's all I need to say)
the community can work on plugins, custom loaders, tooling, etc... everything is hackable and you should be able to make it work the way you prefer

Issues:

it uses bindings (via a pipe or a directive) which means that it works at runtime and you can experience some kind of FOC effect (flash of content) when the translations are loaded and applied. Also it takes some memory and some processor time when change detection is triggered
if you want to split translations, it doesn't work well, the setup is complicated and there are bugs in the library
json is not an official translation format, and most professional translation tool don't handle that, but you can use different loaders to support other formats (like po) so that's not a super huge issue
it's hard to test
if it breaks, then your app will have no text!
it doesn't support angular elements (components, directives, pipes) because there's no "compile" at runtime for AOT applications

Changes in Angular
Like I said, I've been working on Angular i18n for almost a year now. I've actually worked on a lot of other things as well, and the changes in i18n were clearly not the priority for the framework. A lot of internal changes were also necessary before we could do the changes that we wanted.
I've greatly improved the documentation (i18n guide), I've created demo projects with and without the cli to help people get started. I've worked on bugs, and made a few changes, but we've not released anything major for translations.
Finally for v6 the big changes are coming, translating will be done at runtime. Having access to the internals of the framework means that it will be way more efficient than what ngx-translate does. You shouldn't experience the FOC effect, and it won't take any resource during change detection. You'll be able to do code translations, at last! There will only be one bundle per application for all of the locales (or multiple, if you prefer). And libraries should be translatable.
What will not change:

you'll still have to extract translations using the extraction tool and merge them at build time, which means that's it's not very easy to use in development
there's no json format yet (we've been discussing internally about opening the API so that developers can write their own serializers if they want)
it'll still be more complicated to setup and to use than ngx-translate
you can translate at runtime in your code, but the templates will be translated at bootstrap, which means that you cannot change the locale without reloading the app
new features will still take a long time to be implemented, because we don't have the freedom that a library like ngx-translate has

So what about ngx-translate future?
This has been a long post, and we're finally getting to the part where we talk about the future of ngx-translate. The way I see it there are 2 solutions:
1/ we continue like it has been for the past year, only merging a few PRs, not working on new features and not improving the workflow. I keep working on making Angular i18n better and hopefully people will stop using this library because the native solution will be better. Or maybe a real alternative will emerge (like https://github.com/robisim74/angular-l10n).
2/ I change the way I work and decide to spend more time on the library (at least 1 day/week) to improve it: fixing lazy loading, code splitting, adding functions to help with testing, support ICU expressions, create well documented and maintained examples, finally tackle ionic and other mobile issues, ...
I focus on making sure that the library stays a viable alternative to Angular i18n by providing solutions to the "problems" that Angular i18n will not fix. I write better tooling, maybe even an editor for the translations. I rewrite the documentation, on a real website with shiny examples.
To do all of that, I would need to make this library profitable somehow. I was thinking about changing the license to require companies to pay for the library (while keeping it free for open source and personal projects) in exchange for priority support (for bugs fixing, and for working on the features that they want the most).
Obviously the current version would remain free and MIT-licensed, since there's no legal way to retroactively change a license, and it would be stupid to do that anyway. But new versions would be using this new license.
This library is downloaded ~350 000 times / month on npm now, if you compare that to the ~2 400 000 downloads of @angular/core, it means that my library is used in 1 out of 7 Angular projects! That's crazy, and it gives me confidence that this is viable.
What do you guys think? Would your companies be willing to pay for a better ngx-translate? Do you see any other alternative?

attract more contributors and leveraging the community would be a good idea for making this lib live longer and keep it maintained,  encouraging others to share ownership of the project can greatly reduce your own workload since you don't have enough time to review all PRs and issues. Maybe it'll take some times to do so but here's my suggestions:

It's difficult for someone unfamiliar with the codebase of the lib to gauge the difficulty of an issue (Only ~10% of the current 207 open issues are labeled).
Creating templates for PRs and issues, establish proper contributing guidelines with a clear Code of Conduct.

About:

I would need to make this library profitable somehow

I read an interesting article a few weeks ago about Why Funding Open Source is Hard,
so if you want to make this lib a business, changing the license is often the most suitable approach. Companies that rely only on open source projects and libraries are not willing to pay for a license, they'll seek for alternatives.

In my opinion, what the project really needs at this is an active maintainer and a lot of quality. As I've been mentioning earlier in the thread, this can be solved by putting the label "Looking for maintainer", and people will understand.
We have been using this library for more than a year, and besides it is really great and easy to use, it has been also a constant source of our problems due to bugs and constant rewrites. We use custom loaders to enable main application load translations from multiple sources at runtime. And to our greatest regret, the ngx-translate became our common denominator for rxjs and Angular versions. The last major issue for us was Lazy Loading problem with the code that has never been even executed (not alone unit tested) to see it is not working.
So we are probably going to just reimplement the service ourselves, given the main ngx-translate maintainer does not have time/energy/passion/money to improve the library. Essentially, the project consists of three blocks - a loader, a Pipe and a Service, not much to have 207 open issues and 400+ closed one, in my opinion. If someone really wants to build their own - you can grab a free (or paid) copy of my book "Developing with Angular" and check the "Internationalisation (i18n)" and get your own basic translation up and running in 5-15 minutes.
So, for
1): sorry to say that, but I pesonally would suggest people just forking and tuning to fit the project needs, given the past speed of maintenance, OR building own i18n service from scratch, that's not so difficult as it sounds, and definitely not a year of work.
2): licensing a Pipe and a Service is a bit too much

licensing a Pipe and a Service is a bit too much

If you think that it's the only thing that this library offers, sure. Not counting the time it takes to work on issues, edge cases and such. The time it took to research stuff, to create the library, bundle it, distribute it. The time it takes to write the tests, the plugins, to maintain the website, to write the documentation, the examples and to reply to people asking for help.
And my offering was more than just what exists right now, it was helpers for tests, better docs, better examples, taking care of the existing bugs, probably creating a forum for support (because github issues is not ideal for that), adding new functionalities, new tooling, and premium support.
If the license was for example 500$, how much time do you think that writing that library + its ecosystem of plugins would take you? Only a day? Maybe a week? How much are you paid for your job? If you work in the US, probably at least 500$/day.
For me that's a cheap bargain, you're getting the work done, and support if needed, and in exchange of a small fee you get to focus on the real value of your business instead of spending time reinventing the wheel.

Love this project, @ocombe keep on maintaining. plz.
I'm fine with both options,
but option 1 would be more community like.
anyway, great important valuable job

If you think that it's the only thing that this library offers, sure.

I don't think he actually sees it that way, but I can see his point of view. Think of this way, consumers of this library are your customers, you are doing a great job and tremendous amount of work in order to deliver it but all they see is a service and a pipe. They don't really see what's going on under the hood. They never see the part of maintaining a library and keeping it stable. That's why people would think this way, and if you start charging for it, they'll just fork the library and make it a part of their project. Since, current version works for almost every app as is, they won't need to add new feature or fix some bugs. I think finding some collaborators and going with slow pace is the best option here.

I can see lot of negativity and little respect for the work of @ocombe in this discussion. I really would like to see people saying today "I'm not gonna pay, I'll fork it", forking and maintaining their own version of the library, it's just a simple Pipe+Service, right? Please, do it, meanwhile I'm going to buy some popcorn to watch the show. 🍿 Probably the only thing people can do is just clicking on "Fork" button and stop.
If we are not able or comfortable to pay to use his library (as it seems), just suggest to adopt option 1: whenever he will have time to merge PRs he will do and many many thanks for his hard work in advance. Meanwhile he can concentrate on i18n for Angular core and get paid for it!

Thanks. I'm not against taking some other maintainers, but from experience people start "playing" maintainer but give up really fast when they see the amount of work for no reward.
If anyone is interested, let me know and I'll add you to the project.

I'd prefer it if Angular i18n would work better. I've been using both ngx-translate and official Angular i18n in two different large-scale projects, and in my experience it's actually been somewhat easier to get started with the official plugin. The main drawback has been no code translations, but it's coming soon! :heart:
If you feel like you would get more out of working on this project and related offerings I might pay for a license, but it really depends on the cost. If I can spend a couple of hours to convert a project to use Angular i18n instead I might do that instead of paying some monthly license cost. It's difficult to compete with "free", sadly.
It feels to me like Angular i18n is more geared towards larger more "enterprisey" businesses, while ngx-translate is geared more towards smaller projects. And, unfortunately for you, I also think that the larger businesses are more likely to pay for licenses than the smaller ones.
It really depends on your extra tooling and such in that case.
I'd definitely pay for a good tool that integrates really well with our git-based workflow and makes it easier to send off our JSON (or whatever format) translation files to translators.
Lastly, great job on both ngx-translate and Angular i18n. I hope that you'll be happy whichever way you choose.

@Maistho this might be an interesting tool for your translators: https://www.codeandweb.com/babeledit

@ocombe I love what you're doing with this project.
A big plus is the run-time change of language.
I use it in NativeScript projects so my users can switch the language easily.
With multiple bundles (Angular i18n) I would have to distribute multiple apps to the stores, "just" because the language is different.

@ocombe ngx-translate is cool and efficient, it's pragmatic and I really like it.
IMO companies can pay for the service if they have a guarantee that the library will always be maintained. If you have several applications in production which use a library you don't want to be forced to change a library... unless you facilitate migration from ngx-translate to angular's implementation maybe ? if I know I can easily migrate from ngx-translate to Angular's solution I think I'll keep ngx-translate for some time, because it's perfect for what I'm doing and I know I can switch easily in case the lib disappears.
In case of doubt I guess a big company will probably choose "security" of a standard, which would in this case be @angular's implementation. As you are working for google it also seems to me that some kind of conflict may help you choose not to maintain the library eternally...
Personally after what you wrote above I must admit that Angular team seems to be taking seriously i18n topic for big companies (delegating translations to professional translator is a real concern) though I'm a bit disappointed that switching locale implies reloading the app. OK I do not expect a lot of our users to switch locale several times a day (a user in front office, discussing with end clients, might need this however).
As a developer I think I'll use ngx-translate for my personal projects as long as it's maintained. Regarding professional projects I think that, the day Angular's solution with i18n is OK for my needs I'll switch.
Hope this helps. Good luck and thanks for your great work !

Maybe you could start an OpenCollective or some way for people to donate individually to the project. Maybe something like a Kickstarter where each threshold unlocks a new feature to be implemented or issue to be resolved. I feel like ngx-translate is already 90% done, it just needs a few final touches.
I'd like to use the official i18n solution, but it simply isn't flexible enough for me yet, and I'll keep using ngx-translate until it is. I don't see that being anytime soon, to be honest.
I would donate personally. Having to go through a corporate process of purchasing and dealing with licensing though (dealing with procurement teams, legal teams, etc) - I would probably just stay on the current free version rather than deal with that to be honest.

Bit late, but here's my feedback: We have a fairly large app at work which was written in AngularJS. When we started the migration to Angular 2, internationalization turned out to be a big challenge. We were using angular-translate with JSON files, runtime language switching, in-code translations, and ICU syntax. To make the long (and ongoing) migration to Angular feasible, we need all of this to work seamlessly across our hybrid app, so Angular's official solution was a long way off the mark. The only thing missing from ngx-translate, on the other hand, was the ICU syntax. Talking to Pascal Precht at a conference last year, he encouraged me to contribute to this library to add that feature, which I have done. ngx-translate was and continues to be crucial for the development of our app. Thanks again, @ocombe.
About the future:

I'd prefer to be on the official track, but the upcoming changes will still not make that realistic.
It looks to me like the long-term goal should be to make the official solution suit more scenarios, but ngx-translate will remain relevant for some time yet.
I can't say that paying for a licence would come easy, but it's not out of the question. My feeling is that donations could work out better, but I'm not speaking from experience.
As the maintainer of ngx-translate-messageformat-compiler, my biggest pain point would be the complicated handling of async translation loading. I love rxjs, but I have a hard time understanding the control flow for all of the edge cases (not that I've invested a ton of time, mind you). Users keep running into timing-related problems, in any case (https://github.com/lephyrus/ngx-translate-messageformat-compiler/issues/21, https://github.com/lephyrus/ngx-translate-messageformat-compiler/issues/20).
It's not like you owe anyone anything regarding this library - I'd say concentrate on what's interesting to you.

Well I have one question, is there a way on Anguari18n for angular 5 to load .json source files ?
In my case we don't need to generate neither to extract as all the translations are pre-configured in a json file.
Thanks in advance

If anyone interested, I've started working on an alternative solution: https://www.npmjs.com/package/@ngstack/translate.
Not trying to make a framework out of a library, and keeping things very simple and small. Should cover most of the real-life scenarios as well as addressing the most common issues my team has been struggling with when using ngx-translate/core during the last year.

Hi @ocombe . First of all, congratulations for you success story and the awesome work you've done till now. I think ngx-translate it's a great library and I'd like if you didn't stop to mantain it. My company is thinking to move on and migrate to i18n but we didn't take a decision yet both for the migration effort that will take and for the missing features on i18n like code translation. I would like to ask you if it's worth to change for a big, and already started project to change. If so, is there a guide to facilitate the process? Have you already decided a future for your library, will it be deprecated if i18n will fill the gap with the missing features?

Hi @ocombe,
what is the final result of this discussion?
what's gonna happening with ngx-translate, once ivy is released and the official i18n is updated with features like translation in code?

I'll keep it alive (updating for new versions of Angular) since it'll still be the only way to change the language without reloading the app, and also because a lot of people who are using it probably don't want to refactor their code to replace that lib as long as it works for them.

@ocombe not all heroes wear capes, merci ❤

Merci beaucoup @ocombe ! ❤👍🍾

Seems like I'm late to the discussion, yet I would like to add that in my case, i18n doesn't cover my company needs, we handle versions of every language by client processes, so they dictate what texts they get to see, we're currently working with angular-translate done we're on angularjs still, but migrating to angular is on our roadmap, and this library would make the migration smoother, yet, I don't see my company paying for a license since we're still a small business.. That's IMO, I would be contributing either with donations or helping maintaining the library (as much as I could, I could be considered a Jr but with a will to help)

I'm having the same issue with @vivainio, I'm seeing references here and there to translation in the typescript, but can't see any documentation for it at all. The Angular 6 docs documentation doesn't have anything, and the changelog doesn't seem to mention it for 6.x?

it's not in 6.x, it'll be with ivy (v7)

Hi! Will there be support for the translation of libraries in the Angular i18n? Or until it is implemented? And thank you for your work!

it's on the roadmap yes

@ocombe I think both options are valid and I think there would be enough people to buy the license. For this to happen I think you need to clarify the advantages of ngx-translate over angulars solution.
To this day there are still a couple of pretty important things missing in angulars i18n

still no support for other formats like PO(!) or JSON.
The xlf or xmb format is pretty weird to use and looks just like a giant mess

Haven't found a single translator familiar with any of those formats and so far haven't found a proper editor to use to edit translations by myself (for example didn't found an editor that supports ICU expressions)
It is pretty prone to merge conflict errors that result in removing previous translations
Extracted translations are not sorted alphabetically but rather by time they were added to the code
New lines and following spaces are parsed as well in the key, so changing the indentation of your code will actually remove translations (because for angular the key has changed)
Unused translations are immediately removed instead of commented out or flagged as unused

Overall pretty complex to get it running
Translation files can't be loaded over http

The list probably goes on. I know couple of things probably are personal preference (or regional differences), but the big dealbreaker for me is the file formats. When I evaluated  i18n possibilities for a big project I'm working on (I used ngx-translate in a couple of private projects before), I decided against ngx-translate and for Angulars i18n because it was not clear if this project will be forever maintained and Angular claimed to add the missing functionality. I didn't want to refactor everything later so I started to use Angulars i18n (also I think if there is a proper native solution it makes sense to use it). Now half a year later, I'm actually considering switching to ngx-translate and refactor everything, because I'm completely unsatisfied with Angulars i18n. So many troubles, problems and issues. And for most of them it is still not in sight that they might get tackled in the future.
I know that you work on the Angular i18n implementation, maybe you can shed some light on a couple of issues. Is it planned to support different file types or is it still "up for internal discussion" like mentioned on of their github issues? Is it planned to support loading translation files async over http? (Or maybe this is already possible and I just didn't found the proper solution)
This should be by no mean a rant or critic towards you or your work here or at Angular. I know you are doing a great job over there and i18n has gotten a lot better, it is just nowhere near the state I expect it to be from Angular. And I just have the feeling it does not have a high priority on their roadmap - and that probably is what boggles me the most. To me this is just such a core and important functionality.
Thanks for your great work at this library, and I hope it will continue to being maintained :)

Is it planned to support different file types or is it still "up for internal discussion" like mentioned on of their github issues
We won't be adding new file types, but the API will probably be open with the big refactor for ivy, meaning that anyone can write a new parser and use it with Angular i18n (I say probably because we aren't at that part in the refactor yet, and I don't have the final vote on the question). The extraction won't be supported for new formats, but that's also something that can be written externally. I'll try to push for an open API there also because honestly I think that people prefer to be able to do things, even if we do breaking changes from time to time instead of locking everything up.

Is it planned to support loading translation files async over http
yes, the loading part should be let to the user's appreciation (bundle, http, ...), the important thing is that you will need tp have the translations loaded when the app bootstraps

thanks for your reply.

We won't be adding new file types, but the API will probably be open with the big refactor for ivy, meaning that anyone can write a new parser and use it with Angular i18n (I say probably because we aren't at that part in the refactor yet, and I don't have the final vote on the question)

Well but then there is the question what is the advantage of using the Angulars i18n in the first place if you need a separate parser, separate extractor and maybe even a separate loader depending on the prefered behavior. To me it sounds easier to just use one external lib (e.g. ngx-translate) that handles everything instead of plugging couple of external libs into the native behavior.

For one main reason: it's integrated into the framework and it's a lot more efficient (I know the codebase of both, and there's no comparison).
But if ngx translate works for you, then it's perfect, don't change something that works. But there are limitations (like lazy loading per module) that will most likely not be fixed.

I'm a ngx-translate user. For me the things missing for i18n are the flexibility of being able to dynamically switch languages without a full page refresh, and the JSON format. If those things were available I'd switch.
The only thing I really miss from ngx-translate is an easy way to avoid the Flash-Of-Content problem on initial load (this is using dynamically-loaded translations). IMHO it makes the initial load seem less professional - but I haven't figured out a good solution. Not sure if ngx-translate itself can help there.

@mischkl maybe you will find some inspirations in the following topic for your glitch -> https://github.com/ngx-translate/core/issues/754

@peterpeterparker unfortunately I'm not using Angular Universal, so it's not that helpful in my case

@mischkl even my very last post in the topic where json are imported without http loader?

@peterpeterparker there are a couple of issues with that approach. First, all of the languages must be bundled, which creates a lot of bloat beyond a couple of languages. Second, some (approx half) of our translations are purposefully fetched from the server at runtime rather than being part of the Frontend, since we want to be able to update them in the backend without changing the Frontend. For these reasons simply importing the JSONs is not an option.

@mischkl makes sense, good luck

I'm personally waiting for a proper solution from Angular since v4 (it was promised in v5 back days). If promises will fail again in v7, I think I'll never trust Angular team in this question. And the current situation tears me apart. I really like the extraction part of the official implementation, it's the way how it should be. But the unfished state of code translations makes me feel pain.
I see a lot of complaints about missed JSON format, but XLIFF is an open XML format. Write a converter is probably a 1-2 days task. Probably, your translation tool already does it out of the box.
Regarding the initial question, I think @ocombe is better to focus on the official solution with some mitigation of current pain like it was done with ngx-translate/i18n-polyfill

@fetis my hope is that we'll be able to use any format with angular runtime i18n (with ivy) by using a custom formatter lib. If I can make it happen the way I want, then I'll write a JSON formatter lib.

@ocombe to make it clear, this will happen only after new i18n runtime, which happens only after Ivy official release (after v7 according to this https://github.com/angular/angular/issues/21706#issuecomment-425183461). Correct?

Yes to both.
The team leads had a meeting yesterday to try to accelerate things up by pulling all our resources (including the cli and material teams) onto ivy until it gets released because we've deviated a lot from our initial estimate (which was to have a beta last summer, during the v7 beta) and it's the thing that everyone is waiting for right now (inside and outside google).

I want to know if I18N still does not support translation of component library.

@ngehlert I know :( ... I'm just trying to get some multiple-choice/dynamic translations in. I also noticed I can't get certain places translated in this library (such as input placeholders).
not that the angular method doesn't have it's fair share of problems and their idea that having to start from 0 on your webapp when changing language is acceptable in 2018-19 is ludicrous.
so far I'm a bit frustrated by how little automation there is as compared to the angular way but am pleased with the use of JSON, which you can organize really really precisely (by page + by view + by component) also I was up and running really REALLY fast. but yeah I'm still only 5% of the way on all my translatable fields after a day it feels sooooooo slow to go get them one by one.
luckyly I only have to search my project by the i18n tag so that save alot of time.

@tatsujb well multiple-choice/dynamic translations is not a problem in ngx-translate. afaik there are even plugins e.g. for the angular router so you can swap language based on the url. And i know for sure you can translate input placeholders :)
eh and you don't have to extract them by hand. there is automation for it. have a look here: https://github.com/biesbjerg/ngx-translate-extract
just have another look. pretty sure ngx-translate will feature all your needs... I'm just still struggling because it is not sure whether this lib is being supported in the future and I highly prefer native ways - but in this case the native way is just not good enough

@ngehlert what I tried was :
<mat-form-field class="my-date-input">
              <input
                [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [matDatepicker]="picker"
                formControlName="dateFC"
                i18n="confirmedDate"
                >
              <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
              <mat-datepicker #picker></mat-datepicker>
            </mat-form-field>

and this resulted in :
Uncaught Error: Template parse errors:
Parser Error: Got interpolation ({{}}) where expression was expected at column 0 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("
            <mat-form-field class="my-date-input">
              <input
                [ERROR ->][placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [matDatepi"): ng:///AppModule/ForecastFormComponent.html@18:16
Parser Error: Unexpected token {, expected identifier, keyword, or string at column 2 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("
            <mat-form-field class="my-date-input">
              <input
                [ERROR ->][placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [matDatepi"): ng:///AppModule/ForecastFormComponent.html@18:16
Parser Error: Missing expected : at column 32 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("
            <mat-form-field class="my-date-input">
              <input
                [ERROR ->][placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [matDatepi"): ng:///AppModule/ForecastFormComponent.html@18:16
Parser Error: Unexpected token } at column 32 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("
            <mat-form-field class="my-date-input">
              <input
                [ERROR ->][placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [matDatepi"): ng:///AppModule/ForecastFormComponent.html@18:16
Parser Error: Unexpected token '}' at column 33 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("
            <mat-form-field class="my-date-input">
              <input
                [ERROR ->][placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [matDatepi"): ng:///AppModule/ForecastFormComponent.html@18:16
Parser Error: Got interpolation ({{}}) where expression was expected at column 0 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("         [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [ERROR ->][matDatepicker]="picker"
                formControlName="dateFC"
                i18n="confirmedDate"): ng:///AppModule/ForecastFormComponent.html@20:16
Parser Error: Unexpected token {, expected identifier, keyword, or string at column 2 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("         [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [ERROR ->][matDatepicker]="picker"
                formControlName="dateFC"
                i18n="confirmedDate"): ng:///AppModule/ForecastFormComponent.html@20:16
Parser Error: Missing expected : at column 32 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("         [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [ERROR ->][matDatepicker]="picker"
                formControlName="dateFC"
                i18n="confirmedDate"): ng:///AppModule/ForecastFormComponent.html@20:16
Parser Error: Unexpected token } at column 32 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("         [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [ERROR ->][matDatepicker]="picker"
                formControlName="dateFC"
                i18n="confirmedDate"): ng:///AppModule/ForecastFormComponent.html@20:16
Parser Error: Unexpected token '}' at column 33 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("         [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
                [ERROR ->][matDatepicker]="picker"
                formControlName="dateFC"
                i18n="confirmedDate"): ng:///AppModule/ForecastFormComponent.html@20:16
Parser Error: Got interpolation ({{}}) where expression was expected at column 0 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("<div class=".col-lg-8	.col-xl-12">
            <mat-form-field class="my-date-input">
              [ERROR ->]<input
                [placeholder]="{{ 'confirmedDate' | translate }}"
                matInput
"): ng:///AppModule/ForecastFormComponent.html@17:14, Directive DefaultValueAccessor
Parser Error: Unexpected token {, expected identifier, keyword, or string at column 2 in [{{ 'confirmedDate' | translate }}] in ng:///AppModule/ForecastFormComponent.html@18:16 ("<div class=".col-lg-8	.col-xl-12">
            <mat-form-field class="my-date-input">
              [ERROR ->]<input
                [placeholder]="{{ 'confirmedDate' | translate }}"
            vendor.js:33106)
    at<EMAIL_ADDRESS>(vendor.js:46936)
    at<EMAIL_ADDRESS>(vendor.js:56793)
    at<EMAIL_ADDRESS>(vendor.js:56780)
    at vendor.js:56723
    at Set.forEach (<anonymous>)
    at<EMAIL_ADDRESS>(vendor.js:56723)
    at vendor.js:56633
    at Object.then (vendor.js:33097)
    at<EMAIL_ADDRESS>(vendor.js:56632)

if I remove the placeholder tag it works but this input is not translated.

I don't have a project to test it on right now, but I'm pretty sure you have an error in your syntax. try use the placeholder without the brackets [ and ].
so instead of [placeholder]="{{ 'confirmedDate' | translate }}"
do placeholder="{{ 'confirmedDate' | translate }}"
or even this one should be possible [placeholder]="'confirmedDate' | translate"
you just mixed up different versions of the syntax together.

Can anyone tell how did you translate using native way?, you need angular CLI for that right?.
Ionic 3 project is not even angular project.

@anilgr you find everything here https://angular.io/guide/i18n
no you don't need angular cli for that
ionic 3 is an angular project as it uses angular :) it may not use the angular cli but it is still an angular project. i'm using the native translation in ionic 3 by myself

@ocombe Does Angular i18n and/or ngx-translate support AngularJS (version 1.x)? Can these services be downgraded in used in AngualrJS?

For me one of the great things about ngx-translate is the ability to load multiple translations with fallbacks, on the fly.
I use this approach:

global translations (these are always loaded first, mainly used for the list of languages.)
language translations (e.g. English)
country translations (e.g. override pants with trousers and color with colour in UK)

ngx-translate is better than what comes with angular. We can't switch at this point. It's waaaay too late. otherwise we have zero issues with your library. it is great.

@ocombe Now that angular v8 with Ivy opt-in is out is there a new estimate on translation plans?

Once ivy is the default in google apps we will start working on the translation service for external users. So anywhere between soon and v9 :)

@ocombe, what is your plan about upgrading ngx-translate to support Angular 8.x?

it's supposed to work with v8 already

Hello @ocombe,
I'm curious about the current state of things. What would you recommend for a brand new project? ngx-translate or angular i18n?
I find it hard to clearly see where I should be going..

For people waiting for runtime i18n with ivy: bad news, I had to leave the Angular team (budget cuts) and this means that i18n will get less attention.
Pete B. Darwin will work on it part time, but he also has a lot of other priority things on his list (like ngcc).
The current plan is to have translations working with ivy for v9 but only as a build step (like it is right now). This means that it's still going to be 1 build / locale for now, and there won't be code translations (only template translations).
Looks like ngx-translate still is the best choice for now 😕 I'll see what I can do on my free time to improve the lib. I might rewrite it from scratch for ivy because there's a lot of flaws in the current design that would require a complete rewrite to fix, and I think that we can use runtime translations from ivy to do a good part of the work (meaning better perf). We would loose the ability to change the language without reloading the app (or at least the templates), which I don't think it's too big of a deal (and for those who absolutely need this, then the current ngx-translate would still work).

WTF, Google have no money?!!

They are recruiting internally for the team, it's just the budget for external contractors like me that was over budget

@ocombe last time I tried the current ngx-translate does not work with the Ivy preview and AOT. And Ivy will become the default in the future, so that's going to be a problem.
I can help with development. However, we need the ability to switch the language, and doing so without reloading the whole app and without complicating the build is a big pro (though not absolutely necessary). I guess my ideal would be to have two strategies, the fast one requiring a reload, and the slower but more flexible one doing everything at runtime with no reloads.

If it doesn't work with ivy&aot then it's a bug that I should fix. I don't really see why that would be the case since ivy is supposed to be 99% compatible with view engine. @alessiostalla could you open an issue with a repro project that I could use to see what's the issue? Thanks!

@ocombe that are some really sad news :( code translations not even in V9?... that was supposed to be in couple of major versions ago - and somehow always postponed.
I know it's not your fault^^ still just sad to hear after all, that (at least in my eyes) such an important feature seems to be completely ignored by the angular team.
Maybe it's time to go back to ngx-translate 👍

Since this thread is what is being used for "general discussion", I made a blog post on a possible alternative approach: https://dev.to/vivainio/trivial-typesafe-translations-in-angular-3aod

@ngehlert I'm going to work on some new tools / services for ivy, hopefully for v9.
Hold on for a few weeks while I figure things out, but I shall bring some good news to the community soon :)

Great library! Have used it successfully for years. #gratitude. Fix the small issues and feature enhancements, bump the major version and charge $9.99 for it. Assume worst case scenario 10% of your 350K downloads upgrade (which they will), you just netted $350K.  Charge for major versions going forward with a cheaper upgrade path for existing customers.
Thank you @ocombe

Indeed.  I can no longer wait for google to come up with a runtime i18n solution.  I would pay more than $10, especially if there was an automated migration path.

Option 1. There are people that use your library in free open source projects.
@ocombe why don't you use opencollective to collect donations?

@ocombe I couldn't reproduce it. Maybe it depended on some Angular.next version that has been superseded.

So now that I left Google, I have some time to work on all the things that I wanted to do for so long. I'll be working part time on https://www.locl.app/. It will be the next gen library for i18n with a bunch of tools to go with that.
Since that represents a lot of work, some parts will be free (the lib most likely) and some will be a subscription or something like that. In any case it'll be free for open source projects.
I will also see if I have the time to work on ngx-translate to fix all the current issues and add some new features, and offer paid support (which could be part of the subscription to locl)

Also check out what Netanel is doing with Transloco: https://github.com/ngneat/transloco / https://netbasal.com/introducing-transloco-angular-internationalization-done-right-54710337630c

@ocombe thanks for your work!
@bjornharvold we migrate to Transloco. It's really awesome library.

@ocombe thanks for your work!
@bjornharvold we migrate to Transloco. It's really awesome library.

I migrated to transloco, too. It's very good and easy to migrate. Works with my translation files and the migration process took me only 15 minutes 😄 👍

I've got together a blog post about translations and i18n in Angular, it touches the topic from the perspective of the architecture. You could say that it is translations as a code, the best thing is that they are fully typed and lazy-loaded.
Feel free to have a look, migration from ngx-translate is pretty easy.
https://medium.com/angular-in-depth/angular-typed-translations-29353f0a60bc

hi, I saw release v12 has a few new features. Does it mean that the 2nd solution was chosen @ocombe ?

Not really, I've just taken the time to merge all of the existing PRs :)
But I'm focusing my efforts on my new project Locl that will be free for open source and paid for commercial projects

@ocombe Do you still maintain this library for angular 9? I mean to fix some of the existing issues and release a new version for Angular 9 and after.

Yes, I haven't had time to look into it, if you could make a PR that would be awesome!

Well, I am very disheartened by progress with localization support in Angular.  First of all I'd like to say huge thank you to @ocombe for the work you've been doing and for being passionate about this topic and all the effort you've put it into making it happen.  I've been following your progress and Angular team progress on localization and ngx-translate was my choice (pre Angular 9 release). Fortunately or unfortunately, we could hold off on the decision for while however, now I need to make a decision for our localization strategy.   I was really hoping, that with you on Angular team, the built-in solution would do all the things we need. Sadly its not so.  I no longer have trust that Angular 10 will be any better.

Yeah, I just hired someone to help me on the project, hopefully you should see some progress on that part soon!

@ocombe any news Locl and ngx-translate future?

Well, I am very disheartened by progress with localization support in Angular. First of all I'd like to say huge thank you to @ocombe for the work you've been doing and for being passionate about this topic and all the effort you've put it into making it happen. I've been following your progress and Angular team progress on localization and ngx-translate was my choice (pre Angular 9 release). Fortunately or unfortunately, we could hold off on the decision for while however, now I need to make a decision for our localization strategy. I was really hoping, that with you on Angular team, the built-in solution would do all the things we need. Sadly its not so. I no longer have trust that Angular 10 will be any better.
Given that your effort is now focused on locl I don't think ngx-translate is a viable choice for us. As it stands, I would have to choose between transloco and locl. I'd love to support your work but, there is no clarity to pricing model and I am not sure when that will become available. I really hope you can publish those details soon otherwise I'd only have 1 choice.

@SimonNodel-AI what feature is missing for you in Angular 9? With the new $localize service I managed to get translations completely running (also in TypeScript) in Angular 9, without any external library.

Hey, @ocombe .  if you have a few minutes, could we talk about your project?  Our company is weighing in the support for ngx-translate, but my boss needs a bit more information.  My email address is in my profile...
Thank you!

Hi @ocombe, First of all, I would like to thank you for your efforts on the @ngx-translate/core package.
I have created an extensible library @rxweb/ngx-translate-extension of @ngx-translate/core. This provides more than 50+ spectacular features.
The objective of creating this library for helping the existing users who using @ngx-translate/core package but not getting a quick solution if they stuck somewhere or the limitations of the features which they are expecting as an intuitive solution in the base library.  As you are the expert so I would request you please review the features provided by @rxweb/ngx-translate-extension as well as the sample application and share your precious inputs which make this library even better for ngx-translate community users.
As I said this is an extensible library of ngx-translate not a migration from ngx-translate to ngx-translate-extension. The base remains the same. Please refer extensible guide for taking a glimpse of the extension. In simple words, we can say ngx-translate is active by using 'ngx-translate-extension' package for new features and bug fixes.
High-level Features

Component/ HTML section-wise resolve the translation content.
One Configuration through the application. Not required to use 'forChild'.
Resolve translation content through @translate decorator.[NEW]
The more intuitive way to bind the FormControl error messages.
Pure pipe for translation.
Many More...

Here is the snap of extending the features.

I will wait for your exemplary response.

@ajayojha does your library support zoneless operation?

Please just go on with this one. After a looong time i tried to use the official i18n again.  Yeah the builds are faster now and i can use it in typescript. But it is still way to painful to use.

@mbeckenbach out of curiosity what is missing for you from the official i18n package?

@ngehlert Besides the possibility to switch language at runtime, tooling is simply bad.
There is nothing like xliffmerge built in. Because never people need to sync such files…
Then when you bring it together with xliffmerge and universal you maintain the list of languages in how many places? Many

@ngehlert  Another think missing in official one is a possibility to have strongly typed keys. @@foo.bar is a magic string. With NGX translate and some effort i can have it strongly typed and refactoring safe.

Hi @ocombe , is there any idea to provide a migration guide from your solution to angular i18n? As you have been working for both sides I'm sure you can recommend us how to proceed. Is there any thread talking about this process?
I want to appreciate the effort you have done for still keep this library updated but I understand that at some point you will stop doing the support if this library is not profitable at all.
Thanks a lot!

Hello there is an rumor that ngx translate is not maintened and need to migrate to transloco ?

I published a new release a month ago, so this it just a rumor.
I don't add new features, that's true, so if you want new stuff then use transloco, but I make sure that the lib still works with new versions of Angular

Hi @ocombe!
"but I make sure that the lib still works with new versions of Angular" -> Do you have plan, which will be the latest version?
Thank you!

@n84ck , as the maintainer stated on Dec 8, a new version is published that is compatible with ng 13. (latest version of the Library).
Is that what you are asking?

I also thank @ocombe for his work on ngx-translate. We used it since 2017, but never actually went to production with translations. We are now looking at converting to the standard XLF format using in-built Angular 13 support. I hope Angular will continue to work on this core feature.

@dobrinsky can your app.module.ts in a gist (or here)?   Maybe try getting it to work in a StackBlitz and see if you can trace the problem.

@TaylorAckley, thank you very much for your reply. The first application's app.module.ts is:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,

    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
      isolate: true
    }),

    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },

      {
        path: 'constants/wasteManagementOperation',
        loadChildren: () => import('./modules/Constants/WasteManagementOperations/wasteManagementOperation.module').then(m => m.WasteManagementOperationModule)
      },

      {
        path: 'constants/wasteCode',
        loadChildren: () => import('./modules/Constants/WasteCodes/wasteCode.module').then(m => m.WasteCodeModule)
      },

      {
        path: 'constants/wasteCode/WorkPointWasteCodes',
        loadChildren: () => import('./modules/Constants/WasteCodes/WorkPointWasteCodes/workPointWasteCode.module').then(m => m.WorkPointWasteCodeModule)
      },

      {
        path: 'constants/environmentalAgency',
        loadChildren: () => import('./modules/Constants/EnvironmentalAgencies/environmentalAgency.module').then(m => m.EnvironmentalAgencyModule)
      },

      {
        path: 'wasteManagement/generatedWaste',
        loadChildren: () => import('./modules/GeneratedWastes/generatedWaste.module').then(m => m.GeneratedWasteModule)
      },

      {
        path: 'wasteManagement/downloadFiles',
        loadChildren: () => import('./modules/DownloadFilesWasteManagement/downloadFilesWasteManagement.module').then(m => m.DownloadFilesWasteModule)
      },

      {
        path: 'wasteManagement/takenWaste',
        loadChildren: () => import('./modules/TakenWastes/takenWaste.module').then(m => m.TakenWasteModule)
      },

      {
        path: 'wasteManagement/managedWaste',
        loadChildren: () => import('./modules/ManagedWastes/managedWaste.module').then(m => m.ManagedWasteModule)
      },

      {
        path: 'wasteManagement/sortedWaste',
        loadChildren: () => import('./modules/SortedWastes/sortedWaste.module').then(m => m.SortedWasteModule)
      },

      {
        path: 'wasteManagement/processedWaste',
        loadChildren: () => import('./modules/ProcessedWastes/processedWaste.module').then(m => m.ProcessedWasteModule)
      },

      {
        path: 'wasteManagement/productionWaste',
        loadChildren: () => import('./modules/ProductionWastes/productionWaste.module').then(m => m.ProductionWasteModule)
      },

      {
        path: 'wasteManagement/factoryWaste',
        loadChildren: () => import('./modules/FactoryWastes/factoryWaste.module').then(m => m.FactoryWasteModule)
      },

      {
        path: 'wasteManagement/constants/wasteEliminationOperation',
        loadChildren: () => import('./modules/Constants/WasteEliminationOperations/wasteEliminationOperation.module').then(m => m.WasteEliminationOperationModule)
      },

      {
        path: 'wasteManagement/apmStatement',
        loadChildren: () => import('./modules/Statement/apmStatement.module').then(m => m.APMStatementModule)
      },

      {
        path: 'wasteManagement/wasteBuyer',
        loadChildren: () => import('./modules/WasteBuyers/wasteBuyer.module').then(m => m.WasteBuyerModule)
      },

      {
        path: 'wasteManagement/wasteOperator',
        loadChildren: () => import('./modules/WasteOperators/wasteOperator.module').then(m => m.WasteOperatorModule)
      },

      {
        path: 'wasteManagement/wasteTransporter',
        loadChildren: () => import('./modules/WasteTransporters/wasteTransporter.module').then(m => m.WasteTransporterModule)
      },

      {
        path: 'wasteManagement/wasteCollector',
        loadChildren: () => import('./modules/WasteCollectors/wasteCollector.module').then(m => m.WasteCollectorModule)
      },

      {
        path: 'wasteManagement/pvppRegistration',
        loadChildren: () => import('./modules/PVPPRegistrations/pvppRegistration.module').then(m => m.PVPPRegistrationModule)
      },

      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },

      { path: '**', redirectTo: 'home' },

    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

// AOT compilation support
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

This is the state with some of the changes I tried to implement for it to work. Initially, TranslateModule was simply imported, not declared with .forRoot(...)
Can it be the case that SharedModule is this application is imported from the main application (that imports the modules of this application)?
The main application that imports the modules from this application has the following app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { ApiAuthorizationModule } from 'src/api-authorization/api-authorization.module';
import { AuthorizeGuard } from 'src/api-authorization/authorize.guard';
import { AuthorizeInterceptor } from 'src/api-authorization/authorize.interceptor';
import { ConfigService } from './services/Common/config.service';
import { ServerBusyService } from './services/Common/serverBusy.service';
import { AuthGuard } from '../AuthGuards/auth.guard';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { NavigationComponent } from './components/Shared/HeaderNavigation/navigation.component';
import { BreadcrumbComponent } from './components/Shared/Breadcrumb/breadcrumb.component';
import { SidebarComponent } from './components/Shared/Sidebar/sidebar.component';
import { SidebarAFMComponent } from './components/Shared/Sidebar/sidebar.afm.component';
import { ListErrorsComponent } from './components/Errors/error.component';
import { HelpErrorComponent } from './components/Errors/help.error.component';
import { SharedModule } from './modules/Common/shared.module';
import { OwlDateTimeModule, OwlNativeDateTimeModule } from 'ng-pick-datetime';
import { ModuleService } from './services/Course/module.service';
import { ListOfModuleService } from './services/Shared/listOfModule.service';
import { MonthlyQuantitiesService } from './services/MonthlyQuantities/monthlyQuantities.service';
import { UserService } from './services/User/user.service';
import { FilesService } from './services/Common/Files/files.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent,

    NavMenuComponent,

    NavigationComponent,

    HomeComponent,
    CounterComponent,
    FetchDataComponent,

    BreadcrumbComponent,
    SidebarComponent,
    SidebarAFMComponent,
    ListErrorsComponent,

    HelpErrorComponent,

  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,

    FormsModule,
    ApiAuthorizationModule,

    BrowserAnimationsModule,

    //OilModule,
    //DangerousSubstanceModule,

    OwlDateTimeModule,
    OwlNativeDateTimeModule,

    SharedModule,

    //NgIdleKeepaliveModule.forRoot(),

    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
      isolate: true
    }),

    RouterModule.forRoot([

      { path: '', component: HomeComponent, pathMatch: 'full' },

      { path: 'home', component: HomeComponent },

      { path: 'list-error', component: ListErrorsComponent, canActivate: [AuthGuard] },

      {
        path: 'dashboard',
        loadChildren: () => import('./modules/Dashboard/dashboard.module').then(m => m.DashboardModule)
      },

      {
        path: 'oils',
        loadChildren: () => import('./modules/Oils/oil.module').then(m => m.OilModule)
      },
      {
        path: 'dangerousSubstances',
        loadChildren: () => import('./modules/DangerousSubstances/dangerousSubstance.module').then(m => m.DangerousSubstanceModule)
      },
      {
        path: 'stationaryEmissions',
        loadChildren: () => import('./modules/StationaryEmissions/stationaryEmission.module').then(m => m.StationaryEmissionModule)
      },
      {
        path: 'suppliers',
        loadChildren: () => import('./modules/Suppliers/supplier.module').then(m => m.SupplierModule)
      },

      {
        path: 'suppliers/suppliersFromNationalMarket',
        loadChildren: () => import('./modules/Suppliers/supplierFromNationalMarket.module').then(m => m.SupplierFromNationalMarketModule)
      },

      {
        path: 'products',
        loadChildren: () => import('./modules/Products/product.module').then(m => m.ProductModule)
      },

      {
        path: 'products/productGroup',
        loadChildren: () => import('./modules/Products/Groups/productGroup.module').then(m => m.ProductGroupModule)
      },

      {
        path: 'products/weightedProduct',
        loadChildren: () => import('./modules/Products/Weighted/weightedProduct.module').then(m => m.WeightedProductModule)
      },

      {
        path: 'products/codesFromNationalMarket',
        loadChildren: () => import('./modules/Products/FromNationalMarket/codeFromNationalMarket.module').then(m => m.CodeFromNationalMarketModule)
      },

      {
        path: 'products/productsFromNationalMarket',
        loadChildren: () => import('./modules/Products/FromNationalMarket/productFromNationalMarket.module').then(m => m.ProductFromNationalMarketModule)
      },

      {
        path: 'products/productFromNationalMarketInput',
        loadChildren: () => import('./modules/Products/FromNationalMarket/productFromNationalMarketInput.module').then(m => m.ProductFromNationalMarketInputModule)
      },

      {
        path: 'products/productCategory',
        loadChildren: () => import('./modules/Products/Categories/productCategory.module').then(m => m.ProductCategoryModule)
      },

      {
        path: 'reusablePackage',
        loadChildren: () => import('./modules/ReusablePackaging/reusablePackage.module').then(m => m.ReusablePackageModule)
      },

      {
        path: 'reusablePackage/inputs',
        loadChildren: () => import('./modules/ReusablePackaging/Inputs/reusablePackageInput.module').then(m => m.ReusablePackageInputModule)
      },

      {
        path: 'reusablePackage/outputs',
        loadChildren: () => import('./modules/ReusablePackaging/Outputs/reusablePackageOutput.module').then(m => m.ReusablePackageOutputModule)
      },

      {
        path: 'reusablePackage/waste',
        loadChildren: () => import('./modules/ReusablePackaging/Waste/reusablePackageWaste.module').then(m => m.ReusablePackageWasteModule)
      },

      {
        path: 'monthlyQuantities',
        loadChildren: () => import('./modules/MonthlyQuantities/monthlyQuantities.module').then(m => m.MonthlyQuantitiesModule)
      },

      {
        path: 'monthlyQuantities/toBeDecreased',
        loadChildren: () => import('./modules/MonthlyQuantities/ToBeDecreased/productToBeDecreased.module').then(m => m.ProductToBeDecreasedModule)
      },

      {
        path: 'monthlyQuantities/toBeIncreased',
        loadChildren: () => import('./modules/MonthlyQuantities/ToBeIncreased/productToBeIncreased.module').then(m => m.ProductToBeIncreasedModule)
      },

      {
        path: 'annualObjectives/accomplishedByOTR',
        loadChildren: () => import('./modules/AnnualObjectives/AccomplishedByOTR/accomplishedByOTR.module').then(m => m.AccomplishedByOTRModule)
      },

      {
        path: 'annualObjectives/individuallyAccomplished',
        loadChildren: () => import('./modules/AnnualObjectives/IndividuallyAccomplished/individuallyAccomplished.module').then(m => m.IndividuallyAccomplishedModule)
      },

      {
        path: 'annualObjectives/takenByOTR',
        loadChildren: () => import('./modules/AnnualObjectives/TakenByOTR/takenByOTR.module').then(m => m.TakenByOTRModule)
      },

      {
        path: 'estimates',
        loadChildren: () => import('./modules/Estimates/estimate.module').then(m => m.EstimateModule)
      },

      {
        path: 'reports/buyingJournal',
        loadChildren: () => import('./modules/Reports/BuyingJournal/buyingJournal.module').then(m => m.BuyingJournalModule)
      },

      {
        path: 'constants/unitType',
        loadChildren: () => import('./modules/Constants/UnitTypes/unitType.module').then(m => m.UnitTypeModule)
      },

      {
        path: 'constants/supportingDocumentSource',
        loadChildren: () => import('./modules/Constants/SupportingDocumentSources/supportingDocumentSource.module').then(m => m.SupportingDocumentSourceModule)
      },

      {
        path: 'constants/measurementUnit',
        loadChildren: () => import('./modules/Constants/MeasurementUnits/measurementUnit.module').then(m => m.MeasurementUnitModule)
      },

      {
        path: 'constants/electronicsAndHouseholdAppliance',
        loadChildren: () => import('./modules/Constants/ElectronicsAndHouseholdAppliances/electronicsAndHouseholdApplianceCategory.module').then(m => m.ElectronicsAndHouseholdApplianceCategoryModule)
      },

      {
        path: 'constants/batteryType',
        loadChildren: () => import('./modules/Constants/BatteryTypes/batteryType.module').then(m => m.BatteryTypeModule)
      },

      {
        path: 'activityJournal',
        loadChildren: () => import('./modules/ActivityJournals/activityJournal.module').then(m => m.ActivityJournalModule)
      },

      {
        path: 'constants/target',
        loadChildren: () => import('./modules/Constants/Targets/target.module').then(m => m.TargetModule)
      },

      //{
      //  path: 'constants/wasteManagementOperation',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/Constants/WasteManagementOperations/wasteManagementOperation.module').then(m => m.WasteManagementOperationModule)
      //},

      {
        path: 'constants/wasteCode',
        loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/Constants/WasteCodes/wasteCode.module').then(m => m.WasteCodeModule)
      },

      //{
      //  path: 'constants/environmentalAgency',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/Constants/EnvironmentalAgencies/environmentalAgency.module').then(m => m.EnvironmentalAgencyModule)
      //},

      {
        path: 'wasteManagement/generatedWaste',
        loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/GeneratedWastes/generatedWaste.module').then(m => m.GeneratedWasteModule)
      },

      //{
      //  path: 'wasteManagement/downloadFiles',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/DownloadFilesWasteManagement/downloadFilesWasteManagement.module').then(m => m.DownloadFilesWasteModule)
      //},

      //{
      //  path: 'wasteManagement/takenWaste',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/TakenWastes/takenWaste.module').then(m => m.TakenWasteModule)
      //},

      //{
      //  path: 'wasteManagement/managedWaste',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/ManagedWastes/managedWaste.module').then(m => m.ManagedWasteModule)
      //},

      //{
      //  path: 'wasteManagement/sortedWaste',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/SortedWastes/sortedWaste.module').then(m => m.SortedWasteModule)
      //},

      //{
      //  path: 'wasteManagement/processedWaste',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/ProcessedWastes/processedWaste.module').then(m => m.ProcessedWasteModule)
      //},

      //{
      //  path: 'wasteManagement/productionWaste',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/ProductionWastes/productionWaste.module').then(m => m.ProductionWasteModule)
      //},

      //{
      //  path: 'wasteManagement/factoryWaste',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/FactoryWastes/factoryWaste.module').then(m => m.FactoryWasteModule)
      //},

      //{
      //  path: 'wasteManagement/constants/wasteEliminationOperation',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/Constants/WasteEliminationOperations/wasteEliminationOperation.module').then(m => m.WasteEliminationOperationModule)
      //},

      //{
      //  path: 'wasteManagement/apmStatement',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/Statement/apmStatement.module').then(m => m.APMStatementModule)
      //},

      //{
      //  path: 'wasteManagement/wasteBuyer',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/WasteBuyers/wasteBuyer.module').then(m => m.WasteBuyerModule)
      //},

      //{
      //  path: 'wasteManagement/wasteOperator',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/WasteOperators/wasteOperator.module').then(m => m.WasteOperatorModule)
      //},

      //{
      //  path: 'wasteManagement/wasteTransporter',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/WasteTransporters/wasteTransporter.module').then(m => m.WasteTransporterModule)
      //},

      //{
      //  path: 'wasteManagement/wasteCollector',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/WasteCollectors/wasteCollector.module').then(m => m.WasteCollectorModule)
      //},

      //{
      //  path: 'wasteManagement/pvppRegistration',
      //  loadChildren: () => import('../../../../WasteManagment/ClientApp/src/app/modules/PVPPRegistrations/pvppRegistration.module').then(m => m.PVPPRegistrationModule)
      //},

      {
        path: 'companies',
        loadChildren: () => import('./modules/Companies/company.module').then(m => m.CompanyModule)
      },

      {
        path: 'account',
        loadChildren: () => import('./modules/Account/account.module').then(m => m.AccountModule)
      },

      {
        path: 'timesheets',
        loadChildren: () => import('./modules/Timesheets/timesheet.module').then(m => m.TimesheetModule)
      },

      {
        path: 'course',
        loadChildren: () => import('./modules/Course/course.module').then(m => m.CourseModule)
      },

      { path: '**', redirectTo: 'home' },

      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },

    ])
  ],
  providers: [

    ConfigService,
    ServerBusyService,

    FilesService,

    AuthGuard,

    UserService,

    ModuleService,

    ListOfModuleService,

    MonthlyQuantitiesService,

    { provide: HTTP_INTERCEPTORS, useClass: AuthorizeInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

// AOT compilation support
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

The problem is that both applications start independently, but when I click on the routes of the first application, e.g. GeneratedWaste module's routes, only then I get the error with TranslateService.
Thank you very much,
Andrei

Please don't talk about specific code issues in this topic, create a new issue for it

I understand the message. The reason I wrote here was because of the issue:
https://github.com/ngx-translate/core/issues/1324
Which seems to point that there is something not working in versions 12 and 13 of Angular. I wrote here because I thought it might be something with the update. I will write in issue 1324.
Sorry

Welp. It's been 5 years... It's now Angular v15, they still can't support runtime translations... Sadge 😥

Welp. It's been 5 years... It's now Angular v15, they still can't support runtime translations... Sadge 😥

@bernatgy in fact Angular supports runtime translations!
You can easily achieve it using the loadTranslations function from the @angular/localize package.
There is only one limitation - you should not use translations in a component template (i18n and i18n-* attributes).
I've created a demo repository to show how it can be achieved - ng-i18n-dynamic.

Recently, i thought its ngx-translate/core runtime rendering performance can be improve through Signal spec.
Here is the concept code i did from ngx-translate/core forked version.
https://gist.github.com/leo6104/1d8da771f1cb3da237ca3ba06fe4fdea
It almost 200+ lines removed and more readable logic with signal.
I didn't fully understand signal API but it seems quite simple.

Nice, I will have to look at this, I haven't dived deep into Signal either but that's a good idea

@ocombe from my side,
I hope its possible for you to add funding and sponsoring options
I can speak up on my side I know my company relies on their mobile developments on this library and from what I'm reading we really don't want to move to the official support

Any news on future of the library? Is it dead? 🤔

It depends what you mean by dead. It's in maintenance mode, just making sure it doesn't break with new versions of angular, but not adding anything else.

Thanks, thats not so bad. But what about the open PRs? Will they be left open for all eternity? And do you have a backup person with access rights to this repo for the day when you can't/won't fix any breaking changes introduced through new Angular versions?

I tried multiple times to find worthy maintainers, but people who wanted to just ended up not doing it. So yeah, probably the PRs will stay like this, unless I need this library personally at some point and decide to invest more time into it, but that's not on the menu for now

Hi @ocombe, first of all thank you for the great work. Do you plan to add a license file for the ngx-translate core and the @ngx-translate/http-loader package?

Hi all,
It's quite sad to see such a great library fading away. ngx-translate is still fully functional and designed in a way that ensures it will work for years to come. Its modular concept provides a level of flexibility that no other solution matches.
That's why I've decided to keep the project alive and continue working on the library.
I've started by reviewing the entire codebase and creating updated documentation:
https://ngx-translate.org/
The documentation now covers installation on Angular 18+ and is divided into smaller, more readable sections, making it easier to digest than the README in the main project. I've also documented the additional interfaces and explained how to develop custom plugins.
Next, I plan to update the list of plugins and check which ones still work with the current version of Angular. If any important plugins are broken, I'll consider forking and maintaining them.
Additionally, I've created an updated tutorial here:
https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-angular-app-with-ngx-translate
This tutorial walks you through creating a translated Angular app from scratch, but it should also serve as a guide for integrating ngx-translate into your existing project.
What's currently missing: I don’t have access to the npm repository for ngx-translate, so I can’t update the modules themselves at the moment. Maybe @ocombe might give me access to that?
Now, you might ask: Why am I investing time into this library?
First and foremost, we use ngx-translate in one of our own projects, so keeping it up-to-date benefits us directly.
Beyond that, we developed a JSON file editor called BabelEdit, initially for our own use. We released it to the public in 2017, and many of our customers are active ngx-translate users. We don’t want to leave them unsupported.
We are CodeAndWeb GmbH, a two-developer company, and we've been building and supporting tools since 2010, providing regular updates and solid customer service. We plan to do the same for ngx-translate.
To be clear, ngx-translate will remain open source under the MIT license. We'll keep it updated, fix bugs, and maintain the documentation and tutorials, all at no cost to you.
Best
Andreas

Thanks @CodeAndWeb for these kind words. Are you also thinking about taking on this approach  using signals?

Thanks @CodeAndWeb for these kind words. Are you also thinking about taking on this approach  using signals?

Sounds useful and perhaps yes. But this will take time.

For current Angular Signals spec, it was impossible to implement. (the root issue: https://github.com/angular/angular/issues/49967 )
Recently, Angular team change effect behavior to allow signal write
https://github.com/angular/angular/commit/4e890cc5ac6eaa04a6f7ca988908812a65991c14
Maybe it will be landed to v19.

Hi @ocombe, it's great to see you're still around! I've tried reaching
out via email and other channels but haven't had any luck. I was hoping
we could discuss the future of the library. As I mentioned earlier, I'm
interested in taking on the responsibility of maintaining it.
Right now, it's difficult to make any progress. We can't merge pull
requests or perform other necessary actions. The CI system is broken as
well, which adds to the frustration.
Maintaining the library only makes sense if there's a strong, active
user base. An isolated fork with a small number of users wouldn't be
worth the effort.
In the meantime, I've been integrating pull requests into my fork and
closing the ones I've worked on to track what's been merged. Reopening
them here only to let them sit idle for years helps no one.
I've also updated [my unofficial documentation](https://www.ngx-
transalte.org) to help users get started with Standalone Components.
Unfortunately, it's also not possible to update the official documentation
here at the moment...

I've created a fork of ngx-translate, which you can find here:
https://github.com/codeandweb/ngx-translate.
For pull requests or bug reports, please switch to that repository, as I can integrate changes directly.
Additionally, I've published new npm packages for this fork:

@codeandweb/ngx-translate
@codeandweb/http-loader

The first release of my fork is now available, featuring:

Support for Standalone Components
Enhanced behavior for multiple calls to use()
MIT license included in npm modules
Interpolation of nested translation objects
Improved API typing

A migration guide is available to assist in transitioning from @ngx-translate/core to @codeandweb/ngx-translate:  Migration Guide.

@ocombe Would it be possible to give @CodeAndWeb access to this repo? His new changes look good, the documentation seems correct and up to date and he wants to maintain this library. Switching to the new packages means changing A LOT of files in our repositories...

I just did that. @CodeAndWeb you can merge your fork into the main project if you want

I would also need access to the npm repo to publish the new releases. @ocombe please contact me at support at codeandweb.com for that.

Just released @ngx-translate/core@16.
I guess we can close this issue for now...

@CodeAndWeb what does this mean for people who already moved to your fork? Should we move back to this one now?

Yes. I'll mark it deprecated soon.
I created the fork since I had no way to work on this repository - since I now have access to GitHub & npm, I can now update the code directly from here.

Yes. I'll mark it @codeandweb/ngx-translate deprecated soon. I created the fork since I had no rights to work on this repository - since I now have access to GitHub & npm, I can now update the code directly from here. Keeping 2 modules up-to-date that practically do the same thing does not make much sense.

so does that mean we should move back now, or do we need to wait for something? :)

No - just move back. Sorry for this inconvenience.


more D3 Line Chart improvement

Add checkbox to toggle on log10 base scale for chart's y Axis (only in /d3test)
Add limit for zoom scale
Dynamically enable the time toggle buttons (1h/1d/1w/1m/1y)

Current coverage is 36.44% (diff: 100%)

Merging #257 into d3 will increase coverage by 0.01%

@@                 d3       #257   diff @@
==========================================
  Files           260        260
  Lines         14209      14209
  Methods           0          0
  Messages          0          0
  Branches       2389       2389
==========================================
+ Hits           5176       5178     +2
+ Misses         8314       8312     -2
  Partials        719        719

Powered by Codecov. Last update edf2c15...049f1e3


Update notepack.io to ~3.0.1

This is a follow-up to https://github.com/socketio/socket.io-redis-emitter/pull/113
I found out that the way Date instances are serialized changes from notepack.io 2 to 3, so after upgrading socket.io-redis-emitter, Dates get decoded as eg. [ -1, <Buffer 90 b8 57 00 63 37 5d 19> ]. Seems like the library version needs to be kept in sync.
CC @darrachequesne 🤗

Ping @darrachequesne :)

Thanks a lot! 🙇


Try Dotty

[ ] single compose method
[ ] replace macro by new meta programming

https://github.com/lampepfl/dotty/issues/5941

https://github.com/lampepfl/dotty-example-project
https://github.com/lampepfl/dotty.g8/
https://github.com/lampepfl/dotty-cross.g8

Experimentation in this repo https://github.com/julien-truffaut/Monocly


Conflict with @solflare-wallet/utl-sdk

Using a clean next project and installing both @solflare-wallet/utl-sdk and @bonfida/spl-name-service results in the following error when using @solflare-wallet/utl-sdk:
TypeError: Cannot read properties of undefined (reading 'prototype')
    at extendBorsh (webpack-internal:///(rsc)/./node_modules/@metaplex-foundation/mpl-core/dist/src/utils/borsh.js:14:26)
    at eval (webpack-internal:///(rsc)/./node_modules/@metaplex-foundation/mpl-core/dist/src/utils/borsh.js:30:25)

After investigating, I found that the issue started with @bonfida/spl-name-service version 2.3.3. It's unclear whether the problem lies with @solflare-wallet/utl-sdk or @bonfida/spl-name-service.
Steps to Reproduce:

Create a new Next.js app with default settings:
bunx create-next-app

Install the required packages:
bun install @solflare-wallet/utl-sdk @bonfida/spl-name-service

Replace the content of page.tsx with the following code:
import { Client, Token } from "@solflare-wallet/utl-sdk";
import { PublicKey } from<EMAIL_ADDRESS>
export default async function Home() {
  const utl = new Client();
  const token: Token = await utl.fetchMint(
    new PublicKey("So11111111111111111111111111111111111111112")
  );

  return <>{token.logoURI}</>;
}

Start the development server:
bun run dev

Hi @KoenRijpstra! Thanks for opening the issue, I will investigate and get back to you

It looks like the issue you're encountering is related to how bun handles package resolutions, specifically with different versions of borsh.
Here are a few points to consider:

Bun vs. npm: The issue seems to be specific to bun. When using npm, everything works fine. You can see more details here: .
Version Change: In version 2.3.3 of @bonfida/spl-name-service, we upgraded to borsh 1.0.0. This change might be causing conflicts with other packages that rely on older versions of borsh.
No Direct Dependency: Our SDK does not have a dependency on @metaplex-foundation. The error you're seeing (TypeError: Cannot read properties of undefined (reading 'prototype')) seems to be related to how bun resolves borsh dependencies.
Dependency Conflicts: It appears that other packages in your project are relying on borsh versions earlier than 1.0.0. This version mismatch could be causing the issue.
To resolve this, you might want to try using npm instead of bun, or ensure that all packages in your project are compatible with borsh 1.0.0.
Hope this helps! If you have any more questions, feel free to ask.
Best regards,

It looks like the issue you're encountering is related to how bun handles package resolutions, specifically with different versions of borsh. When using npm, everything works fine. You can see more details here on this test repo https://github.com/dr497/test-issue/tree/main
Our SDK does not have a dependency on @metaplex-foundation. The error you're seeing (TypeError: Cannot read properties of undefined (reading 'prototype')) seems to be related to how bun resolves borsh dependencies. In version 2.3.3 of @bonfida/spl-name-service, we upgraded to borsh 1.0.0. This change might be causing conflicts with other packages that rely on older versions of borsh.
To resolve this, you might want to try using npm instead of bun, or ensure that all packages in your project are compatible with borsh >= 1.0.0.

Thanks, that explains a lot! Will lock it to 2.3.2 for now and maybe I can use overrides to fix the issue.


Problem to import map in CARLA 0.9.12

Hi everyone,
I just installed CARLA 0.9.12 in my computer and i'm trying to insert a map that i created in RoadRunner.
I'm following the steps described here:
https://carla.readthedocs.io/en/0.9.12/tuto_M_add_map_source/
but by running "make import" no folder is being created in the Content folder. And the output in terminal is not the same as before in 0.9.11. So i think something is wrong:

make import  ARGS="--no-carla-materials"
-[Setup]: [Batch params]: --boost-toolset msvc-14.2 --no-carla-materials
-[Setup]: Asynchronous jobs:  16
-[Setup]: Boost toolset:      msvc-14.2
-[Setup]: Install directory:  "D:\carla\Build\"
-[Setup]: Installing zlib...
    -[install_zlib]: [Batch params]: --build-dir "D:\carla\Build\"
    -[install_zlib]: A zlib installation already exists.
    -[install_zlib]: Delete "D:\carla\Build\zlib-install\" if you want to force a rebuild.
    -[install_zlib]: Exiting...
-[Setup]: Installing libpng...
    -[install_libpng]: [Batch params]: --build-dir "D:\carla\Build\" --zlib-install-dir "D:\carla\Build\zlib-install\"
    -[install_libpng]: A libpng installation already exists.
    -[install_libpng]: Delete "D:\carla\Build\libpng-1.2.37-install\" if you want to force a rebuild.
    -[install_libpng]: Exiting...
-[Setup]: Installing rpclib...
    -[install_rpclib]: [Batch params]: --build-dir "D:\carla\Build\"
    -[install_rpclib]: A rpclib installation already exists.
    -[install_rpclib]: Delete "D:\carla\Build\rpclib-install\" if you want to force a rebuild.
    -[install_rpclib]: Exiting...
-[Setup]: Installing Google Test...
    -[install_gtest]: [Batch params]: --build-dir "D:\carla\Build\"
    -[install_gtest]: A Google Test installation already exists.
    -[install_gtest]: Delete "D:\carla\Build\gtest-install\" if you want to force a rebuild.
    -[install_gtest]: Exiting...
-[Setup]: Installing "Recast & Detour"...
    -[install_recast]: [Batch params]: --build-dir "D:\carla\Build\"
    -[install_recast]: A "Recast & Detour" installation already exists.
    -[install_recast]: Delete "D:\carla\Build\recast-0b13b0-install\" if you want to force a rebuild.
    -[install_recast]: Exiting...
-[Setup]: Installing Boost...
    -[install_boost]: [Batch params]: --build-dir "D:\carla\Build\" --toolset msvc-14.2 --version 1.72.0 -j 16
    -[install_boost]: A Boost installation already exists.
    -[install_boost]: Delete "D:\carla\Build\boost-1.72.0-install\" if you want to force a rebuild.
    -[install_boost]: Exiting...
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
-[Setup]: Installing Xercesc...
    -[install_xercesc]: [Batch params]: --build-dir "D:\carla\Build\"
    -[install_xercesc]: A xerces installation already exists.
    -[install_xercesc]: Delete "D:\carla\Build\xerces-c-3.2.3-install\" if you want to force a rebuild.
    -[install_xercesc]: Exiting...
        1 Datei(en) kopiert.

-[Setup]: Installing PROJ
    -[install_proj]: [Batch params]: --build-dir "D:\carla\Build\"
    -[install_proj]: A PROJ installation already exists.
    -[install_proj]: Delete "D:\carla\Build\proj-install" if you want to force a rebuild.
    -[install_proj]: Exiting...
        1 Datei(en) kopiert.
-[Setup]: Creating "CMakeLists.txt.in"...
-[Setup]:
   ###########
   # SUCCESS #
   ###########

   IMPORTANT!

   All the CARLA library dependences should be installed now.
   (You can remove all "*-src" folders in D:\carla\Build\ directory)

   You only need the ASSET PACK with all the meshes and textures.

   This script provides the assets for CARLA 0.9.12:
   You can download the assets from here:

       http://carla-assets.s3.amazonaws.com/20210730_564bcdc.tar.gz

   Unzip it in the "D:\carla\Unreal\CarlaUE4\Content\Carla\" folder.
   If you want another version, search it in D:\carla\Util\ContentVersions.txt.

-[BuildLibCarla]: [Batch params]: --server
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19042.
-- Build debug:   ON
-- Build release: ON
-- Build test:    ON
-- Configuring done
-- Generating done
-- Build files have been written to: D:/carla/Build/libcarla-visualstudio
Microsoft (R)-Build-Engine, Version 16.10.2+857e5a733 für .NET Framework
Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.

  carla_server.vcxproj -> D:\carla\Build\libcarla-visualstudio\LibCarla\cmake\server\Release\carla_server.lib
  carla_server_debug.vcxproj -> D:\carla\Build\libcarla-visualstudio\LibCarla\cmake\server\Release\carla_server_debug.lib
  -- Install configuration: "Release"
-[BuildLibCarla]: LibCarla server has been successfully installed in "D:\carla\Unreal\CarlaUE4\Plugins\Carla\CarlaDependencies\"!

have anyone any idea what is going wrong?

You can import the map manually from Content Browser in CarlaUE4.

I have tried it too. But then i'm getting this error:
ERROR: unable to parse the OpenDRIVE XML string

You can import the map manually from Content Browser in CarlaUE4.

it didn't work.

You can import map with RoadRunner plugin and save map in Content/Carla/maps.

You can import map with RoadRunner plugin and save map in Content/Carla/maps.

but this error may occur:
ERROR: unable to parse the OpenDRIVE XML string