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

Fix for formatDuration method for russian locale #260

Merged
merged 2 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 69 additions & 58 deletions core/src/main/java/org/ocpsoft/prettytime/i18n/Resources_ru.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.ocpsoft.prettytime.impl.TimeFormatProvider;
import org.ocpsoft.prettytime.units.*;

import java.util.Arrays;
import java.util.ListResourceBundle;

/**
Expand All @@ -18,83 +19,91 @@ public class Resources_ru extends ListResourceBundle implements TimeFormatProvid
private static final int tolerance = 50;

// see http://translate.sourceforge.net/wiki/l10n/pluralforms
private static final int russianPluralForms = 3;
private static final int russianPluralForms = 4;

private static class TimeFormatAided implements TimeFormat
{
private class TimeFormatAided implements TimeFormat {
private final String[] pluarls;

public TimeFormatAided(String... plurals)
{
public TimeFormatAided(String... plurals) {
if (plurals.length != russianPluralForms) {
throw new IllegalArgumentException("Wrong plural forms number for russian language!");
throw new IllegalArgumentException(String.format("Wrong plural forms number for russian language! " +
"Expected %s, got %s\nPlurals: %s", russianPluralForms, plurals.length, Arrays.toString(plurals)));
}
this.pluarls = plurals;
}

@Override
public String format(Duration duration)
{
long quantity = duration.getQuantityRounded(tolerance);
return String.valueOf(quantity);
}

@Override
public String formatUnrounded(Duration duration)
{
long quantity = Math.abs(duration.getQuantity());
return String.valueOf(quantity);
}

@Override
public String decorate(Duration duration, String time)
{
return performDecoration(
duration.isInPast(),
duration.isInFuture(),
duration.getQuantityRounded(tolerance),
time);
public String format(Duration duration) {
long roundedQuantity = Math.abs(duration.getQuantityRounded(tolerance));
return performFormat(roundedQuantity, true);
}

@Override
public String decorateUnrounded(Duration duration, String time)
{
return performDecoration(
duration.isInPast(),
duration.isInFuture(),
Math.abs(duration.getQuantity()),
time);
public String formatUnrounded(Duration duration) {
long unroundedQuantity = Math.abs(duration.getQuantity());
return performFormat(unroundedQuantity, true);
}

private String performDecoration(boolean past, boolean future, long n, String time)
{
public String performFormat(long n, boolean isDuration) {
// a bit cryptic, yet well-tested
// consider http://translate.sourceforge.net/wiki/l10n/pluralforms
int pluralIdx = (n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4
&& (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);

if (pluralIdx > russianPluralForms) {
// impossible happening
throw new IllegalStateException("Wrong plural index was calculated somehow for russian language");
}

StringBuilder result = new StringBuilder();
String result = String.valueOf(n) +
' ' +
pluarls[isDuration && pluralIdx == 0 ? pluralIdx : pluralIdx + 1];

if (future) {
result.append("через ");
}
return result;
}

result.append(time);
result.append(' ');
result.append(pluarls[pluralIdx]);
@Override
public String decorate(Duration duration, String time) {
if(requiresReformatting(duration, true)) {
long roundedQuantity = Math.abs(duration.getQuantityRounded(tolerance));
return performDecoration(duration, performFormat(roundedQuantity, false));
}
return performDecoration(duration, time);
}

if (past) {
result.append(" назад");
@Override
public String decorateUnrounded(Duration duration, String time) {
if(requiresReformatting(duration, false)) {
long unroundedQuantity = Math.abs(duration.getQuantity());
return performDecoration(duration, performFormat(unroundedQuantity, false));
}
return performDecoration(duration, time);
}

return result.toString();
public String performDecoration(Duration duration, String time) {
if (duration.isInFuture()) {
return "через " + time;
}
if (duration.isInPast()) {
return time + " назад";
}
return time;
}

/**
* While in English format can be achieved by simply adding " ago" to formatDuration result,
* in Russian there's difference: "1 minute" is "1 минута" but "1 minute ago" is "1 минуту назад"
* see here: <a href="https://www.thoughtco.com/russian-cases-4768614">article about russian grammatical cases</a>
* This hacky method checks if it's the case when result of format method should be corrected.
* @param duration The original {@link Duration} instance from which the time string should be decorated.
* @param isRounded Determines whether rounded quantity be checked or plain one
* @return Is reformatting required (is case "1 минута" - "1 минуту назад" - "через 1 минуту" reached)
*/
public boolean requiresReformatting(Duration duration, boolean isRounded) {
long quantity = isRounded ? Math.abs(duration.getQuantityRounded(tolerance)) : Math.abs(duration.getQuantity());
return quantity == 1;
}
}

@Override
public Object[][] getContents()
{
Expand Down Expand Up @@ -129,6 +138,8 @@ private String performFormat(Duration duration)
return null;
}



@Override
public String decorate(Duration duration, String time)
{
Expand All @@ -143,37 +154,37 @@ public String decorateUnrounded(Duration duration, String time)
};
}
else if (t instanceof Century) {
return new TimeFormatAided("век", "века", "веков");
return new TimeFormatAided("век", "век", "века", "веков");
}
else if (t instanceof Day) {
return new TimeFormatAided("день", "дня", "дней");
return new TimeFormatAided("день", "день", "дня", "дней");
}
else if (t instanceof Decade) {
return new TimeFormatAided("десятилетие", "десятилетия", "десятилетий");
return new TimeFormatAided("десятилетие", "десятилетие", "десятилетия", "десятилетий");
}
else if (t instanceof Hour) {
return new TimeFormatAided("час", "часа", "часов");
return new TimeFormatAided("час", "час", "часа", "часов");
}
else if (t instanceof Millennium) {
return new TimeFormatAided("тысячелетие", "тысячелетия", "тысячелетий");
return new TimeFormatAided("тысячелетие", "тысячелетие", "тысячелетия", "тысячелетий");
}
else if (t instanceof Millisecond) {
return new TimeFormatAided("миллисекунду", "миллисекунды", "миллисекунд");
return new TimeFormatAided("миллисекунда", "миллисекунду", "миллисекунды", "миллисекунд");
}
else if (t instanceof Minute) {
return new TimeFormatAided("минуту", "минуты", "минут");
return new TimeFormatAided("минута", "минуту", "минуты", "минут");
}
else if (t instanceof Month) {
return new TimeFormatAided("месяц", "месяца", "месяцев");
return new TimeFormatAided("месяц", "месяц", "месяца", "месяцев");
}
else if (t instanceof Second) {
return new TimeFormatAided("секунду", "секунды", "секунд");
return new TimeFormatAided("секунда", "секунду", "секунды", "секунд");
}
else if (t instanceof Week) {
return new TimeFormatAided("неделю", "недели", "недель");
return new TimeFormatAided("неделя", "неделю", "недели", "недель");
}
else if (t instanceof Year) {
return new TimeFormatAided("год", "года", "лет");
return new TimeFormatAided("год", "год", "года", "лет");
}
return null; // error
}
Expand Down
Loading