getRelativeTimeSpanString 的默认语言环境
Posted
技术标签:
【中文标题】getRelativeTimeSpanString 的默认语言环境【英文标题】:default locale for getRelativeTimeSpanString 【发布时间】:2014-03-31 03:38:00 【问题描述】:我使用以下方法覆盖我的应用程序的语言环境:
Locale locale = new Locale("ca");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
但似乎getRelativeTimeSpanString
不适用于应用程序上下文,而是使用系统语言环境。
【问题讨论】:
【参考方案1】:您的解决方案几乎是正确的。
但是,由于字符串是从系统资源加载的,因此您必须更新系统资源的配置。以下是我所做的:
Configuration configuration = new Configuration(Resources.getSystem().getConfiguration());
configuration.locale = Locale.GERMANY; // or whichever locale you desire
Resources.getSystem().updateConfiguration(configuration, null);
(注意:从Jelly Bean MR1开始,建议使用
configuration.setLocale(Locale.GERMANY);
更改区域设置而不是直接设置成员。)
【讨论】:
谢谢。让我省了很多麻烦。 似乎在较新的平台(API > 24,也许是其他平台)上,您必须改为设置 Locale.setDefault(Locale.GERMANY)。【参考方案2】:我今天遇到了这个问题,花了我几个小时来“解决”。
如果您可以使用 getRelativeTimeSpanString(context, long, boolean) ,我建议您这样做。这不是我的情况,因为结果字符串与 getRelativeTimeSpanString(long) 不同。
我的解决方法需要将几个字符串的一些 android 内部资源复制到您的代码中,因此如果您要支持很多语言,这将非常烦人。
我跟踪了Android(4.4 r1)的当前源代码并提取了DateUtils并进行了更改,以便您可以像这样使用它:
CharSequence desiredString = MyDateUtils.getRelativeTimeSpanString(time,
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR, activity);
这将为您提供与 getRelativeTimeSpanString(long) 相同的结果。
为了让 MyDateUtils 我只保留:
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, int flags, Context c)
我将上下文添加到方法中,然后将系统资源更改为上下文资源,并将所有内部 android 字符串更改为我自己的字符串(与 android 相同,但找不到使用它们的方法,因为它们是 internal )。
private static final String getRelativeDayString(Resources r, long day, long today)
还保留了这种方法作为先前使用的方法。在这里我也改变了字符串。
用于复制粘贴
这是我的 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);
在值文件夹 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">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>
例如,对于另一种语言,例如葡萄牙语,在 values-pt 文件夹 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>
【讨论】:
遗憾的是,这仅适用于具有简单复数规则(如“add s”)的语言。这意味着如果是塞尔维亚语,我就完蛋了。 +1 以节省我的时间..您也可以使用 NumberFormat.getInstance(resources.getConfiguration().locale).format(count);也将 %d 替换为 %s 进一步解释,String.format(format, count) 使用 Locale.getDefault() 返回设备的默认区域设置,该区域设置可能与应用程序的区域设置不同【参考方案3】:我使用自定义方法来处理这个:
public static String getRelativeTimeSpanString(Context context, Date fromdate)
long then;
then = fromdate.getTime();
Date date = new Date(then);
StringBuffer dateStr = new StringBuffer();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
Calendar now = Calendar.getInstance();
int days = daysBetween(calendar.getTime(), now.getTime());
int weeks= days/7;
int minutes = hoursBetween(calendar.getTime(), now.getTime());
int hours = minutes / 60;
if (days == 0)
int second = minuteBetween(calendar.getTime(), now.getTime());
if (minutes > 60)
if (hours >= 1 && hours <= 24)
dateStr.append(String.format("%s %s %s",
hours,
context.getString(R.string.hour)
,context.getString(R.string.ago)));
else
if (second <= 10)
dateStr.append(context.getString(R.string.now));
else if (second > 10 && second <= 30)
dateStr.append(context.getString(R.string.few_seconds_ago));
else if (second > 30 && second <= 60)
dateStr.append(String.format("%s %s %s",
second,
context.getString(R.string.seconds)
,context.getString(R.string.ago)));
else if (second >= 60 && minutes <= 60)
dateStr.append(String.format("%s %s %s",
minutes,
context.getString(R.string.minutes)
,context.getString(R.string.ago)));
else
if (hours > 24 && days < 7)
dateStr.append(String.format("%s %s %s",
days,
context.getString(R.string.days)
,context.getString(R.string.ago)));
else if(weeks == 1)
dateStr.append(String.format("%s %s %s",
weeks,
context.getString(R.string.weeks)
,context.getString(R.string.ago)));
else
/**
* make formatted createTime by languageTag("fa")
*
* @return
*/
return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,new Locale("fra"))
.format(date).toUpperCase();
return dateStr.toString();
public static int minuteBetween(Date d1, Date d2)
return (int) ((d2.getTime() - d1.getTime()) / android.text.format.DateUtils.SECOND_IN_MILLIS);
public static int hoursBetween(Date d1, Date d2)
return (int) ((d2.getTime() - d1.getTime()) / android.text.format.DateUtils.MINUTE_IN_MILLIS);
public static int daysBetween(Date d1, Date d2)
return (int) ((d2.getTime() - d1.getTime()) / android.text.format.DateUtils.DAY_IN_MILLIS);
我将日期设置为该方法的参数:
return getRelativeTimeSpanString(context,this.createdTime);
这个按我想要的位置返回字符串!希望有所帮助。
【讨论】:
以上是关于getRelativeTimeSpanString 的默认语言环境的主要内容,如果未能解决你的问题,请参考以下文章