class TestVariants(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" -variant = { [a] A *[b] B } foo = { -variant } bar = { -variant[a] } baz = { -variant[b] } qux = { -variant[c] } """)) def test_returns_the_default_variant(self): val, errs = self.ctx.format('foo', {}) self.assertEqual(val, 'B') self.assertEqual(len(errs), 0) def test_choose_other_variant(self): val, errs = self.ctx.format('bar', {}) self.assertEqual(val, 'A') self.assertEqual(len(errs), 0) def test_choose_default_variant(self): val, errs = self.ctx.format('baz', {}) self.assertEqual(val, 'B') self.assertEqual(len(errs), 0) def test_choose_missing_variant(self): val, errs = self.ctx.format('qux', {}) self.assertEqual(val, 'B') self.assertEqual(len(errs), 1) self.assertEqual(errs, [FluentReferenceError("Unknown variant: c")])
class TestResolving(unittest.TestCase): def setUp(self): self.args_passed = [] def number_processor(number): self.args_passed.append(number) return number self.ctx = FluentBundle( ['en-US'], use_isolating=False, functions={'NUMBER_PROCESSOR': number_processor}) self.ctx.add_messages( dedent_ftl(""" pass-number = { NUMBER_PROCESSOR(1) } pass-arg = { NUMBER_PROCESSOR($arg) } """)) def test_args_passed_as_numbers(self): val, errs = self.ctx.format('pass-arg', {'arg': 1}) self.assertEqual(val, "1") self.assertEqual(len(errs), 0) self.assertEqual(self.args_passed, [1]) def test_literals_passed_as_numbers(self): val, errs = self.ctx.format('pass-number', {}) self.assertEqual(val, "1") self.assertEqual(len(errs), 0) self.assertEqual(self.args_passed, [1])
class TestBillionLaughs(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" lol0 = 01234567890123456789012345678901234567890123456789 lol1 = {lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0} lol2 = {lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1} lol3 = {lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2} lol4 = {lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3} lolz = {lol4} elol0 = { "" } elol1 = {elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0} elol2 = {elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1} elol3 = {elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2} elol4 = {elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3} elol5 = {elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4} elol6 = {elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5} emptylolz = {elol6} """)) def test_max_length_protection(self): val, errs = self.ctx.format('lolz') self.assertEqual(val, ('0123456789' * 1000)[0:2500]) self.assertNotEqual(len(errs), 0) def test_max_expansions_protection(self): # Without protection, emptylolz will take a really long time to # evaluate, although it generates an empty message. val, errs = self.ctx.format('emptylolz') self.assertEqual(val, '???') self.assertEqual(len(errs), 1)
class TestNumbersInValues(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" foo = Foo { $num } bar = { foo } baz = .attr = Baz Attribute { $num } qux = { "a" -> *[a] Baz Variant A { $num } } """)) def test_can_be_used_in_the_message_value(self): val, errs = self.ctx.format('foo', {'num': 3}) self.assertEqual(val, 'Foo 3') self.assertEqual(len(errs), 0) def test_can_be_used_in_the_message_value_which_is_referenced(self): val, errs = self.ctx.format('bar', {'num': 3}) self.assertEqual(val, 'Foo 3') self.assertEqual(len(errs), 0) def test_can_be_used_in_an_attribute(self): val, errs = self.ctx.format('baz.attr', {'num': 3}) self.assertEqual(val, 'Baz Attribute 3') self.assertEqual(len(errs), 0) def test_can_be_used_in_a_variant(self): val, errs = self.ctx.format('qux', {'num': 3}) self.assertEqual(val, 'Baz Variant A 3') self.assertEqual(len(errs), 0)
class TestAttributesWithStringValues(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages(dedent_ftl(""" foo = Foo .attr = Foo Attribute bar = { foo } Bar .attr = Bar Attribute ref-foo = { foo.attr } ref-bar = { bar.attr } """)) def test_can_be_referenced_for_entities_with_string_values(self): val, errs = self.ctx.format('ref-foo', {}) self.assertEqual(val, 'Foo Attribute') self.assertEqual(len(errs), 0) def test_can_be_referenced_for_entities_with_pattern_values(self): val, errs = self.ctx.format('ref-bar', {}) self.assertEqual(val, 'Bar Attribute') self.assertEqual(len(errs), 0) def test_can_be_formatted_directly_for_entities_with_string_values(self): val, errs = self.ctx.format('foo.attr', {}) self.assertEqual(val, 'Foo Attribute') self.assertEqual(len(errs), 0) def test_can_be_formatted_directly_for_entities_with_pattern_values(self): val, errs = self.ctx.format('bar.attr', {}) self.assertEqual(val, 'Bar Attribute') self.assertEqual(len(errs), 0)
class TestUseIsolating(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US']) self.ctx.add_messages(dedent_ftl(""" foo = Foo bar = { foo } Bar baz = { $arg } Baz qux = { bar } { baz } """)) def test_isolates_interpolated_message_references(self): val, errs = self.ctx.format('bar', {}) self.assertEqual(val, FSI + "Foo" + PDI + " Bar") self.assertEqual(len(errs), 0) def test_isolates_interpolated_string_typed_variable_references(self): val, errs = self.ctx.format('baz', {'arg': 'Arg'}) self.assertEqual(val, FSI + "Arg" + PDI + " Baz") self.assertEqual(len(errs), 0) def test_isolates_interpolated_number_typed_variable_references(self): val, errs = self.ctx.format('baz', {'arg': 1}) self.assertEqual(val, FSI + "1" + PDI + " Baz") self.assertEqual(len(errs), 0) def test_isolates_complex_interpolations(self): val, errs = self.ctx.format('qux', {'arg': 'Arg'}) expected_bar = FSI + FSI + "Foo" + PDI + " Bar" + PDI expected_baz = FSI + FSI + "Arg" + PDI + " Baz" + PDI self.assertEqual(val, expected_bar + " " + expected_baz) self.assertEqual(len(errs), 0)
class TestSelectExpressionWithPluralCategories(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" foo = { 1 -> [one] A *[other] B } bar = { 1 -> [1] A *[other] B } baz = { "not a number" -> [one] A *[other] B } qux = { $num -> [one] A *[other] B } """)) def test_selects_the_right_category(self): val, errs = self.ctx.format('foo', {}) self.assertEqual(val, "A") self.assertEqual(len(errs), 0) def test_selects_exact_match(self): val, errs = self.ctx.format('bar', {}) self.assertEqual(val, "A") self.assertEqual(len(errs), 0) def test_selects_default_with_invalid_selector(self): val, errs = self.ctx.format('baz', {}) self.assertEqual(val, "B") self.assertEqual(len(errs), 0) def test_with_a_missing_selector(self): val, errs = self.ctx.format('qux', {}) self.assertEqual(val, "B") self.assertEqual(errs, [FluentReferenceError("Unknown external: num")]) def test_with_argument_integer(self): val, errs = self.ctx.format('qux', {'num': 1}) self.assertEqual(val, "A") self.assertEqual(len(errs), 0) val, errs = self.ctx.format('qux', {'num': 2}) self.assertEqual(val, "B") self.assertEqual(len(errs), 0) def test_with_argument_float(self): val, errs = self.ctx.format('qux', {'num': 1.0}) self.assertEqual(val, "A") self.assertEqual(len(errs), 0)
class TestDatetimeBuiltin(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" implicit-call = { $date } explicit-call = { DATETIME($date) } call-with-arg = { DATETIME($date, dateStyle: "long") } """)) def test_implicit_call_date(self): val, errs = self.ctx.format('implicit-call', {'date': date(2018, 2, 1)}) self.assertEqual(val, "Feb 1, 2018") self.assertEqual(len(errs), 0) def test_implicit_call_datetime(self): val, errs = self.ctx.format('implicit-call', {'date': datetime(2018, 2, 1, 14, 15, 16)}) self.assertEqual(val, "Feb 1, 2018") self.assertEqual(len(errs), 0) def test_explicit_call_date(self): val, errs = self.ctx.format('explicit-call', {'date': date(2018, 2, 1)}) self.assertEqual(val, "Feb 1, 2018") self.assertEqual(len(errs), 0) def test_explicit_call_datetime(self): val, errs = self.ctx.format('explicit-call', {'date': datetime(2018, 2, 1, 14, 15, 16)}) self.assertEqual(val, "Feb 1, 2018") self.assertEqual(len(errs), 0) def test_explicit_call_date_fluent_date(self): val, errs = self.ctx.format( 'explicit-call', {'date': fluent_date(date(2018, 2, 1), dateStyle='short')}) self.assertEqual(val, "2/1/18") self.assertEqual(len(errs), 0) def test_arg(self): val, errs = self.ctx.format('call-with-arg', {'date': date(2018, 2, 1)}) self.assertEqual(val, "February 1, 2018") self.assertEqual(len(errs), 0) def test_arg_overrides_fluent_date(self): val, errs = self.ctx.format( 'call-with-arg', {'date': fluent_date(date(2018, 2, 1), dateStyle='short')}) self.assertEqual(val, "February 1, 2018") self.assertEqual(len(errs), 0)
class TestFunctionCalls(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False, functions={'IDENTITY': lambda x: x}) self.ctx.add_messages( dedent_ftl(""" foo = Foo .attr = Attribute pass-nothing = { IDENTITY() } pass-string = { IDENTITY("a") } pass-number = { IDENTITY(1) } pass-message = { IDENTITY(foo) } pass-attr = { IDENTITY(foo.attr) } pass-external = { IDENTITY($ext) } pass-function-call = { IDENTITY(IDENTITY(1)) } """)) def test_accepts_strings(self): val, errs = self.ctx.format('pass-string', {}) self.assertEqual(val, "a") self.assertEqual(len(errs), 0) def test_accepts_numbers(self): val, errs = self.ctx.format('pass-number', {}) self.assertEqual(val, "1") self.assertEqual(len(errs), 0) def test_accepts_entities(self): val, errs = self.ctx.format('pass-message', {}) self.assertEqual(val, "Foo") self.assertEqual(len(errs), 0) def test_accepts_attributes(self): val, errs = self.ctx.format('pass-attr', {}) self.assertEqual(val, "Attribute") self.assertEqual(len(errs), 0) def test_accepts_externals(self): val, errs = self.ctx.format('pass-external', {'ext': 'Ext'}) self.assertEqual(val, "Ext") self.assertEqual(len(errs), 0) def test_accepts_function_calls(self): val, errs = self.ctx.format('pass-function-call', {}) self.assertEqual(val, "1") self.assertEqual(len(errs), 0) def test_wrong_arity(self): val, errs = self.ctx.format('pass-nothing', {}) self.assertEqual(val, "IDENTITY()") self.assertEqual(len(errs), 1) self.assertEqual(type(errs[0]), TypeError)
class TestStrings(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" foo = { $arg } """)) def test_can_be_a_string(self): val, errs = self.ctx.format('foo', {'arg': 'Argument'}) self.assertEqual(val, 'Argument') self.assertEqual(len(errs), 0)
class TestSelectExpressionWithNumbers(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" foo = { 1 -> *[0] A [1] B } bar = { 2 -> *[0] A [1] B } baz = { $num -> *[0] A [1] B } qux = { 1.0 -> *[0] A [1] B } """)) def test_selects_the_right_variant(self): val, errs = self.ctx.format('foo', {}) self.assertEqual(val, "B") self.assertEqual(len(errs), 0) def test_with_a_non_matching_selector(self): val, errs = self.ctx.format('bar', {}) self.assertEqual(val, "A") self.assertEqual(len(errs), 0) def test_with_a_missing_selector(self): val, errs = self.ctx.format('baz', {}) self.assertEqual(val, "A") self.assertEqual(errs, [FluentReferenceError("Unknown external: num")]) def test_with_argument_int(self): val, errs = self.ctx.format('baz', {'num': 1}) self.assertEqual(val, "B") def test_with_argument_float(self): val, errs = self.ctx.format('baz', {'num': 1.0}) self.assertEqual(val, "B") def test_with_float(self): val, errs = self.ctx.format('qux', {}) self.assertEqual(val, "B")
class TestMissing(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" missing = { MISSING(1) } """)) def test_falls_back_to_name_of_function(self): val, errs = self.ctx.format("missing", {}) self.assertEqual(val, "MISSING()") self.assertEqual(errs, [FluentReferenceError("Unknown function: MISSING")])
class Translation(): def __init__(self): self.__language = 'de' self.__locales = None self.__bundle = None def setLanguage(self, language): self.__language = language self.setupTranslation() def getLanguage(self): return self.__language def setLocaleDirectory(self, locales): self.__locales = locales def setupTranslation(self): messages = "" self.__bundle = FluentBundle([self.__language]) path = Path("{}/{}".format(self.__locales, self.__language)) for file in path.iterdir(): with open(file, "r") as f: messages += f.read() self.__bundle.add_messages(messages) def addMessage(self, message): self.__bundle.add_messages(message) print("Message '{}' added.".format(message)) def getMessage(self, id, args): return self.__bundle.format(id, args)
class TestMessagesCalledFromTerms(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" msg = Msg is {$arg} -foo = {msg} ref-foo = {-foo(arg: 1)} """)) def test_messages_inherit_term_args(self): # This behaviour may change in future, message calls might be # disallowed from inside terms val, errs = self.ctx.format('ref-foo', {'arg': 2}) self.assertEqual(val, 'Msg is 1') self.assertEqual(errs, [])
def getStruct(resource): pp = pprint.PrettyPrinter(indent=0) bundle = FluentBundle(["en-US"]) bundle.add_messages(resource) parser = fs.FluentParser() resource = parser.parse(resource) thing = fs.ast.to_json(resource) # json.loads(thing) # pp.pprint(thing) # pp.pprint(thing['body']) template_data = {} for m in thing['body']: if 'id' in m: # print(m['id']['name']) template_id = m['id']['name'] # pp.pprint(m['value']['elements']) new_entry = indvPieces(m, pp) template_data[template_id] = new_entry # print("FIRST OUTPUT") # pp.pprint(template_data) for k in template_data.keys(): # print(k) passedVars = passUpVars(template_data, k) for v in passedVars: if v not in template_data[k]['variables']: template_data[k]['variables'].append(v) passedVariants = passUpVariants(template_data, k) for v in passedVariants.keys(): if v not in template_data[k]['variants']: template_data[k]['variants'][v] = passedVariants[v] # print("SECOND OUTPUT") # pp.pprint(template_data) return template_data
class TestAttributesWithSimplePatternValues(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages(dedent_ftl(""" foo = Foo bar = Bar .attr = { foo } Attribute baz = { foo } Baz .attr = { foo } Attribute qux = Qux .attr = { qux } Attribute ref-bar = { bar.attr } ref-baz = { baz.attr } ref-qux = { qux.attr } """)) def test_can_be_referenced_for_entities_with_string_values(self): val, errs = self.ctx.format('ref-bar', {}) self.assertEqual(val, 'Foo Attribute') self.assertEqual(len(errs), 0) def test_can_be_formatted_directly_for_entities_with_string_values(self): val, errs = self.ctx.format('bar.attr', {}) self.assertEqual(val, 'Foo Attribute') self.assertEqual(len(errs), 0) def test_can_be_referenced_for_entities_with_pattern_values(self): val, errs = self.ctx.format('ref-baz', {}) self.assertEqual(val, 'Foo Attribute') self.assertEqual(len(errs), 0) def test_can_be_formatted_directly_for_entities_with_pattern_values(self): val, errs = self.ctx.format('baz.attr', {}) self.assertEqual(val, 'Foo Attribute') self.assertEqual(len(errs), 0) def test_works_with_self_references(self): val, errs = self.ctx.format('ref-qux', {}) self.assertEqual(val, 'Qux Attribute') self.assertEqual(len(errs), 0) def test_works_with_self_references_direct(self): val, errs = self.ctx.format('qux.attr', {}) self.assertEqual(val, 'Qux Attribute') self.assertEqual(len(errs), 0)
class TestNestedParameterizedTerms(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" -thing = { $article -> *[definite] { $first-letter -> *[lower] the thing [upper] The thing } [indefinite] { $first-letter -> *[lower] a thing [upper] A thing } } both-args = { -thing(first-letter: "upper", article: "indefinite") }. outer-arg = This is { -thing(article: "indefinite") }. inner-arg = { -thing(first-letter: "upper") }. neither-arg = { -thing() }. """)) def test_both_args(self): val, errs = self.ctx.format('both-args', {}) self.assertEqual(val, 'A thing.') self.assertEqual(errs, []) def test_outer_arg(self): val, errs = self.ctx.format('outer-arg', {}) self.assertEqual(val, 'This is a thing.') self.assertEqual(errs, []) def test_inner_arg(self): val, errs = self.ctx.format('inner-arg', {}) self.assertEqual(val, 'The thing.') self.assertEqual(errs, []) def test_inner_arg_with_external_args(self): val, errs = self.ctx.format('inner-arg', {'article': 'indefinite'}) self.assertEqual(val, 'The thing.') self.assertEqual(errs, []) def test_neither_arg(self): val, errs = self.ctx.format('neither-arg', {}) self.assertEqual(val, 'the thing.') self.assertEqual(errs, [])
class TestKeywordArgs(unittest.TestCase): def setUp(self): self.args_passed = [] def my_function(arg, kwarg1=None, kwarg2="default"): self.args_passed.append((arg, kwarg1, kwarg2)) return arg self.ctx = FluentBundle(['en-US'], use_isolating=False, functions={'MYFUNC': my_function}) self.ctx.add_messages( dedent_ftl(""" pass-arg = { MYFUNC("a") } pass-kwarg1 = { MYFUNC("a", kwarg1: 1) } pass-kwarg2 = { MYFUNC("a", kwarg2: "other") } pass-kwargs = { MYFUNC("a", kwarg1: 1, kwarg2: "other") } pass-user-arg = { MYFUNC($arg) } """)) def test_defaults(self): val, errs = self.ctx.format('pass-arg', {}) self.assertEqual(self.args_passed, [("a", None, "default")]) self.assertEqual(len(errs), 0) def test_pass_kwarg1(self): val, errs = self.ctx.format('pass-kwarg1', {}) self.assertEqual(self.args_passed, [("a", 1, "default")]) self.assertEqual(len(errs), 0) def test_pass_kwarg2(self): val, errs = self.ctx.format('pass-kwarg2', {}) self.assertEqual(self.args_passed, [("a", None, "other")]) self.assertEqual(len(errs), 0) def test_pass_kwargs(self): val, errs = self.ctx.format('pass-kwargs', {}) self.assertEqual(self.args_passed, [("a", 1, "other")]) self.assertEqual(len(errs), 0) def test_missing_arg(self): val, errs = self.ctx.format('pass-user-arg', {}) self.assertEqual(self.args_passed, [(FluentNone('arg'), None, "default")]) self.assertEqual(len(errs), 1)
class TestSkipIsolating(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US']) self.ctx.add_messages(dedent_ftl(""" -brand-short-name = Amaya foo = { -brand-short-name } with-arg = { $arg } """)) def test_skip_isolating_chars_if_just_one_message_ref(self): val, errs = self.ctx.format('foo', {}) self.assertEqual(val, 'Amaya') self.assertEqual(len(errs), 0) def test_skip_isolating_chars_if_just_one_placeable_arg(self): val, errs = self.ctx.format('with-arg', {'arg': 'Arg'}) self.assertEqual(val, 'Arg') self.assertEqual(len(errs), 0)
class TestSelectExpressionWithStrings(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) def test_with_a_matching_selector(self): self.ctx.add_messages( dedent_ftl(""" foo = { "a" -> [a] A *[b] B } """)) val, errs = self.ctx.format('foo', {}) self.assertEqual(val, "A") self.assertEqual(len(errs), 0) def test_with_a_non_matching_selector(self): self.ctx.add_messages( dedent_ftl(""" foo = { "c" -> [a] A *[b] B } """)) val, errs = self.ctx.format('foo', {}) self.assertEqual(val, "B") self.assertEqual(len(errs), 0) def test_with_a_missing_selector(self): self.ctx.add_messages( dedent_ftl(""" foo = { $none -> [a] A *[b] B } """)) val, errs = self.ctx.format('foo', {}) self.assertEqual(val, "B") self.assertEqual(errs, [FluentReferenceError("Unknown external: none")]) def test_with_argument_expression(self): self.ctx.add_messages( dedent_ftl(""" foo = { $arg -> [a] A *[b] B } """)) val, errs = self.ctx.format('foo', {'arg': 'a'}) self.assertEqual(val, "A")
class TestSelectExpressionWithTerms(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" -my-term = term .attr = termattribute ref-term-attr = { -my-term.attr -> [termattribute] Term Attribute *[other] Other } ref-term-attr-other = { -my-term.attr -> [x] Term Attribute *[other] Other } ref-term-attr-missing = { -my-term.missing -> [x] Term Attribute *[other] Other } """)) def test_ref_term_attribute(self): val, errs = self.ctx.format('ref-term-attr') self.assertEqual(val, "Term Attribute") self.assertEqual(len(errs), 0) def test_ref_term_attribute_fallback(self): val, errs = self.ctx.format('ref-term-attr-other') self.assertEqual(val, "Other") self.assertEqual(len(errs), 0) def test_ref_term_attribute_missing(self): val, errs = self.ctx.format('ref-term-attr-missing') self.assertEqual(val, "Other") self.assertEqual(len(errs), 1) self.assertEqual( errs, [FluentReferenceError('Unknown attribute: -my-term.missing')])
class TestTermsCalledFromTerms(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" -foo = {$a} {$b} -bar = {-foo(b: 2)} -baz = {-foo} ref-bar = {-bar(a: 1)} ref-baz = {-baz(a: 1)} """)) def test_term_args_isolated_with_call_syntax(self): val, errs = self.ctx.format('ref-bar', {}) self.assertEqual(val, 'a 2') self.assertEqual(errs, []) def test_term_args_isolated_without_call_syntax(self): val, errs = self.ctx.format('ref-baz', {}) self.assertEqual(val, 'a b') self.assertEqual(errs, [])
class TestParameterizedTermAttributes(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" -brand = Cool Thing .status = { $version -> [v2] available *[v1] deprecated } attr-with-arg = { -brand } is { -brand.status(version: "v2") -> [available] available, yay! *[deprecated] deprecated, sorry } -other = { $arg -> [a] ABC *[d] DEF } missing-attr-ref = { -other.missing(arg: "a") -> [ABC] ABC option *[DEF] DEF option } """)) def test_with_argument(self): val, errs = self.ctx.format('attr-with-arg', {}) self.assertEqual(val, 'Cool Thing is available, yay!') self.assertEqual(errs, []) def test_missing_attr(self): # We should fall back to the parent, and still pass the args. val, errs = self.ctx.format('missing-attr-ref', {}) self.assertEqual(val, 'ABC option') self.assertEqual( errs, [FluentReferenceError('Unknown attribute: -other.missing')])
class TestFluentBundle(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US']) def test_add_messages(self): self.ctx.add_messages( dedent_ftl(""" foo = Foo bar = Bar -baz = Baz """)) self.assertIn('foo', self.ctx._messages_and_terms) self.assertIn('bar', self.ctx._messages_and_terms) self.assertIn('-baz', self.ctx._messages_and_terms) def test_has_message(self): self.ctx.add_messages(dedent_ftl(""" foo = Foo """)) self.assertTrue(self.ctx.has_message('foo')) self.assertFalse(self.ctx.has_message('bar')) def test_has_message_for_term(self): self.ctx.add_messages( dedent_ftl(""" -foo = Foo """)) self.assertFalse(self.ctx.has_message('-foo')) def test_has_message_with_attribute(self): self.ctx.add_messages( dedent_ftl(""" foo = Foo .attr = Foo Attribute """)) self.assertTrue(self.ctx.has_message('foo')) self.assertFalse(self.ctx.has_message('foo.attr')) self.assertFalse(self.ctx.has_message('foo.other-attribute')) def test_plural_form_english_ints(self): ctx = FluentBundle(['en-US']) self.assertEqual(ctx._plural_form(0), 'other') self.assertEqual(ctx._plural_form(1), 'one') self.assertEqual(ctx._plural_form(2), 'other') def test_plural_form_english_floats(self): ctx = FluentBundle(['en-US']) self.assertEqual(ctx._plural_form(0.0), 'other') self.assertEqual(ctx._plural_form(1.0), 'one') self.assertEqual(ctx._plural_form(2.0), 'other') self.assertEqual(ctx._plural_form(0.5), 'other') def test_plural_form_french(self): # Just spot check one other, to ensure that we # are not getting the EN locale by accident or ctx = FluentBundle(['fr']) self.assertEqual(ctx._plural_form(0), 'one') self.assertEqual(ctx._plural_form(1), 'one') self.assertEqual(ctx._plural_form(2), 'other') def test_format_args(self): self.ctx.add_messages('foo = Foo') val, errs = self.ctx.format('foo') self.assertEqual(val, 'Foo') val, errs = self.ctx.format('foo', {}) self.assertEqual(val, 'Foo') def test_format_missing(self): self.assertRaises(LookupError, self.ctx.format, 'a-missing-message') def test_format_term(self): self.ctx.add_messages( dedent_ftl(""" -foo = Foo """)) self.assertRaises(LookupError, self.ctx.format, '-foo') self.assertRaises(LookupError, self.ctx.format, 'foo') def test_message_and_term_separate(self): self.ctx.add_messages( dedent_ftl(""" foo = Refers to { -foo } -foo = Foo """)) val, errs = self.ctx.format('foo', {}) self.assertEqual(val, 'Refers to \u2068Foo\u2069') self.assertEqual(errs, [])
# Create Fluent bundle for composing Fluent objects bundle = FluentBundle(["en-US"]) # Test String emailTestString = """ unread-emails = { $unreadEmailsCount -> [one] You have {$unreadEmailsCount} unread email. *[other] You have {$unreadEmailsCount} unread emails. }""" print("FLUENT MESSAGE:" + emailTestString + "\n") # Add String to bundle bundle.add_messages(emailTestString) # Add another test string straight to bundle # bundle.add_messages(""" # shared-photos = # {$userName} {$photoCount -> # [one] added a new photo # *[other] added {$photoCount} new photos # } to {$userGender -> # [male] his stream # [female] her stream # *[other] their stream # }.""") # Get compiled fluent message # translated, errs = bundle.format('shared-photos')
class TestMissing(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages(dedent_ftl(""" foo = Foo bar = Bar .attr = Bar Attribute baz = { foo } Baz qux = { foo } Qux .attr = Qux Attribute ref-foo = { foo.missing } ref-bar = { bar.missing } ref-baz = { baz.missing } ref-qux = { qux.missing } attr-only = .attr = Attr Only Attribute ref-double-missing = { missing.attr } """)) def test_falls_back_for_msg_with_string_value_and_no_attributes(self): val, errs = self.ctx.format('ref-foo', {}) self.assertEqual(val, 'Foo') self.assertEqual(errs, [FluentReferenceError( 'Unknown attribute: foo.missing')]) def test_falls_back_for_msg_with_string_value_and_other_attributes(self): val, errs = self.ctx.format('ref-bar', {}) self.assertEqual(val, 'Bar') self.assertEqual(errs, [FluentReferenceError( 'Unknown attribute: bar.missing')]) def test_falls_back_for_msg_with_pattern_value_and_no_attributes(self): val, errs = self.ctx.format('ref-baz', {}) self.assertEqual(val, 'Foo Baz') self.assertEqual(errs, [FluentReferenceError( 'Unknown attribute: baz.missing')]) def test_falls_back_for_msg_with_pattern_value_and_other_attributes(self): val, errs = self.ctx.format('ref-qux', {}) self.assertEqual(val, 'Foo Qux') self.assertEqual(errs, [FluentReferenceError( 'Unknown attribute: qux.missing')]) def test_attr_only_main(self): # For reference, Javascript implementation returns null for this case. # For Python returning `None` doesn't seem appropriate, since this will # only blow up later if you attempt to add this to a string, so we raise # a LookupError instead, as per entirely missing messages. self.assertRaises(LookupError, self.ctx.format, 'attr-only', {}) def test_attr_only_attribute(self): val, errs = self.ctx.format('attr-only.attr', {}) self.assertEqual(val, 'Attr Only Attribute') self.assertEqual(len(errs), 0) def test_missing_message_and_attribute(self): val, errs = self.ctx.format('ref-double-missing', {}) self.assertEqual(val, 'missing.attr') self.assertEqual(errs, [FluentReferenceError('Unknown attribute: missing.attr')])
class TestNumberBuiltin(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" implicit-call = { 123456 } implicit-call2 = { $arg } defaults = { NUMBER(123456) } percent-style = { NUMBER(1.234, style: "percent") } currency-style = { NUMBER(123456, style: "currency", currency: "USD") } from-arg = { NUMBER($arg) } merge-params = { NUMBER($arg, useGrouping: 0) } """)) def test_implicit_call(self): val, errs = self.ctx.format('implicit-call', {}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_implicit_call2_int(self): val, errs = self.ctx.format('implicit-call2', {'arg': 123456}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_implicit_call2_float(self): val, errs = self.ctx.format('implicit-call2', {'arg': 123456.0}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_implicit_call2_decimal(self): val, errs = self.ctx.format('implicit-call2', {'arg': Decimal('123456.0')}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_defaults(self): val, errs = self.ctx.format('defaults', {}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_percent_style(self): val, errs = self.ctx.format('percent-style', {}) self.assertEqual(val, "123%") self.assertEqual(len(errs), 0) def test_currency_style(self): val, errs = self.ctx.format('currency-style', {}) self.assertEqual(val, "$123,456.00") self.assertEqual(len(errs), 0) def test_from_arg_int(self): val, errs = self.ctx.format('from-arg', {'arg': 123456}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_from_arg_float(self): val, errs = self.ctx.format('from-arg', {'arg': 123456.0}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_from_arg_decimal(self): val, errs = self.ctx.format('from-arg', {'arg': Decimal('123456.0')}) self.assertEqual(val, "123,456") self.assertEqual(len(errs), 0) def test_from_arg_missing(self): val, errs = self.ctx.format('from-arg', {}) self.assertEqual(val, "arg") self.assertEqual(len(errs), 1) self.assertEqual(errs, [FluentReferenceError('Unknown external: arg')]) def test_partial_application(self): number = fluent_number(123456.78, currency="USD", style="currency") val, errs = self.ctx.format('from-arg', {'arg': number}) self.assertEqual(val, "$123,456.78") self.assertEqual(len(errs), 0) def test_merge_params(self): number = fluent_number(123456.78, currency="USD", style="currency") val, errs = self.ctx.format('merge-params', {'arg': number}) self.assertEqual(val, "$123456.78") self.assertEqual(len(errs), 0)
class TestPlaceables(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" message = Message .attr = Message Attribute -term = Term .attr = Term Attribute -term2 = { *[variant1] Term Variant 1 [variant2] Term Variant 2 } uses-message = { message } uses-message-attr = { message.attr } uses-term = { -term } uses-term-variant = { -term2[variant2] } bad-message-ref = Text { not-a-message } bad-message-attr-ref = Text { message.not-an-attr } bad-term-ref = Text { -not-a-term } self-referencing-message = Text { self-referencing-message } cyclic-msg1 = Text1 { cyclic-msg2 } cyclic-msg2 = Text2 { cyclic-msg1 } self-cyclic-message = Parent { self-cyclic-message.attr } .attr = Attribute { self-cyclic-message } self-attribute-ref-ok = Parent { self-attribute-ref-ok.attr } .attr = Attribute self-parent-ref-ok = Parent .attr = Attribute { self-parent-ref-ok } """)) def test_placeable_message(self): val, errs = self.ctx.format('uses-message', {}) self.assertEqual(val, 'Message') self.assertEqual(len(errs), 0) def test_placeable_message_attr(self): val, errs = self.ctx.format('uses-message-attr', {}) self.assertEqual(val, 'Message Attribute') self.assertEqual(len(errs), 0) def test_placeable_term(self): val, errs = self.ctx.format('uses-term', {}) self.assertEqual(val, 'Term') self.assertEqual(len(errs), 0) def test_placeable_term_variant(self): val, errs = self.ctx.format('uses-term-variant', {}) self.assertEqual(val, 'Term Variant 2') self.assertEqual(len(errs), 0) def test_placeable_bad_message(self): val, errs = self.ctx.format('bad-message-ref', {}) self.assertEqual(val, 'Text not-a-message') self.assertEqual(len(errs), 1) self.assertEqual( errs, [FluentReferenceError("Unknown message: not-a-message")]) def test_placeable_bad_message_attr(self): val, errs = self.ctx.format('bad-message-attr-ref', {}) self.assertEqual(val, 'Text Message') self.assertEqual(len(errs), 1) self.assertEqual( errs, [FluentReferenceError("Unknown attribute: message.not-an-attr")]) def test_placeable_bad_term(self): val, errs = self.ctx.format('bad-term-ref', {}) self.assertEqual(val, 'Text -not-a-term') self.assertEqual(len(errs), 1) self.assertEqual(errs, [FluentReferenceError("Unknown term: -not-a-term")]) def test_cycle_detection(self): val, errs = self.ctx.format('self-referencing-message', {}) self.assertEqual(val, 'Text ???') self.assertEqual(len(errs), 1) self.assertEqual(errs, [FluentCyclicReferenceError("Cyclic reference")]) def test_mutual_cycle_detection(self): val, errs = self.ctx.format('cyclic-msg1', {}) self.assertEqual(val, 'Text1 Text2 ???') self.assertEqual(len(errs), 1) self.assertEqual(errs, [FluentCyclicReferenceError("Cyclic reference")]) def test_allowed_self_reference(self): val, errs = self.ctx.format('self-attribute-ref-ok', {}) self.assertEqual(val, 'Parent Attribute') self.assertEqual(len(errs), 0) val, errs = self.ctx.format('self-parent-ref-ok.attr', {}) self.assertEqual(val, 'Attribute Parent') self.assertEqual(len(errs), 0)
def fluent_bundle(): ctx = FluentBundle(['pl'], use_isolating=False) ctx.add_messages(FTL_CONTENT) return ctx
class TestParameterizedTerms(unittest.TestCase): def setUp(self): self.ctx = FluentBundle(['en-US'], use_isolating=False) self.ctx.add_messages( dedent_ftl(""" -thing = { $article -> *[definite] the thing [indefinite] a thing [none] thing } thing-no-arg = { -thing } thing-no-arg-alt = { -thing() } thing-with-arg = { -thing(article: "indefinite") } thing-positional-arg = { -thing("foo") } thing-fallback = { -thing(article: "somethingelse") } bad-term = { -missing() } """)) def test_argument_omitted(self): val, errs = self.ctx.format('thing-no-arg', {}) self.assertEqual(val, 'the thing') self.assertEqual(errs, []) def test_argument_omitted_alt(self): val, errs = self.ctx.format('thing-no-arg-alt', {}) self.assertEqual(val, 'the thing') self.assertEqual(errs, []) def test_with_argument(self): val, errs = self.ctx.format('thing-with-arg', {}) self.assertEqual(val, 'a thing') self.assertEqual(errs, []) def test_positional_arg(self): val, errs = self.ctx.format('thing-positional-arg', {}) self.assertEqual(val, 'the thing') self.assertEqual(errs, [ FluentFormatError( "Ignored positional arguments passed to term '-thing'") ]) def test_fallback(self): val, errs = self.ctx.format('thing-fallback', {}) self.assertEqual(val, 'the thing') self.assertEqual(errs, []) def test_no_implicit_access_to_external_args(self): # The '-thing' term should not get passed article="indefinite" val, errs = self.ctx.format('thing-no-arg', {'article': 'indefinite'}) self.assertEqual(val, 'the thing') self.assertEqual(errs, []) def test_no_implicit_access_to_external_args_but_term_args_still_passed( self): val, errs = self.ctx.format('thing-with-arg', {'article': 'none'}) self.assertEqual(val, 'a thing') self.assertEqual(errs, []) def test_bad_term(self): val, errs = self.ctx.format('bad-term', {}) self.assertEqual(val, '-missing') self.assertEqual(errs, [FluentReferenceError('Unknown term: -missing')])