summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibLocale/PluralRules.h
blob: 0f93234b7f8f0910ea515e2210b497ea7b460614 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Assertions.h>
#include <AK/StringView.h>
#include <AK/Types.h>
#include <LibLocale/Forward.h>

namespace Locale {

enum class PluralForm {
    Cardinal,
    Ordinal,
};

enum class PluralCategory : u8 {
    Other,
    Zero,
    One,
    Two,
    Few,
    Many,

    // https://unicode.org/reports/tr35/tr35-numbers.html#Explicit_0_1_rules
    ExactlyZero,
    ExactlyOne,
};

// https://unicode.org/reports/tr35/tr35-numbers.html#Plural_Operand_Meanings
struct PluralOperands {
    static constexpr StringView symbol_to_variable_name(char symbol)
    {
        if (symbol == 'n')
            return "number"sv;
        if (symbol == 'i')
            return "integer_digits"sv;
        if (symbol == 'f')
            return "fraction_digits"sv;
        if (symbol == 'v')
            return "number_of_fraction_digits"sv;
        if (symbol == 't')
            return "fraction_digits_without_trailing"sv;
        if (symbol == 'w')
            return "number_of_fraction_digits_without_trailing"sv;
        VERIFY_NOT_REACHED();
    }

    static constexpr bool symbol_requires_floating_point_modulus(char symbol)
    {
        // From TR-35: "The modulus (% or mod) is a remainder operation as defined in Java; for
        // example, where n = 4.3 the result of n mod 3 is 1.3."
        //
        // So, this returns whether the symbol represents a decimal value, and thus requires fmod.
        return symbol == 'n';
    }

    double number { 0 };
    u64 integer_digits { 0 };
    u64 fraction_digits { 0 };
    u64 number_of_fraction_digits { 0 };
    u64 fraction_digits_without_trailing { 0 };
    u64 number_of_fraction_digits_without_trailing { 0 };
};

PluralForm plural_form_from_string(StringView plural_form);
StringView plural_form_to_string(PluralForm plural_form);

// NOTE: This must be defined inline to be callable from the code generators.
constexpr PluralCategory plural_category_from_string(StringView category)
{
    if (category == "other"sv)
        return PluralCategory::Other;
    if (category == "zero"sv)
        return PluralCategory::Zero;
    if (category == "one"sv)
        return PluralCategory::One;
    if (category == "two"sv)
        return PluralCategory::Two;
    if (category == "few"sv)
        return PluralCategory::Few;
    if (category == "many"sv)
        return PluralCategory::Many;
    if (category == "0"sv)
        return PluralCategory::ExactlyZero;
    if (category == "1"sv)
        return PluralCategory::ExactlyOne;
    VERIFY_NOT_REACHED();
}

// NOTE: This must be defined inline to be callable from the code generators.
constexpr StringView plural_category_to_string(PluralCategory category)
{
    switch (category) {
    case PluralCategory::Other:
        return "other"sv;
    case PluralCategory::Zero:
        return "zero"sv;
    case PluralCategory::One:
        return "one"sv;
    case PluralCategory::Two:
        return "two"sv;
    case PluralCategory::Few:
        return "few"sv;
    case PluralCategory::Many:
        return "many"sv;
    case PluralCategory::ExactlyZero:
        return "0"sv;
    case PluralCategory::ExactlyOne:
        return "1"sv;
    }

    VERIFY_NOT_REACHED();
}

PluralCategory determine_plural_category(StringView locale, PluralForm form, PluralOperands operands);
Span<PluralCategory const> available_plural_categories(StringView locale, PluralForm form);
PluralCategory determine_plural_range(StringView locale, PluralCategory start, PluralCategory end);

}