Skip to content

Commit

Permalink
feat: calendar internationalization (#786)
Browse files Browse the repository at this point in the history
* started i18n

* fixed circular dependency

* added documentation

* made 0 = sunday
  • Loading branch information
MattL75 committed May 9, 2019
1 parent 918b388 commit b7d47de
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,21 @@ <h2>Range Selection Calendar</h2>
</component-example>
<code-example [code]="calendarRangeSource" [language]="'typescript'"></code-example>

<separator></separator>
<h2>Monday Start Calendar</h2>
<description>Use the <code>startingDayOfWeek</code> input to change the order in which the days of the week appear. 1 is Monday, 2 is Tuesday, etc.</description>
<description>Use the <code>startingDayOfWeek</code> input to change the order in which the days of the week appear. 0 is for Sunday, 1 is Monday, 2 is Tuesday, etc.</description>
<component-example [name]="'ex3'">
<fd-calendar-monday-start-example></fd-calendar-monday-start-example>
</component-example>
<code-example [code]="calendarMondayStartSource" [language]="'typescript'"></code-example>

<separator></separator>
<h2>Internationalization</h2>
<description>
The calendar uses a custom service called CalendarI18n to populate the month names, week days, etc.
It also uses a separate service called CalendarI18nLabels to populate aria labels in the component itself.
</description>
<component-example [name]="'ex4'">
<fd-calendar-i18n-example></fd-calendar-i18n-example>
</component-example>
<code-example [code]="calendari18nTs" [language]="'typescript'"></code-example>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Component, OnInit } from '@angular/core';
import * as calendarRangeSrc from '!raw-loader!./examples/calendar-range-example.component.ts';
import * as calendarSingleSrc from '!raw-loader!./examples/calendar-single-example.component.ts';
import * as calendarMondayStartSrc from '!raw-loader!./examples/calendar-monday-start-example.component.ts';
import * as calendarIntlSrc from '!raw-loader!./examples/calendar-i18n-example.component.ts';

@Component({
selector: 'app-calendar',
Expand All @@ -13,6 +14,7 @@ export class CalendarDocsComponent implements OnInit {
calendarSingleSource = calendarSingleSrc;
calendarRangeSource = calendarRangeSrc;
calendarMondayStartSource = calendarMondayStartSrc;
calendari18nTs = calendarIntlSrc;

exampleFunctionsHtml = `Example Disable and Block Functions:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { CalendarI18n } from '../../../../../../library/src/lib/calendar/i18n/calendar-i18n';
import { Component, Injectable } from '@angular/core';
import { CalendarI18nLabels } from '../../../../../../library/src/lib/calendar/i18n/calendar-i18n-labels';

const localized_values = {
'fr': {
weekdays: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
months: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Aou', 'Sep', 'Oct', 'Nov', 'Déc'],
fullMonths: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet',
'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
}
};

@Injectable()
export class CustomCalendarI18n extends CalendarI18n {

// You could also define a custom service and inject it here
language: string = 'fr';

getDayAriaLabel(date: Date): string {
return date.getDate() + ' ' + localized_values[this.language].fullMonths[date.getMonth()] + ' ' + date.getFullYear();
}
getAllFullMonthNames(): string[] {
return localized_values[this.language].fullMonths;
}

getAllShortMonthNames(): string[] {
return localized_values[this.language].months;
}

getAllShortWeekdays(): string[] {
return localized_values[this.language].weekdays;
}
}

// Aria labels i18n
@Injectable()
export class CustomI18nLabels extends CalendarI18nLabels {

yearSelectionLabel: string = 'Sélection de l\'année';

previousYearLabel: string = 'Année précédente';

nextYearLabel: string = 'Année suivante';

monthSelectionLabel: string = 'Sélection du mois';

previousMonthLabel: string = 'Mois précédent';

nextMonthLabel: string = 'Mois suivant';
}

@Component({
selector: 'fd-calendar-i18n-example',
template: `<fd-calendar [(ngModel)]="selectedDay"></fd-calendar>`,

// Note that this can be provided in the root of your application.
providers: [
{
provide: CalendarI18n,
useClass: CustomCalendarI18n
},
{
provide: CalendarI18nLabels,
useClass: CustomI18nLabels
}
]
})
export class CalendarI18nExampleComponent {
selectedDay = {
date: new Date()
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,17 @@ <h2>Simple Date Picker</h2>
<code-example [code]="datePickerSingleJs" [language]="'typescript'"></code-example>

<separator></separator>

<h2>Range Date Picker</h2>
<description>Allows the selection of a range of dates. Only the first and last dates are passed back under ngModel.</description>
<component-example [name]="'ex2'">
<fd-date-picker-range-example></fd-date-picker-range-example>
</component-example>
<code-example [code]="datePickerRangeJs" [language]="'typescript'"></code-example>

<separator></separator>
<h2>Internationalization</h2>
<description>It is possible to internationalize both the aria labels and the month names/weekdays through providing a service.</description>
<component-example [name]="'ex3'">
<fd-datepicker-i18n-example></fd-datepicker-i18n-example>
</component-example>
<code-example [code]="datePickerI18NTs" [language]="'typescript'"></code-example>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component } from '@angular/core';

import * as datePickerRangeSrc from '!raw-loader!./examples/date-picker-range-example.component.ts';
import * as datePickerSingleSrc from '!raw-loader!./examples/date-picker-single-example.component.ts';
import * as datePickeri18nSrc from '!raw-loader!./examples/date-picker-i18n-example.component.ts';

@Component({
selector: 'app-date-picker',
Expand All @@ -11,5 +12,5 @@ export class DatePickerDocsComponent {

datePickerSingleJs = datePickerSingleSrc;
datePickerRangeJs = datePickerRangeSrc;

datePickerI18NTs = datePickeri18nSrc;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { CalendarI18n } from '../../../../../../library/src/lib/calendar/i18n/calendar-i18n';
import { Component, Injectable } from '@angular/core';
import { CalendarI18nLabels } from '../../../../../../library/src/lib/calendar/i18n/calendar-i18n-labels';

const localized_values = {
'fr': {
weekdays: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'],
months: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Aou', 'Sep', 'Oct', 'Nov', 'Déc'],
fullMonths: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet',
'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
}
};

@Injectable()
export class CustomCalendarI18n extends CalendarI18n {

// You could also define a custom service and inject it here
language: string = 'fr';

getDayAriaLabel(date: Date): string {
return date.getDate() + ' ' + localized_values[this.language].fullMonths[date.getMonth()] + ' ' + date.getFullYear();
}
getAllFullMonthNames(): string[] {
return localized_values[this.language].fullMonths;
}

getAllShortMonthNames(): string[] {
return localized_values[this.language].months;
}

getAllShortWeekdays(): string[] {
return localized_values[this.language].weekdays;
}
}

// Aria labels i18n
@Injectable()
export class CustomI18nLabels extends CalendarI18nLabels {

yearSelectionLabel: string = 'Sélection de l\'année';

previousYearLabel: string = 'Année précédente';

nextYearLabel: string = 'Année suivante';

monthSelectionLabel: string = 'Sélection du mois';

previousMonthLabel: string = 'Mois précédent';

nextMonthLabel: string = 'Mois suivant';
}

@Component({
selector: 'fd-datepicker-i18n-example',
template: `<fd-date-picker [(ngModel)]="selectedDay"></fd-date-picker>`,

// Note that this can be provided in the root of your application.
providers: [
{
provide: CalendarI18n,
useClass: CustomCalendarI18n
},
{
provide: CalendarI18nLabels,
useClass: CustomI18nLabels
}
]
})
export class DatePickerI18nExampleComponent {
selectedDay = {
date: new Date()
};
}
6 changes: 5 additions & 1 deletion docs/modules/documentation/documentation.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ import { TreeHeaderComponent } from './containers/tree/tree-header/tree-header.c
import { ROUTES } from './documentation.routes';
import { ComplexTitleExampleComponent } from './containers/tabs/examples/complex-title-example/complex-title-example.component';
import { AddingTabExampleComponent } from './containers/tabs/examples/adding-tab-example/adding-tab-example.component';
import { CalendarI18nExampleComponent } from './containers/calendar/examples/calendar-i18n-example.component';
import { DatePickerI18nExampleComponent } from './containers/date-picker/examples/date-picker-i18n-example.component';

export function highlightJsFactory() {
return hljs;
Expand Down Expand Up @@ -548,7 +550,9 @@ export function highlightJsFactory() {
TokenHeaderComponent,
TreeHeaderComponent,
ComplexTitleExampleComponent,
AddingTabExampleComponent
AddingTabExampleComponent,
CalendarI18nExampleComponent,
DatePickerI18nExampleComponent
],
entryComponents: [ModalContentComponent, ModalInModalComponent, ModalInModalSecondComponent, AlertContentComponent],
imports: [
Expand Down
5 changes: 4 additions & 1 deletion docs/modules/documentation/utilities/api-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ export const API_FILES = {
'ButtonGroupedDirective'
],
calendar: [
'CalendarComponent'
'CalendarComponent',
'CalendarI18n',
'CalendarI18nDefault',
'CalendarI18nLabels'
],
comboboxInput: [
'ComboboxInputComponent'
Expand Down
14 changes: 7 additions & 7 deletions library/src/lib/calendar/calendar.component.html
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<header class="fd-calendar__header">
<div class="fd-calendar__navigation">
<div class="fd-calendar__action">
<button id="arrowLeft" class=" fd-button--toolbar fd-button--xs sap-icon--slim-arrow-left"
[attr.aria-label]="showCalendarYears ? 'previous year' : 'previous month'"
<button id="arrowLeft" class="fd-button--toolbar fd-button--xs sap-icon--slim-arrow-left"
[attr.aria-label]="showCalendarYears ? calendarI18nLabels?.previousYearLabel : calendarI18nLabels?.previousMonthLabel"
(click)="showCalendarYears ? loadPrevYearsList() : goToPreviousMonth()"></button>
</div>
<div class="fd-calendar__action">
<button class=" fd-button--light fd-button--s"
aria-label="month selection"
[attr.aria-label]="calendarI18nLabels?.monthSelectionLabel"
(click)="openMonthSelection()">{{monthName}}</button>
</div>
<div class="fd-calendar__action">
<button class=" fd-button--light fd-button--s"
aria-label="year selection"
[attr.aria-label]="calendarI18nLabels?.yearSelectionLabel"
(click)="openYearSelection()">{{year}}</button>
</div>
<div class="fd-calendar__action">
<button class=" fd-button--toolbar fd-button--xs sap-icon--slim-arrow-right"
[attr.aria-label]="showCalendarYears ? 'next year' : 'next month'"
<button class="fd-button--toolbar fd-button--xs sap-icon--slim-arrow-right"
[attr.aria-label]="showCalendarYears ? calendarI18nLabels?.nextYearLabel : calendarI18nLabels?.nextMonthLabel"
(click)="showCalendarYears ? loadNextYearsList() : goToNextMonth()"></button>
</div>
</div>
Expand Down Expand Up @@ -69,7 +69,7 @@
*ngFor="let row of calendarGrid; let i = index;">
<td class="fd-calendar__item"
role="gridcell"
aria-label="day of the month"
[attr.aria-label]="cell.ariaLabel"
*ngFor="let cell of row; let cellIndex = index;"
[ngClass]='(cell.monthStatus !== "current" ? " fd-calendar__item--other-month": "") +
(cell.selected ? " is-selected": "") +
Expand Down

0 comments on commit b7d47de

Please sign in to comment.