Fluent to Fluent Migrations
When migrating existing Fluent messages,
it’s possible to copy a source directly with COPY_PATTERN
,
or to apply string replacements and other changes
by extending the TransformPattern
visitor class.
These transforms work with individual Fluent patterns, i.e. the body of a Fluent message or one of its attributes.
Copying Fluent Patterns
Consider for example a patch modifying an existing message to move the original
value to a alt
attribute.
Original message:
about-logins-icon = Warning icon
.title = Breached website
New message:
about-logins-breach-icon =
.alt = Warning icon
.title = Breached website
This type of changes requires a new message identifier, which in turn causes existing translations to be lost. It’s possible to migrate the existing translated content with:
from fluent.migrate import COPY_PATTERN
ctx.add_transforms(
"browser/browser/aboutLogins.ftl",
"browser/browser/aboutLogins.ftl",
transforms_from(
"""
about-logins-breach-icon =
.alt = {COPY_PATTERN(from_path, "about-logins-icon")}
.title = {COPY_PATTERN(from_path, "about-logins-icon.title")}
""",from_path="browser/browser/aboutLogins.ftl"),
)
In this specific case, the destination and source files are the same. The dot
notation is used to access attributes: about-logins-icon.title
matches
the title
attribute of the message with identifier
about-logins-icon
, while about-logins-icon
alone matches the value
of the message.
Warning
The second argument of COPY_PATTERN
and TransformPattern
identifies a pattern, so using the message identifier will not
migrate the message as a whole, with all its attributes, only its value.
Transforming Fluent Patterns
To apply changes to Fluent messages, you may extend the
TransformPattern
class to create your transformation.
This is a powerful general-purpose tool, of which COPY_PATTERN
is the
simplest extension that applies no transformation to the source.
Consider for example a patch copying an existing message to strip out its HTML content to use as an ARIA value.
Original message:
videocontrols-label =
{ $position }<span data-l10n-name="duration"> / { $duration }</span>
New message:
videocontrols-scrubber =
.aria-valuetext = { $position } / { $duration }
A migration may be applied to create this new message with:
from fluent.migrate.transforms import TransformPattern
import fluent.syntax.ast as FTL
class STRIP_SPAN(TransformPattern):
def visit_TextElement(self, node):
node.value = re.sub("</?span[^>]*>", "", node.value)
return node
def migrate(ctx):
path = "toolkit/toolkit/global/videocontrols.ftl"
ctx.add_transforms(
path,
path,
[
FTL.Message(
id=FTL.Identifier("videocontrols-scrubber"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("aria-valuetext"),
value=STRIP_SPAN(path, "videocontrols-label"),
),
],
),
],
)
Note that a custom extension such as STRIP_SPAN
is not supported by
the transforms_from
utility, so the list of transforms needs to be
defined explicitly.
Internally, TransformPattern
extends the fluent.syntax
Transformer
, which defines the FTL
AST used here.
As a specific convenience, pattern element visitors such as
visit_TextElement
are allowed to return a FTL.Pattern
to replace themselves with more than one node.