fluent.rst (4296B)
1 .. role:: bash(code) 2 :language: bash 3 4 .. role:: js(code) 5 :language: javascript 6 7 .. role:: python(code) 8 :language: python 9 10 11 =========================== 12 Fluent to Fluent Migrations 13 =========================== 14 15 When migrating existing Fluent messages, 16 it's possible to copy a source directly with :python:`COPY_PATTERN`, 17 or to apply string replacements and other changes 18 by extending the :python:`TransformPattern` visitor class. 19 20 These transforms work with individual Fluent patterns, 21 i.e. the body of a Fluent message or one of its attributes. 22 23 Copying Fluent Patterns 24 ----------------------- 25 26 Consider for example a patch modifying an existing message to move the original 27 value to a :js:`alt` attribute. 28 29 Original message: 30 31 32 .. code-block:: fluent 33 34 about-logins-icon = Warning icon 35 .title = Breached website 36 37 38 New message: 39 40 41 .. code-block:: fluent 42 43 about-logins-breach-icon = 44 .alt = Warning icon 45 .title = Breached website 46 47 48 This type of changes requires a new message identifier, which in turn causes 49 existing translations to be lost. It’s possible to migrate the existing 50 translated content with: 51 52 53 .. code-block:: python 54 55 from fluent.migrate import COPY_PATTERN 56 57 ctx.add_transforms( 58 "browser/browser/aboutLogins.ftl", 59 "browser/browser/aboutLogins.ftl", 60 transforms_from( 61 """ 62 about-logins-breach-icon = 63 .alt = {COPY_PATTERN(from_path, "about-logins-icon")} 64 .title = {COPY_PATTERN(from_path, "about-logins-icon.title")} 65 """,from_path="browser/browser/aboutLogins.ftl"), 66 ) 67 68 69 In this specific case, the destination and source files are the same. The dot 70 notation is used to access attributes: :js:`about-logins-icon.title` matches 71 the :js:`title` attribute of the message with identifier 72 :js:`about-logins-icon`, while :js:`about-logins-icon` alone matches the value 73 of the message. 74 75 76 .. warning:: 77 78 The second argument of :python:`COPY_PATTERN` and :python:`TransformPattern` 79 identifies a pattern, so using the message identifier will not 80 migrate the message as a whole, with all its attributes, only its value. 81 82 Transforming Fluent Patterns 83 ---------------------------- 84 85 To apply changes to Fluent messages, you may extend the 86 :python:`TransformPattern` class to create your transformation. 87 This is a powerful general-purpose tool, of which :python:`COPY_PATTERN` is the 88 simplest extension that applies no transformation to the source. 89 90 Consider for example a patch copying an existing message to strip out its HTML 91 content to use as an ARIA value. 92 93 Original message: 94 95 96 .. code-block:: fluent 97 98 videocontrols-label = 99 { $position }<span data-l10n-name="duration"> / { $duration }</span> 100 101 102 New message: 103 104 105 .. code-block:: fluent 106 107 videocontrols-scrubber = 108 .aria-valuetext = { $position } / { $duration } 109 110 111 A migration may be applied to create this new message with: 112 113 114 .. code-block:: python 115 116 from fluent.migrate.transforms import TransformPattern 117 import fluent.syntax.ast as FTL 118 119 class STRIP_SPAN(TransformPattern): 120 def visit_TextElement(self, node): 121 node.value = re.sub("</?span[^>]*>", "", node.value) 122 return node 123 124 def migrate(ctx): 125 path = "toolkit/toolkit/global/videocontrols.ftl" 126 ctx.add_transforms( 127 path, 128 path, 129 [ 130 FTL.Message( 131 id=FTL.Identifier("videocontrols-scrubber"), 132 attributes=[ 133 FTL.Attribute( 134 id=FTL.Identifier("aria-valuetext"), 135 value=STRIP_SPAN(path, "videocontrols-label"), 136 ), 137 ], 138 ), 139 ], 140 ) 141 142 143 Note that a custom extension such as :python:`STRIP_SPAN` is not supported by 144 the :python:`transforms_from` utility, so the list of transforms needs to be 145 defined explicitly. 146 147 Internally, :python:`TransformPattern` extends the `fluent.syntax`__ 148 :python:`Transformer`, which defines the :python:`FTL` AST used here. 149 As a specific convenience, pattern element visitors such as 150 :python:`visit_TextElement` are allowed to return a :python:`FTL.Pattern` 151 to replace themselves with more than one node. 152 153 __ https://projectfluent.org/python-fluent/fluent.syntax/stable/