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'