Como definir a localidade no DatePipe no Angular 2?

138

Quero exibir a Data usando o formato europeu, dd/MM/yyyymas usando o formato DatePipe shortDate , ele é exibido apenas no estilo de data dos EUA MM/dd/yyyy.
Estou assumindo que é a localidade padrão é en_US. Talvez esteja faltando nos documentos, mas como posso alterar as configurações padrão de localidade em um aplicativo Angular2? Ou talvez haja alguma maneira de passar um formato personalizado para o DatePipe?

nsbm
fonte
1
Eu também gostaria de saber disso. Eu encontrei os documentos de canal de data que explicam a ordem dos y's m 'e d's na string de formato são ignorados, pois a ordem é definida pelo código do idioma. Mas nenhuma indicação de como definir (ou até obter) o local.
precisa saber é o seguinte

Respostas:

276

No Angular2 RC6, você pode definir a localidade padrão no módulo do aplicativo, adicionando um provedor:

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

Os canais de Moeda / Data / Número devem selecionar o código do idioma. LOCALE_ID é um OpaqueToken , a ser importado do angular / core.

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

Para um caso de uso mais avançado, convém escolher a localidade de um serviço. A localidade será resolvida (uma vez) quando o componente usando o canal de datas for criado:

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

Espero que funcione para você.

corola
fonte
43
Estou surpreso que isso ainda não pareça estar documentado em lugar algum. Não na página Data Pipe ( angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html ), não na página geral de pipes ( angular.io/docs/ts/latest/guide/pipes .html ) e esta pergunta é realmente o primeiro hit no Google ( google.com/search?q=angular%202%20locales&rct=j ). Ótima descoberta.
JP ten Berge
2
Para usar um canal no código, você deve formatá-lo agora como new CurrencyPipe('en-US');. Esperemos que isso seja útil para algo que apareceu como o primeiro resultado ao pesquisar meu problema no Google.
Ash Blue
1
@corolla Você pode lançar alguma luz sobre esse serviço? Gostaria de alterar o código do idioma quando o aplicativo estiver em execução, isso é possível com esse serviço? E como eu implementaria esse serviço?
Martijn van den Bergh
1
@MartijnvandenBergh, o serviço apenas retorna a sequência de código de idioma - nada sofisticado. Tivemos resultados variados tentando alterar a localidade enquanto o aplicativo é executado. Acabou de recarregar a página para lidar com todos os casos. YMMV.
Corola #
1
Eu também lutei muito com este assunto e espero que o artigo que escrevi sobre isso pode ajudar algumas pessoas: medium.com/dailyjs/dynamic-locales-in-angular-dd9a527ebe1f
Michael Karen
72

A solução com LOCALE_ID é ótima se você deseja definir o idioma do seu aplicativo uma vez. Mas não funciona, se você deseja alterar o idioma durante o tempo de execução. Nesse caso, você pode implementar um canal de data personalizado.

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);
  }

}

Agora, se você alterar o idioma de exibição do aplicativo usando o TranslateService (consulte ngx-translate )

this.translateService.use('en');

os formatos no seu aplicativo devem ser atualizados automaticamente.

Exemplo de uso:

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

ou verifique meu projeto "Notes" simples aqui .

insira a descrição da imagem aqui

Milan Hlinák
fonte
Estou recebendo erro de análise de modelo; não é possível compilar o filtro 'localizedDate' que usei da mesma maneira sugerida.
Prasad Shinde 26/09
Você declarou LocalizedDatePipe corretamente? Veja pipe.module.ts no meu projeto de exemplo .
Milan Hlinák 27/09/17
Sim, eu resolvi isso antes, @Milan Hlinak, eu deveria ter respondido apenas no meu comentário naquele momento. De qualquer forma, obrigado pela sua pronta resposta. Você está indo bem.
Prasad Shinde
Aparentemente, isso é o que eu estava procurando. Sua vergonha a que um tubo personalizado é necessário apenas para a mudança de localidade em tempo de execução embora ..
dendimiiii
2
Funciona, mas preste atenção que o uso de tubos "impuros" é mais lento que o "puro". Como diz o guia Angular : Angular executa um tubo impuro durante cada ciclo de detecção de alterações de componentes. Um tubo impuro é chamado com frequência, com a mesma frequência de cada pressionamento de tecla ou movimento do mouse. Com essa preocupação em mente, implemente um tubo impuro com muito cuidado. Um tubo caro e de longa execução pode destruir a experiência do usuário.
Luca Ritossa #
64

Com angular5a resposta acima, não funciona mais!

O código a seguir:

app.module.ts

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

Leva ao seguinte erro:

Erro: faltam dados de localidade para a localidade "de-at".

Com angular5você, você deve carregar e registrar o arquivo de localidade usado por conta própria.

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...
  ]
})

Documentação

zgue
fonte
De fato, se você precisar usar outro local, exceto en-US, registre-o. Obrigado pela resposta, @zgue
MikkaRin
1
OK, que me impediu outra dor de cabeça .. Thx! O documento é um pouco complicado, já que eu pensei que isso registerLocaleDataera suficiente, bem, não é.
danger89
1
Melhor resposta para o Ionic 4!
parrycima 23/01
22

Se você usar TranslateServicefrom @ngx-translate/core, a seguir há uma versão sem criar um novo canal que funcione com a comutação dinâmica no tempo de execução (testado no Angular 7). Usando o localeparâmetro DatePipe ( docs ):

Primeiro, declare os códigos de idioma que você usa no seu aplicativo, por exemplo 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');
}

Em seguida, use seu pipe dinamicamente:

myComponent.component.html

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

myComponent.component.ts

 constructor(public translateService: TranslateService) { ... }
knnhcn
fonte
2
Isso é surpreendentemente bom. Você nem precisa do @ ngx-translate para isso. Você pode explicar o que a declaração do modelo faz?
lama
2
@lama, dueDate (qualquer data que você deseja formatar) | date: 'shortDate' (1º parâmetro do canal de datas correspondente a 'format') : '' (2º parâmetro => timeZone, "Quando não fornecido, usa o fuso horário do sistema local do usuário final".) : trasnlateService.currentLang (terceiro parâmetro => local), pintinho esse DatePipe
Diego Osornio
e se você tiver um formato personalizado? isso seria localizado também?
Wildhammer
12

Eu dei uma olhada no date_pipe.ts e ele tem dois bits de informação que são de interesse. próximo ao topo estão as duas linhas a seguir:

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

Perto da parte inferior está esta linha:

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

Isso sugere para mim que o canal de data está atualmente codificado para ser 'en-US'.

Por favor, me esclareça se estou errado.

Mark Farmiloe
fonte
Você pode conferir a resposta da corolla abaixo. É mais atualizado e oferece uma ótima solução.
Mark Langer
9

Em app.module.ts, adicione as seguintes importações. Há uma lista de opções LOCALE aqui .

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

Em seguida, adicione o provedor

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

Use tubos em html. Aqui está a documentação angular para isso.

{{ dateObject | date: 'medium' }}
Alejandro del Río
fonte
Justo necesitaba esto!
alexchvrches 22/07
5

Você faz algo assim:

{{ dateObj | date:'shortDate' }}

ou

{{ dateObj | date:'ddmmy' }}

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

Langley
fonte
desculpe se não estava claro na minha pergunta, mas é exatamente isso que estou fazendo, mas com o padrão 'shortDate' e mostra apenas no estilo dos EUA. O estilo da hora está bom.
Nsbm
O segundo exemplo mostra um formato sendo passado para o DatePipe, é isso que você não queria?
Langley
Tentei, mas não funciona. Mostre apenas o número '5' independentemente da data.
Nsbm
3

Eu estava lutando com o mesmo problema e não funcionou para mim usando este

{{dateObj | date:'ydM'}}

Então, tentei uma solução alternativa, não a melhor solução, mas funcionou:

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

Sempre posso criar um pipe personalizado.

hydrangenius
fonte
3

Para aqueles que têm problemas com o AOT, é necessário fazê-lo de maneira um pouco diferente com o useFactory:

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

@NgModule({
  providers: [
    { provide: LOCALE_ID, useFactory: getCulture },
    //otherProviders...
  ]
})
vidalsasoon
fonte
4
a partir de angular5, você pode usar uma expressão seta gordura na matriz provedores
iuliust
{ provide: LOCALE_ID, useFactory: () => 'fr-CA'}fiz o truque para mim;)
JoxieMedina
0

Copiado o tubo do Google mudou o código de idioma e funciona para o meu país; é possível que eles não o concluam em todos os códigos de idioma. Abaixo está o código.

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); }
}
Dživo Jelić
fonte
0

Ok, eu proponho esta solução, muito simples, usando 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);
  }

}
LizanLycan
fonte
-1

Pode ser um pouco tarde, mas no meu caso (angular 6), criei um pipe simples no topo do DatePipe, algo como isto:

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);
}

Pode não ser a melhor solução, mas simples e funciona.

Ngoc Nam Nguyen
fonte