overview.rst (4831B)
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 Migration Recipes and Their Lifecycle 12 ===================================== 13 14 The actual migrations are performed running Python modules called **migration 15 recipes**, which contain directives on how to migrate strings, which files are 16 involved, transformations to apply, etc. These recipes are stored in 17 `mozilla-central`__. 18 19 __ https://hg.mozilla.org/mozilla-central/file/default/python/l10n/fluent_migrations 20 21 When part of Firefox’s UI is migrated to Fluent, a migration recipe should be 22 attached to the same patch that adds new strings to `.ftl` files. 23 24 Migration recipes can quickly become obsolete, because the referenced strings 25 and files are removed from repositories as part of ongoing development. 26 For these reasons, l10n-drivers periodically clean up the `fluent_migrations` 27 folder in mozilla-central, keeping only recipes for 2 28 shipping versions (Nightly and Beta). 29 30 31 .. hint:: 32 33 As a developer you don’t need to bother about updating migration recipes 34 already in `mozilla-central`: if a new patch removes a string or file that is 35 used in a migration recipe, simply ignore it, since the entire recipe will be 36 removed within a couple of cycles. 37 38 39 How to Write Migration Recipes 40 ============================== 41 42 The migration recipe’s filename should start with a reference to the associated 43 bug number, and include a brief description of the bug, e.g. 44 :bash:`bug_1451992_preferences_applicationManager.py` is the migration recipe 45 used to migrate the Application Manager window in preferences. It’s also 46 possible to look at existing recipes in `mozilla-central`__ for inspiration. 47 48 __ https://hg.mozilla.org/mozilla-central/file/default/python/l10n/fluent_migrations 49 50 51 General Recipe Structure 52 ======================== 53 54 A migration recipe is a Python module, implementing the :py:func:`migrate` 55 function, which takes a :py:class:`MigrationContext` as input. The API provided 56 by the context is 57 58 .. code-block:: python 59 60 class MigrationContext: 61 def add_transforms(self, target, reference, transforms): 62 """Define transforms for target using reference as template. 63 64 `target` is a path of the destination FTL file relative to the 65 localization directory. `reference` is a path to the template FTL 66 file relative to the reference directory. 67 68 Each transform is an extended FTL node with `Transform` nodes as some 69 values. 70 71 For transforms that merely copy legacy messages or Fluent patterns, 72 using `fluent.migrate.helpers.transforms_from` is recommended. 73 """ 74 75 The skeleton of a migration recipe just implements the :py:func:`migrate` 76 function calling into :py:func:`ctx.add_transforms`, and looks like 77 78 .. code-block:: python 79 80 # coding=utf8 81 82 # Any copyright is dedicated to the Public Domain. 83 # http://creativecommons.org/publicdomain/zero/1.0/ 84 85 from __future__ import absolute_import 86 87 88 def migrate(ctx): 89 """Bug 1552333 - Migrate feature to Fluent, part {index}""" 90 target = 'browser/browser/feature.ftl' 91 reference = 'browser/browser/feature.ftl' 92 ctx.add_transforms( 93 target, 94 reference, 95 [], # Actual transforms go here. 96 ) 97 98 One can call into :py:func:`ctx.add_transforms` multiple times. In particular, one 99 can create migrated content in multiple files as part of a single migration 100 recipe by calling :py:func:`ctx.add_transforms` with different target-reference 101 pairs. 102 103 The *docstring* for this function will be used 104 as a commit message in VCS, that’s why it’s important to make sure the bug 105 reference is correct, and to keep the `part {index}` section: multiple strings 106 could have multiple authors, and would be migrated in distinct commits (part 1, 107 part 2, etc.). 108 109 Transforms 110 ========== 111 112 The work of the migrations is done by the transforms that are passed as 113 last argument to :py:func:`ctx.add_transforms`. They're instances of either Fluent 114 :py:class:`fluent.syntax.ast.Message` or :py:class:`Term`, and their content 115 can depend on existing translation sources. The skeleton of a Message looks like 116 117 .. code-block:: python 118 119 FTL.Message( 120 id=FTL.Identifier( 121 name="msg", 122 ), 123 value=FTL.Pattern( 124 elements=[ 125 FTL.TextElement( 126 value="A string", 127 ), 128 ], 129 ), 130 ) 131 132 When migrating existing legacy translations, you'll replace an 133 ``FTL.TextElement`` with a ``COPY(legacy_path, "old_id")``, or one of its 134 variations we detail :doc:`next <legacy>`. When migrating existing Fluent 135 translations, an ``FTL.Pattern`` is replaced with a 136 ``COPY_PATTERN(old_path, "old-id")``.