Skip to content

Commit

Permalink
Never migrate partial translations
Browse files Browse the repository at this point in the history
Partial translations may break the AST because they produce `TextElements` with
`None` values. For now, explicitly skip any transforms which depend on at least
one missing legacy string.

In the future we might be able to allow partial migrations in some situations,
like migrating a subset of attributes of a message. See
https://bugzilla.mozilla.org/show_bug.cgi?id=1321271.
  • Loading branch information
stasm committed Feb 5, 2018
1 parent 01be516 commit 5fe65e1
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 18 deletions.
8 changes: 5 additions & 3 deletions fluent/migrate/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,11 @@ def in_changeset(ident):
if len(message_deps) == 0:
return True

# If the intersection of the dependencies and the current
# changeset is non-empty, merge this message.
return message_deps & changeset
# Make sure all the dependencies are present in the current
# changeset. Partial migrations are not currently supported.
# See https://bugzilla.mozilla.org/show_bug.cgi?id=1321271
available_deps = message_deps & changeset
return message_deps == available_deps

# Merge legacy translations with the existing ones using the
# reference as a template.
Expand Down
302 changes: 288 additions & 14 deletions tests/migrate/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ def test_missing_reference_file(self):


@unittest.skipUnless(compare_locales, 'compare-locales requried')
class TestEmptyLocalization(unittest.TestCase):
class TestMissingLocalizationFiles(unittest.TestCase):
def setUp(self):
# Silence all logging.
logging.disable(logging.CRITICAL)
Expand All @@ -266,7 +266,40 @@ def tearDown(self):
# Resume logging.
logging.disable(logging.NOTSET)

def test_all_localization_missing(self):
def test_missing_file(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
value=COPY(
'aboutDownloads.dtd',
'aboutDownloads.title'
)
),
FTL.Message(
id=FTL.Identifier('header'),
value=COPY(
'missing.dtd',
'missing'
)
),
])

expected = {
'aboutDownloads.ftl': ftl_resource_to_json('''
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
title = Pobrane pliki
''')
}

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
expected
)

def test_all_files_missing(self):
pattern = ('No localization files were found')
with self.assertRaisesRegexp(EmptyLocalizationError, pattern):
self.ctx.add_transforms('existing.ftl', 'existing.ftl', [
Expand All @@ -281,7 +314,9 @@ def test_all_localization_missing(self):


@unittest.skipUnless(compare_locales, 'compare-locales requried')
class TestIncompleteLocalization(unittest.TestCase):
class TestMissingLocalizationStrings(unittest.TestCase):
maxDiff = None

def setUp(self):
# Silence all logging.
logging.disable(logging.CRITICAL)
Expand All @@ -296,20 +331,128 @@ def tearDown(self):
# Resume logging.
logging.disable(logging.NOTSET)

def test_missing_localization_file(self):
self.ctx.add_transforms('existing.ftl', 'existing.ftl', [
def test_missing_string_in_simple_value(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('foo'),
id=FTL.Identifier('title'),
value=COPY(
'existing.dtd',
'foo'
'aboutDownloads.dtd',
'missing'
)
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_only_variant(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('bar'),
value=COPY(
'missing.dtd',
'bar'
id=FTL.Identifier('title'),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=FTL.SelectExpression(
expression=FTL.CallExpression(
callee=FTL.Identifier('PLATFORM')
),
variants=[
FTL.Variant(
key=FTL.VariantName('other'),
default=True,
value=COPY(
'aboutDownloads.dtd',
'missing'
)
),
]
)
),
]
)
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_all_variants(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=FTL.SelectExpression(
expression=FTL.CallExpression(
callee=FTL.Identifier('PLATFORM')
),
variants=[
FTL.Variant(
key=FTL.VariantName('windows'),
default=False,
value=COPY(
'aboutDownloads.dtd',
'missing.windows'
)
),
FTL.Variant(
key=FTL.VariantName('other'),
default=True,
value=COPY(
'aboutDownloads.dtd',
'missing.other'
)
),
]
)
),
]
)
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_one_of_variants(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=FTL.SelectExpression(
expression=FTL.CallExpression(
callee=FTL.Identifier('PLATFORM')
),
variants=[
FTL.Variant(
key=FTL.VariantName('windows'),
default=False,
value=COPY(
'aboutDownloads.dtd',
'aboutDownloads.title'
)
),
FTL.Variant(
key=FTL.VariantName('other'),
default=True,
value=COPY(
'aboutDownloads.dtd',
'missing.other'
)
),
]
)
),
]
)
),
])
Expand All @@ -319,6 +462,139 @@ def test_missing_localization_file(self):
{}
)

def test_missing_string_in_all_attributes(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
attributes=[
FTL.Attribute(
FTL.Identifier('one'),
COPY(
'aboutDownloads.dtd',
'missing.one'
)
),
FTL.Attribute(
FTL.Identifier('two'),
COPY(
'aboutDownloads.dtd',
'missing.two'
)
),
]
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_one_of_attributes(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
attributes=[
FTL.Attribute(
FTL.Identifier('title'),
COPY(
'aboutDownloads.dtd',
'aboutDownloads.title'
)
),
FTL.Attribute(
FTL.Identifier('missing'),
COPY(
'aboutDownloads.dtd',
'missing'
)
),
]
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_only_attribute(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
attributes=[
FTL.Attribute(
FTL.Identifier('one'),
COPY(
'aboutDownloads.dtd',
'missing'
)
),
]
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_all_attributes(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
attributes=[
FTL.Attribute(
FTL.Identifier('one'),
COPY(
'aboutDownloads.dtd',
'missing.one'
)
),
FTL.Attribute(
FTL.Identifier('two'),
COPY(
'aboutDownloads.dtd',
'missing.two'
)
),
]
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)

def test_missing_string_in_one_of_attributes(self):
self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [
FTL.Message(
id=FTL.Identifier('title'),
attributes=[
FTL.Attribute(
FTL.Identifier('title'),
COPY(
'aboutDownloads.dtd',
'aboutDownloads.title'
)
),
FTL.Attribute(
FTL.Identifier('missing'),
COPY(
'aboutDownloads.dtd',
'missing'
)
),
]
),
])

self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
{}
)


@unittest.skipUnless(compare_locales, 'compare-locales requried')
class TestExistingTarget(unittest.TestCase):
Expand Down Expand Up @@ -360,7 +636,6 @@ def test_existing_target_ftl_missing_string(self):
''')
}

self.maxDiff = None
self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
expected
Expand Down Expand Up @@ -399,7 +674,6 @@ def test_existing_target_ftl_existing_string(self):
''')
}

self.maxDiff = None
self.assertDictEqual(
to_json(self.ctx.merge_changeset()),
expected
Expand Down
Loading

0 comments on commit 5fe65e1

Please sign in to comment.