Packages
localize
0.18.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.41.3
0.41.2
0.41.1
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.1
0.30.0
retired
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
0.1.0-alpha.1
Localization (parsing, formatting) of numbers, dates/time/calendar, units of measure, messages and lists. Includes localized collation.
Current section
Files
Jump to
Current section
Files
src/rbnf_parser.yrl
Nonterminals quotient_rule modulo_rule invoke_rule cardinal_rule ordinal_rule
rule literal rbnf_rule rule_part character.
Terminals rule_cardinal_start rule_ordinal_start number_format
rule_name conditional_start conditional_end modulo_call
quotient_call rule_call plural_rules right_paren
left_paren dollar comma char.
Rootsymbol rbnf_rule.
Left 100 rbnf_rule.
Right 400 modulo_call.
Right 500 quotient_call.
Right 600 character.
rbnf_rule -> rule_part rbnf_rule : ['$1'] ++ '$2'.
rbnf_rule -> rule_part : ['$1'].
rule_part -> literal : '$1'.
rule_part -> quotient_rule : '$1'.
rule_part -> modulo_rule : '$1'.
rule_part -> invoke_rule : '$1'.
rule_part -> cardinal_rule : '$1'.
rule_part -> ordinal_rule : '$1'.
rule_part -> conditional_start rbnf_rule conditional_end : {conditional, '$2'}.
quotient_rule -> quotient_call rule quotient_call quotient_call : {quotient, '$2'}.
quotient_rule -> quotient_call rule quotient_call : {quotient, '$2'}.
quotient_rule -> quotient_call quotient_call : {quotient, nil}.
modulo_rule -> modulo_call rule modulo_call : {modulo, '$2'}.
modulo_rule -> modulo_call modulo_call : {modulo, nil}.
% Note that here we are treating >>> as equivalent to >>
% This is not strictly true since the spec says we should
% ... but bypass the normal rule-selection process and just
% use the rule that precedes this one in this rule list.
modulo_rule -> modulo_call modulo_call modulo_call : {modulo, nil}.
invoke_rule -> rule_call rule rule_call : {call, '$2'}.
cardinal_rule -> dollar left_paren rule_cardinal_start comma
plural_rules right_paren dollar : {cardinal, to_map('$5')}.
ordinal_rule -> dollar left_paren rule_ordinal_start comma
plural_rules right_paren dollar : {ordinal, to_map('$5')}.
rule -> rule_name : {rule, normalize_rule_name('$1')}.
rule -> number_format : {format, unwrap('$1')}.
literal -> character literal : append('$1', '$2').
literal -> character : {literal, unwrap('$1')}.
character -> char : '$1'.
character -> comma : '$1'.
character -> number_format : '$1'.
Erlang code.
% Consolidate characters into a binary
append({char, _, _} = Char, {literal, Literal}) ->
{literal, list_to_binary([unwrap(Char), Literal])};
append({comma, _, _} = Char, {literal, Literal}) ->
{literal, list_to_binary([unwrap(Char), Literal])};
append({number_format, _, _} = Char, {literal, Literal}) ->
{literal, list_to_binary([unwrap(Char), Literal])};
append({literal, Literal1}, {literal, Literal2}) ->
{literal, list_to_binary([Literal2, Literal1])}.
% We will turn rule names into functions later on so
% we normalise the names to a format that is acceptable.
normalize_rule_name({_,_,[$%, $% | Name]}) ->
erlang:binary_to_atom(unicode:characters_to_binary(force_valid_function_name(Name)), utf8);
normalize_rule_name({_,_,[$% | Name]}) ->
erlang:binary_to_atom(unicode:characters_to_binary(force_valid_function_name(Name)), utf8).
% Return a token value as a binary
unwrap({_,_,V}) when is_list(V) -> unicode:characters_to_binary(V);
unwrap({_,_,V}) -> V.
% Force a valid function name. This is in two parts:
% 1. If the function name starts with a number, prepend
% a letter
% 2. Replace "-" with "_"
force_valid_function_name([Digit | Rest]) when Digit >= $0 andalso Digit =< $9 ->
underscore([$r, Digit | Rest]);
force_valid_function_name(Other) ->
underscore(Other).
% Substitute "_" for "-" since we will use these rule names
% as functions later on.
underscore([$-| Rest]) ->
[$_ | underscore(Rest)];
underscore([]) ->
[];
underscore([Char | Rest]) ->
[Char | underscore(Rest)].
% Convert ordinal and cardinal rules into a map
to_map(Plurals) ->
String = unwrap(Plurals),
Parts = binary:split(String, [<<"{">>,<<"}">>], [global, trim]),
Proplist = to_proplist(Parts),
maps:from_list(Proplist).
% Convert a list into a proplist
to_proplist([K,V | T]) -> [{erlang:binary_to_atom(K, utf8),V} | to_proplist(T)];
to_proplist([]) -> [].