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

International pluralization #78

Closed
Grawl opened this issue Oct 30, 2016 · 33 comments · Fixed by #451
Closed

International pluralization #78

Grawl opened this issue Oct 30, 2016 · 33 comments · Fixed by #451

Comments

@Grawl
Copy link

Grawl commented Oct 30, 2016

In English, pluralization looks simple: one and many. But it's not too simple for Russian language. And there is some other languages.

i18n means Internationalization.

I suggest to use something better for pluralization into $tc()/Vue.tc().

For example, smart-plurals.


Now I using it with Vue like this:

// pluralize.js
import Vue from 'vue'
import smartPlurals from 'smart-plurals'
export default function pluralize(string, amount, lang) {
    string = Vue.t(string, lang).split(' | ')
    return smartPlurals.Plurals.getRule(lang)(amount, string)
}

So I can now write different amount of plural forms for different languages in one format: singular | plural for English or singular | few | plural for Russian for example.

And then just pluralize('key', value, Vue.config.lang) as a function in JS

And {{ $t('key') | pluralize(computedProperty()) }} as a filter in templates:

<!-- module.vue -->
<script>
    import filters from './filters'
    export default {
        filters: filters,}
</script>
// filters.js
import Vue from 'vue'
import pluralize from './modules/pluralize'
export default {
    pluralize: function(string, amount) {
        return pluralize(string, amount, Vue.config.lang)
    }
}

Other sources you can see in this repo.

@skyrpex
Copy link

skyrpex commented Dec 14, 2016

The need of a better pluralization is there, but I think this is a bit cumbersome.

Wouldn't it be easier if we just let the translations to use the Laravel's pluralization format? 'apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many',.

IMO, it's simpler and more clear. Also, we could reuse Laravel labels... 👏

@Grawl
Copy link
Author

Grawl commented Dec 14, 2016

@skyrpex looks good! I like this format.

And, since Laravel supports Vue out of the box, it's good to be compatible.

@skyrpex
Copy link

skyrpex commented Dec 14, 2016

Maybe we could create some sort of abstraction and let the user to register custom pluralization plugins (just like custom formatters)?

//  The simplest implementation
Vue.config.i18nPluralizer = (string, count) => {
  const parts = string.split('|');
  if (count === 1) {
      return parts[0];
  }
  
  return parts[1];
};

@Grawl
Copy link
Author

Grawl commented Dec 14, 2016

@skyrpex I think better to include it into vue-i18n. Pluralization should be simple. smart-plurals do.

@skyrpex
Copy link

skyrpex commented Dec 14, 2016

There would be a default implementation for sure, but having the power to customize it is priceless.

@Grawl
Copy link
Author

Grawl commented Dec 15, 2016

Why should we customize it? There is a languages, each have it's rules.

@skyrpex
Copy link

skyrpex commented Dec 15, 2016

Letting the "pluralizer" to be customizable would make the users able to choose whatever pluralization method they need. This means one could use Laravel's syntax ('apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many') or something that uses smart-plurals, like:

{
    apples: {
        singular: 'There is an apple',
        few: 'There are {count} apples',
        plural: 'There are so many apples',
    }
}

@Grawl
Copy link
Author

Grawl commented Dec 15, 2016

Sounds good. I agree.

@xpepermint
Copy link

xpepermint commented Dec 15, 2016

How about http://formatjs.io? Having this as vue component would be awesome!

@Grawl
Copy link
Author

Grawl commented Dec 16, 2016

@xpepermint looks cool!

@skyrpex
Copy link

skyrpex commented Dec 16, 2016

That library looks awesome, I must admit! It handles formatting and pluralization with a single pass, though. The public vue-i18n API should change, then?

@xpepermint
Copy link

@kazupon what do you think about ICU format? Is there a chance that we get this into vue-i18n? That would be super awesome :).

@xpepermint
Copy link

xpepermint commented Dec 16, 2016

A quick and dirty proposal/example - it would be great not to depend on Intl and intl-messageformat (i think I saw a version of vue-intl package which implements this) because you need a polyfill for old browsers.

import * as merge from 'lodash.merge';
import IntlMessageFormat from 'intl-messageformat';

export class I18n {
  locale: string;
  messages: any;
  formats: any;

  /*
  * Class constructor.
  */

  constructor ({
    locale = 'en-US',
    messages = {},
    formats = {}
  }: {
    locale: string,
    messages?: any,
    formats?: any
  }) {
    this.locale = locale;
    this.messages = messages;
    this.formats = merge(IntlMessageFormat.formats, formats);
  }

  formatNumber (value: number, options: any = {}) {
    let {format, ...props} = options;
    props = merge(this.formats.number[format], props);

    return new Intl.NumberFormat(this.locale, props).format(value);
  }

  formatDate (value: number | Date, options: any = {}) {
    let {format, ...props} = options;
    props = merge(this.formats.date[format], props);

    return new Intl.DateTimeFormat(this.locale, props).format(value);
  }

  formatTime (value: number | Date, options: any = {}) {
    let {format, ...props} = options;
    props = merge(this.formats.time[format], props);

    if (Object.keys(props).length === 0) {
      props = this.formats.time.short;
    }

    return new Intl.DateTimeFormat(this.locale, props).format(value);
  }

  formatMessage (message: string, vars: any = {}) {
    return new IntlMessageFormat(message, this.locale, this.formats).format(vars);
  }

}

@xpepermint
Copy link

Here is another alternative: http://i18njs.com/#pluralisation

@kazupon
Copy link
Owner

kazupon commented Dec 18, 2016

@xpepermint
Thanks for your referennce link! 👍
Looks great to me!!

I think that i want to support translation based on ECMA-402.
#14

In vue-i18n v5.0 later, I'll plan to support it and full-scrach development.

@kazupon
Copy link
Owner

kazupon commented Dec 18, 2016

ref: vue-intl
https://github.com/learningequality/vue-intl

@xpepermint
Copy link

xpepermint commented Dec 18, 2016

Yeah, I tried vue-intl, also their vue2 branch but some methods just don't work and I feel there's a lack of interest for fixing it. I've created vue-translated for now because we have to deploy our platform in a month.

Hurray for the decision about ECMA-402! Five Points from Gryffindor :)!

If I go back to the actual theme of this thread ... I believe that pluralization is something that this package should allow for all languages. This is something that currently prevents us from using this package in our projects. What are your plans about that?

@kazupon kazupon added the v7 label Apr 5, 2017
@kazupon kazupon removed the v7 label May 26, 2017
@rodneyrehm
Copy link
Contributor

I see Intl.DateFormat and Intl.NumberFormat have made it into v7, thanks ❤️.

What's holding back (ICU) MessageFormat (e.g. via intl-messageformat) as suggested by @xpepermint? Did you decide to not pursue this furthor in favor of having implementors use Custom Formatting as shown in the custom formatting example?

@krukid
Copy link

krukid commented Jul 10, 2017

It's actually fairly straight-forward to implement pluralization and relative dates manually. I personally did exactly that, because my whole app takes up about 60K and the RFC/Intl shenanigan takes up 20K per messageformat and relativeformat + another 60K for Intl polyfill, not to mention whatever integration code you still have to write. If you need something pragmatic, then it makes sense to just bundle up your locales along with pluralization functions (see https://github.com/svenfuchs/rails-i18n/tree/master/lib/rails_i18n/common_pluralizations) and whatever locale-specific helpers you need and dynamically import them on locale switch. Thanks to Webpack that's a breeze. The relative dates feature is just a single common function that builds on top of that. Here's my quick and dirty plugin that takes up just 1.5K gzipped https://gist.github.com/krukid/eb4aea19721ed360d27ec4eea818320f, the rest is loaded by loadLocale() when invoked. You can even wrap this up nicely in a vue-router middleware that will block until non-packaged locale is being pulled.

@ilyavaiser
Copy link

Is it already implemented?

@outOFFspace
Copy link

Nice implementation has Yii2 framework Yii2 guide

@mitar
Copy link

mitar commented Feb 14, 2018

I like the smart plurals approach from @Grawl, I hope this could be added.

@outOFFspace
Copy link

Any plans to implement this feature?

@Xowap
Copy link

Xowap commented Apr 11, 2018

I find it interesting that a translation system would propose pluralization that only works in English. This kind of defeats the purpose of translating... And this ticket has been open for almost two years.

In other words, are you guys motherfucking NUTS? You reached version 7 without noticing this?! Wake the fuck up guys...

Thanks ❤️

@skyrpex
Copy link

skyrpex commented Apr 11, 2018

I didn't dig too much into this, but I think you can already implement your own formatter.

@adinvadim
Copy link

adinvadim commented Jun 12, 2018

@kazupon
Any plans to implement this feature?

@kazupon
Copy link
Owner

kazupon commented Jun 13, 2018

In the future, I'll implement vue-i18n with full-scratch.
In the timing, I might plan to adopt ICU format.

@prakhargahlot
Copy link

We're using vue-i18n too, and as we look at expanding to other platforms and languages, this feature would really help us in implementing without superfluous plugins.

@victor-ponamariov
Copy link

So there is still no possibility to work with pluralization in other languages except English?

@3amprogrammer
Copy link

3amprogrammer commented Oct 25, 2018

Unfortunately below solution doesn't cover this syntax:

'apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many'

It only supports simple plural forms discovered based on getPluralIndex function. I also had to do my own formatting as BaseFormatter isn't exported...

class PluralizableMessageFormatter {
    constructor(locale) {
        this.locale = locale;
    }

    interpolate(message, values) {
        // This is the greatest hack in history
        if (!values || !values.hasOwnProperty('number')) {
            return [message];
        }

        const index = getPluralIndex(this.locale, values.number);
        const template = message.split('|')[index];
        return [
            Object
            .keys(values)
            .reduce((result, key) => result.replace(`{${key}}`, values[key]), template.trim())
        ];
    }
}

You ignore $tc function all together and instead you use $t with number key...

{{ $t('messages.years_old', { number: contractor.age, age: contractor.age }) }}

The number key imitates second argument in normal trans_choice function.
You also need to create getPluralIndex.js copied from \Illuminate\Translation\MessageSelector::getPluralIndex.
https://gist.github.com/3amprogrammer/56e543472850923936d2b5f2194d6640

@Raiondesu
Copy link
Contributor

Raiondesu commented Oct 25, 2018

@kazupon, would you accept potential PR that implements this feature in an extendable way?

I'd propose simething like an ability to override a function on VueI18n prototype that would behave somewhat similar to fetchChoise.

This would not break any current logic while also allowing users to define custom behaviour for plurals, for example.

Just to clarify if it makes sense for me to do it...

P.S. As an additional argument - this issue is 2 years old and there were multiple somewhat breaking updates in this time period. Maybe this needs to be implemented already?..

@Raiondesu
Copy link
Contributor

Ah, I'll do it anyway...

@Raiondesu
Copy link
Contributor

Raiondesu commented Oct 25, 2018

Everyone in need can install the updated lib from my github for now:

npm install raiondesu/vue-i18n#master

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

Successfully merging a pull request may close this issue.