Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,50 @@ function SchedulerDemo() {

`material-ui-cron` is written in TypeScript with complete definitions.

## Internalization and Localization

This library supports Internalization (i18n). Currently languages supported are:

1. English

We are welcoming translation contributions from the community.

### How to contribute to translation

1. Clone `/src/localization/enLocal.ts` and rename it to desired langauge prefix
(based on
https://meta.wikimedia.org/wiki/Template:List_of_language_names_ordered_by_code).

2. Add language prefix to `definedLocales` type inside `/src/types.ts`

3. Add locale mapping inside `/src/i18n.ts`

### How to use translation

#### Using predefined locale:

```javascript
<Scheduler
cron={cronExp}
setCron={setCronExp}
setCronError={setCronError}
isAdmin={isAdmin}
locale={'en'} // if not supplied, localization defaults to en
/>
```

#### Using custom locale:

```javascript
<Scheduler
cron={cronExp}
setCron={setCronExp}
setCronError={setCronError}
isAdmin={isAdmin}
customLocale={{...your translations}} // should be a valid object of type Locale, overrides value supplied to locale prop
/>
```

## Acknowledgement

This library was developed as a part of [Udaan](https://udaan.com/)'s Data
Expand Down
15 changes: 14 additions & 1 deletion src/Scheduler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ import Minute from './fields/Minute'
import Month from './fields/Month'
import Period from './fields/Period'
import Week from './fields/Week'
import { supportedLanguages } from './i18n'
import { cronExpState } from './selector'
import {
cronExpInputState,
cronValidationErrorMessageState,
dayOfMonthState,
hourState,
isAdminState,
localeState,
minuteState,
monthState,
periodState,
Expand All @@ -37,7 +39,7 @@ const useStyles = makeStyles({
})

export default function Scheduler(props: SchedulerProps) {
const { cron, setCron, setCronError, isAdmin } = props
const { cron, setCron, setCronError, isAdmin, locale, customLocale } = props
const classes = useStyles()
const period = useRecoilValue(periodState)
const [periodIndex, setPeriodIndex] = React.useState(0)
Expand All @@ -48,6 +50,7 @@ export default function Scheduler(props: SchedulerProps) {
const setIsAdmin = useSetRecoilState(isAdminState)

const [cronExpInput, setCronExpInput] = useRecoilState(cronExpInputState)
const setResolvedLocale = useSetRecoilState(localeState)

const resetCronExpInput = useResetRecoilState(cronExpInputState)
const resetMinute = useResetRecoilState(minuteState)
Expand Down Expand Up @@ -91,6 +94,16 @@ export default function Scheduler(props: SchedulerProps) {
}
}, [cron])

React.useEffect(() => {
if (customLocale) {
setResolvedLocale(customLocale)
} else if (locale) {
setResolvedLocale(supportedLanguages[locale])
} else {
setResolvedLocale(supportedLanguages['en'])
}
}, [locale, customLocale])

return (
<>
<Box display='flex' flexDirection='column' className={classes.box}>
Expand Down
11 changes: 8 additions & 3 deletions src/components/CronReader.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { makeStyles, createStyles } from '@material-ui/styles'
import Box from '@material-ui/core/Box'
import Typography from '@material-ui/core/Typography'
import cronstrue from 'cronstrue'
import cronstrue from 'cronstrue/i18n'
import React from 'react'
import { useRecoilValue } from 'recoil'
import { cronExpState } from '../selector'
import { cronValidationErrorMessageState } from '../store'
import { cronValidationErrorMessageState, localeState } from '../store'

const useStyles = makeStyles(() =>
createStyles({
Expand All @@ -18,6 +18,7 @@ const useStyles = makeStyles(() =>
export default function CronReader() {
const classes = useStyles()
const cronExp = useRecoilValue(cronExpState)
const resolvedLocale = useRecoilValue(localeState)

const [cronHr, setCronHr] = React.useState('')

Expand All @@ -27,7 +28,11 @@ export default function CronReader() {

React.useEffect(() => {
try {
setCronHr(cronstrue.toString(cronExp))
setCronHr(
cronstrue.toString(cronExp, {
locale: resolvedLocale.cronDescriptionText,
})
)
} catch (e) {
setCronHr('Incorrect cron selection')
}
Expand Down
139 changes: 49 additions & 90 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,35 @@ export const generateOrdinalOptions = (

/* PERIOD */

export const periodOptions: SelectOptions[] = [
export const getPeriodOptions = (
periodOptionLabels: string[]
): SelectOptions[] => [
{
label: periodOptionLabels[0],
value: 'hour',
label: 'hour',
},
{
label: periodOptionLabels[1],
value: 'day',
label: 'day',
},
{
label: periodOptionLabels[2],
value: 'week',
label: 'week',
},
{
label: periodOptionLabels[3],
value: 'month',
label: 'month',
},
{
label: periodOptionLabels[4],
value: 'year',
label: 'year',
},
]

const periodOptionsWithHourDisabled = () =>
periodOptions.map((periodOption) =>
export const getPeriodOptionsWithHourDisabled = (
periodOptionLabels: string[]
) =>
getPeriodOptions(periodOptionLabels).map((periodOption) =>
periodOption.value === 'hour'
? {
...periodOption,
Expand All @@ -60,39 +64,14 @@ const periodOptionsWithHourDisabled = () =>
: periodOption
)

export const periodOptionsNonAdmin: SelectOptions[] =
periodOptionsWithHourDisabled()

/* WEEK */

export const WEEK_DAYS = [
'SUNDAY',
'MONDAY',
'TUESDAY',
'WEDNESDAY',
'THURSDAY',
'FRIDAY',
'SATURDAY',
]

export const defaultWeekOptions = () =>
WEEK_DAYS.map((day, idx) => ({
export const weekOptions = (weekDayLabels: string[]): SelectOptions[] =>
weekDayLabels.map((day, idx) => ({
value: `${idx}`,
label: day,
}))

export const DEFAULT_WEEK_OPTS = [
{ value: '0', label: 'SUNDAY' },
{ value: '1', label: 'MONDAY' },
{ value: '2', label: 'TUESDAY' },
{ value: '3', label: 'WEDNESDAY' },
{ value: '4', label: 'THURSDAY' },
{ value: '5', label: 'FRIDAY' },
{ value: '6', label: 'SATURDAY' },
]

export const defaultWeekSelection = () => defaultWeekOptions()

/* DAY OF MONTH */

export const defaultDayOfMonthOptions = () => {
Expand All @@ -108,59 +87,28 @@ export const defaultDayOfMonthOptionsWithOrdinal = () => {
return generateOrdinalOptions(1, 31)
}

export const LAST_DAY_OF_MONTH_OPT = {
export const getLastDayOfMonthOption = (lastDayOfMonthLabel: string) => ({
value: 'L',
label: 'Last Day of Month',
}
label: lastDayOfMonthLabel,
})

export const DEFAULT_DAY_OF_MONTH_OPTS_WITH_L =
defaultDayOfMonthOptionsWithOrdinal().concat(LAST_DAY_OF_MONTH_OPT)
export const getDayOfMonthsOptionsWithL = (lastDayOfMonthLabel: string) =>
defaultDayOfMonthOptionsWithOrdinal().concat(
getLastDayOfMonthOption(lastDayOfMonthLabel)
)

export const DEFAULT_DAY_OF_MONTH_OPTS_WITH_ORD =
defaultDayOfMonthOptionsWithOrdinal()
export const DEFAULT_DAY_OF_MONTH_OPTS_WITH_ORD = defaultDayOfMonthOptionsWithOrdinal()

export const DEFAULT_DAY_OF_MONTH_OPTS = defaultDayOfMonthOptions()

/* MONTH */

export const MONTHS = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]

export const MONTHS_SHORT = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
]

export const defaultMonthOptions = () =>
MONTHS.map((month, idx) => ({
export const getMonthOptions = (monthOptionLabels: string[]) =>
monthOptionLabels.map((month, idx) => ({
value: `${idx + 1}`,
label: MONTHS_SHORT[idx],
label: month,
}))

export const DEFAULT_MONTH_OPTS = defaultMonthOptions()

/* HOUR */

export const defaultHourOptionsHr = () => {
Expand Down Expand Up @@ -201,48 +149,59 @@ export const defaultMinuteOptionsWithOrdinal = () => DEFAULT_MINUTE_OPTS

export const DEFAULT_MINUTE_OPTS = defaultMinuteOptions()

export const atEveryOptions: SelectOptions[] = [
export const atEveryOptions = (
atLabel: string,
everyLabel: string
): SelectOptions[] => [
{
value: 'at',
label: 'at',
label: atLabel,
},
{
value: 'every',
label: 'every',
label: everyLabel,
},
]

export const everyOptionsNonAdmin: SelectOptions[] = [
export const everyOptionsNonAdmin = (
atLabel: string,
everyLabel: string
): SelectOptions[] => [
{
value: 'at',
label: 'at',
label: atLabel,
disabled: true,
},
{
value: 'every',
label: 'every',
label: everyLabel,
},
]

export const atOptionsNonAdmin: SelectOptions[] = [
export const atOptionsNonAdmin = (
atLabel: string,
everyLabel: string
): SelectOptions[] => [
{
value: 'at',
label: 'at',
label: atLabel,
},
{
value: 'every',
label: 'every',
label: everyLabel,
disabled: true,
},
]

export const onEveryOptions: SelectOptions[] = [
export const onEveryOptions = (
onLabel: string,
everyLabel: string
): SelectOptions[] => [
{
value: 'on',
label: 'on',
label: onLabel,
},
{
value: 'every',
label: 'every',
label: everyLabel,
},
]
Loading