Skip to content

Support Intl.RelativeTimeFormat for relativeTime formatting #1056

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

Closed
kvnxiao opened this issue May 6, 2024 · 13 comments · Fixed by #1057
Closed

Support Intl.RelativeTimeFormat for relativeTime formatting #1056

kvnxiao opened this issue May 6, 2024 · 13 comments · Fixed by #1057
Labels
enhancement New feature or request unconfirmed Needs triage.

Comments

@kvnxiao
Copy link

kvnxiao commented May 6, 2024

Is your feature request related to a problem? Please describe.

Currently, the formatter for Formatting date and time ranges does not support additional configuration other than specifying the exact unit to display the output in.

The relative time formatting should support all the options from Intl.RelativeTimeFormat and not just RelativeTimeFormatUnit

Describe the solution you'd like

Instead of:

type RelativeTimeFormatOptions = {
    now?: number | Date;
    unit?: Intl.RelativeTimeFormatUnit;
};
export default RelativeTimeFormatOptions;

The RelativeTimeFormatOptions type should also accept the options from the Intl.RelativeTimeFormat constructor:

  • numberingSystem
  • style
  • numeric

Describe alternatives you've considered

The only alternative would be to use the native Intl API directly, but this should be integrated into the formatter in next-intl IMO

@amannn
Copy link
Owner

amannn commented May 7, 2024

Hey, thanks for the report! I agree, we could definitely support numberingSystem and style.

As for numeric I'm a bit hesitant though, as it can lead to issues when values are rounded: #765.

See also:

return new Intl.RelativeTimeFormat(locale, {
// `numeric: 'auto'` can theoretically produce output like "yesterday",
// but it only works with integers. E.g. -1 day will produce "yesterday",
// but -1.1 days will produce "-1.1 days". Rounding before formatting is
// not desired, as the given dates might cross a threshold were the
// output isn't correct anymore. Example: 2024-01-08T23:00:00.000Z and
// 2024-01-08T01:00:00.000Z would produce "yesterday", which is not the
// case. By using `always` we can ensure correct output. The only exception
// is the formatting of times <1 second as "now".
numeric: unit === 'second' ? 'auto' : 'always'
}).format(value, unit);

Do you need numeric for your use case? If so, can you include further details?

I've added #1057 to look into this.

@kvnxiao
Copy link
Author

kvnxiao commented May 7, 2024

At the moment, I only have a need for the style to specify long, short, or narrow.

I think numberingSystem and style is sufficient for now!

@amannn
Copy link
Owner

amannn commented May 8, 2024

Sounds good, thanks for the feedback!

juanforlizzi pushed a commit to juanforlizzi/next-intl that referenced this issue Jan 16, 2025
@kvnxiao
Copy link
Author

kvnxiao commented Apr 30, 2025

Circling back to this @amannn I have come across needing the numeric formatting option now for the formatting style to show "today" and "yesterday" 😅

@amannn
Copy link
Owner

amannn commented May 1, 2025

Interesting. Can you share what your exact use case is?

From my personal observation, "yesterday" is a nice thing to read, but it's easy to run into a wrong output due to rounding (see #1056 (comment)). "Yesterday" might not actually be the day before today, but could be the day before yesterday.

@kvnxiao
Copy link
Author

kvnxiao commented May 1, 2025

The use case is exactly as described, requiring the use of localizations for "yesterday" and "today". I don't think we should be too worried about the rounding because IMO the idea is that doing the correct math beforehand is a prerequisite that's on the onus of the developer (otherwise it wouldn't make much sense for the official Intl.RelativeTimeFormat to support numeric: "auto")

For what it's worth, what I'm currently doing is I'm using Luxon to do proper date-time calculations of the math in "days" (with the local machine timezones set) via dateTime.startOf('day'), before converting it back into a JS Date and passing it into the Intl.RelativeTimeFormat with numeric: auto.

@kvnxiao
Copy link
Author

kvnxiao commented May 2, 2025

Let me know if you would like me to open a new issue to track this discussion!

@amannn
Copy link
Owner

amannn commented May 2, 2025

The use case is exactly as described, requiring the use of localizations for "yesterday" and "today"

The current output would be "1 day ago" instead of "yesterday". I'd say that "yesterday" reads a bit nicer, but the rounding problem make this a bit error prone. Is there a particular issue with using "1 day ago" in your app?

otherwise it wouldn't make much sense for the official Intl.RelativeTimeFormat to support numeric: "auto"

So with auto, you either get values like "yesterday" (for integers) or "1.1 days ago" (for floating point numbers). That's when you're using Intl.RelativeTimeFormat yourself—without next-intl.

However, next-intl does rounding internally in order to render more readable values like "1 day ago"—an approximation.

// We have to round the resulting values, as `Intl.RelativeTimeFormat`
// will include fractions like '2.1 hours ago'.
return Math.round(seconds / UNIT_SECONDS[unit]);

The docs mention this capability:

Note that values are rounded, so e.g. if 126 minutes have passed, “2 hours ago” will be returned.

So if next-intl would allow to pass numeric: 'auto' we'd have the user run into problematic scenarios due to rounding. If you're using Intl.RelativeTimeFormat directly, the rounding is on you. It seems to me like that puts you in a better position than if next-intl would support this.

That's at least my current understanding. I might have to give this more thought, but it seems like a potentially problematic feature to support.

What do you think?

@kvnxiao
Copy link
Author

kvnxiao commented May 2, 2025

Is there a particular issue with using "1 day ago" in your app

Yes, the designers specifically want more friendly localized dates for "today" and "yesterday", instead of "1 day ago".

Currently I'm fetching the locale via next-intl's useLocale and passing it into Intl.RelativeTimeFormat directly. May I ask, what's wrong with trying to support the same feature set as Intl.RelativeTimeFormat directly? The onus is already on the developer to make sure they're doing the rounding properly when using Intl.RelativeTimeFormat and numeric: auto, so can we not just document that as a caveat and mirror it's behaviour in next-intl directly? This is just a minor inconvenience, but if next-intl had this support directly in the formatter it would just save me having to pass around the locale to various Intl.XYZ functions.

@kvnxiao
Copy link
Author

kvnxiao commented May 2, 2025

Also as a side note, in other languages, the equivalent localizations of "yesterday" as opposed to "1 day ago" and "today" instead of "in 0 days" sounds much less awkward.

In Chinese for example, "1 day ago" is "1天前", but this is not a phrase that anyone would ever use colloquially, the better way would be "昨天" which transliterates to "yesterday". And for "in 0 days", the phrase "0天后" wouldn't even make sense to use anywhere and would actually seem like an error whereas "今天" is the correct translation for "today".

The point of this add-on comment here is to express why numeric: auto in Intl.RelativeTimeFormat has value existing, and my hope here is for next-intl to support the same options directly within the library so that I can achieve the same thing via useFormatter without having to manually pass around a locale string + constructing a new Intl.RelativeTimeFormater for the sole purpose of using numeric: auto on rare occasions.

@amannn
Copy link
Owner

amannn commented May 2, 2025

Hmm, I have another idea here.

What if next-intl would detect if rounding is necessary, and if not, we could switch to numeric: 'auto'. That would avoid the footgun of using numeric: 'auto' with rounded values and I think would also cover your case.

Here's a PR with a proposal: #1872.

What do you think? I might have to give it another thought and see if this feels right when writing docs, but it could be an option.

@amannn
Copy link
Owner

amannn commented May 2, 2025

@kvnxiao Do you by chance have an idea if this code snippet could be simplified?

https://github.com/amannn/next-intl/pull/1872/files#r2071663776

Also I'm still wondering if there are edge cases that I'm overlooking … Or maybe cases where numeric: 'auto' is not desired.

@kvnxiao
Copy link
Author

kvnxiao commented May 2, 2025

I like the idea so far, took a look over the PR itself and had left a comment: https://github.com/amannn/next-intl/pull/1872/files#r2072115257

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request unconfirmed Needs triage.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants