simply-translate-angular
TypeScript icon, indicating that this package has built-in type declarations

0.30.0-pre.2 • Public • Published

Simply Translate for Angular

Simplest translations for Angular (tested for v10+).

Breaking changes

(v0.30.0-pre.1)

PRERELEASE: Not stable, may change
  • removed init method in root import
  • changed injections: instead of deps[] use Injector as first parameter of provided functions
  • changed resolver
  • standalone ready
  • added EnvironmentProviders as preferable initialization (provideTranslation)
  • changed translate directive it is now structural

(v0.20.0)

  • see plain JS library changes.
  • deprecated init method in root import. Instead use addMiddleware, loadDictionaries and final methods instead.
  • lang and fallbackLang now in the root import.
  • added middleware pipeline (see Pipeline).
  • removed $less property. Instead of $less use placeholder = 'single'.
  • added fallback property to directive.
  • defaultLang renamed to lang.
  • extend in forChild initialization changed to loadDictionaries.
  • added language detection change for directives and pipes
  • after initialization lang and fallbackLang can be changed only from TranslateRootService.
  • removed dynamic cache.

Basics

Please use link above to learn more about basic interaction, dictionaries, pluralization, cases, etc.

Install

npm i simply-translate-angular

Initialize

import { provideTranslation, withDictionary } from 'simply-translate-angular';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    provideTranslation(
      {
        lang: 'ru-RU',
        fallbackLang: 'ru-RU',
      },
      withDictionary(({ lang }, inject) => {
        const client = inject.get(HttpClient);
        return client.get(...).pipe(map((result) => ({[lang]: result})));
      })
    ),
  ],
};
Root Module
import { TranslateModule, TranslateService } from 'simply-translate-angular';

@NgModule({
  declarations: [AppComponent, AppViewComponent],
  imports: [
    TranslateModule.forRoot({
      // language
      lang: window.navigator.language,
      fallbackLang: 'ru-RU',
      // static dictionaries
      dictionaries:{'ru-RU':{...}}
      // load dictionaries
      loadDictionaries:({lang, fallbackLang}, injector) => {
        const client = injector.get(HttpClient);
        return client.get(...).pipe(map((result) => ({[lang]: result})));
      }
    })
  ]
});

See Load dictionaries

Use Directive

<!-- use default language -->
<h2 *translate="'hello_user'; values:{ user: 'Oleg' }; let result = value;">{{ result }}</h2>
<!-- use other language -->
<h2 *translate="'hello_user'; to:'ru-RU';values:{ user: 'Oleg' }; let result = value">{{ result }}</h2>
<!-- use fallback -->
<h2 *translate="'hello_user_not_there'; values:{ user: 'Oleg' }; fallback:'Hello user'; let result = value">{{ result }}</h2>

Directives will detect dynamic language change by default. Use [detect] property to disable it.

<h2 *translate="'hello_user'; values:{ user: 'Oleg' }; detect:false; let result = value;">{{ result }}</h2>

Directive can use inner text as a fallback.

Use Pipe

<h2>{{ 'hello_user' | translate: { user: 'Oleg' } }}</h2>
<!-- use other language -->
<h2>{{ 'hello_user' | translateTo: 'ru-RU': { user: 'Oleg' } }}</h2>
<!-- use fallback -->
<h2>{{ 'hello_user_not_there' | translate: { user: 'Oleg' } : 'Hello ${user}'}}</h2>

Pipes are pure by default. However if application has dynamic language change you may use special impure directive (it has internal dirty check), it will detect language changes as well as pipe parameters.

<h2>{{ 'hello_user' | translate$: { user: 'Oleg' } }}</h2>

Use Service

@Component({
    ...
})
export class Component {
    hello: string;
    constructor(private translate: TranslateService) {
        // use default language
        this.hello = translate.translate('hello_user', { user: 'Oleg' })
        // use other language
        this.hello = translate.translateTo('ru-RU','hello_user', { user: 'Oleg' })
        // use fallback
        this.hello = translate.translateTo('ru-RU','hello_user_not_there', { user: 'Oleg' }, 'Hello ${user}')
    }
}

To change language use TranslateRootService lang property.
To detect changes subscribe on languageChange$ and dictionaryChange$. Note that loadDictionaries method in root settings will not execute when language changes.

export class Component {
  constructor(private rootTranslate: TranslateRootService) {
    rootTranslate.lang = 'en-US';
  }
}

Load dictionaries

You can use loader helper.

function getDictionary(lang: string, client: HttpClient) {
  return client.get<Dictionary>(`/assets/translations/${lang}.json`);
}

Provider

You can use withDictionary feature to fetch dictionaries.

import { provideTranslation, withDictionary } from 'simply-translate-angular';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    provideTranslation(
      {
        lang: 'ru-RU',
        fallbackLang: 'en-US',
      },
      withDictionary(({ langm fallbackLang }, inject) => {
        const client = inject.get(HttpClient);
        return forkJoin([getDictionary(lang, client), getDictionary(fallbackLang, client)]).pipe(
          map(([current, fallback]) => {
            return { [lang]: current, [fallbackLang]: fallback };
          })
        );
      })
    ),
  ],
};

Or split into two withDictionary

      withDictionary(({ fallbackLang }, inject) => {
        const client = inject.get(HttpClient);
        return getDictionary(fallbackLang, client).pipe(
          map((fallback) => {
            return { [fallbackLang]: fallback };
          })
        );
      }),
      withDictionary(({ lang }, inject) => {
        const client = inject.get(HttpClient);
        return getDictionary(lang, client).pipe(
          map((dictionary) => {
            return { [lang]: dictionary };
          })
        );
      }),
Root Module

forRoot initialization allows you to fetch dictionaries with its loadDictionaries field. It returns Observable that contains set of dictionaries

import { TranslateModule } from 'simply-translate-angular';

@NgModule({
  declarations: [...],
  imports: [
    ...
    TranslateModule.forRoot({
      lang: window.navigator.language,
      fallbackLang: 'ru-RU',

      loadDictionaries: ({lang, fallbackLang}, injector) => {
        const client = injector.get(HttpClient)
        const res$ = forkJoin([getDictionary(lang, client), getDictionary(fbLang, client)]).pipe(
          map((res) => {
            return { [lang]: res[0], fbLang: res[1] };
          })
        );

        return res$;
      },
    }),
    ...
  ],
  ...
})

Note: it is might be useful to hardcode fallback dictionary in .ts or .json file then import it rather then use http client to download.

import fallback from './translations/fallback';
provideTranslation(
      {
        lang: 'en-US',
        fallbackLang: 'en-US',
      },
      withDictionary(({ fallbackLang }) => fallback),
      withDictionary(/* Regular load*/)
    ),
Root Module
TranslateModule.forRoot({
  ...
  fallbackLang: env.fallbackLanguage,
  dictionaries: {
    [env.fallbackLanguage]: fallback,
  },
  loadDictionaries: /* Regular load */
  ...
})

Lazy

Load dictionaries for Lazy modules or components things become a little more complicated. To add synchronous dictionaries it is the same as for Root

import { extendTranslation } from 'simply-translate-angular';
@Component({
  standalone: true,
  providers:[
    ...extendTranslation(withDictionaryExtend(({ lang }) => (...)),
  ],
  template: `...`,
})
export class DynamicComponent {
  constructor() {}
}
Child Module
@NgModule({
  declarations: [...],
  imports: [
    TranslateModule.forChild({
      deps: [ HttpClient ],
      dictionaries: ({ lang }) => (...),
    ...
    })
  ]
})
export class DynamicModule {}

But to Asynchronously load dictionaries you would need to use translateResolve.
Do not forget to provide service for lazy routes with extendTranslation in providers of route

export const routes: Routes = [
  {
    path: '...',
    loadComponent: () => import('./dynamic/dynamic.component').then((m) => m.DynamicComponent),
    resolve: translateResolve(
      withDictionary(({ lang }, inject) => {
        const client = inject.get(HttpClient);
        return getDictionary(lang, client).pipe(
          map((current) => {
            return { [lang]: current };
          })
        );
      }),
    ),
    providers: [
      ...extendTranslation()
    ]
  }

For rare cases you may use id parameter for sub modules or components, that allows having different values with same key.
Unique values will be available only for modules with that special id and for that special id.

import { extendTranslation } from 'simply-translate-angular';
@Component({
  standalone: true,
  providers: [...extendTranslation(withIdentifier('my unique id'))],
  template: `...`,
})
export class DynamicComponent {
  constructor() {}
}
Child Module
@NgModule({
  declarations: [...],
  imports: [
    TranslateModule.forChild({
      id: 'my unique id'
      dictionaries: ({ lang }) => ({[lang]:{
        'key':'Value for Lazy'
      }})
    })
  ]
})

Pipeline

Currently it is possible to append middleware to the end of translation pipeline.
It might be specially useful to add logger or rarely fine-tune translation result.

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(),
    provideTranslation(...,
      withMiddleware(()=>
        (injector) => {
          const logger = injector.get(Logger)
          return [
             ({params, result}) => {
               if (result.fallingBack) {
                 logger.log(`Translation absent [${params.lang}:${params.key}]`);
               }
             },
           ];
         },
      )
    ),
  ],
};
Root Module
@NgModule({
  declarations: [...],
  imports: [
    ...
    TranslateModule.forRoot({
      addMiddleware: (injector) => {
        const logger = injector.get(Logger);
        return [
          ({params, result}) => {
            if (result.fallingBack) {
              logger.log(`Translation absent [${params.lang}:${params.key}]`);
            }
          },
        ];
      },
    }),
    ...
  ],
  ...
})

Package Sidebar

Install

npm i simply-translate-angular

Weekly Downloads

27

Version

0.30.0-pre.2

License

MIT

Unpacked Size

178 kB

Total Files

28

Last publish

Collaborators

  • oleg.wx