Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

default locale for getRelativeTimeSpanString

I override the locale of my app using:

 Locale locale = new Locale("ca");
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config,
            getBaseContext().getResources().getDisplayMetrics());

But it seems that getRelativeTimeSpanString doesn't work with application context, and instead use the system locale.

like image 910
user1458180 Avatar asked Feb 27 '14 15:02

user1458180


2 Answers

Your solution was almost correct.

However, since the strings are loaded from the system resources, you must update the configuration of the system resources. Below is what I did:

    Configuration configuration = new Configuration(Resources.getSystem().getConfiguration());
        configuration.locale = Locale.GERMANY; // or whichever locale you desire
        Resources.getSystem().updateConfiguration(configuration, null);

(NB: From Jelly Bean MR1 onwards, it is recommended to use

configuration.setLocale(Locale.GERMANY);

to change the locale rather then setting the member directly.)

like image 68
Thorstenvv Avatar answered Oct 17 '22 13:10

Thorstenvv


I had this problem today and took me several hours to "solve".

I recommend you that if you can use getRelativeTimeSpanString(context, long, boolean) instead do so. It was not my case as the resulting string is not the same as getRelativeTimeSpanString(long).

My workaround requires to copy some android internal resources of a couple of strings to your code so it will be quite annoying if you have a lot of languages to support.

I tracked the current source code of Android (4.4 r1) and extracted DateUtils and changed so you can use it like this:

CharSequence desiredString = MyDateUtils.getRelativeTimeSpanString(time, 
                System.currentTimeMillis(), 
                DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR, activity);

That will give you the same result as getRelativeTimeSpanString(long).

To make MyDateUtils i only kept:

public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, int flags, Context c)

I added the context to the method, then changed the system resources for context resources and all the internal android strings for my own strings (which are the same as android's but couldnt find a way to use them as they were internal).

private static final String getRelativeDayString(Resources r, long day, long today)

Also kept this method as its used by the prior. Here i changed the strings as well.

For copy paste purposes

This is my implementation of MyDateUtils:

import java.util.Locale;
import android.content.Context;
import android.content.res.Resources;
import android.text.format.DateUtils;
import android.text.format.Time;
import com.YOURPACKAGE.R;
/**
 * This class contains various date-related utilities for creating text for things like
 * elapsed time and date ranges, strings for days of the week and months, and AM/PM text     etc.
 */
public class MyDateUtils
{

/**
 * Returns a string describing 'time' as a time relative to 'now'.
 * <p>
 * Time spans in the past are formatted like "42 minutes ago". Time spans in
 * the future are formatted like "in 42 minutes".
 * <p>
 * Can use {@link #FORMAT_ABBREV_RELATIVE} flag to use abbreviated relative
 * times, like "42 mins ago".
 *
 * @param time the time to describe, in milliseconds
 * @param now the current time in milliseconds
 * @param minResolution the minimum timespan to report. For example, a time
 *            3 seconds in the past will be reported as "0 minutes ago" if
 *            this is set to MINUTE_IN_MILLIS. Pass one of 0,
 *            MINUTE_IN_MILLIS, HOUR_IN_MILLIS, DAY_IN_MILLIS,
 *            WEEK_IN_MILLIS
 * @param flags a bit mask of formatting options, such as
 *            {@link #FORMAT_NUMERIC_DATE} or
 *            {@link #FORMAT_ABBREV_RELATIVE}
 */
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution,
        int flags, Context c) {
    Resources r = c.getResources();
    //boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;

    boolean past = (now >= time);
    long duration = Math.abs(now - time);

    int resId;
    long count;
    if (duration < DateUtils.MINUTE_IN_MILLIS && minResolution < DateUtils.MINUTE_IN_MILLIS) {
        count = duration / DateUtils.SECOND_IN_MILLIS;
        if (past) {
            resId = R.plurals.num_seconds_ago;
        } else {
            resId = R.plurals.in_num_seconds;
        }
    } else if (duration < DateUtils.HOUR_IN_MILLIS && minResolution < DateUtils.HOUR_IN_MILLIS) {
        count = duration / DateUtils.MINUTE_IN_MILLIS;
        if (past) {
            resId = R.plurals.num_minutes_ago;
        } else {
            resId = R.plurals.in_num_minutes;
        }
    } else if (duration < DateUtils.DAY_IN_MILLIS && minResolution < DateUtils.DAY_IN_MILLIS) {
        count = duration / DateUtils.HOUR_IN_MILLIS;
        if (past) {
            resId = R.plurals.num_hours_ago;
        } else {
            resId = R.plurals.in_num_hours;
        }
    } else if (duration < DateUtils.WEEK_IN_MILLIS && minResolution < DateUtils.WEEK_IN_MILLIS) {
        return getRelativeDayString(r, time, now);
    } else {
        // We know that we won't be showing the time, so it is safe to pass
        // in a null context.
        return DateUtils.formatDateRange(null, time, time, flags);
    }

    String format = r.getQuantityString(resId, (int) count);
    return String.format(format, count);
}



/**
 * Returns a string describing a day relative to the current day. For example if the day is
 * today this function returns "Today", if the day was a week ago it returns "7 days ago", and
 * if the day is in 2 weeks it returns "in 14 days".
 *
 * @param r the resources
 * @param day the relative day to describe in UTC milliseconds
 * @param today the current time in UTC milliseconds
 */
private static final String getRelativeDayString(Resources r, long day, long today) {
    Locale locale = r.getConfiguration().locale;
    if (locale == null) {
        locale = Locale.getDefault();
    }

    // TODO: use TimeZone.getOffset instead.
    Time startTime = new Time();
    startTime.set(day);
    int startDay = Time.getJulianDay(day, startTime.gmtoff);

    Time currentTime = new Time();
    currentTime.set(today);
    int currentDay = Time.getJulianDay(today, currentTime.gmtoff);

    int days = Math.abs(currentDay - startDay);
    boolean past = (today > day);

    // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
    if (days == 1) {
        if (past) {
            return r.getString(R.string.yesterday);
        } else {
            return r.getString(R.string.tomorrow);
        }
    } else if (days == 0) {
        return r.getString(R.string.today);
    }

    int resId;
    if (past) {
        resId = R.plurals.num_days_ago;
    } else {
        resId = R.plurals.in_num_days;
    }

    String format = r.getQuantityString(resId, days);
    return String.format(format, days);
}
}

On values folder string.xml add:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 <string name="yesterday">yesterday</string>
 <string name="tomorrow">tomorrow</string>
 <string name="today">today</string>

    <plurals name="num_seconds_ago">
        <item quantity="one">1 second ago</item>
        <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds ago</item>
    </plurals>
    <plurals name="num_minutes_ago">
        <item quantity="one">1 minute ago</item>
        <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes ago</item>
    </plurals>
    <plurals name="num_hours_ago">
        <item quantity="one">1 hour ago</item>
        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
    </plurals>
    <plurals name="num_days_ago">
        <item quantity="one">yesterday</item>
        <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
    </plurals>
    <plurals name="in_num_seconds">
        <item quantity="one">in 1 second</item>
        <item quantity="other">in <xliff:g id="count">%d</xliff:g> seconds</item>
    </plurals>
    <plurals name="in_num_minutes">
        <item quantity="one">in 1 minute</item>
        <item quantity="other">in <xliff:g id="count">%d</xliff:g> minutes</item>
    </plurals>
    <plurals name="in_num_hours">
        <item quantity="one">in 1 hour</item>
        <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
    </plurals>
    <plurals name="in_num_days">
        <item quantity="one">tomorrow</item>
        <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
    </plurals>
</resources>

As an example, for another language such as Portuguese, on values-pt folder string.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">


    <string name="yesterday">ontem</string>
    <string name="tomorrow">manhã</string>
    <string name="today">hoje</string>

    <plurals name="num_seconds_ago">
        <item msgid="4869870056547896011" quantity="one">"1 segundo atrás"</item>
        <item msgid="3903706804349556379" quantity="other">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
    </plurals>
    <plurals name="num_minutes_ago">
        <item msgid="3306787433088810191" quantity="one">"1 minuto atrás"</item>
        <item msgid="2176942008915455116" quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
    </plurals>
    <plurals name="num_hours_ago">
        <item msgid="9150797944610821849" quantity="one">"1 hora atrás"</item>
        <item msgid="2467273239587587569" quantity="other">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
    </plurals>
    <plurals name="num_days_ago">
        <item msgid="861358534398115820" quantity="one">"ontem"</item>
        <item msgid="2479586466153314633" quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
    </plurals>
    <plurals name="in_num_seconds">
        <item msgid="2729745560954905102" quantity="one">"em 1 segundo"</item>
        <item msgid="1241926116443974687" quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
    </plurals>
    <plurals name="in_num_minutes">
        <item msgid="8793095251325200395" quantity="one">"em 1 minuto"</item>
        <item msgid="3330713936399448749" quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
    </plurals>
    <plurals name="in_num_hours">
        <item msgid="7164353342477769999" quantity="one">"em 1 hora"</item>
        <item msgid="547290677353727389" quantity="other">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
    </plurals>
    <plurals name="in_num_days">
        <item msgid="5413088743009839518" quantity="one">"amanhã"</item>
        <item msgid="5109449375100953247" quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
    </plurals>

</resources>
like image 6
Antilope Avatar answered Oct 17 '22 14:10

Antilope