Modify localization interface #7

Closed
YURSHAT opened this Issue Jul 11, 2015 · 6 comments

Projects

None yet

2 participants

@YURSHAT
YURSHAT commented Jul 11, 2015

Hello!
I want translate interface into Russian language, but could not make that correctly because current functional allow use only one 'plural', but for Russian need two.
Example for seconds

1       - секунда
2 - 4   - секунды
5 - 20  - секунд
21      - секунда
22 - 24 - секунды
25 - 30 - секунд

Russian localization must be so

countdown.setLabels(
    ' миллисекунда| секунда| минута| час| день| неделя| месяц| год| декада| столетие| тысячелетие',
    ' миллисекунды| секунды| минуты| часа| дня| недели| месяца| года| декады| столетия| тысячелетия',
    ' миллисекунд| секунд| минут| часов| дней| недель| месяцев| лет| декад| столетий| тысячелетий',
    ' и ',
    ', ',
    '');

Please, modify setLabels function for these.
Thanks

@mckamey
Owner
mckamey commented Jul 11, 2015

This is an interesting problem. The localization features of countdown.js are obviously pretty limited and very English-centric. I don't think that adding a Russian-specific parameter is the correct solution. Odds are very good that there will be another language that has yet another unique variation. It just doesn't scale well.

But a catch-all solution might be to let it take a function which allows custom formatting. I'm thinking this would allow you to set some function which looks like:

/**
 * Format the time unit using Russian plurality rules.
 * @param {number} value The time value.
 * @param {number} unit The time unit constant.
 * @return {string}
 */
function(value, unit) {
  switch(unit) {
    case countdown.MILLENNIA:
    // ...
    case countdown.SECONDS:
      // I tried to generalize the rules you mention but don't know if this is correct...
      var plural = value % 10;
      if (plural === 1) {
        // singular
        return value+' секунда';
      }
      if ((plural > 1 && plural < 5) && (value < 5 || value > 22)) {
        // plurals 2-4 but not 12-14
        return value+' секунды';
      }
      // general plural
      return value+' секунд';
    case countdown.MILLISECONDS:
    // ...
  }
}
@mckamey mckamey added a commit that referenced this issue Jul 11, 2015
@mckamey Improving localization interface for more customization. Fixes #1, #7.
Changing from a parameter list to a format object. This makes it easier when only changing a few settings.
Adding a formatter function option which enables custom formatting for more complex plurality rules.
472b65e
@mckamey
Owner
mckamey commented Jul 11, 2015

TODO: update docs.

@YURSHAT
YURSHAT commented Jul 12, 2015

@mckamey, thanks for your answer

I don't think that adding a Russian-specific parameter is the correct solution.

This is not only 'Russian-specific' parameter. In many other languages has a similar structure - Ukrainain, Bosnian, Czech, Croatian, Polish, Slovak, Serbian, Thai and many more...

For example this plugin well implemented multilanguage.

I think if you expand the language functional it will increase the number of users of your wonderful plugin

@mckamey
Owner
mckamey commented Jul 12, 2015

@YURSHAT did you try out the option I added? I think that it is more flexible than what you are asking for. I added a unit test (see below) which follows your pattern.

I'm concerned that even in the other languages you mentioned they may be "similar" but not the "same". From what I know of Thai it doesn't work this way at all. Many of the others have more similar etymological roots so it doesn't surprise me if they have similar grammatical rules.

I could do something similar to the plugin you linked to but that is about as much code as the solution that I provided but not as flexible:

    var ONE = ' миллисекунда| секунда| минута| час| день| неделя| месяц| год| декада| столетие| тысячелетие'.split('|');
    var FEW = ' миллисекунды| секунды| минуты| часа| дня| недели| месяца| года| декады| столетия| тысячелетия'.split('|');
    var MANY = ' миллисекунд| секунд| минут| часов| дней| недель| месяцев| лет| декад| столетий| тысячелетий'.split('|');

    var russianUnits = function(value, unit) {
        // Tried to generalize the rules but don't know if this is really correct...
        var plural = value % 10;
        if (plural === 1) {
            // singular
            return value+ONE[unit];
        }
        if ((plural >= 2 && plural <= 4) && (value < 10 || value > 19)) {
            // plurals n2-n4 but not 12-14
            return value+FEW[unit];
        }
        // general plural
        return value+MANY[unit];
    };

    countdown.setFormat({ formatter: russianUnits });

I think this simple expansion is sufficient to cover all the examples I've seen so far. Feel free to post on here others that cannot be performed this way.

@mckamey mckamey closed this Jul 12, 2015
@YURSHAT
YURSHAT commented Jul 12, 2015

@mckamey yes, I tried. This is a good way 👍 . Thanks.

Correct Russian sample

var ONE = ' миллисекунда| секунда| минута| час| день| неделя| месяц| год| декада| столетие| тысячелетие'.split('|');
var FEW = ' миллисекунды| секунды| минуты| часа| дня| недели| месяца| года| декады| столетия| тысячелетия'.split('|');
var MANY = ' миллисекунд| секунд| минут| часов| дней| недель| месяцев| лет| декад| столетий| тысячелетий'.split('|');

var russianUnits = function(value, unit) {
    var singular = value % 10;
    var plural = Math.floor((value % 100) / 10);

    if (value == 1) {
        return value + ONE[unit];
    }
    else if (singular >= 2 && singular <= 4 && plural != 1) {
        return value + FEW[unit];
    }
    else if (singular == 1 && plural != 1) {
        return value + ONE[unit];
    }
    else {
        return value + MANY[unit];
    }
};

countdown.setLabels('', '', ' и ', ', ', '');
countdown.setFormat({ formatter: russianUnits });

Best Regards

@mckamey
Owner
mckamey commented Jul 15, 2015

Sounds good. That new setFormat method actually takes the params from setLabels as an object, so no need to do them both. So here is the logic slightly more succinct.

    var ONE = ' миллисекунда| секунда| минута| час| день| неделя| месяц| год| декада| столетие| тысячелетие'.split('|');
    var TWO = ' миллисекунды| секунды| минуты| часа| дня| недели| месяца| года| декады| столетия| тысячелетия'.split('|');
    var MANY = ' миллисекунд| секунд| минут| часов| дней| недель| месяцев| лет| декад| столетий| тысячелетий'.split('|');

    var russianUnits = function(value, unit) {
        if (Math.floor((value % 100) / 10) !== 1) {
            var mod = value % 10;
            if (mod === 1) {
                // singular or plurals ending in 1 except 11
                return value+ONE[unit];
            }
            if (mod >= 2 && mod <= 4) {
                // plurals ending in 2-4 except 12-14
                return value+TWO[unit];
            }
        }
        // general plurals
        return value+MANY[unit];
    };

    countdown.setFormat({
        last: ' и ',
        delim: ', ',
        formatter: russianUnits
    });

I still need to update the docs...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment