Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: future of the library #783

Open
ocombe opened this issue Jan 30, 2018 · 122 comments
Open

Discussion: future of the library #783

ocombe opened this issue Jan 30, 2018 · 122 comments

Comments

@ocombe
Copy link
Collaborator

ocombe commented Jan 30, 2018

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?

@bnymncoskuner
Copy link

Hello,

I've been using your library as long as I've been using Angular (4+). Last year, around this time I'd been using AngularJs for a while and since Angular 2 was finally released, I decided to give it a try. It seemed a lot more complicated than AngularJs, and i18n was almost impossible for me to use. At that time, I had other projects to work on so I stopped using Angular 2.

Few months passed, I had a chance to join the Ng-Conf. At the conference, I found John Papa at a hall and asked him about i18n in Angular. He said there is a built-in solution. I checked it out and it was too complicated. Extracting files, dealing with xml .... Also, we'd been using a tool for i18n, and we've put all of our translations into a json file. So, built in i18n was not an ideal solution for me.
Then, I kept digging and came across your library (as it was named ng2-translate then). I, immediately, fell in love with it. It was super easy to include, configure and use. And, it used JSON! Since then, I've been using it for all of my angular projects (plus I just started using Ionic, and I included ngx-translate into that project as well).

You listed some of the issues with ngx-translate. I think the most important one is that if, somehow, a user cannot download translation file or there is an exception somewhere, you could end up with messed up screen. Other issues, for me, are not so important.

Also, another feature of ngx-translate I really like, is code translation. I could use TranslateService within my code to get any translation I want which I always need to do so.

Long story short, I'd love to see you to keep maintaining this library even if you spend little time on it. I don't think angular built-in i18n solution should be the only one. I think having alternatives is always better.

For license, I think companies would stop using it if you start charging new versions or they'll just use an old version which works just fine. It is because, purchasing a licence in a company is a painful process and I think most people would just avoid it and go for other solutions. Also, I have to mention that if a company buys a license, they expect 24/7 pro support. At least, mine does :) So, that would be hard to deal with.
For other alternative, you could get funding through donations or at least try it for a while and then go for paid license.

@davidefavia
Copy link

davidefavia commented Jan 30, 2018

Hi @ocombe,
first of all thanks for your hard work and for this open discussion.
I'm fine with option number 1 (few PRs merging, no new features), projects I'm working on don't present any critical issue within your library, so a maintenance mode could be fine.
The company I work for could probably afford a paid license but we have a lot of JavaScript stuff (vanilla, jQuery, Vue.js), it could be difficult to justify expenses just for few projects (~5%) using Angular.
I found difficult to use official i18n solution because of:

  • one bundle per locale,
  • impossibility to switch language at runtime without reloading the app,
  • xliff file IDs synchronization,
  • cannot translate inside code, only in templates.

If my personal issues could be addressed by the official i18n solution, I could switch without any problem.

@stefangrossmann
Copy link

We started using “ngx-translate” at the company because it delivers exactly what we need:

  • The JSON format worked out of the box with our professional translation tool, and it is easy to read and to handle.
  • Switching the language during runtime helps our professional translators to find correct translations and to verify them.
  • We use our own Translate-Loader to combine translation sources. This way we for example can allow our customers to provide languages we don’t support by default.

But if we would need to buy a license, I think we would stop using it. It would be hard to argue to pay for it, if Angular itself has something for free. And I can confirm that the process of purchasing a license in a big company is a painful process.

I am not sure if you can make your project profitable with a paid license for commercial usage. Other models I know are, that there is a limited free version of a product and a commercial one with support, extended features and extended documentation. But because “ngx-translate” is easy to use and does exactly what it should, there is no need for us to pay for additional stuff ;-) :-/.

@vivainio
Copy link

+1 for option 1. In the end everyone wants to be on the official solution, esp. since v6 seems to fix the biggest limitations (and that they wanted to fix those in the first place, i.e. it's not going to pursue "wrong" direction forever.

@peterpeterparker
Copy link

First of all, thx @ocombe for your library and amazing work. I use ngx-translate in every single frontend development project I do, one of the first dependency I inject ;)

Furthermore to the simplicity of implementation, I use ngx-translate because supporting multi-languages is a must for all my projects.

My major concern, because my main app is a Ionic/Cordova app, is having the abilility to have only one bundle and to boot the app in the right language. If that would be possible in the future with i18n, well I might be open to the idea to migrate to it . If that will not be possible, there is no way that I gonna migrate to i18n, I can't boot for example an app in english, then switch to french and restart the mobile app, that would be a crazy user behavior.

About your question itself, I'm not a big company, just a single developper, so I could not tells you if they would be or not be open to a licence fee.

But maybe a third option, just throwing that idea out of loud, to the two you listed above would be a donation model or even maybe better to start a kickstarter? Like "I need xx'xxx euros for the next x years in which I gonna implement these and these features and perform support and bug fixes etc.".

@ocombe
Copy link
Collaborator Author

ocombe commented Jan 31, 2018

Solution 1 is not "ditching it", just making sure it still runs on the current Angular and merging PRs that seem interesting or fix bugs. That's how it's been working for the past year.

@vivainio
Copy link

@DenisVuyka The projects is already hosted under ngx-translate github team. There wouldn't need to be "transfer of ownership", just assign PR merge rights to some trusted lieutenants.

Truth be told, resources would still be better assigned as third party improvements to angular-i18n ecosystem (tools, hooks, what have you). That would provide some freedom of innovation outside Angular's strict quality policy while not diverging from the core offering

@bnymncoskuner
Copy link

What about proposing to angular team to make this an official alternative to angular i18n? Angular team may offer two different solutions for i18n. Would this not be better?

@ocombe
Copy link
Collaborator Author

ocombe commented Jan 31, 2018

This is not an option no.

@bnymncoskuner
Copy link

Then, I think option 1 is the one. People don't expect much out of this library, because, most of the apps just need something as simple as ngx-translate to support i18n. Angular solution may be powerful and better, but often it is overkill and may be harder to manage.

@Bil0
Copy link

Bil0 commented Feb 1, 2018

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.

@ocombe
Copy link
Collaborator Author

ocombe commented Feb 1, 2018

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.

The bugs that made you "loose so much time" could have been resolved by me instead of your team.

@web-dave
Copy link

web-dave commented Feb 2, 2018

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

@bnymncoskuner
Copy link

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.

@davidefavia
Copy link

davidefavia commented Feb 2, 2018

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 click on GitHub "Fork" button and stop then.
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 it and many many thanks for his hard work in advance. Meanwhile he can concentrate on i18n for Angular core getting paid for it!

@ocombe
Copy link
Collaborator Author

ocombe commented Feb 2, 2018

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.

@Maistho
Copy link

Maistho commented Feb 5, 2018

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! ❤️

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.

@rowdyrabouw
Copy link

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

@rowdyrabouw
Copy link

@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.

@loicsalou
Copy link

@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 !

@Matmo10
Copy link

Matmo10 commented Feb 21, 2018

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.

@lephyrus
Copy link
Contributor

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 (SelectOrdinal Error when Changing Languages lephyrus/ngx-translate-messageformat-compiler#21, ERROR TypeError: Cannot read property 'value' of undefined lephyrus/ngx-translate-messageformat-compiler#20).
  • It's not like you owe anyone anything regarding this library - I'd say concentrate on what's interesting to you.

@CodeAndWeb
Copy link
Collaborator

I am currently trying to help @ocombe with ngx-translate, getting the issues cleaned up, fixing smaller things. I don't want to see ngx-translate rot and die...

Shot information about me: My name is Andreas Löw, owner of CodeAndWeb GmbH. We create tools for developers - main focus is game development (TexturePacker) but we've recently created a JSON editor called BabelEdit which works with ngx-translate.

I'm a developer for quite a long time - started programming when I was 10... which means that I've 34 years of experience ;) My usual work is in C++, PHP for webpages and Javascript/Typescript.

I've been working on an Angular project for the last year - but I must admit this does not make me an expert. As I said: I have good knowledge in coding - but not about Angular in depth.

@ocombe Why don't you go to https://www.patreon.com ? It should be easy to setup and collect some money from donations.

@hamzapoly
Copy link

hamzapoly commented Mar 30, 2018

Well I have one question, is there a way on Angulari18n 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

@DenysVuika
Copy link

DenysVuika commented Mar 31, 2018

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.

Live demos:

@tnicola
Copy link

tnicola commented Apr 24, 2018

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. 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?

@admir86
Copy link

admir86 commented May 25, 2018

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?

@ocombe
Copy link
Collaborator Author

ocombe commented May 25, 2018

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.

@peterpeterparker
Copy link

@ocombe not all heroes wear capes, merci ❤️

@vivainio
Copy link

Seems there is no real documentation for js-driven i18n in Angular 6 docs. What's the best place to look?

@mbeckenbach
Copy link

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

@ngehlert
Copy link

ngehlert commented Jul 7, 2021

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

@mbeckenbach
Copy link

@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

@mbeckenbach
Copy link

@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.

@TaylorAckley
Copy link

Sorry to be that guy - Seems like the status is of ngx-translate is still up in the air based on that thread, but it's been quite a while since there was a substantial commit to core. Is ngx-translate in hibernation in favor of locl?

@ocombe
Copy link
Collaborator Author

ocombe commented Aug 26, 2021

@TaylorAckley ngx translate is in maintenance mode because I don't have the time nor the incentive to work on it, and it's in a stable mode (a lot of people are still using it, the usage is even growing).
I'm just maintaining it so that it doesn't break (for example I will release a new version for Angular v13 which requires ivy-compiled libraries).
I'm not working on locl either because I never got enough traction to make it worth while...

@TaylorAckley
Copy link

Thanks, @ocombe! I appreciate everything you do!

@AndresBabe-Nexplore
Copy link

AndresBabe-Nexplore commented Nov 11, 2021

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 keeping 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!

@pcouas
Copy link

pcouas commented Dec 8, 2021

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

@ocombe
Copy link
Collaborator Author

ocombe commented Dec 8, 2021

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

@n84ck
Copy link

n84ck commented Dec 21, 2021

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!

@TaylorAckley
Copy link

@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?

@robertmazzo
Copy link

robertmazzo commented Jan 12, 2022

I also thank @ocombe for his work on ngx-translate. We had been using 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
Copy link

Hello @ocombe!

Thank you very much for the work you have done. I would be definitely be willing to pay for the work you have done!

There is a problem when we have an application and another one imports the first application's modules. We receive "NullInjectorError: R3InjectorError(GeneratedWasteModule)[TranslateService -> TranslateService -> TranslateService -> TranslateService]:
NullInjectorError: No provider for TranslateService!"

Here is an issue:

#1324

According to:

kubeflow/kubeflow#6042

This might not work?

@TaylorAckley
Copy link

@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.

@dobrinsky
Copy link

@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

@ocombe
Copy link
Collaborator Author

ocombe commented May 10, 2022

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

@dobrinsky
Copy link

I understand the message. The reason I wrote here was because of the issue:

#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

@bernatgy
Copy link

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

@leo6104
Copy link

leo6104 commented Apr 22, 2023

Recently, i thought its ngx-translate/core runtime performance & code complexity 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 150+ lines removed and more readable logic with signal. I didn't fully understand signal API but it seems quite simple and don't need to consider multiple Observable/subscription handling.

PS) above gist code also includes other new feature.

  • use TranslateState to preserve the used translations and use its translations in client-side rendering.

@ocombe
Copy link
Collaborator Author

ocombe commented Apr 22, 2023

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

@modus-jose
Copy link

@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

@seriouz
Copy link

seriouz commented Sep 4, 2023

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

@ocombe
Copy link
Collaborator Author

ocombe commented Sep 4, 2023

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.

@seriouz
Copy link

seriouz commented Sep 4, 2023

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?

@ocombe
Copy link
Collaborator Author

ocombe commented Sep 4, 2023

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 again at some point in the future and decide to invest more time into it, but that's not on the menu for now

@GrandeApps
Copy link

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests