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
|
import textwrap
import fluent.syntax.ast as FTL
from fluent.syntax.parser import FluentParser, FluentParserStream
fluent_parser = FluentParser(with_spans=False)
def parse(Parser, string):
if Parser is FluentParser:
return fluent_parser.parse(string)
# Parsing a legacy resource.
# Parse the string into the internal Context.
parser = Parser()
# compare-locales expects ASCII strings.
parser.readContents(string.encode("utf8"))
# Transform the parsed result which is an iterator into a dict.
return {ent.key: ent for ent in parser}
def ftl_resource_to_ast(code):
return fluent_parser.parse(ftl(code))
def ftl_resource_to_json(code):
return fluent_parser.parse(ftl(code)).to_json()
def ftl_pattern_to_json(code):
ps = FluentParserStream(ftl(code))
return fluent_parser.maybe_get_pattern(ps).to_json()
def to_json(merged_iter):
return {path: resource.to_json() for path, resource in merged_iter}
LOCALIZABLE_ENTRIES = (FTL.Message, FTL.Term)
def get_message(body, ident):
"""Get message called `ident` from the `body` iterable."""
for entity in body:
if isinstance(entity, LOCALIZABLE_ENTRIES) and entity.id.name == ident:
return entity
def get_transform(body, ident):
"""Get entity called `ident` from the `body` iterable."""
for transform in body:
if transform.id.name == ident:
return transform
def skeleton(node):
"""Create a skeleton copy of the given node.
For localizable entries, the value is None and the attributes are {}.
That's not a valid Fluent entry, so it requires further manipulation to
set values and/or attributes.
"""
if isinstance(node, LOCALIZABLE_ENTRIES):
return type(node)(id=node.id.clone(), value=None)
return node.clone()
def ftl(code):
"""Nicer indentation for FTL code.
The code returned by this function is meant to be compared against the
output of the FTL Serializer. The input code will end with a newline to
match the output of the serializer.
"""
# The code might be triple-quoted.
code = code.lstrip("\n")
return textwrap.dedent(code)
def fold(fun, node, init):
"""Reduce `node` to a single value using `fun`.
Apply `fun` against an accumulator and each subnode of `node` (in postorder
traversal) to reduce it to a single value.
"""
def fold_(vals, acc):
if not vals:
return acc
head = list(vals)[0]
tail = list(vals)[1:]
if isinstance(head, FTL.BaseNode):
acc = fold(fun, head, acc)
if isinstance(head, list):
acc = fold_(head, acc)
if isinstance(head, dict):
acc = fold_(head.values(), acc)
return fold_(tail, fun(acc, head))
return fold_(vars(node).values(), init)
|