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

Add possibility to provide diffrent values for past and future name and pluralName #12

Closed
ssaarinen opened this issue Mar 23, 2012 · 35 comments

Comments

@ssaarinen
Copy link
Contributor

Hi,

I started making Finnish translation for pretty time but realized that Finnish being awkward language needs different values for name/pluralName depending whether the duration is in the past or future.
eg.
1 minute ago = 1 minuutti sitten
1 minute from now = 1 minuutin päästä
3 minutes ago = 3 minuuttia sitten
3 minutes from now = 3 minuutin päästä

As you can (probably ;) see Finnish word minuutti (= minute) conjugation is different for past and future and it also depends if the duration is singular or not. So using just the past and future suffix leads to grammatically incorrect durations.

I could give this a stab my self but was just wondering what would be the best way to tackle this.

@lincolnthree
Copy link
Member

Hmmm... This is a good question! I'll need to think about it, but I'd love to entertain ideas!

@lincolnthree
Copy link
Member

It's possible that the resource bundle could specify a pluralizer object, which would handle making this type of decusion. How do you think we should do it?

@ssaarinen
Copy link
Contributor Author

Currently the decision to use plural name or not is made here:
https://github.com/ocpsoft/prettytime/blob/master/src/main/java/com/ocpsoft/pretty/time/BasicTimeFormat.java#L102

I think the straight forward way would be to add (past|future)[Plural]Name for the time unit and use those. It'd work in this case but would not be very pretty if there would be a need for more similar additions in the future.

Another thing that's some what related is the possibility for different time patterns for single and plural cases... At least in Finnish it is more fluent language to leave the number out of the phrase when there's only one eg. "minuutti sitten" vs "1 minuutti sitten". Same as in English "minute ago" vs "1 minute ago". The latter might be more acceptable in English but it looks like poor Finnish.

@lincolnthree
Copy link
Member

Yeah, in English, "1 minute ago" is proper. "Minute ago" doesn't have any meaning. But I can understand that would certainly be different in other languages :)

Do you think you could enumerate the different scenarios here so that I can see what types of complexity we are dealing with?

E.g: In English I would do this -

--- MINUTES
40 minutes ago
2 minutes ago
1 minute ago
--- SECONDS
moments ago
just now
moments from now
--- MINUTES
1 minute from now
2 minutes from now
40 minutes from now

Could you do the same thing in finnish, adding any other cases that may be different? Thanks!

@lincolnthree
Copy link
Member

I think it might be possible to add a few extra properties to the resource bundle in order to solve this. plus a few extra conditions in the time units to pick up these new properties. But I'll need to see.

@ssaarinen
Copy link
Contributor Author

Ok I wrote the combinations here: https://docs.google.com/spreadsheet/pub?key=0At8V2V1eCy5wdFdCcm8zbWt2U2h5RGl0bHV4MFFlVmc&output=html

For Finnish the different name for past and future timeunit would be adequate and maybe different pattern for single and plural.

And while we're at it I though about 1 day ago = yesterday and 1 day from now = tomorrow but it would still complicate matters.

@lincolnthree
Copy link
Member

Hey! I'd love to get that working, but we need to strategize an API to make it extendable and not break things :) Will take a look at your list and see what we can think of. Please feel free to suggest interfaces / APIs that would let this work smoothly!

@ssaarinen
Copy link
Contributor Author

Well adding the (past|future)[Plural]Name that could be used if present in the bundle and same for pluralPattern.

For the special cases maybe Timeformat#decorate could first delegate to some custom decorator passing it the duration and if it knows how to format the duration it could be used and if not do what it does now.

Default decorator could eg. use pattern generated from the duration to look up resource bundle like past_1_day=yesterday future_1_day=tomorrow

@lincolnthree
Copy link
Member

Adding another person to this thread for discussion.

@452
Copy link
Contributor

452 commented Mar 28, 2012

Ukrainian
--- хвилини(MINUTES)
45 хвилиН тому
44 хвилинИ тому
43 хвилинИ тому
42 хвилинИ тому
41 хвилинА тому (було 41 хвилинУ тому)
40 хвилиН тому (minutes ago)
5 хвилин тому
4 хвилинИ тому
3 хвилинИ тому (minutes ago)
2 хвилинИ тому (minutes ago)
1 хвилинА тому (minute ago)
0 хвилиН тому
було 1 хвилинУ тому
--- SECONDS
щойно (or and момент тому - but it's not beautiful) (moments ago)
тільки що (or and зараз) (just now)
через (moments from now)
--- MINUTES
через 0 хвилиН
через 1 хвилинУ (1 minute from now)
через дві хвилинИ (2 minutes from now)
через 40 хвилиН (40 minutes from now)

--- look this =)

years
через 1 ріК
через 2 рокИ
через 5 рокіВ

@452
Copy link
Contributor

452 commented Mar 28, 2012

Russian
--- минуты(MINUTES)
45 минуТ назад
44 минутЫ назад
43 минутЫ назад
42 минутЫ назад
41 минутУ назад (было 41 минутУ назад)
40 минуТ назад (minutes ago)
5 минуТ назад
4 минутЫ назад
3 минутЫ назад (minutes ago)
2 минутЫ назад (minutes ago)
1 минутУ назад (minute ago)
0 минут назад
было 1 минутУ назад
--- SECONDS
только что (or and момент назад - but it's not beautiful) (moments ago)
только что (or and сейчас) (just now)
через (moments from now)
--- MINUTES
через 0 минуТ
через 1 минутУ (1 minute from now)
через 2 минутЫ (2 minutes from now)
через 40 минуТ (40 minutes from now)

--- look this =)
years
через 1 гоД
через 2 годА
через 5 ЛЕТ

I write upper Changed word.

@452
Copy link
Contributor

452 commented Mar 28, 2012

what we have?:

--- MINUTES

  1. хвилинА (minute) (1, 21, 31, 41, 51, 61, 71, 101, 20001) - 1
  2. хвилинУ (minute) (1, 21, 31, 41, 51, 61, 71, 101, 20001) - 1
  3. хвилиН (minutes) (5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,30,40,50,60,70,80,90,100,110,120,130 ...)
  4. хвилинИ (minutes) (2,3,4,22,23,24,32,33,34) - 2,3,4
    need samples look up ^ (Ukrainian)

--- HOURS

  1. годинА (hour) (1, 21, 31, 41, 51, 61, 71, 101, 20001) - 1
  2. годинУ (hour) (1, 21, 31, 41, 51, 61, 71, 101, 20001) - 1
  3. годиН (hours) (5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,30,40,50,60,70,80,90,100,110,120,130 ...)
  4. годинИ (hours) (2,3,4,22,23,24,32,33,34) - 2,3,4

--- MONTHS

  1. місяцЬ (month) (1, 21, 31, 41, 51, 61, 71, 101, 20001) - 1
  2. місяцІ (months) (2,3,4,22,23,24,32,33,34) - 2,3,4
  3. місяціВ (months) (5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,30,40,50,60,70,80,90,100,110,120,130 ...)

--- YEARS

  1. рік (year) (1, 21, 31, 41, 51, 61, 71, 101, 20001) - 1
  2. роки (years) (2,3,4,22,23,24,32,33,34) - 2,3,4
  3. років (years) (5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,30,40,50,60,70,80,90,100,110,120,130 ...)

@452
Copy link
Contributor

452 commented Mar 28, 2012

sum in words on Russian ;) on English same function for PrettyTime it`s meybe good
http://www.sql.ru/forum/actualthread.aspx?tid=649518
http://lechlukasz.wordpress.com/2010/03/26/speak-russian-numbers-in-java/

@lincolnthree
Copy link
Member

It sounds like maybe the easiest thing to do is to add an interface to the resource bundles that would allow the resource bundle to handle control over the pluralization. If the bundle implements this resource, then the getPluralizer() can be called to return a Pluralizer object. This object will handle the logic for specific languages, but if not provided, the default behavior will be used. What do you think?

@ssaarinen
Copy link
Contributor Author

I think it would work. And after seeing the Ukrainian version I don't think Finnish is so complicated after all ;)

@lincolnthree
Copy link
Member

Haha :) Do you want to take a shot at implementing this, since you know what you need it to do? To be honest, I'm very confused trying to read your languages! :)

If you do, try to make sure that you only need to implement the interface in Resource bundles that need this feature. The others should be able to remain unchanged.

(I'm thinking about something like, if(bundle implements Pluralizer) { // do the work ... } etc... that might be a good start.

@ssaarinen
Copy link
Contributor Author

I'll try to work something out during the weekend...

@452
Copy link
Contributor

452 commented Mar 30, 2012

sample class for Ukrainian
/**
*

  • @author ihor
    */
    public class TimeSense {
    private String sense;

    public String Minutes(Integer timeVariant,int i){
    int lastNumber = i%10;
    switch(lastNumber){
    case 1: if (timeVariant.equals(1)) sense = "хвилину"; else sense = "хвилина";
    break;
    case 2:
    case 3:
    case 4: sense = "хвилини"; break;
    case 0:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9: sense = "хвилин";
    default:
    }
    return sense;
    }

    public String Hours(Integer timeVariant,int i){
    int lastNumber = i%10;
    switch(lastNumber){
    case 1: if (timeVariant.equals(1)) sense = "годину"; else sense = "година";
    break;
    case 2:
    case 3:
    case 4: sense = "години"; break;
    case 0:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9: sense = "годин";
    default:
    }
    return sense;
    }

    public String Months(int i){
    int lastNumber = i%10;
    switch(lastNumber){
    case 1: sense = "місяць"; break;
    case 2:
    case 3:
    case 4: sense = "місяці"; break;
    case 0:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9: sense = "місяців";
    default:
    }
    return sense;
    }

    public String Years(int i){
    int lastNumber = i%10;
    switch(lastNumber){
    case 1: sense = "рік"; break;
    case 2:
    case 3:
    case 4: sense = "роки"; break;
    case 0:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9: sense = "років";
    default:
    }
    return sense;
    }
    }

@ssaarinen
Copy link
Contributor Author

I guess "i" is the amount but what is timeVariant?

@452
Copy link
Contributor

452 commented Mar 30, 2012

timeVariant it's perfect variant of words

we have:
(1 minute ago)
1 хвилинУ тому/1минутУ назад - Ukrainian/Russian
(1 minute from now)
через 1 хвилинУ/через 1 минутУ
but in Ukrainian and Russian languages beautiful and perfect need variant(for the normal formation of the sentence):
1 хвилинА/1 минутА

English: minute, minutes
Ukrainian: хвилин (minutes), хвилина (minute), хвилини (minutes), хвилину (minute)
Russian: минут (minutes), минута (minute), минуты (minutes), минуту (minute)


Samples
Він був 41 хвилинУ тому.
Вона прийша через 41 хвилинУ.
До нового року залишилась 41 хвилинА. - it's hidden trouble for PrettyTime in future

{ "MinuteName", "хвилина" },
{ "MinuteName", "хвилину" },
{ "MinutePluralName", "хвилин" },

or PrettyTime very limit the possibility of forming a normal speech:
{ "MinuteName", "хвилину" },
{ "MinutePluralName", "хвилин" },

@lincolnthree
Copy link
Member

Fantastic! Let me know how I can help! I may try to lay out some kind of initial API if that would be of use :) You guys are the language experts, though!

@ssaarinen
Copy link
Contributor Author

Go ahead. I have to say that the Ukrainian/Russian variant is mind boggling :)

@452
Copy link
Contributor

452 commented Mar 31, 2012

I have friend from Belarusian, and can translate...
and have some trouble Ukrainian/Russian/Belarusian - it's http://en.wikipedia.org/wiki/East_Slavic_languages
http://en.wikipedia.org/wiki/Ukrainian_language
http://en.wikipedia.org/wiki/Belarusian_language
http://en.wikipedia.org/wiki/Russian_language

Minutes:
хвілін
хвіліна
хвіліну
хвіліны

@lincolnthree
Copy link
Member

Okay guys. Tell me what you think. I had to break backwards compatability to get this to work, but ResourceBundles may now implement TimeFormatProvider, and specify TimeFormat instances for TimeUnits directly:

This should give you full control over formatting duration objects. Once we see the patterns required to do this, we could possibly update the API or create some base-classes to make things simpler.

For now, however, what I need you guys to do, is to try to implement your Resources_XX files using this new API. It may not be super easy, but you have control. We can make things easier after we see how this needs to work.

You can take a look at an example test-case here: https://github.com/ocpsoft/prettytime/tree/master/src/test/java/org/ocpsoft/pretty/time/i18n

Please submit pull requests when you have something!
~Lincoln

@lincolnthree
Copy link
Member

Consequently, because of the API breakage, the next release will be 2.0.

@ssaarinen
Copy link
Contributor Author

Looks good. I'll try to implement the Finnish version during Easter.

@452
Copy link
Contributor

452 commented Apr 6, 2012

decorateUnrounded not used.

test ok.

but i not test Russian - Years - 1 год, 2 года, 5 лет. it's dif words. in Ukrainian it's 1 рік, 2 роки, 5 років - we have "р".

package org.ocpsoft.pretty.time.i18n;
/*

  • Copyright 2012 Lincoln Baxter, III
  • Licensed under the Apache License, Version 2.0 (the "License");
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
  • http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an "AS IS" BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.
    */

import java.util.ListResourceBundle;
import org.ocpsoft.pretty.time.Duration;
import org.ocpsoft.pretty.time.TimeFormat;
import org.ocpsoft.pretty.time.TimeUnit;
import org.ocpsoft.pretty.time.impl.TimeFormatProvider;
import org.ocpsoft.pretty.time.units.Hour;
import org.ocpsoft.pretty.time.units.Minute;
import org.ocpsoft.pretty.time.units.Month;
import org.ocpsoft.pretty.time.units.Year;

public class Resources_ua extends ListResourceBundle implements TimeFormatProvider
{
private static final Object[][] OBJECTS = new Object[][] {};

@OverRide
public Object[][] getContents()
{
return OBJECTS;
}

@OverRide
public TimeFormat getFormatFor(TimeUnit t)
{
if (t instanceof Minute)
{
return new TimeFormat() {

        @Override
        public String decorate(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=11 ? "у" : (lastNumber>1 && lastNumber<5 && (duration.getQuantity()<11 || duration.getQuantity()>15)) ? "и" : "");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String decorateUnrounded(Duration duration, String time)
        {
           String result = duration.getQuantity() > 1 ? time + "i" : "o";
           result += duration.isInPast() ? " тому" : " через";
           return result;
        }

        @Override
        public String format(Duration duration)
        {
           return duration.getQuantityRounded(50) + " хвилин";
        }

        @Override
        public String formatUnrounded(Duration duration)
        {
           return duration.getQuantity() + " хвилин";
        }
     };
  }
  if (t instanceof Hour)
  {
     return new TimeFormat() {

        @Override
        public String decorate(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=11 ? "у" : (lastNumber>1 && lastNumber<5 && (duration.getQuantity()<11 || duration.getQuantity()>15)) ? "и" : "");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String decorateUnrounded(Duration duration, String time)
        {
           String result = duration.getQuantity() > 1 ? time + "i" : "o";
           result += duration.isInPast() ? " тому" : " через";
           return result;
        }

        @Override
        public String format(Duration duration)
        {
           return duration.getQuantityRounded(50) + " годин";
        }

        @Override
        public String formatUnrounded(Duration duration)
        {
           return duration.getQuantity() + " годин";
        }
     };
  }
  if (t instanceof Month)
  {
     return new TimeFormat() {

        @Override
        public String decorate(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=11 ? "ь" : (lastNumber>1 && lastNumber<4) ? "і" : "ів");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String decorateUnrounded(Duration duration, String time)
        {
           String result = duration.getQuantity() > 1 ? time + "i77" : "o";
           result += duration.isInPast() ? " тому" : " через";
           return result;
        }

        @Override
        public String format(Duration duration)
        {
           return duration.getQuantityRounded(50) + " місяц";
        }

        @Override
        public String formatUnrounded(Duration duration)
        {
           return duration.getQuantity() + " місяц";
        }
     };
  }
  if (t instanceof Year)
  {
     return new TimeFormat() {

        @Override
        public String decorate(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=11 ? "ік" : (lastNumber>1 && lastNumber<4) ? "оки" : "оків");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String decorateUnrounded(Duration duration, String time)
        {
           String result = duration.getQuantity() > 1 ? time + "i77" : "o";
           result += duration.isInPast() ? " тому" : " через";
           return result;
        }

        @Override
        public String format(Duration duration)
        {
           return duration.getQuantityRounded(50) + " р";
        }

        @Override
        public String formatUnrounded(Duration duration)
        {
           return duration.getQuantity() + " р";
        }
     };
  }
  return null;

}

}

package org.ocpsoft.pretty.time.i18n;

import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import org.junit.Assert;
import org.junit.Test;
import org.ocpsoft.pretty.time.PrettyTime;
import org.ocpsoft.pretty.time.impl.TimeFormatProvider;

public class TimeFormatProviderTest
{
@test
public void test()
{
ResourceBundle bundle = ResourceBundle.getBundle("org.ocpsoft.pretty.time.i18n.Resources", new Locale("ua"));
Assert.assertTrue(bundle instanceof TimeFormatProvider);
}

/*
@test
public void test1FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 1));
Assert.assertEquals("через 1 хвилину", result);
}

@test
public void test4FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 4));
Assert.assertEquals("через 4 хвилин", result);
}
_/
@test
public void test6FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 6));
Assert.assertEquals("через 6 хвилин", result);
}
@test
public void test10FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 10));
Assert.assertEquals("через 10 хвилин", result);
}
@test
public void test11FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 11));
Assert.assertEquals("через 11 хвилин", result);
}
@test
public void test12FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 12));
Assert.assertEquals("через 12 хвилин", result);
}
@test
public void test13FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 13));
Assert.assertEquals("через 13 хвилин", result);
}
@test
public void test14FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 14));
Assert.assertEquals("через 14 хвилин", result);
}
@test
public void test15FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 15));
Assert.assertEquals("через 15 хвилин", result);
}
@test
public void test20FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 20));
Assert.assertEquals("через 20 хвилин", result);
}
@test
public void test21FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 21));
Assert.assertEquals("через 21 хвилину", result);
}
@test
public void test22FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 22));
Assert.assertEquals("через 22 хвилини", result);
}
@test
public void test23FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 23));
Assert.assertEquals("через 23 хвилини", result);
}
@test
public void test24FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 24));
Assert.assertEquals("через 24 хвилини", result);
}
@test
public void test25FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 25));
Assert.assertEquals("через 25 хвилин", result);
}
@test
public void test26FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 26));
Assert.assertEquals("через 26 хвилин", result);
}
@test
public void test27FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 27));
Assert.assertEquals("через 27 хвилин", result);
}
@test
public void test28FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 28));
Assert.assertEquals("через 28 хвилин", result);
}
@test
public void test29FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 29));
Assert.assertEquals("через 29 хвилин", result);
}
@test
public void test59FormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 59));
Assert.assertEquals("через 59 хвилин", result);
}
@test
public void test1HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 1));
Assert.assertEquals("через 1 годину", result);
}
@test
public void test2HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 2));
Assert.assertEquals("через 2 години", result);
}
@test
public void test3HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 3));
Assert.assertEquals("через 3 години", result);
}
@test
public void test4HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 4));
Assert.assertEquals("через 4 години", result);
}
@test
public void test5HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 5));
Assert.assertEquals("через 5 годин", result);
}
@test
public void test6HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 6));
Assert.assertEquals("через 6 годин", result);
}
@test
public void test7HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 7));
Assert.assertEquals("через 7 годин", result);
}
@test
public void test8HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8));
Assert.assertEquals("через 8 годин", result);
}
@test
public void test9HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 9));
Assert.assertEquals("через 9 годин", result);
}
@test
public void test10HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10));
Assert.assertEquals("через 10 годин", result);
}
@test
public void test11HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 11));
Assert.assertEquals("через 11 годин", result);
}
@test
public void test12HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12));
Assert.assertEquals("через 12 годин", result);
}
@test
public void test13HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 13));
Assert.assertEquals("через 13 годин", result);
}
@test
public void test14HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 14));
Assert.assertEquals("через 14 годин", result);
}
@test
public void test15HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 15));
Assert.assertEquals("через 15 годин", result);
}
@test
public void test16HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 16));
Assert.assertEquals("через 16 годин", result);
}
@test
public void test17HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 17));
Assert.assertEquals("через 17 годин", result);
}
@test
public void test18HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 18));
Assert.assertEquals("через 18 годин", result);
}
@test
public void test19HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 19));
Assert.assertEquals("через 19 годин", result);
}
@test
public void test20HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 20));
Assert.assertEquals("через 20 годин", result);
}
@test
public void test21HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 21));
Assert.assertEquals("через 21 годину", result);
}
@test
public void test22HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 22));
Assert.assertEquals("через 22 години", result);
}
@test
public void test23HourFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 23));
Assert.assertEquals("через 23 години", result);
}
@test
public void test1MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3));
Assert.assertEquals("через 1 місяць", result);
}
@test
public void test2MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_2));
Assert.assertEquals("через 2 місяці", result);
}
@test
public void test3MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_3));
Assert.assertEquals("через 3 місяці", result);
}
@test
public void test5MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_4));
Assert.assertEquals("через 5 місяців", result);
}
@test
public void test6MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_5));
Assert.assertEquals("через 6 місяців", result);
}
@test
public void test7MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_6));
Assert.assertEquals("через 7 місяців", result);
}
@test
public void test8MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_7));
Assert.assertEquals("через 8 місяців", result);
}
@test
public void test9MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_8));
Assert.assertEquals("через 9 місяців", result);
}
@test
public void test10MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_9));
Assert.assertEquals("через 10 місяців", result);
}
@test
public void test11MonthFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_10));
Assert.assertEquals("через 11 місяців", result);
}
@test
public void test1YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_12));
Assert.assertEquals("через 1 рік", result);
}
@test
public void test2YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_12_2));
Assert.assertEquals("через 2 роки", result);
}
@test
public void test3YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_3_12_3));
Assert.assertEquals("через 3 роки", result);
}
@test
public void test4YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_2_15_4));
Assert.assertEquals("через 4 роки", result);
}
@test
public void test5YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_2_15_5));
Assert.assertEquals("через 5 років", result);
}
@test
public void test6YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_2_15_6));
Assert.assertEquals("через 6 років", result);
}
@test
public void test9YearFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() + 1000000000L_2_15_9));
Assert.assertEquals("через 9 років", result);
}
}

@lincolnthree
Copy link
Member

Looks like this is working! I have a few questions.

  1. Why so many nested ternary operators? Makes it really hard to follow (and refactor later) :)
  2. Why did you not need decorateUnrounded(). Does this function serve no purpose?
  3. Looks like there is a big opportunity for code-reuse within your ResourceBundle - perhaps some refactoring could help here?
  4. I assume you're working on the rest of the time units? Surely you have more than just Minute, Hour, Month, and Year in Russian :) Unless I'm mistaken, currently this code will not be able to Format the other units?
  5. Awesome tests! I love tests!
  6. What could be different to make this easier for you?

Again, awesome! Looks great so far!
~Lincoln

@452
Copy link
Contributor

452 commented Apr 6, 2012

  1. I newbie in Java - I migrate from embedded systems (c,c++,delphi,php,AS3). and now learn Java Core... =)))
  2. All work fine and decorateUnrounded() not needed. All tests results good. o_O why you need?
  3. Maybe I newbie.
  4. Can be, yes, we have, but usually we use the same unit of time as used you.
  5. Yes and I too love tests from now. This is my first use of tests.
  6. o_O not understand question=)))

@lincolnthree
Copy link
Member

  1. Ok, no problem :) But for my benefit, could you replace these with if(...) {} else {} statements? Thanks! That will make it easier for me to do Issue 13: PrettyTimeConverter JSF not locale aware #3 (below)
  2. .decorateUnrounded() is used when performing prettyTime.format(prettyTime.calculatePreciseDuration()) - perhaps you should try this in your tests and see what happens :)
  3. If you keep writing tests, I can try to do this for you.
  4. Ok cool, when you have the rest of them, with tests, please send a pull request and I will try to do some refactoring and clean things up :)
  5. :)
  6. I was asking if there is anything I can change to make it easier, or simpler to achieve this goal.

@452
Copy link
Contributor

452 commented Apr 6, 2012

.decorateUnrounded() ... - )))
if (t instanceof Minute)
{
return new TimeFormat() {

        @Override
        public String decorate(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=11 ? "у" : (lastNumber>1 && lastNumber<5 && (duration.getQuantity()<11 || duration.getQuantity()>15)) ? "и" : "");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String decorateUnrounded(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=-11 ? "у" : (lastNumber<-1 && lastNumber>-5 && (duration.getQuantity()>-11 || duration.getQuantity()<-15)) ? "и" : "");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String format(Duration duration)
        {
           return duration.getQuantityRounded(50) + " хвилин";
        }

        @Override
        public String formatUnrounded(Duration duration)
        {
           return duration.getQuantity() + " хвилин";
        }
     };

@test
public void test6AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(new Date(System.currentTimeMillis() - 1000 * 60 * 6));
Assert.assertEquals("6 хвилин тому", result);
}
@test
public void test11AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 11)));
Assert.assertEquals("11 хвилин тому", result);
}
@test
public void test14AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 14)));
Assert.assertEquals("14 хвилин тому", result);
}
@test
public void test22AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 22)));
Assert.assertEquals("22 хвилини тому", result);
}
@test
public void test23AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 23)));
Assert.assertEquals("23 хвилини тому", result);
}
@test
public void test53AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 53)));
Assert.assertEquals("53 хвилини тому", result);
}
@test
public void test25AgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 25)));
Assert.assertEquals("25 хвилин тому", result);
}

@452
Copy link
Contributor

452 commented Apr 6, 2012

and only last test not work, and some time test work good, and some time have error, sample: 22 hours 22 minutes ago or moments ago 22 minutes ago.

  if (t instanceof Hour)
  {
     return new TimeFormat() {

        @Override
        public String decorate(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=11 ? "у" : (lastNumber>1 && lastNumber<5 && (duration.getQuantity()<11 || duration.getQuantity()>15)) ? "и" : "");
           result += duration.isInPast() ? " тому" : "";
           return result;
        }

        @Override
        public String decorateUnrounded(Duration duration, String time)
        {
           String result = duration.isInFuture() ? "через " : "";
           Long lastNumber = duration.getQuantity()%10;
           result += time+(lastNumber==1 && duration.getQuantity()!=-11 ? "у" : (lastNumber<-1 && lastNumber>-5 && (duration.getQuantity()>-11 || duration.getQuantity()<-15)) ? "и" : "");
           result += duration.isInPast() ? " тому": "";
           return result;
        }

        @Override
        public String format(Duration duration)
        {
           return duration.getQuantityRounded(50) + " годин";
        }

        @Override
        public String formatUnrounded(Duration duration)
        {
           return duration.getQuantity() + " годин";
        }
     };
  }

@test
public void test8Hours20minAgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 500)));
Assert.assertEquals("-8 годин 20 хвилин тому", result);
}
@test
public void test8Hours22minAgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 502)));
Assert.assertEquals("-8 годин 22 хвилини тому", result);
}
@test
public void test16Hours42minAgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 1002)));
Assert.assertEquals("-16 годин 42 хвилини тому", result);
}
@test
public void test22Hours32minAgoFormatFromDirectFormatOverride() throws Exception
{
PrettyTime prettyTime = new PrettyTime(new Locale("ua"));
String result = prettyTime.format(prettyTime.calculatePreciseDuration(new Date(System.currentTimeMillis() - 1000 * 60 * 1352)));
Assert.assertEquals("-22 години 32 хвилини тому", result);
}

@lincolnthree
Copy link
Member

I don't believe you want your numbers to start with '-' do you? Also, if your rounded and unRounded methods are the same, why not just call one from the other?

@lincolnthree
Copy link
Member

I am going to close this issue since it seems like this feature is now working. We can continue discussion of your implementation on the forums, or on a pull-request here.

@ntobeko-mkhize
Copy link

Is there a way to return 1 day ago as yesterday from the standard resource bundle? I see this considered in this thread

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