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

Localisation capabilities of the RelativeTime plugin are insufficient for fusional languages #302

Closed
prantlf opened this issue Aug 15, 2018 · 5 comments

Comments

@prantlf
Copy link
Contributor

prantlf commented Aug 15, 2018

What do you think about re-working the current locale definition of the RelativeTime plugin to support fusional languages without grammatical mistakes?

Moment.js has more complicated locale definitions, but it allows grammatically correct localisation for Slavic languages, for example. Your Russian localisation suffers from the second problem below and my Czech localisation from both, which makes the localised expressions look so wrong, that they cannot be used in real-world applications.

Problem

  1. Localisation expressions for future ("after %s") and past ("before %s") contain the same rest of the expression. However, they contain different prepositions and thus they may need different declension in the rest of the expression.
  2. There is only one localisation expression for multiple seconds ("%d seconds"), minutes ("%d minutes") etc. However, different numerals may need different declension of the following noun.

For example, Slavic languages do not use just one noun form for singlular (one second) and one for plural (many seconds). Usually there are different forms after numerals 1, 2-4 and 5+. Additionally, the noun changes according to to the grammatical case, which is needed in the particular expression. The grammatical case depends on the preposition, for example.

Examples of English, German Russian and Czech expressions

Years - Past

 a year ago    vor einem Jahr   в прошлом году   vloni (před rokem)
 2 years ago   vor 2 Jahren     2 года назад     před 2 roky
 5 years ago   vor 5 Jahren     5 лет назад      před 5 lety

Years - Future

 in a year     in einem Jahr   через год      za rok
 in 2 years    in 2 Jahren     через 2 года   za 2 roky
 in 5 years    in 5 Jahren     через 5 лет    za 5 let

Days - Past

 yesterday    gestern          вчера          včera
(a day ago    vor einem Tag)   день назад     před jedním dnem)
 2 days ago   vor 2 Tagen      2 дни назад    před 2 dny
 5 days ago   vor 5 Tagen      5 дней назад   před 5 dny

Days - Future

 tomorrow    morgen         завтра         zítra
(in a day    in einem Tag   через день     za den)
 in 2 days   in 2 Tagen     через 2 дни    za 2 dny
 in 5 days   in 5 Tagen     через 5 дней   za 5 dní

Seconds - Past

 a second ago              vor einer Sekonde      секунду назад            před sekundou
 2 seconds ago             vor 2 Sekonden         2 секунды назад          před 2 sekundami
 5 seconds ago             vor 5 Sekonden         5 секунд назад           před 5 sekundami
 a couple of seconds ago   vor wenigen Sekonden   несколько секунд назад   před pár (několika) sekundami

Seconds - Future

 in a second              in einer Sekonde      через секунду            za sekundu
 in 2 seconds             in 2 Sekonden         через 2 секунды          za 2 sekundy
 in 5 seconds             in 5 Sekonden         через 5 секунд           za 5 sekund
 in a couple of seconds   in wenigen Sekonden   через несколько секунд   za pár (několik) sekund

Solution

  1. Duplicate all expressions for future and past instead of combining them with the two prepositions.
  2. Introduce the third expression with the numeral for many (5). Use the current expressions for one (1) and few (2-4).
const locale = {
  name: 'cs',
  weekdays: 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),
  months: 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'),
  ordinal: n => `${n}.`,
  relativeTime: {
    future: {
      s: 'za několik sekund',
      m: 'za minutu',
      mm: 'za %d minuty',
      mmm: 'za %d minut',
      h: 'za hodinu',
      hh: 'za %d hodiny',
      hhh: 'za %d hodin',
      d: 'zítra',
      dd: 'za %d dny',
      ddd: 'za %d dní',
      M: 'za měsíc',
      MM: 'za %d měsíce',
      MMM: 'za %d měsícú',
      y: 'za rok',
      yy: 'za %d roky',
      yyy: 'za %d let'
    },
    past: {
      s: 'před několika sekundami',
      m: 'před minutou',
      mm: 'před %d minutami',
      mmm: 'před %d minutami',
      h: 'před hodinu',
      hh: 'před %d hodinami',
      hhh: 'před %d hodinami',
      d: 'včera',
      dd: 'před %d dny',
      ddd: 'před %d dny',
      M: 'před měsícem',
      MM: 'před %d měsíci',
      MMM: 'před %d měsíci',
      y: 'vloni',
      yy: 'před %d roky',
      yyy: 'před %d lety'
    }
  }
}
@prantlf prantlf changed the title Localisation capabilities are insufficient for fusional languages Localisation capabilities of the RelativeTime plugin are insufficient for fusional languages Aug 16, 2018
@Haprog
Copy link
Contributor

Haprog commented Sep 25, 2018

This is also needed for proper Finnish translation. Otherwise either future or past tense can't work correctly and is unacceptable for real use.

E.g.
in 2 hours -> 2 tunnin kuluttua
2 hours ago -> 2 tuntia sitten

Haprog added a commit to Haprog/dayjs that referenced this issue Sep 25, 2018
This adds basic support for Finnish locale but atm. proper Finnish support can't be implemented until issue iamkun#302 is fixed.
relativeTime properties are now configured for past tense usage only because I think it's a more common use case with this kind of library.
For now using future tense with this locale will result in incorrect forms and text that doesn't make sense.
@limonte
Copy link
Contributor

limonte commented Sep 29, 2018

@iamkun please prioritize this issue. I do understand that it will probably be a breaking change (new major release), but it's essential in order to move further and ensure the bright future of dayjs.

A lot of localisations are invalid with the format dayjs has currently.

@prantlf
Copy link
Contributor Author

prantlf commented Sep 29, 2018

@limonte, I took care not to break the existing language packs in the suggested fix #304. Czech, Slovak, Russian and Ukrainian language packs are updated. The others are loaded and work as they did before the change. They can be gradually upgraded as the community goes on.

I reused the existing patterns "m" and "mm" for the mnemonic tags "one" and "few". I added pattern "mmm" for the "many" tag. Tag "zero" is not needed for relative time values. Tag "two" is rare and tag "other" has no common rules. Tags "one", "few" and "many" hardcoded for 1, 2-4 and 5+ numbers mean a small change and cover many languages. The future step could be implementing the full CLDR rules. See plural rules on CLDR for more information.)

@prantlf
Copy link
Contributor Author

prantlf commented Oct 14, 2018

My original simplification was not enough. Even the common languages were not covered well with the three plural forms and the single rule for them, as @leovp pointed out.

It would be better to go for the universal solution right away instead of trying something simpler as I did originally. For example, by specifying both the plural rule (a number or a function) and the plural forms as an array of strings, which the plural rule is an index to.

  relativeTime: {
    // Slavic (Slovak, Czech), 3 plural forms for 1, 2-4, 5-
    pluralRule: 8,
    duration: {
      s: 'několik sekund',
      m: 'minuta',
      mm: ['%d minuta', '%d minuty', '%d minut'],
      h: 'hodina',
      hh: ['%d hodina', '%d hodiny', '%d hodin'],
      d: 'den',
      dd: ['%d den', '%d dny', '%d dní'],
      M: 'měsíc',
      MM: ['%d měsíc', '%d měsíce', '%d měsícú'],
      y: 'rok',
      yy: ['%d rok', '%d roky', '%d let']
    },
    future: {
      s: 'za několik sekund',
      m: 'za minutu',
      mm: ['za %d minutu', 'za %d minuty', 'za %d minut'],
      h: 'za hodinu',
      hh: ['za %d hodinu', 'za %d hodiny', 'za %d hodin'],
      d: 'zítra',
      dd: ['za %d den', 'za %d dny', 'za %d dní'],
      M: 'za měsíc',
      MM: ['za %d měsíc', 'za %d měsíce', 'za %d měsícú'],
      y: 'za rok',
      yy: ['za %d rok', 'za %d roky', 'za %d let']
    },
    past: {
      s: 'před několika sekundami',
      m: 'před minutou',
      mm: ['před %d minutou', 'před %d minutami', 'před %d minutami'],
      h: 'před hodinou',
      hh: ['před %d hodinou', 'před %d hodinami', 'před %d hodinami'],
      d: 'včera',
      dd: ['před %d dnem', 'před %d dny', 'před %d dny'],
      M: 'před měsícem',
      MM: ['před %d měsícem', 'před %d měsíci', 'před %d měsíci'],
      y: 'vloni',
      yy: ['před %d rokem', 'před %d roky', 'před %d lety']
    }
  }
  // Plural rule #8
  n => n === 1 ? 0 : n >= 2 && n <= 4 ? 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 updated #304 with this approach.

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.

@iamkun
Copy link
Owner

iamkun commented Jan 6, 2020

fixed in #767

@iamkun iamkun closed this as completed Jan 6, 2020
andrewhood125ruhuc added a commit to andrewhood125ruhuc/SidRH2 that referenced this issue May 10, 2022
This adds basic support for Finnish locale but atm. proper Finnish support can't be implemented until issue iamkun/dayjs#302 is fixed.
relativeTime properties are now configured for past tense usage only because I think it's a more common use case with this kind of library.
For now using future tense with this locale will result in incorrect forms and text that doesn't make sense.
andrewhood125ruhuc added a commit to andrewhood125ruhuc/SidRH2 that referenced this issue May 10, 2022
This adds basic support for Finnish locale but atm. proper Finnish support can't be implemented until issue iamkun/dayjs#302 is fixed.
relativeTime properties are now configured for past tense usage only because I think it's a more common use case with this kind of library.
For now using future tense with this locale will result in incorrect forms and text that doesn't make sense.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants