Skip to main content
Enhanced MS supports multiple languages out of the box, but you can also create custom language definitions for languages that aren’t built-in or to customize existing ones.

Language definition structure

A language definition is an object that conforms to the LanguageDefinition interface:
interface LanguageDefinition {
  decimal: '.' | ',';
  and?: string | ((words: string[]) => string[]);
  units: Record<Unit, LanguageUnitDefinition>;
}

Required properties

decimal

decimal
'.' | ','
required
The decimal separator the language uses.
  • Use '.' for English, Chinese, etc.
  • Use ',' for German, Italian, French, etc.
decimal: '.'
// Parses: "1.5 hours" → 5400000ms

decimal: ','
// Parses: "1,5 Stunden" → 5400000ms

units

units
Record<Unit, LanguageUnitDefinition>
required
Definitions for all time units in the language. Must include all units: nanosecond, microsecond, millisecond, second, minute, hour, day, week, month, year, decade, century, millennium.
Each unit definition has three properties:
name
string | ((count: number) => string)
required
The full name of the unit. Can be a string or a function that returns different forms based on count (for pluralization).
// Simple string (no pluralization)
name: 'hour'

// Function for pluralization
name: (count) => count === 1 ? 'hour' : 'hours'

// Complex pluralization (e.g., Russian)
name: (count) => {
  if (count % 10 === 1 && count % 100 !== 11) return 'час';
  if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'часа';
  return 'часов';
}
abbreviation
string | ((count: number) => string)
The abbreviated form of the unit. Can be a string or a function. Omitting this will cause errors if you use useAbbreviations: true.
// Simple abbreviation
abbreviation: 'h'

// Function (less common for abbreviations)
abbreviation: (count) => count === 1 ? 'hr' : 'hrs'
matches
Lowercase<string>[]
required
Array of lowercase strings to match when parsing duration strings. Should include the full name, plural forms, abbreviations, and common variations.
matches: ['hour', 'hours', 'h', 'hr', 'hrs']

// For languages with gender variations
matches: ['stunde', 'stunden', 'std', 'std.']

Optional properties

and

and
string | ((words: string[]) => string[])
The word to use for “and” in formatted output. Omitting this will cause errors if you use insertAnd: true (if that option exists in your version).
// English
and: 'and'

// German
and: 'und'

// Function for complex logic
and: (words) => {
  // Insert 'and' before the last word
  const last = words.pop();
  return [...words, 'and', last];
}

Creating a custom language

Here’s a complete example of creating a custom language definition:
import { createMs } from 'enhanced-ms';
import type { LanguageDefinition } from 'enhanced-ms';

const customLanguage: LanguageDefinition = {
  decimal: '.',
  and: 'and',
  
  units: {
    nanosecond: {
      name: (c) => c === 1 ? 'nanosecond' : 'nanoseconds',
      abbreviation: 'ns',
      matches: ['nanosecond', 'nanoseconds', 'ns'],
    },
    microsecond: {
      name: (c) => c === 1 ? 'microsecond' : 'microseconds',
      abbreviation: 'μs',
      matches: ['microsecond', 'microseconds', 'μs', 'us'],
    },
    millisecond: {
      name: (c) => c === 1 ? 'millisecond' : 'milliseconds',
      abbreviation: 'ms',
      matches: ['millisecond', 'milliseconds', 'ms'],
    },
    second: {
      name: (c) => c === 1 ? 'second' : 'seconds',
      abbreviation: 's',
      matches: ['second', 'seconds', 's', 'sec'],
    },
    minute: {
      name: (c) => c === 1 ? 'minute' : 'minutes',
      abbreviation: 'm',
      matches: ['minute', 'minutes', 'm', 'min'],
    },
    hour: {
      name: (c) => c === 1 ? 'hour' : 'hours',
      abbreviation: 'h',
      matches: ['hour', 'hours', 'h', 'hr'],
    },
    day: {
      name: (c) => c === 1 ? 'day' : 'days',
      abbreviation: 'd',
      matches: ['day', 'days', 'd'],
    },
    week: {
      name: (c) => c === 1 ? 'week' : 'weeks',
      abbreviation: 'w',
      matches: ['week', 'weeks', 'w', 'wk'],
    },
    month: {
      name: (c) => c === 1 ? 'month' : 'months',
      abbreviation: 'mo',
      matches: ['month', 'months', 'mo'],
    },
    year: {
      name: (c) => c === 1 ? 'year' : 'years',
      abbreviation: 'y',
      matches: ['year', 'years', 'y', 'yr'],
    },
    decade: {
      name: (c) => c === 1 ? 'decade' : 'decades',
      abbreviation: 'dec',
      matches: ['decade', 'decades', 'dec'],
    },
    century: {
      name: (c) => c === 1 ? 'century' : 'centuries',
      abbreviation: 'c',
      matches: ['century', 'centuries', 'c'],
    },
    millennium: {
      name: (c) => c === 1 ? 'millennium' : 'millennia',
      abbreviation: 'mil',
      matches: ['millennium', 'millennia', 'mil'],
    },
  },
};

const ms = createMs({ language: customLanguage });

ms(90000);
// Output: "1 minute 30 seconds"

ms('2 hours 30 minutes');
// Output: 9000000

Real-world example: German

Here’s how you might create a German language definition:
import { createMs } from 'enhanced-ms';
import type { LanguageDefinition } from 'enhanced-ms';

const german: LanguageDefinition = {
  decimal: ',',
  and: 'und',
  
  units: {
    nanosecond: {
      name: (c) => c === 1 ? 'Nanosekunde' : 'Nanosekunden',
      abbreviation: 'ns',
      matches: ['nanosekunde', 'nanosekunden', 'ns'],
    },
    microsecond: {
      name: (c) => c === 1 ? 'Mikrosekunde' : 'Mikrosekunden',
      abbreviation: 'μs',
      matches: ['mikrosekunde', 'mikrosekunden', 'μs', 'us'],
    },
    millisecond: {
      name: (c) => c === 1 ? 'Millisekunde' : 'Millisekunden',
      abbreviation: 'ms',
      matches: ['millisekunde', 'millisekunden', 'ms'],
    },
    second: {
      name: (c) => c === 1 ? 'Sekunde' : 'Sekunden',
      abbreviation: 's',
      matches: ['sekunde', 'sekunden', 's', 'sek'],
    },
    minute: {
      name: (c) => c === 1 ? 'Minute' : 'Minuten',
      abbreviation: 'm',
      matches: ['minute', 'minuten', 'm', 'min'],
    },
    hour: {
      name: (c) => c === 1 ? 'Stunde' : 'Stunden',
      abbreviation: 'Std.',
      matches: ['stunde', 'stunden', 'std', 'std.', 'h'],
    },
    day: {
      name: (c) => c === 1 ? 'Tag' : 'Tage',
      abbreviation: 'T',
      matches: ['tag', 'tage', 't'],
    },
    week: {
      name: (c) => c === 1 ? 'Woche' : 'Wochen',
      abbreviation: 'W',
      matches: ['woche', 'wochen', 'w'],
    },
    month: {
      name: (c) => c === 1 ? 'Monat' : 'Monate',
      abbreviation: 'Mo',
      matches: ['monat', 'monate', 'mo'],
    },
    year: {
      name: (c) => c === 1 ? 'Jahr' : 'Jahre',
      abbreviation: 'J',
      matches: ['jahr', 'jahre', 'j'],
    },
    decade: {
      name: (c) => c === 1 ? 'Jahrzehnt' : 'Jahrzehnte',
      abbreviation: 'Jz',
      matches: ['jahrzehnt', 'jahrzehnte', 'jz'],
    },
    century: {
      name: (c) => c === 1 ? 'Jahrhundert' : 'Jahrhunderte',
      abbreviation: 'Jh',
      matches: ['jahrhundert', 'jahrhunderte', 'jh'],
    },
    millennium: {
      name: (c) => c === 1 ? 'Jahrtausend' : 'Jahrtausende',
      abbreviation: 'Jt',
      matches: ['jahrtausend', 'jahrtausende', 'jt'],
    },
  },
};

const ms = createMs({ language: german });

ms(90000);
// Output: "1 Minute 30 Sekunden"

ms('2 Stunden 30 Minuten');
// Output: 9000000

Using built-in languages

Enhanced MS includes built-in support for several languages. Instead of creating a custom definition, you can use a language key:
import { createMs } from 'enhanced-ms';

const ms = createMs({ language: 'de' }); // German
const msRu = createMs({ language: 'ru' }); // Russian
const msEs = createMs({ language: 'es' }); // Spanish
See the main documentation for a full list of supported languages.

Contributing languages

If you create a language definition for a language that isn’t supported, consider contributing it to the project! You can make a pull request at the Enhanced MS repository.

Type information

Language definition types are located in src/languages/helpers/definition-types.ts:3. The English language definition in src/languages/en.ts:1 serves as a good reference implementation.

Build docs developers (and LLMs) love