Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#ifndef intl_components_RelativeTimeFormat_h_
#define intl_components_RelativeTimeFormat_h_
#include "mozilla/Try.h"
#include "mozilla/intl/ICU4CGlue.h"
#include "mozilla/intl/ICUError.h"
#include "mozilla/intl/NumberPart.h"
#include "unicode/ureldatefmt.h"
#include "unicode/utypes.h"
namespace mozilla::intl {
struct RelativeTimeFormatOptions {
enum class Style { Short, Narrow, Long };
Style style = Style::Long;
enum class Numeric {
/**
* Only strings with numeric components like `1 day ago`.
*/
Always,
/**
* Natural-language strings like `yesterday` when possible,
* otherwise strings with numeric components as in `7 months ago`.
*/
Auto,
};
Numeric numeric = Numeric::Always;
};
/**
* A RelativeTimeFormat implementation that roughly mirrors the API provided by
* the ECMA-402 Intl.RelativeTimeFormat object.
*
*/
class RelativeTimeFormat final {
public:
/**
*
* Initialize a new RelativeTimeFormat for the provided locale and using the
* provided options.
*
*/
static Result<UniquePtr<RelativeTimeFormat>, ICUError> TryCreate(
const char* aLocale, const RelativeTimeFormatOptions& aOptions);
RelativeTimeFormat() = default;
RelativeTimeFormat(RelativeTimeFormatOptions::Numeric aNumeric,
URelativeDateTimeFormatter* aFormatter,
UFormattedRelativeDateTime* aFormattedRelativeDateTime);
RelativeTimeFormat(const RelativeTimeFormat&) = delete;
RelativeTimeFormat& operator=(const RelativeTimeFormat&) = delete;
~RelativeTimeFormat();
enum class FormatUnit {
Second,
Minute,
Hour,
Day,
Week,
Month,
Quarter,
Year
};
/**
* Formats a double to the provider buffer (either utf-8 or utf-16)
*
*/
template <typename B>
Result<Ok, ICUError> format(double aNumber, FormatUnit aUnit,
B& aBuffer) const {
static_assert(
std::is_same_v<typename B::CharType, char> ||
std::is_same_v<typename B::CharType, char16_t>,
"The only buffer CharTypes supported by RelativeTimeFormat are char "
"(for UTF-8 support) and char16_t (for UTF-16 support).");
auto fmt = mNumeric == RelativeTimeFormatOptions::Numeric::Auto
? ureldatefmt_format
: ureldatefmt_formatNumeric;
if constexpr (std::is_same_v<typename B::CharType, char>) {
mozilla::Vector<char16_t, StackU16VectorSize> u16Vec;
MOZ_TRY(FillBufferWithICUCall(
u16Vec, [this, aNumber, aUnit, fmt](UChar* target, int32_t length,
UErrorCode* status) {
return fmt(mFormatter, aNumber, ToURelativeDateTimeUnit(aUnit),
target, length, status);
}));
if (!FillBuffer(u16Vec, aBuffer)) {
return Err(ICUError::OutOfMemory);
}
return Ok{};
} else {
static_assert(std::is_same_v<typename B::CharType, char16_t>);
return FillBufferWithICUCall(
aBuffer, [this, aNumber, aUnit, fmt](UChar* target, int32_t length,
UErrorCode* status) {
return fmt(mFormatter, aNumber, ToURelativeDateTimeUnit(aUnit),
target, length, status);
});
}
}
/**
* Formats the relative time to a utf-16 string, and fills the provided parts
* vector. The string view is valid until another time is formatted.
* Accessing the string view after this event is undefined behavior.
*
* This is utf-16 only because the only current use case is in
* SpiderMonkey. Supporting utf-8 would require recalculating the offsets
* in NumberPartVector from fixed width to variable width, which might be
* tricky to get right and is work that won't be necessary if we switch to
*
*/
Result<Span<const char16_t>, ICUError> formatToParts(
double aNumber, FormatUnit aUnit, NumberPartVector& aParts) const;
private:
RelativeTimeFormatOptions::Numeric mNumeric =
RelativeTimeFormatOptions::Numeric::Always;
URelativeDateTimeFormatter* mFormatter = nullptr;
UFormattedRelativeDateTime* mFormattedRelativeDateTime = nullptr;
static constexpr size_t StackU16VectorSize = 128;
URelativeDateTimeUnit ToURelativeDateTimeUnit(FormatUnit unit) const;
};
} // namespace mozilla::intl
#endif