Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pluralization issue with Russian locale (and possibly others) #4

Open
leovp opened this issue Oct 4, 2018 · 1 comment
Open

Pluralization issue with Russian locale (and possibly others) #4

leovp opened this issue Oct 4, 2018 · 1 comment
Assignees
Labels
bug Something isn't working enhancement New feature or request good first issue Good for newcomers

Comments

@leovp
Copy link

leovp commented Oct 4, 2018

New locale handling is pretty cool, thanks. But I think I found a bug in relativeTime plugin.

So, there are three declensions of nouns in Russian: singular, dual and plural. The library does have h, hh and hhh for all of those (this is the case with other units as well), but it assumes that single-letter format is only used when the value of whatever unit is exactly 1. For example "час назад" ("an hour ago"). Then if the last digit of value is less than 5, hh handles it, otherwise it's going to be hhh.

In Russian though (and I assume a few other languages), singular rule works for 1, 21, 31, 41, ..., 101, etc.
Then dual works for 2, 3, 4, 22, 23, 24, ..., 102, 103, 104, 122, 123, 124, etc.
Then plural works for everything else.
See Reference for a complete formula.

Example of a bug:

dayjs('2018-10-04 15:00:00').to('2018-10-04 15:21:00')
"через 21 минут" 

It should be "через 21 минуту", same as if it was 1 minute ("через минуту").
I think single-letter formats should have a "%d" in there as well, so that they work for all units that are singular.

Relevant code comment: https://github.com/prantlf/dayjs/blob/combined/src/plugin/relativeTime/index.js#L103-L106
Reference: http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html

@prantlf
Copy link
Owner

prantlf commented Oct 14, 2018

Thanks a lot, @leovp! Especially the second link and the links further on from it are great source of information.

My original simplification was quick to implement, but not enough. Even the common languages were not covered well with the three plural forms and the single rule for them. I went for the universal solution as done by Mozilla localizers. Newly I specify both the plural rule (a number or a function) and the plural forms as an array of strings. The plural rule function returns an index to the array of plural forms.

  relativeTime: {
    // 3 plural forms for 1 and x1, 2-4 and x2-4, 5-
    pluralRule: 7,
    duration: {
      s: 'несколько секунд',
      m: 'минута',
      mm: ['%d минута', '%d минуты', '%d минут'],
      h: 'час',
      hh: ['%d час', '%d часа', '%d часов'],
      d: 'день',
      dd: ['%d день', '%d дня', '%d дней'],
      M: 'месяц',
      MM: ['%d месяц', '%d месяца', '%d месяцев'],
      y: 'год',
      yy: ['%d год', '%d года', '%d лет']
    },
    future: {
      s: 'через несколько секунд',
      m: 'через минуту',
      mm: ['через %d минуту', 'через %d минуты', 'через %d минут'],
      h: 'через час',
      hh: ['через %d час', 'через %d часа', 'через %d часов'],
      d: 'завтра',
      dd: ['через %d день', 'через %d дня', 'через %d дней'],
      M: 'через месяц',
      MM: ['через %d месяц', 'через %d месяца', 'через %d месяцев'],
      y: 'через год',
      yy: ['через %d год', 'через %d года', 'через %d лет']
    },
    past: {
      s: 'несколько секунд назад',
      m: 'минуту назад',
      mm: ['%d минуту назад', '%d минуты назад', '%d минут назад'],
      h: 'час назад',
      hh: ['%d час назад', '%d часа назад', '%d часов назад'],
      d: 'вчера',
      dd: ['%d день назад', '%d дня назад', '%d дней назад'],
      M: 'месяц назад',
      MM: ['%d месяц назад', '%d месяца назад', '%d месяцев назад'],
      y: 'в прошлом году',
      yy: ['%d год назад', '%d года назад', '%d лет назад']
    }
  }
  // Plural rule #7 (3 forms)
  // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian)
  n => n % 10 === 1 && n % 100 !== 11 ? 0
    : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2,

I had to to separate the special singular form from the plural forms. It has usually no number and thus the first plural form (for 1, 21, 31, ...) cannot be reused for it.

I released this feature in 1.12.2. At first, locales cs, ru, sk and ua are correct there.

Eventually, the plural rules should make it out of the relativeTime plugin to the dayjs core utilities. Or may be event out of this module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants