diff --git a/README.md b/README.md
index 74d5eb0..b16a2fe 100644
--- a/README.md
+++ b/README.md
@@ -130,6 +130,7 @@ HumanReadable.timeAgo(instant) // "il y a 3 jours"
### Supported languages
+* Arabic (since 1.13.0)
* Czech
* Chinese (since 1.3.0)
* Dutch
diff --git a/demo/src/webMain/kotlin/Language.kt b/demo/src/webMain/kotlin/Language.kt
index 657aec9..a519aaa 100644
--- a/demo/src/webMain/kotlin/Language.kt
+++ b/demo/src/webMain/kotlin/Language.kt
@@ -1,5 +1,6 @@
internal enum class Language(val code: String) {
English("en"),
+ Arabic("ar"),
Czech("cs"),
Chinese("zh"),
Dutch("nl"),
diff --git a/src/appleAndJsMain/kotlin/nl/jacobras/humanreadable/extendLibresPlurals.kt b/src/appleAndJsMain/kotlin/nl/jacobras/humanreadable/extendLibresPlurals.kt
index 759b096..732d740 100644
--- a/src/appleAndJsMain/kotlin/nl/jacobras/humanreadable/extendLibresPlurals.kt
+++ b/src/appleAndJsMain/kotlin/nl/jacobras/humanreadable/extendLibresPlurals.kt
@@ -73,4 +73,15 @@ internal actual fun extendLibresPlurals() {
else -> PluralForm.Other
}
}
+
+ PluralRules["ar"] = PluralRule { number ->
+ when {
+ number == 0 -> PluralForm.Zero
+ number == 1 -> PluralForm.One
+ number == 2 -> PluralForm.Two
+ number % 100 in 3..10 -> PluralForm.Few
+ number % 100 in 11..99 -> PluralForm.Many
+ else -> PluralForm.Other
+ }
+ }
}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/nl/jacobras/humanreadable/HumanReadableDuration.kt b/src/commonMain/kotlin/nl/jacobras/humanreadable/HumanReadableDuration.kt
index eff5915..9f38aab 100644
--- a/src/commonMain/kotlin/nl/jacobras/humanreadable/HumanReadableDuration.kt
+++ b/src/commonMain/kotlin/nl/jacobras/humanreadable/HumanReadableDuration.kt
@@ -1,5 +1,6 @@
package nl.jacobras.humanreadable
+import io.github.skeptick.libres.LibresSettings
import kotlin.math.roundToInt
import kotlin.time.Duration
@@ -19,26 +20,43 @@ internal fun formatDuration(
return when {
secondsAgo < 60 -> {
- "$secondsAgo ${TimeUnit.Seconds.format(secondsAgo, relativeTime)}"
+ formatUnit(secondsAgo, TimeUnit.Seconds, relativeTime)
}
secondsAgo < 3600 -> {
val minutes = duration.inWholeMinutes.toInt()
- "$minutes ${TimeUnit.Minutes.format(minutes, relativeTime)}"
+ formatUnit(minutes, TimeUnit.Minutes, relativeTime)
}
daysAgo < 1 -> {
- "$hoursAgo ${TimeUnit.Hours.format(hoursAgo, relativeTime)}"
+ formatUnit(hoursAgo, TimeUnit.Hours, relativeTime)
}
daysAgo < 7 -> {
- "$daysAgo ${TimeUnit.Days.format(daysAgo, relativeTime)}"
+ formatUnit(daysAgo, TimeUnit.Days, relativeTime)
}
daysAgo < 30 -> {
- "$weeksAgo ${TimeUnit.Weeks.format(weeksAgo, relativeTime)}"
+ formatUnit(weeksAgo, TimeUnit.Weeks, relativeTime)
}
monthsAgo < 12 || yearsAgo == 0 -> {
- "$monthsAgo ${TimeUnit.Months.format(monthsAgo, relativeTime)}"
+ formatUnit(monthsAgo, TimeUnit.Months, relativeTime)
}
else -> {
- "$yearsAgo ${TimeUnit.Years.format(yearsAgo, relativeTime)}"
+ formatUnit(yearsAgo, TimeUnit.Years, relativeTime)
}
}
+}
+
+/**
+ * Formats a [count] with its [unit]. Normally produces "$count $unit", but for Arabic the
+ * singular (1) and dual (2) forms are encoded in the unit word itself, so the numeral is omitted.
+ */
+private fun formatUnit(
+ count: Int,
+ unit: TimeUnit,
+ relativeTime: RelativeTime
+): String {
+ val unitText = unit.format(count, relativeTime)
+ return if (LibresSettings.languageCode == "ar" && (count == 1 || count == 2)) {
+ unitText
+ } else {
+ "$count $unitText"
+ }
}
\ No newline at end of file
diff --git a/src/commonMain/libres/strings/data_units_ar.xml b/src/commonMain/libres/strings/data_units_ar.xml
new file mode 100644
index 0000000..5a567c8
--- /dev/null
+++ b/src/commonMain/libres/strings/data_units_ar.xml
@@ -0,0 +1,8 @@
+
+
+ ب
+ ك.ب
+ م.ب
+ ج.ب
+ ت.ب
+
diff --git a/src/commonMain/libres/strings/distance_units_ar.xml b/src/commonMain/libres/strings/distance_units_ar.xml
new file mode 100644
index 0000000..54999bb
--- /dev/null
+++ b/src/commonMain/libres/strings/distance_units_ar.xml
@@ -0,0 +1,7 @@
+
+
+ م
+ كم
+ قدم
+ ميل
+
diff --git a/src/commonMain/libres/strings/time_units_ar.xml b/src/commonMain/libres/strings/time_units_ar.xml
new file mode 100644
index 0000000..b03787e
--- /dev/null
+++ b/src/commonMain/libres/strings/time_units_ar.xml
@@ -0,0 +1,111 @@
+
+
+
+ - ثانية
+ - ثانية
+ - ثانيتان
+ - ثوان
+ - ثانية
+ - ثانية
+
+
+ - ثانيتين
+
+
+ - ثانيتين
+
+
+
+ - دقيقة
+ - دقيقة
+ - دقيقتان
+ - دقائق
+ - دقيقة
+ - دقيقة
+
+
+ - دقيقتين
+
+
+ - دقيقتين
+
+
+
+ - ساعة
+ - ساعة
+ - ساعتان
+ - ساعات
+ - ساعة
+ - ساعة
+
+
+ - ساعتين
+
+
+ - ساعتين
+
+
+
+ - يوم
+ - يوم
+ - يومان
+ - أيام
+ - يوم
+ - يوم
+
+
+ - يومين
+
+
+ - يومين
+
+
+
+ - أسبوع
+ - أسبوع
+ - أسبوعان
+ - أسابيع
+ - أسبوع
+ - أسبوع
+
+
+ - أسبوعين
+
+
+ - أسبوعين
+
+
+
+ - شهر
+ - شهر
+ - شهران
+ - أشهر
+ - شهر
+ - شهر
+
+
+ - شهرين
+
+
+ - شهرين
+
+
+
+ - سنة
+ - سنة
+ - سنتان
+ - سنوات
+ - سنة
+ - سنة
+
+
+ - سنتين
+
+
+ - سنتين
+
+
+ قبل ${time}
+ بعد ${time}
+ الآن
+
diff --git a/src/commonTest/kotlin/nl/jacobras/humanreadable/localized/LocalizedTests.kt b/src/commonTest/kotlin/nl/jacobras/humanreadable/localized/LocalizedTests.kt
index e9653cd..70f61b7 100644
--- a/src/commonTest/kotlin/nl/jacobras/humanreadable/localized/LocalizedTests.kt
+++ b/src/commonTest/kotlin/nl/jacobras/humanreadable/localized/LocalizedTests.kt
@@ -47,6 +47,32 @@ class LocalizedTests {
private val oneYearAgo = now - oneYear
private val oneYearFromNow = now + oneYear
+ @Test
+ fun ar_arabic() {
+ LibresSettings.languageCode = "ar"
+ assertThat(HumanReadable.duration(0.seconds)).isEqualTo("0 ثانية")
+ assertThat(HumanReadable.duration(1.seconds)).isEqualTo("ثانية")
+ assertThat(HumanReadable.duration(2.seconds)).isEqualTo("ثانيتان")
+ assertThat(HumanReadable.duration(3.seconds)).isEqualTo("3 ثوان")
+ assertThat(HumanReadable.duration(11.seconds)).isEqualTo("11 ثانية")
+
+ assertThat(HumanReadable.timeAgo(now, baseInstant = now)).isEqualTo("الآن")
+ assertThat(HumanReadable.timeAgo(twoSecondsAgo, baseInstant = now)).isEqualTo("قبل ثانيتين")
+ assertThat(HumanReadable.timeAgo(oneMinuteFromNow, baseInstant = now)).isEqualTo("بعد دقيقة")
+ assertThat(HumanReadable.duration(3.days)).isEqualTo("3 أيام")
+ assertThat(HumanReadable.duration(twoMonths)).isEqualTo("شهران")
+ assertThat(HumanReadable.duration(oneYear)).isEqualTo("سنة")
+
+ assertThat(HumanReadable.number(1_000_000.34, decimals = 2)).isEqualTo("1,000,000.34")
+ assertThat(HumanReadable.number(-4.34, decimals = 2)).isEqualTo("-4.34")
+
+ assertThat(HumanReadable.fileSize(2_000_000, decimals = 1)).isEqualTo("1.9 م.ب")
+
+ assertThat(HumanReadable.abbreviation(5_100_000, decimals = 1)).isEqualTo("5.1M")
+
+ assertThat(HumanReadable.distance(7234, unit = DistanceUnit.Meter)).isEqualTo("7.2 كم")
+ }
+
@Test
fun cs_czech() {
LibresSettings.languageCode = "cs"
@@ -307,4 +333,4 @@ class LocalizedTests {
assertThat(HumanReadable.number(1_000_000.34, decimals = 2)).isEqualTo("1,000,000.34")
assertThat(HumanReadable.number(-4.34, decimals = 2)).isEqualTo("-4.34")
}
-}
\ No newline at end of file
+}