Skip to content

Commit

Permalink
Feat: add L10nTimeAgo pipe & directive
Browse files Browse the repository at this point in the history
  • Loading branch information
robisim74 committed Jun 13, 2019
1 parent 9c550bf commit 5552abe
Show file tree
Hide file tree
Showing 13 changed files with 399 additions and 19 deletions.
41 changes: 30 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion src/angular-l10n.ts
@@ -1,7 +1,7 @@
export { InjectorRef } from './models/injector-ref';
export { Logger } from './models/logger';
export { Caching } from './models/caching';
export { StorageStrategy, ProviderType, ISOCode, DateTimeOptions, DigitsOptions, LogLevel } from './models/types';
export { StorageStrategy, ProviderType, ISOCode, DateTimeOptions, DigitsOptions, RelativeTimeOptions, LogLevel } from './models/types';
export { L10N_CONFIG, L10nConfigRef, L10nConfig, l10nConfigFactory, Token } from './models/l10n-config';
export { LocalizedRouting } from './models/localized-routing';
export { L10nLoader, LocaleLoader, TranslationLoader, LocalizedRoutingLoader } from './services/l10n-loader';
Expand All @@ -27,6 +27,7 @@ export {
L10nPercentPipe,
L10nCurrencyPipe
} from './pipes/l10n-number.pipe';
export { L10nTimeAgoPipe } from './pipes/l10n-time-ago.pipe';
export { BaseDirective } from './models/base-directive';
export { TranslateDirective } from './directives/translate.directive';
export { L10nDateDirective } from './directives/l10n-date.directive';
Expand All @@ -39,9 +40,11 @@ export {
L10nNumberValidatorDirective,
l10nValidateNumber
} from './directives/l10n-number-validator.directive';
export { L10nTimeAgoDirective } from './directives/l10n-time-ago.directive';
export { L10nJsonLdComponent } from './components/l10n-json-ld.component';
export { TranslationModule, provideRoot, provideChild } from './modules/translation.module';
export { LocalizationModule } from './modules/localization.module';
export { LocalizationExtraModule } from './modules/localization-extra.module';
export { LocaleValidationModule } from './modules/locale-validation.module';
export { CollatorModule } from './modules/collator.module';
export { LocaleSeoModule } from './modules/locale-seo.module';
Expand Down
53 changes: 53 additions & 0 deletions src/directives/l10n-time-ago.directive.ts
@@ -0,0 +1,53 @@
import { Directive, ElementRef, Input, Renderer2 } from '@angular/core';
import { takeUntil } from 'rxjs/operators';

import { LocaleService } from '../services/locale.service';
import { BaseDirective } from '../models/base-directive';
import { RelativeTimeOptions, Unit } from '../models/types';

@Directive({
selector: '[l10nTimeAgo]'
})
export class L10nTimeAgoDirective extends BaseDirective {

@Input() set l10nTimeAgo(format: RelativeTimeOptions) {
this.format = format;
}

@Input() public unit: Unit;

@Input() public format: RelativeTimeOptions;

constructor(protected locale: LocaleService, protected el: ElementRef, protected renderer: Renderer2) {
super(el, renderer);
}

protected setup(): void {
this.replace();
this.locale.defaultLocaleChanged.pipe(takeUntil(this.destroy)).subscribe(
() => { this.replace(); }
);
}

protected replace(): void {
this.replaceText();
this.replaceAttributes();
}

protected replaceText(): void {
if (!!this.key) {
this.setText(this.getValue(this.key));
}
}

protected replaceAttributes(): void {
if (this.attributes.length > 0) {
this.setAttributes(this.getAttributesData());
}
}

protected getValue(key: string): string {
return this.locale.formatRelativeTime(key, this.unit, this.format);
}

}
21 changes: 20 additions & 1 deletion src/models/intl-formatter.ts
Expand Up @@ -5,7 +5,9 @@ import {
DateTimeOptions,
ISO8601_DATE_REGEX,
FORMAT_ALIASES,
NUMBER_FORMAT_REGEXP
NUMBER_FORMAT_REGEXP,
RelativeTimeOptions,
Unit
} from './types';
import { Logger } from './logger';

Expand Down Expand Up @@ -53,6 +55,14 @@ export class IntlFormatter {
return IntlFormatter.dateTimeFormatter(date, defaultLocale, format, timezone);
}

public static formatRelativeTime(value: any, unit: Unit, defaultLocale: string, format?: RelativeTimeOptions): string {
if (!IntlAPI.hasRelativeTimeFormat()) return value + " " + unit;

value = typeof value === "string" && !isNaN(+value - parseFloat(value)) ? +value : value;

return IntlFormatter.relativeTimeFormatter(value, unit, defaultLocale, format);
}

private static numberFormatter(
num: number,
defaultLocale: string,
Expand Down Expand Up @@ -102,6 +112,15 @@ export class IntlFormatter {
return new Intl.DateTimeFormat(defaultLocale, options).format(date).replace(/[\u200e\u200f]/g, "");
}

private static relativeTimeFormatter(value: number, unit: Unit, defaultLocale: string, format?: RelativeTimeOptions): string {
let options: any = {};
if (format) {
options = format;
}

return new Intl.RelativeTimeFormat(defaultLocale, options).format(value, unit);
}

private static isDate(value: any): value is Date {
return value instanceof Date && !isNaN(value.valueOf());
}
Expand Down
11 changes: 10 additions & 1 deletion src/models/types.ts
@@ -1,4 +1,4 @@
export type Type<T> = new(...args: any[]) => T;
export type Type<T> = new (...args: any[]) => T;

export interface DateTimeOptions {

Expand Down Expand Up @@ -26,6 +26,15 @@ export interface DigitsOptions {

}

export interface RelativeTimeOptions {

numeric?: string;
style?: string;

}

export type Unit = 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second';

export interface Locale {
/**
* ISO 639 two-letter or three-letter code.
Expand Down
19 changes: 19 additions & 0 deletions src/modules/localization-extra.module.ts
@@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';

import { L10nTimeAgoPipe } from '../pipes/l10n-time-ago.pipe';
import { L10nTimeAgoDirective } from '../directives/l10n-time-ago.directive';

/**
* Provides extra pipes & directives.
*/
@NgModule({
declarations: [
L10nTimeAgoPipe,
L10nTimeAgoDirective
],
exports: [
L10nTimeAgoPipe,
L10nTimeAgoDirective
]
})
export class LocalizationExtraModule { }
27 changes: 27 additions & 0 deletions src/pipes/l10n-time-ago.pipe.ts
@@ -0,0 +1,27 @@
import { Pipe, PipeTransform } from '@angular/core';

import { LocaleService } from '../services/locale.service';
import { RelativeTimeOptions, Unit } from '../models/types';
import { Logger } from '../models/logger';

@Pipe({
name: 'l10nTimeAgo',
pure: true
})
export class L10nTimeAgoPipe implements PipeTransform {

constructor(protected locale: LocaleService) { }

public transform(
value: any,
defaultLocale: string,
unit: Unit,
format?: RelativeTimeOptions
): string | null {
if (value == null || value === "" || value !== value) return null;
if (typeof defaultLocale === "undefined") Logger.log('L10nTimeAgoPipe', 'missingDefaultLocale');

return this.locale.formatRelativeTime(value, unit, format, defaultLocale);
}

}
10 changes: 7 additions & 3 deletions src/services/intl-api.ts
Expand Up @@ -9,7 +9,7 @@ export class IntlAPI {
}

public static hasDateTimeFormat(): boolean {
return IntlAPI.hasIntl() && Intl.hasOwnProperty("DateTimeFormat");
return IntlAPI.hasIntl() && Intl.hasOwnProperty("DateTimeFormat");
}

public static hasTimezone(): boolean {
Expand All @@ -25,11 +25,15 @@ export class IntlAPI {
}

public static hasNumberFormat(): boolean {
return IntlAPI.hasIntl() && Intl.hasOwnProperty("NumberFormat");
return IntlAPI.hasIntl() && Intl.hasOwnProperty("NumberFormat");
}

public static hasCollator(): boolean {
return IntlAPI.hasIntl() && Intl.hasOwnProperty("Collator");
return IntlAPI.hasIntl() && Intl.hasOwnProperty("Collator");
}

public static hasRelativeTimeFormat(): boolean {
return IntlAPI.hasIntl() && Intl.hasOwnProperty("RelativeTimeFormat");
}

}

0 comments on commit 5552abe

Please sign in to comment.