npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@f-fjs/eslint-plugin-formatjs

v2.0.3

Published

ESLint plugin for formatjs

Downloads

3

Readme

@f-fjs/eslint-plugin-formatjs

This eslint plugin allows you to enforce certain rules in your ICU message. This is currently under development

Usage

npm install @f-fjs/eslint-plugin-formatjs

Then in your eslint config:

{
  "plugins": ["formatjs"],
  "rules": {
    "formatjs/no-offset": "error"
  }
}

Currently this uses intl.formatMessage, defineMessages, <FormattedMessage> from react-intl, or _ from @f-fjs/macro as hooks to verify the message. Therefore, in your code use 1 of the following mechanisms:

import {_} from '@f-fjs/macro';

const message = _({
  defaultMessage: 'foo',
  description: 'bar',
});
import {defineMessages} from 'react-intl';

const messages = defineMessages({
  foo: {
    defaultMessage: 'foo',
    description: 'bar',
  },
});
import {FormattedMessage} from 'react-intl';

<FormattedMessage defaultMessage="foo" description="bar" />;
function foo() {
  intl.formatMessage({
    defaultMessage: 'foo',
  });
}

Available Rules

blacklist-elements

This blacklists usage of specific elements in ICU message.

Why

  • Certain translation vendors cannot handle things like selectordinal

Available elements

enum Element {
  // literal text, like `defaultMessage: 'some text'`
  literal = 'literal',
  // placeholder, like `defaultMessage: '{placeholder} var'`
  argument = 'argument',
  // number, like `defaultMessage: '{placeholder, number} var'`
  number = 'number',
  // date, like `defaultMessage: '{placeholder, date} var'`
  date = 'date',
  // time, like `defaultMessage: '{placeholder, time} var'`
  time = 'time',
  // select, like `defaultMessage: '{var, select, foo{one} bar{two}} var'`
  select = 'select',
  // selectordinal, like `defaultMessage: '{var, selectordinal, one{one} other{two}} var'`
  selectordinal = 'selectordinal',
  // plural, like `defaultMessage: '{var, plural, one{one} other{two}} var'`
  plural = 'plural',
}

Example

{
  "plugins": ["formatjs"],
  "rules": {
    "formatjs/blacklist-elements": [2, ["selectordinal"]]
  }
}

enforce-description

This enforces description in the message descriptor.

Why

  • Description provides helpful context for translators
import {defineMessages} from 'react-intl';

const messages = defineMessages({
  // WORKS
  foo: {
    defaultMessage: 'foo',
    description: 'bar',
  },
  // FAILS
  bar: {
    defaultMessage: 'bar',
  },
});

enforce-default-message

This enforces defaultMessage in the message descriptor.

Why

  • Can be usefull in case we want to extract messages for translations from source code. This way can make sure people won't forget about defaultMessage
import {defineMessages} from 'react-intl';

const messages = defineMessages({
  // WORKS
  foo: {
    defaultMessage: 'This is default message',
    description: 'bar',
  },
  // FAILS
  bar: {
    description: 'bar',
  },
});

enforce-placeholders

Makes sure all values are passed in if message has placeholders (number/date/time/plural/select/selectordinal). This requires values to be passed in as literal object (not a variable).

// WORKS, no error
<FormattedMessage
  defaultMessage="this is a {placeholder}"
  values={{placeholder: 'dog'}}
/>

// WORKS, no error
intl.formatMessage({
  defaultMessage: 'this is a {placeholder}'
}, {placeholder: 'dog'})

// WORKS, error bc no values were provided
<FormattedMessage
  defaultMessage="this is a {placeholder}"
/>

// WORKS, error bc no values were provided
intl.formatMessage({
  defaultMessage: 'this is a {placeholder}'
})

// WORKS, error bc `placeholder` is not passed in
<FormattedMessage
  defaultMessage="this is a {placeholder}"
  values={{foo: 1}}
/>

// WORKS, error bc `placeholder` is not passed in
intl.formatMessage({
  defaultMessage: 'this is a {placeholder}'
}, {foo: 1})

// DOESN'T WORK
<FormattedMessage
  defaultMessage="this is a {placeholder}"
  values={someVar}
/>

// DOESN'T WORK
intl.formatMessage({
  defaultMessage: 'this is a {placeholder}'
}, values)

enforce-plural-rules

Enforce certain plural rules to always be specified/forbidden in a message.

Why

  • It is recommended to always specify other as fallback in the message.
  • Some translation vendors only accept certain rules.

Available rules

enum LDML {
  zero = 'zero',
  one = 'one',
  two = 'two',
  few = 'few',
  many = 'many',
  other = 'other',
}

Example

{
  "plugins": ["formatjs"],
  "rules": {
    "formatjs/enforce-plural-rules": [
      2,
      {
        "one": true,
        "other": true,
        "zero": false
      }
    ]
  }
}

no-camel-case

This make sure placeholders are not camel-case.

Why

  • This is to prevent case-sensitivity issue in certain translation vendors.
import {defineMessages} from 'react-intl';

const messages = defineMessages({
  // WORKS
  foo: {
    defaultMessage: 'foo {snake_case} {nothing}',
  },
  // FAILS
  bar: {
    defaultMessage: 'foo {camelCase}',
  },
});

no-emoji

This prevents usage of emoji in message.

Why

  • Certain translation vendors cannot handle emojis.
  • Cross-platform encoding for emojis are faulty.
import {defineMessages} from 'react-intl';

const messages = defineMessages({
  // WORKS
  foo: {
    defaultMessage: 'Smileys & People',
  },
  // FAILS
  bar: {
    defaultMessage: '😃 Smileys & People',
  },
});

no-multiple-plurals

This prevents specifying multiple plurals in your message.

Why

  • Nested plurals are hard to translate across languages so some translation vendors don't allow it.
import {defineMessages} from 'react-intl'

const messages = defineMessages({
    // WORKS
    foo: {
        defaultMessage: '{p1, plural, one{one}}',
    },
    // FAILS
    bar: {
        defaultMessage: '{p1, plural, one{one}} {p2, plural, one{two}}',
    }
    // ALSO FAILS
    bar2: {
        defaultMessage: '{p1, plural, one{{p2, plural, one{two}}}}',
    }
})

no-offset

This prevents specifying offset in plural rules in your message.

Why

  • Offset has complicated logic implication so some translation vendors don't allow it.
import {defineMessages} from 'react-intl';

const messages = defineMessages({
  // WORKS
  foo: {
    defaultMessage: '{var, plural, one{one} other{other}}',
  },
  // FAILS
  bar: {
    defaultMessage: '{var, plural, offset:1 one{one} other{other}}',
  },
});

supported-datetime-skeleton

Since formatjs only supports a subset of DateTime Skeleton. This rule exists to make sure you don't use a unsupported pattern.