How to set locale in DatePipe in Angular 2?
Asked Answered
G

15

180

I want to display Date using European format dd/MM/yyyy but using DatePipe shortDate format it only display using US date style MM/dd/yyyy.
I'm assuming thats the default locale is en_US. Maybe I am missing in the docs but how can I change the default locale settings in an Angular2 app? Or maybe is there some way to pass a custom format to DatePipe ?

Gook answered 20/1, 2016 at 15:57 Comment(1)
I'd like to know this too. I've found the date pipe docs which explains the order of the y's m' and d's in the format string are ignored as the order is set by the locale. But no indication of how to set (or even get) the locale.Gunter
S
317

As of Angular2 RC6, you can set default locale in your app module, by adding a provider:

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "en-US" }, //replace "en-US" with your locale
    //otherProviders...
  ]
})

The Currency/Date/Number pipes should pick up the locale. LOCALE_ID is an OpaqueToken, to be imported from angular/core.

import { LOCALE_ID } from '@angular/core';

For a more advanced use case, you may want to pick up locale from a service. Locale will be resolved (once) when component using date pipe is created:

{
  provide: LOCALE_ID,
  deps: [SettingsService],      //some service handling global settings
  useFactory: (settingsService) => settingsService.getLanguage()  //returns locale string
}

Hope it works for you.

Sundaysundberg answered 6/9, 2016 at 9:3 Comment(17)
I'm amazed this still doesn't appear to be documented anywhere. Not on the Date Pipe page (angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html), not on the general pipes page (angular.io/docs/ts/latest/guide/pipes.html) and this question is actually the first hit on Google (google.com/search?q=angular%202%20locales&rct=j). Great find.Knighthood
Also: Setting this locale doesn't seem to affect the currency pipe (Angular 2.0 final).Knighthood
Does this also mean we can use an HTTP request to get the locale? Not entirely sure how that works.Polypetalous
@Hyperd, yeah, check out the APP_INITIALIZER approach from the following answer - you'd have a chance to resolve locale before app initializes: https://mcmap.net/q/49256/-how-to-pass-parameters-rendered-from-backend-to-angular2-bootstrap-methodSundaysundberg
To use a pipe in code you must now format it as new CurrencyPipe('en-US');. Hopefully this is useful for something as this showed up as the first result when Googling my issue.Christman
@corolla, seems like LOCALE_ID provider gets called before APP_INITIALIZER (weird!) so you can't really reach your service.Covell
I use this simple factory function without creating a SettingsService: () => navigator.languageArchaism
@Sundaysundberg Can u shed some light on that service? I would like to change the locale when the app is running, is that possible with that service? And how would i implement such service?Krasnodar
@MartijnvandenBergh, the service just returns locale string - nothing fancy. We've had mixed results trying to change locale while app runs. Ended up reloading page to handle all cases. YMMV.Sundaysundberg
@J.P.tenBerge as of now, there is one reference here angular.io/guide/i18nBeeler
I also struggled a lot with this subject and I hope the article I wrote about this can help some people: medium.com/dailyjs/dynamic-locales-in-angular-dd9a527ebe1fOmniscient
@MichaelKarén ugh, that website has the most obnoxious popup on the internet, I was unable to reach the article before closing the browser tabFaggot
@Faggot Yes, I know. Going to move away from it soon.Omniscient
@Sundaysundberg it says Parameter 'settingsService' implicitly has an 'any' type , ErrorAurelioaurelius
In my case the factory is only called once. :( { provide: LOCALE_ID, useFactory: (translate: TranslateService) => {return translate.currentLang; }, deps: [TranslateService] } (ngx-translate). And the currentLang is undefined because set a little bit later. (init order). Why is the factory only called once? How to set LOCALE_ID dynamically?Chore
@Dominik check this answer to change language on runtimeEryneryngo
Before spend some hours in this...finally get it and its thanks to you @corolla. GGWP!!Agle
C
93

Solution with LOCALE_ID is great if you want to set the language for your app once. But it doesn’t work, if you want to change the language during runtime. For this case you can implement custom date pipe.

import { DatePipe } from '@angular/common';
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Pipe({
  name: 'localizedDate',
  pure: false
})
export class LocalizedDatePipe implements PipeTransform {

  constructor(private translateService: TranslateService) {
  }

  transform(value: any, pattern: string = 'mediumDate'): any {
    const datePipe: DatePipe = new DatePipe(this.translateService.currentLang);
    return datePipe.transform(value, pattern);
  }

}

Now if you change the app display language using TranslateService (see ngx-translate)

this.translateService.use('en');

the formats within your app should automatically being updated.

Example of use:

<p>{{ 'note.created-at' | translate:{date: note.createdAt | localizedDate} }}</p>
<p>{{ 'note.updated-at' | translate:{date: note.updatedAt | localizedDate:'fullDate'} }}</p>

or check my simple "Notes" project here.

enter image description here

Cybill answered 10/8, 2017 at 22:34 Comment(8)
I am getting template parse error; can't compile filter 'localizedDate' I used with the same way as suggested.Gluten
Have you declared LocalizedDatePipe correctly? See pipe.module.ts in my example project.Magaretmagas
Yes, I have solved it earlier, @Milan Hlinak I should have answered on my comment at that time only. But anyways thanks for your prompt response. You're doing great.Gluten
This is apparently what i was looking for. Its a shame that a custom pipe is required to just change Locale at runtime though..Teapot
It works but pay attention that use an "impure" pipes is slower than the "pure". As Angular guide says: Angular executes an impure pipe during every component change detection cycle. An impure pipe is called often, as often as every keystroke or mouse-move. With that concern in mind, implement an impure pipe with great care. An expensive, long-running pipe could destroy the user experience.Divaricate
Hi @LucaRitossa, thanks for comment. I have not found another way to do it. If you have some tip, please post it. :) +1 btwMagaretmagas
Check my answer for changing language on runtime without creating custom pipe.Debbi
Why was the pipe made impure?Giannagianni
V
92

With angular5 the above answer no longer works!

The following code:

app.module.ts

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "de-at" }, //replace "de-at" with your locale
    //otherProviders...
  ]
})

Leads to following error:

Error: Missing locale data for the locale "de-at".

With angular5 you have to load and register the used locale file on your own.

app.module.ts

import { NgModule, LOCALE_ID } from '@angular/core';
import { registerLocaleData } from '@angular/common';
import localeDeAt from '@angular/common/locales/de-at';

registerLocaleData(localeDeAt);

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "de-at" }, //replace "de-at" with your locale
    //otherProviders...
  ]
})

Documentation

Vichy answered 23/1, 2018 at 19:51 Comment(4)
Indeed if you need to use some other locale except en-US, you should register it. Thanks for answer, @VichyCyclostyle
OK that prevented me another headache.. Thx! The doc is a bit complicated, since I though that registerLocaleData was enough, well its not.Heady
Best Answer for Ionic 4!Hols
That worked, but now the million dollar question is why does Angular force locale to be en-US instead of using Chrome or OS locale?Puerperium
D
59

If you use TranslateService from @ngx-translate/core, below is a version without creating a new pipe which works with switching dynamically on runtime (tested on Angular 7). Using DatePipe's locale parameter (docs):

First, declare the locales you use in your app, e.g. in app.component.ts:

import localeIt from '@angular/common/locales/it';
import localeEnGb from '@angular/common/locales/en-GB';
.
.
.
ngOnInit() {
    registerLocaleData(localeIt, 'it-IT');
    registerLocaleData(localeEnGb, 'en-GB');
}

Then, use your pipe dynamically:

myComponent.component.html

<span>{{ dueDate | date: 'shortDate' : '' : translateService.currentLang }}</span>

myComponent.component.ts

 constructor(public translateService: TranslateService) { ... }
Debbi answered 21/2, 2019 at 9:5 Comment(7)
This is surprisingly nice. You don't even need @ngx-translate for that. Can you explain what the statement in the template does though?Rhodic
@lama, dueDate (any date you want to format) | date: 'shortDate' (1st parameter for date pipe corresponding to 'format') : '' (2nd parameter => timeZone, "When not supplied, uses the end-user's local system timezone".) : trasnlateService.currentLang (3rd parameter => local), chick this DatePipeEryneryngo
what if you have customized format? would that be localized too?Liftoff
One drawback is that you need to make the translateService public so it's accessible by the template...Stan
Why exactly do you think that this is a drawback? I am interested and would like to know ;)Debbi
Best solution in my opinion, but works perfecly fine without @ngx-translate and TranslateService in my case.Torque
Thanks, it works great for me with a little change in the pipe syntax: date: 'shortDate' : '' : translateService.currentLang ==> date: 'shortDate' : undefined : translateService.currentLangSororicide
I
18

On app.module.ts add the following imports. There is a list of LOCALE options here.

import es from '@angular/common/locales/es';
import { registerLocaleData } from '@angular/common';
registerLocaleData(es);

Then add the provider

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "es-ES" }, //your locale
  ]
})

Use pipes in html. Here is the angular documentation for this.

{{ dateObject | date: 'medium' }}
Incrustation answered 1/10, 2018 at 14:57 Comment(3)
Justo necesitaba esto!Joktan
I couldn't find the list under your link, but here is another good list: iteration.info/Sharing/AllAngular5Locales.rtf (taken from here: https://mcmap.net/q/88891/-locales-in-angular-5)Torque
This should be accepted answerGiorgi
G
12

I've had a look in date_pipe.ts and it has two bits of info which are of interest. near the top are the following two lines:

// TODO: move to a global configurable location along with other i18n components.
var defaultLocale: string = 'en-US';

Near the bottom is this line:

return DateFormatter.format(value, defaultLocale, pattern);

This suggests to me that the date pipe is currently hard-coded to be 'en-US'.

Please enlighten me if I am wrong.

Gunter answered 26/1, 2016 at 16:20 Comment(2)
github.com/angular/angular/blob/master/modules/@angular/common/…Recusancy
You might want to check out corolla's answer below. It's more up to date and provides a great solution.Boanerges
R
5

Starting from Angular 9 localization process changed. Check out official doc.

Follow the steps below:

  1. Add localization package if it's not there yet: ng add @angular/localize
  2. As it's said in docs:

The Angular repository includes common locales. You can change your app's source locale for the build by setting the source locale in the sourceLocale field of your app's workspace configuration file (angular.json). The build process (described in Merge translations into the app in this guide) uses your app's angular.json file to automatically set the LOCALE_ID token and load the locale data.

so set locale in angular.json like this (list of available locales can be found here):

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "test-app": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "i18n": {
        "sourceLocale": "es"
      },
      ....
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          ...
          "configurations": {
            "production": {
             ...
            },
            "ru": {
              "localize": ["ru"]
            },
            "es": {
              "localize": ["es"]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "test-app:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "test-app:build:production"
            },
            "ru":{
              "browserTarget": "test-app:build:ru"
            },
            "es": {
              "browserTarget": "test-app:build:es"
            }
          }
        },
        ...
      }
    },
    ...
  "defaultProject": "test-app"
}

Basically you need to define sourceLocale in i18n section and add build configuration with specific locale like "localize": ["es"]. Optionally you can add it so serve section

  1. Build app with specific locale using build or serve: ng serve --configuration=es
Repudiation answered 19/8, 2020 at 7:0 Comment(1)
As always, you get a much more concise and clear explanation in StackOverflow than Angular official documentation.Edmundoedmunds
R
4

You do something like this:

{{ dateObj | date:'shortDate' }}

or

{{ dateObj | date:'ddmmy' }}

See: https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html

Ribeiro answered 20/1, 2016 at 15:59 Comment(3)
sorry if it wasnt clear in my question but this is exactly what im doing but with pattern 'shortDate' and it shows only in US style. The time style is fine.Gook
The second example shows a format getting passed to the DatePipe, that's what you wanted no?Ribeiro
Tried but it doesnt work. Show just the number '5' independently of the date.Gook
I
4

I was struggling with the same issue and didn't work for me using this

{{dateObj | date:'ydM'}}

So, I've tried a workaround, not the best solution but it worked:

{{dateObj | date:'d'}}/{{dateObj | date:'M'}}/{{dateObj | date:'y'}}

I can always create a custom pipe.

Incongruity answered 20/2, 2016 at 18:38 Comment(0)
M
4

For those having problems with AOT, you need to do it a little differently with a useFactory:

export function getCulture() {
    return 'fr-CA';
}

@NgModule({
  providers: [
    { provide: LOCALE_ID, useFactory: getCulture },
    //otherProviders...
  ]
})
Minerva answered 17/10, 2017 at 14:6 Comment(2)
as of angular5, you can use a fat arrow expression in the providers arrayAdin
{ provide: LOCALE_ID, useFactory: () => 'fr-CA'} did the trick for me ;)Konstanz
V
3

Above answers are certainly correct. Note that is is also possible to pass the locale with the pipe:

  {{ now | date: undefined:undefined:'de-DE' }}

(The 2 first parameters being date format and timezone, leave them undefined if you are great with the defaults)

Not something you want to do for all your pipes, but sometimes it can be handy.

Ventilate answered 27/1, 2022 at 15:50 Comment(0)
G
3

Using Pipes and No other installations.

LocalizedDatePipe.ts

import { Pipe, PipeTransform } from '@angular/core';
import { Locale } from 'src/app/contentful/interfaces/locale';

@Pipe({
  name: 'localizedDate',
})
export class LocalizedDatePipe implements PipeTransform {
  transform(value: any, locale: any): any {
    const date = new Date(value);
    const options: Intl.DateTimeFormatOptions = {
      month: 'short',
      day: 'numeric',
      year: 'numeric',
    };
    return date.toLocaleDateString(locale, options);
  }
}

Search-overlay.component.html

<span *ngIf="card.date" class="hero-cards-carousel__date">
 {{ card.date | localizedDate: vm.locale?.code }}
 </span>

Result

"20. Dez. 2012"

Grisham answered 31/1, 2023 at 11:10 Comment(0)
T
0

Copied the google pipe changed the locale and it works for my country it is posible they didnt finish it for all locales. Below is the code.

import {
    isDate,
    isNumber,
    isPresent,
    Date,
    DateWrapper,
    CONST,
    isBlank,
    FunctionWrapper
} from 'angular2/src/facade/lang';
import {DateFormatter} from 'angular2/src/facade/intl';
import {PipeTransform, WrappedValue, Pipe, Injectable} from 'angular2/core';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';


var defaultLocale: string = 'hr';

@CONST()
@Pipe({ name: 'mydate', pure: true })
@Injectable()
export class DatetimeTempPipe implements PipeTransform {
    /** @internal */
    static _ALIASES: { [key: string]: String } = {
        'medium': 'yMMMdjms',
        'short': 'yMdjm',
        'fullDate': 'yMMMMEEEEd',
        'longDate': 'yMMMMd',
        'mediumDate': 'yMMMd',
        'shortDate': 'yMd',
        'mediumTime': 'jms',
        'shortTime': 'jm'
    };


    transform(value: any, args: any[]): string {
        if (isBlank(value)) return null;

        if (!this.supports(value)) {
            console.log("DOES NOT SUPPORT THIS DUEYE ERROR");
        }

        var pattern: string = isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
        if (isNumber(value)) {
            value = DateWrapper.fromMillis(value);
        }
        if (StringMapWrapper.contains(DatetimeTempPipe._ALIASES, pattern)) {
            pattern = <string>StringMapWrapper.get(DatetimeTempPipe._ALIASES, pattern);
        }
        return DateFormatter.format(value, defaultLocale, pattern);
    }

    supports(obj: any): boolean { return isDate(obj) || isNumber(obj); }
}
Twoup answered 18/4, 2016 at 20:30 Comment(0)
D
0

Ok, I propose this solution, very simple, using ngx-translate

import { DatePipe } from '@angular/common';
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Pipe({
  name: 'localizedDate',
  pure: false
})
export class LocalizedDatePipe implements PipeTransform {

  constructor(private translateService: TranslateService) {
}

  transform(value: any): any {
    const date = new Date(value);

    const options = { weekday: 'long',
                  year: 'numeric',
                  month: 'long',
                  day: 'numeric',
                  hour: '2-digit',
                  minute: '2-digit',
                  second: '2-digit'
                    };

    return date.toLocaleString(this.translateService.currentLang, options);
  }

}
Discussant answered 22/1, 2018 at 1:53 Comment(0)
S
-1

This might be a little bit late, but in my case (angular 6), I created a simple pipe on top of DatePipe, something like this:

private _regionSub: Subscription;
private _localeId: string;

constructor(private _datePipe: DatePipe, private _store: Store<any>) {
  this._localeId = 'en-AU';
  this._regionSub = this._store.pipe(select(selectLocaleId))
    .subscribe((localeId: string) => {
      this._localeId = localeId || 'en-AU';
    });
}

ngOnDestroy() { // Unsubscribe }

transform(value: string | number, format?: string): string {
  const dateFormat = format || getLocaleDateFormat(this._localeId, FormatWidth.Short);
  return this._datePipe.transform(value, dateFormat, undefined, this._localeId);
}

May not be the best solution, but simple and works.

Stomachache answered 20/6, 2018 at 1:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.