Git Product home page Git Product logo

Comments (15)

Romanchuk avatar Romanchuk commented on May 28, 2024

@david-bulte Hi, what is your versions?
angular
i18next
angular-18next

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

Here is demo app runninig on latest version
https://github.com/Romanchuk/angular-i18next-demo
https://romanchuk.github.io/angular-i18next-demo/

from angular-i18next.

david-bulte avatar david-bulte commented on May 28, 2024

My versions:

  • "i18next": "^15.0.4",
  • "i18next-browser-languagedetector": "^3.0.1",
  • "i18next-xhr-backend": "^2.0.1",
  • "@angular/core": "^7.2.7",
  • "angular-i18next": "^6.0.0"

Here's how I use it. As you see I'm listening to the events in the constructor of a pipe. The console.log('>>>>>> translation', translation); is not carried out. Directly using i18next (_i18next in the code below) does work.

import { ChangeDetectorRef, OnDestroy, OnInit, Pipe, PipeTransform } from '@angular/core';
import { I18NextPipe, I18NextService } from 'angular-i18next';
import * as i18n from 'i18next';

const _i18next = i18n.default;

@Pipe({
  name: 'nexuzhealthI18n',
  pure: false
})
export class I18nPipe implements PipeTransform, OnDestroy {

  private langChanged = this.languageChanged.bind(this);

  constructor(private i18Next: I18NextService, private i18NextPipe: I18NextPipe, private changeDetector: ChangeDetectorRef) {

    // bug? cf. https://github.com/Romanchuk/angular-i18next/issues/27
    this.i18Next.events.languageChanged.subscribe(translation => {
      console.log('>>>>>> translation', translation);
      this.changeDetector.markForCheck();
    })

    _i18next.on('languageChanged', this.langChanged);
  }

  transform(value: any, args?: any): any {
    return this.i18NextPipe.transform(value, args);
  }

  ngOnDestroy(): void {
    _i18next.off('languageChanged', this.langChanged)
  }

  languageChanged(lng) {
    this.changeDetector.markForCheck();
  }
}

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

I have reproduced it on demo app, it is not a bug. You are injecting "i18Next: I18NextService", but you should inject it throught token like this:

@Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService

I guess the reason is that you have inited i18next module using token (as recommended)

{
    provide: APP_INITIALIZER,
    useFactory: appInit,
    deps: [I18NEXT_SERVICE],
    multi: true
  }

but then you should inject I18NEXT_SERVICE token everywhere in your app, because you inited it.
You injecting I18NextService, but it was not inited (events was not subscribed).

May be i should depricate I18NextService provider to remove this confusion

from angular-i18next.

david-bulte avatar david-bulte commented on May 28, 2024

This is working much better, thanks! Still I have a little problem. The languageChanged event is not being called in a module that was lazy loaded. I noticed that the ITranslationService instance (now injected via @Inject(I18NEXT_SERVICE)) is not the same in the root as in the (lazy loaded) module, maybe that is the reason?

Here's a snippet of my configuration:

@NgModule({
  imports: [CommonModule, I18NextModule.forRoot()],
  declarations: [I18nPipe],
  exports: [I18NextModule, I18nPipe] // re-exporting I18NextModule, I18nPipe is my own
})
export class SharedUtilI18nModule {

  static forRoot(config: I18NextConfig = {}): ModuleWithProviders {
    return {
      ngModule: SharedUtilI18nModule,
      providers: [
        {provide: i18next_config, useValue: config},
        {
          provide: APP_INITIALIZER,
          useFactory: appInit,
          deps: [I18NEXT_SERVICE, i18next_config],
          multi: true
        }
      ]
    }
  }

}

In my (root) AppModule, I import this like so:

SharedUtilI18nModule.forRoot({ns: {ns: ['gp', 'auth', 'common'], merge: true}})

While in the lazy-loaded module, I just import SharedUtilI18nModule (to be able to use the i18next pipe, SharedUtilI18nModule is re-exporting I18NextModule):

@NgModule({
  imports: [
    //... here are some more modules
    SharedUtilI18nModule
  ],
  declarations: [InboxPageComponent]
})
export class MoaprGpFeatureInboxModule {}

What am I doing wrong? Is it normal that the ITranslationService isn't a singleton?

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

ITranslationService is a singleton, but in your lazy module there is the other Injector, that has no instances of ITranslationService and it creates it own (the new one).
I have in my projects lazy modules and i do it like this:

  • AppModule: import I18NextModule.forRoot(..)
  • Lazy module: import I18NextModule to provide pipes. ITranslationService would be refenced to root ITranslationService and it will be single for whole app.

In your case you should divide your SharedUtilI18nModule and I18NextModule.forRoot, init I18NextModule in AppModule.
SharedUtilI18nModule is only for your pipes and it still imports I18NextModule (without forRoot). And it don't need to export I18NextModule.
InboxPageComponent imports both I18NextModule and SharedUtilI18nModule


The main thing i don't understand: Why do you do it? Why don't you use already implemented mecanisms?

from angular-i18next.

david-bulte avatar david-bulte commented on May 28, 2024

I will try it out later. As for your question, I was looking for a way to dynamically change the translations: you change the language and all translations are immediately refreshed, also the ones in components with ChangeDetection.OnPush (comparable to the AsyncPipe). But maybe you know another way ? :)

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

Here are the reasons why i left idea on making pipes dynamic/impure:
#11 (comment)
In early versions i tryied to implement impure pipes, but left this idea for several reasons:

  1. Some custom controls or pipes can be dependent on angular LOCALE_ID token. So we want to change angular LOCALE_ID with i18next language.
{
 provide: LOCALE_ID,
 deps: [I18NextService],
 useFactory: (i18next: I18NextService) => {
  return i18next.language; //string: 'en', 'ru'...
 }
}

The problem is that angular IOC container resolves dependencies as singleton, once LOCALE_ID was requested it will always resolve as the same value (first resolved). The only way to get actual LOCALE_ID value is to register LOCALE_ID as factory function, but than it will break libraries that expect LOCALE_ID to be 'string' (not function).
Here is my stackoverflow question: Dynamicly get LOCALE_ID (resolve per request)

  1. Custom components with own localization support mostly require complete reinit on language change.

  2. Also most l10n, i18n and date format (momentjs) angular pipes are pure, and changing i18next language or LOCALE_ID won't trigger pipe change detection for them.

  3. Possible memory leaks and perfomant issues. For example zonejs automatically trigger change detection as a result of async operations, this means using jquery libs with ajax could cause your page (full of impure pipes) freeze.

That is why i ended up with simply refreshing page with a new language. We only need to setup right language, locale and formats on angular initialization.


Also i had impure i18next pipe implementation that was statefull - it had memoisation that returned already translated result if input params and language did not change. It worked well. But in my real world projects language changed immediately, but "angular moment " pipes was not called (they are pure), third party controls also needed to be manually reinit...

This experience i had more than one year ago (with angular v2), maybe today it's more possible) i would like to see implementation that would resolve problems that i mentioned above

from angular-i18next.

DevDemba avatar DevDemba commented on May 28, 2024

Hello, I'm an apprentice developer. I would like to have several values that I return from my database for the same Angular interpolation variable.
What is i18next capable of solving this problem?

Here is my configuration in app module :
export function appInit(i18next: ITranslationService) {

return () => i18next
.use(detector)
.use(backend)
.use(sprintf)
.init({
whitelist: ['en', 'fr'],
fallbackLng: 'en',
debug: true,
returnEmptyString: false,
returnObjects: true,
ns: [
'translation'
],
backend: {
loadPath: "./assets/i18n/{{lng}}/{{ns}}.json"
},
lng: 'fr',

  // overloadTranslationOptionHandler: sprintf.overloadTranslationOptionHandler,
});

}

export function localeIdFactory(i18next: ITranslationService) {
return i18next.language;
}

export const I18N_PROVIDERS = [
{
provide: APP_INITIALIZER,
useFactory: appInit,
deps: [I18NEXT_SERVICE],
multi: true
},
{
provide: LOCALE_ID,
deps: [I18NEXT_SERVICE],
useFactory: localeIdFactory
}];
image
Annotation 2019-03-26 101017

this is my JSON "translation.json":

"models": {
"contacts": {
"attributes": {
"roles": {
"author": "Auteur",
"custodian": "Administrateur",
"distributor": "Distributeur",
"originator": "Créateur",
"owner": "Propriétaire",
"pointOfContact": "Point de contact",
"principalInvestigator": "Analyste principal",
"processor": "Responsable du traitement",
"publisher": "Éditeur (publication)",
"resourceProvider": "Fournisseur",
"user": "Utilisateur"
}
}
},

here is my HTML:

{{ 'hello author_or_user.role' | i18next }}

{{ author_or_user.contact.name }}
{{ author_or_user.contact.addressLine1OrNull }}
{{ author_or_user.contact.cityOrNull }}, {{ author_or_user.contact.zipCodeOrNull }}
{{ author_or_user.country }}
{{ author_or_user.contact.phoneNumberOrNull }}
{{ author_or_user.contact.emailOrNull }}

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

@DevDemba Hello, i'm not sure i understand what are you trying to do and what is your problem.

from angular-i18next.

DevDemba avatar DevDemba commented on May 28, 2024

Romanchuk Hello, look at my screenshot.
In my contact block, I want to display a different role for each iteration (for each block displayed on the front) based on the filter values of my API.

I managed to translate the standard variables but not the variables where the values are random.
I would like to put interpolation variables in my json eventually in order to select a translation to apply according to the filtered role.

thanks

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

@DevDemba Did you tried to concat key and translate it?
{{ ('models.contacts.attributes.roles.' + roleVariable) | i18next }}

from angular-i18next.

DevDemba avatar DevDemba commented on May 28, 2024

@Romanchuk Yes exactly. 👍 It worked.
Thank you very much for your help.
I double-checked and I had badly concatenated.
I persist in trying to put the doubles {{ }}.

from angular-i18next.

Romanchuk avatar Romanchuk commented on May 28, 2024

You are welcome.
Closing issue

from angular-i18next.

 avatar commented on May 28, 2024

sorry I have posted quetion on wrong github repo I think my question is related to this conversation here it is can anyone please help I am trying for 4 days now . i18next/ng-i18next#149

from angular-i18next.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.