diff --git a/fluent/migrate/__init__.py b/fluent/migrate/__init__.py index d1c1bf76..2a92dd5e 100644 --- a/fluent/migrate/__init__.py +++ b/fluent/migrate/__init__.py @@ -5,6 +5,6 @@ Source, COPY, REPLACE_IN_TEXT, REPLACE, PLURALS, CONCAT ) from .helpers import ( # noqa: F401 - LITERAL, EXTERNAL_ARGUMENT, MESSAGE_REFERENCE + EXTERNAL_ARGUMENT, MESSAGE_REFERENCE ) from .changesets import convert_blame_to_changesets # noqa: F401 diff --git a/fluent/migrate/context.py b/fluent/migrate/context.py index 8ee779f3..4c8a8c44 100644 --- a/fluent/migrate/context.py +++ b/fluent/migrate/context.py @@ -41,7 +41,7 @@ class MergeContext(object): - A list of `FTL.Message` objects some of whose nodes are special helper or transform nodes: - helpers: LITERAL, EXTERNAL_ARGUMENT, MESSAGE_REFERENCE + helpers: EXTERNAL_ARGUMENT, MESSAGE_REFERENCE transforms: COPY, REPLACE_IN_TEXT, REPLACE, PLURALS, CONCAT """ diff --git a/fluent/migrate/helpers.py b/fluent/migrate/helpers.py index 01fa3fb6..f0e9c088 100644 --- a/fluent/migrate/helpers.py +++ b/fluent/migrate/helpers.py @@ -13,12 +13,6 @@ import fluent.syntax.ast as FTL -def LITERAL(value): - """Create a Pattern with a single TextElement.""" - elements = [FTL.TextElement(value)] - return FTL.Pattern(elements) - - def EXTERNAL_ARGUMENT(name): """Create an ExternalArgument expression.""" diff --git a/fluent/migrate/transforms.py b/fluent/migrate/transforms.py index b1a1ac24..942fbd90 100644 --- a/fluent/migrate/transforms.py +++ b/fluent/migrate/transforms.py @@ -8,36 +8,35 @@ All Transforms evaluate to Fluent Patterns. This makes them suitable for defining migrations of values of message, attributes and variants. The special CONCAT Transform is capable of joining multiple Patterns returned by evaluating -other Transforms into a single Pattern. It can also concatenate Fluent -Expressions, like MessageReferences and ExternalArguments. +other Transforms into a single Pattern. It can also concatenate Pattern +elements: TextElements and Placeables. The COPY, REPLACE and PLURALS Transforms inherit from Source which is a special AST Node defining the location (the file path and the id) of the legacy translation. During the migration, the current MergeContext scans the migration spec for Source nodes and extracts the information about all legacy -translations being migrated. Thus, +translations being migrated. For instance, COPY('file.dtd', 'hello') is equivalent to: - LITERAL(Source('file.dtd', 'hello')) + FTL.Pattern([ + FTL.TextElement(Source('file.dtd', 'hello')) + ]) -where LITERAL is a helper defined in the helpers.py module for creating Fluent -Patterns from the text passed as the argument. - -The LITERAL helper and the special REPLACE_IN_TEXT Transforms are useful for -working with text rather than (path, key) source definitions. This is the case -when the migrated translation requires some hardcoded text, e.g. and -when multiple translations become a single one with a DOM overlay. +Sometimes it's useful to work with text rather than (path, key) source +definitions. This is the case when the migrated translation requires some +hardcoded text, e.g. and when multiple translations become a single +one with a DOM overlay. In such cases it's best to use the AST nodes: FTL.Message( id=FTL.Identifier('update-failed'), value=CONCAT( COPY('aboutDialog.dtd', 'update.failed.start'), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'update.failed.linkText'), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'update.failed.end'), ) ) @@ -45,7 +44,8 @@ The REPLACE_IN_TEXT Transform also takes text as input, making in possible to pass it as the foreach function of the PLURALS Transform. In this case, each slice of the plural string will be run through a REPLACE_IN_TEXT operation. -Those slices are strings, so a REPLACE(path, key, …) isn't suitable for them. +Those slices are strings, so a REPLACE(path, key, …) wouldn't be suitable for +them. FTL.Message( FTL.Identifier('delete-all'), @@ -66,7 +66,12 @@ from __future__ import unicode_literals import fluent.syntax.ast as FTL -from .helpers import LITERAL + + +def pattern_from_text(value): + return FTL.Pattern([ + FTL.TextElement(value) + ]) def evaluate(ctx, node): @@ -120,7 +125,7 @@ class COPY(Source): def __call__(self, ctx): source = super(self.__class__, self).__call__(ctx) - return LITERAL(source) + return pattern_from_text(source) class REPLACE_IN_TEXT(Transform): @@ -210,10 +215,12 @@ class PLURALS(Source): Build an `FTL.SelectExpression` with the supplied `selector` and variants extracted from the source. The source needs to be a semicolon-separated list of variants. Each variant will be run through the `foreach` function, - which should return an `FTL.Node` or a `Transform`. + which should return an `FTL.Node` or a `Transform`. By default, the + `foreach` function transforms the source text into a Pattern with a single + TextElement. """ - def __init__(self, path, key, selector, foreach=LITERAL): + def __init__(self, path, key, selector, foreach=pattern_from_text): super(self.__class__, self).__init__(path, key) self.selector = selector self.foreach = foreach @@ -264,7 +271,7 @@ def concat_elements(acc, cur): return acc raise RuntimeError( - 'CONCAT accepts FTL Patterns and Expressions.' + 'CONCAT accepts FTL Patterns, TextElements and Placeables.' ) # Merge adjecent `FTL.TextElement` nodes. diff --git a/tests/migrate/test_concat.py b/tests/migrate/test_concat.py index 57de66f6..e63f41c2 100644 --- a/tests/migrate/test_concat.py +++ b/tests/migrate/test_concat.py @@ -10,12 +10,8 @@ DTDParser = PropertiesParser = None from fluent.migrate.util import parse, ftl_message_to_json -from fluent.migrate.helpers import ( - LITERAL, EXTERNAL_ARGUMENT, MESSAGE_REFERENCE -) -from fluent.migrate.transforms import ( - evaluate, CONCAT, COPY, REPLACE -) +from fluent.migrate.helpers import EXTERNAL_ARGUMENT, MESSAGE_REFERENCE +from fluent.migrate.transforms import evaluate, CONCAT, COPY, REPLACE class MockContext(unittest.TestCase): @@ -134,9 +130,9 @@ def test_concat_literal(self): FTL.Identifier('update-failed'), value=CONCAT( COPY(self.strings, 'update.failed.start'), - LITERAL(''), + FTL.TextElement(''), COPY(self.strings, 'update.failed.linkText'), - LITERAL(''), + FTL.TextElement(''), COPY(self.strings, 'update.failed.end'), ) ) @@ -154,16 +150,15 @@ class TestConcatInterpolate(MockContext): def setUp(self): self.strings = parse(DTDParser, ''' - + ''') - @unittest.skip('Parser/Serializer trim whitespace') def test_concat_replace(self): msg = FTL.Message( FTL.Identifier('channel-desc'), value=CONCAT( COPY(self.strings, 'channel.description.start'), - EXTERNAL_ARGUMENT('channelname'), + FTL.Placeable(EXTERNAL_ARGUMENT('channelname')), COPY(self.strings, 'channel.description.end'), ) ) @@ -200,7 +195,7 @@ def test_concat_replace(self): ) } ), - LITERAL(''), + FTL.TextElement(''), REPLACE( self.strings, 'community.mozillaLink', @@ -210,11 +205,11 @@ def test_concat_replace(self): ) } ), - LITERAL(''), + FTL.TextElement(''), COPY(self.strings, 'community.middle'), - LITERAL(''), + FTL.TextElement(''), COPY(self.strings, 'community.creditsLink'), - LITERAL(''), + FTL.TextElement(''), COPY(self.strings, 'community.end') ) ) diff --git a/tests/migrate/test_context.py b/tests/migrate/test_context.py index 2f1c88c7..775db8f2 100644 --- a/tests/migrate/test_context.py +++ b/tests/migrate/test_context.py @@ -9,7 +9,6 @@ from fluent.migrate.util import ftl, ftl_resource_to_json, to_json from fluent.migrate.context import MergeContext -from fluent.migrate.helpers import LITERAL from fluent.migrate.transforms import COPY @@ -37,7 +36,9 @@ def test_hardcoded_node(self): self.ctx.add_transforms('aboutDownloads.ftl', [ FTL.Message( id=FTL.Identifier('about'), - value=LITERAL('Hardcoded Value') + value=FTL.Pattern([ + FTL.TextElement('Hardcoded Value') + ]) ), ]) diff --git a/tests/migrate/test_context_real_examples.py b/tests/migrate/test_context_real_examples.py index b10ab431..7953885e 100644 --- a/tests/migrate/test_context_real_examples.py +++ b/tests/migrate/test_context_real_examples.py @@ -8,9 +8,7 @@ from fluent.migrate.util import ftl_resource_to_json, to_json from fluent.migrate.context import MergeContext -from fluent.migrate.helpers import ( - LITERAL, EXTERNAL_ARGUMENT, MESSAGE_REFERENCE -) +from fluent.migrate.helpers import EXTERNAL_ARGUMENT, MESSAGE_REFERENCE from fluent.migrate.transforms import ( CONCAT, COPY, PLURALS, REPLACE_IN_TEXT, REPLACE ) @@ -301,9 +299,9 @@ def setUp(self): id=FTL.Identifier('update-failed'), value=CONCAT( COPY('aboutDialog.dtd', 'update.failed.start'), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'update.failed.linkText'), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'update.failed.end'), ) ), @@ -329,7 +327,7 @@ def setUp(self): ) } ), - LITERAL(''), + FTL.TextElement(''), REPLACE( 'aboutDialog.dtd', 'community.mozillaLink', @@ -339,11 +337,11 @@ def setUp(self): ) } ), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'community.middle'), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'community.creditsLink'), - LITERAL(''), + FTL.TextElement(''), COPY('aboutDialog.dtd', 'community.end') ) ), diff --git a/tests/migrate/test_literal.py b/tests/migrate/test_copy.py similarity index 100% rename from tests/migrate/test_literal.py rename to tests/migrate/test_copy.py diff --git a/tests/migrate/test_merge.py b/tests/migrate/test_merge.py index fec6348d..4da4af44 100644 --- a/tests/migrate/test_merge.py +++ b/tests/migrate/test_merge.py @@ -12,7 +12,6 @@ from fluent.migrate.util import parse, ftl, ftl_resource_to_json from fluent.migrate.merge import merge_resource -from fluent.migrate.helpers import LITERAL from fluent.migrate.transforms import COPY @@ -64,7 +63,9 @@ def setUp(self): ), FTL.Message( FTL.Identifier('about'), - value=LITERAL('Hardcoded Value') + value=FTL.Pattern([ + FTL.TextElement('Hardcoded Value') + ]) ), FTL.Message( FTL.Identifier('open-menuitem'), diff --git a/tests/migrate/test_plural.py b/tests/migrate/test_plural.py index 8e3e3723..095f232d 100644 --- a/tests/migrate/test_plural.py +++ b/tests/migrate/test_plural.py @@ -10,7 +10,7 @@ PropertiesParser = None from fluent.migrate.util import parse, ftl_message_to_json -from fluent.migrate.helpers import LITERAL, EXTERNAL_ARGUMENT +from fluent.migrate.helpers import EXTERNAL_ARGUMENT from fluent.migrate.transforms import evaluate, PLURALS, REPLACE_IN_TEXT @@ -88,8 +88,7 @@ def setUp(self): value=PLURALS( self.strings, 'deleteAll', - EXTERNAL_ARGUMENT('num'), - LITERAL + EXTERNAL_ARGUMENT('num') ) ) diff --git a/tools/migrate/examples/about_dialog.py b/tools/migrate/examples/about_dialog.py index b3adfe91..84dae067 100644 --- a/tools/migrate/examples/about_dialog.py +++ b/tools/migrate/examples/about_dialog.py @@ -2,8 +2,7 @@ import fluent.syntax.ast as FTL from fluent.migrate import ( - CONCAT, LITERAL, EXTERNAL_ARGUMENT, MESSAGE_REFERENCE, COPY, - REPLACE + CONCAT, EXTERNAL_ARGUMENT, MESSAGE_REFERENCE, COPY, REPLACE ) @@ -21,12 +20,12 @@ def migrate(ctx): 'browser/chrome/browser/aboutDialog.dtd', 'update.failed.start' ), - LITERAL(''), + FTL.TextElement(''), COPY( 'browser/chrome/browser/aboutDialog.dtd', 'update.failed.linkText' ), - LITERAL(''), + FTL.TextElement(''), COPY( 'browser/chrome/browser/aboutDialog.dtd', 'update.failed.end' @@ -40,7 +39,7 @@ def migrate(ctx): 'browser/chrome/browser/aboutDialog.dtd', 'channel.description.start' ), - EXTERNAL_ARGUMENT('channelname'), + FTL.Placeable(EXTERNAL_ARGUMENT('channelname')), COPY( 'browser/chrome/browser/aboutDialog.dtd', 'channel.description.end' @@ -59,7 +58,7 @@ def migrate(ctx): ) } ), - LITERAL(''), + FTL.TextElement(''), REPLACE( 'browser/chrome/browser/aboutDialog.dtd', 'community.mozillaLink', @@ -69,17 +68,17 @@ def migrate(ctx): ) } ), - LITERAL(''), + FTL.TextElement(''), COPY( 'browser/chrome/browser/aboutDialog.dtd', 'community.middle2' ), - LITERAL(''), + FTL.TextElement(''), COPY( 'browser/chrome/browser/aboutDialog.dtd', 'community.creditsLink' ), - LITERAL(''), + FTL.TextElement(''), COPY( 'browser/chrome/browser/aboutDialog.dtd', 'community.end3'