Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build

Commits:

3 changed files:

Changes:

  • projects/firefox/build
    ... ... @@ -136,15 +136,50 @@ branding_dir=browser/branding/[% c("var/branding_directory_prefix") %]-[% c("var
    136 136
     
    
    137 137
       [% IF c("var/tor-browser") -%]
    
    138 138
         tar -C "$rootdir" -xf "$rootdir/[% c('input_files_by_name/translation-tor-browser') %]"
    
    139
    +
    
    140
    +    # For the purpose of Weblate, all releases share a single brand.ftl and
    
    141
    +    # brand.properties file per locale in the translations repository.
    
    142
    +    # See tor-browser-build#41372.
    
    143
    +    # In brand.ftl, both `-brand-short-name` and `-brand-full-name` should
    
    144
    +    # differ between releases. As such, they have additional entries in the
    
    145
    +    # translations repository file (Weblate):
    
    146
    +    #   -brand-short-name for the stable release.
    
    147
    +    #   -brand-short-name_alpha for the alpha release.
    
    148
    +    #   -brand-short-name_nightly for the nightly release.
    
    149
    +    # And similarly for -brand-full-name.
    
    150
    +    # For the final build, we only want to keep the string that matches the
    
    151
    +    # built release, and remove its suffix if it has one. So for the stable
    
    152
    +    # release we want to keep -brand-short-name. For the alpha release we want
    
    153
    +    # to keep -brand-short-name_alpha instead, and rename it to be
    
    154
    +    # -brand-short-name.
    
    155
    +    #
    
    156
    +    # As such, we parse the brand.ftl file to rename these strings to keep the
    
    157
    +    # version we want using rename-branding-strings.py.
    
    158
    +    #
    
    159
    +    # We do a similar thing with brandShortName and brandFullName in
    
    160
    +    # brand.properties.
    
    161
    +
    
    162
    +    # Instructions for the script to perform the renames.
    
    163
    +    brand_ftl_renames='{
    
    164
    +      "suffix": "[% c("var/branding_string_suffix") %]",
    
    165
    +      "ids": ["-brand-short-name", "-brand-full-name"]
    
    166
    +    }'
    
    167
    +    brand_properties_renames='{
    
    168
    +      "suffix": "[% c("var/branding_string_suffix") %]",
    
    169
    +      "ids": ["brandShortName", "brandFullName"]
    
    170
    +    }'
    
    171
    +
    
    139 172
         pushd "$rootdir/translation-tor-browser"
    
    140 173
         ln -s ja ja-JP-mac
    
    141 174
         for lang in $supported_locales; do
    
    142 175
           mv $lang/tor-browser.ftl "$l10ncentral/$lang/toolkit/toolkit/global/"
    
    143
    -      # Branding. Currently all releases use the same branding.
    
    176
    +      # Branding.
    
    144 177
           l10n_branding_dir="$l10ncentral/$lang/$branding_dir/"
    
    145 178
           mkdir -p "$l10n_branding_dir"
    
    146
    -      mv $lang/branding/brand.ftl "$l10n_branding_dir"
    
    147
    -      mv $lang/brand.properties "$l10n_branding_dir"
    
    179
    +      # Convert the translations repository branding files into files that work
    
    180
    +      # for this specific build.
    
    181
    +      python3 rename-branding-strings.py $lang/branding/brand.ftl "$brand_ftl_renames" > "$l10n_branding_dir/brand.ftl"
    
    182
    +      python3 rename-branding-strings.py $lang/brand.properties "$brand_properties_renames" > "$l10n_branding_dir/brand.properties"
    
    148 183
         done
    
    149 184
         popd
    
    150 185
     
    

  • projects/firefox/config
    ... ... @@ -54,6 +54,10 @@ var:
    54 54
         rm -Rf "$rezip_tmpdir"
    
    55 55
     
    
    56 56
       l10n-changesets: '[% exec("git --no-pager show " _ c("git_hash") _ ":browser/locales/l10n-changesets.json", { exec_noco => 1 }) %]'
    
    57
    +  # The branding_string_suffix for the alpha and nightly should be
    
    58
    +  # '_alpha' and '_nightly', matching the "suffix" chosen in the
    
    59
    +  # tor-browser:update-translations.yml file.
    
    60
    +  branding_string_suffix: '_[% c("var/channel") %]'
    
    57 61
     
    
    58 62
     steps:
    
    59 63
       src-tarballs:
    
    ... ... @@ -94,6 +98,12 @@ targets:
    94 98
         var:
    
    95 99
           nightly_updates_publish_dir_prefix: basebrowser-
    
    96 100
     
    
    101
    +  release:
    
    102
    +    var:
    
    103
    +      # For the stable release, the suffix is empty.
    
    104
    +      # I.e. we want to select `-brand-short-name` directly.
    
    105
    +      branding_string_suffix: ''
    
    106
    +
    
    97 107
       nightly:
    
    98 108
         git_hash: '[% c("var/project-name") %]-[% c("var/firefox_version") %]-[% c("var/browser_branch") %]'
    
    99 109
         tag_gpg_id: 0
    
    ... ... @@ -183,6 +193,8 @@ input_files:
    183 193
       - project: binutils
    
    184 194
         name: binutils
    
    185 195
         enable: '[% c("var/linux") && ! c("var/linux-cross") %]'
    
    196
    +  - filename: rename-branding-strings.py
    
    197
    +    enable: '[% c("var/has_l10n") && c("var/tor-browser") %]'
    
    186 198
       - filename: fix-info-plist.py
    
    187 199
         enable: '[% c("var/macos") %]'
    
    188 200
       - filename: nsis-uninstall.patch
    

  • projects/firefox/rename-branding-strings.py
    1
    +import argparse
    
    2
    +import json
    
    3
    +import re
    
    4
    +
    
    5
    +arg_parser = argparse.ArgumentParser(
    
    6
    +    description="Filter a branding file to only include the expected strings"
    
    7
    +)
    
    8
    +arg_parser.add_argument("file", metavar="<file>", help="branding file to process")
    
    9
    +arg_parser.add_argument(
    
    10
    +    "details", metavar="<details>", help="JSON specification for renaming"
    
    11
    +)
    
    12
    +
    
    13
    +args = arg_parser.parse_args()
    
    14
    +details_dict = json.loads(args.details)
    
    15
    +# The suffix we want to search for or remove.
    
    16
    +# Can be empty if we want to select the IDs that have no suffix.
    
    17
    +suffix = details_dict["suffix"]
    
    18
    +# The string IDs we want to rename.
    
    19
    +rename_ids = details_dict["ids"]
    
    20
    +
    
    21
    +
    
    22
    +def parse_ids(string, pattern):
    
    23
    +    """
    
    24
    +    Extract the IDs found in a string.
    
    25
    +
    
    26
    +    :param string: The string to parse.
    
    27
    +    :param pattern: The pattern to capture IDs.
    
    28
    +
    
    29
    +    :yields: A tuple containing a chunk of string and whether the chunk
    
    30
    +      is an ID.
    
    31
    +    """
    
    32
    +    regex = re.compile(pattern, flags=re.MULTILINE + re.ASCII)
    
    33
    +    while True:
    
    34
    +        match = regex.search(string)
    
    35
    +        if not match:
    
    36
    +            yield string, False
    
    37
    +            return
    
    38
    +
    
    39
    +        yield string[: match.start("id")], False
    
    40
    +        yield match.group("id"), True
    
    41
    +        string = string[match.end("id") :]
    
    42
    +
    
    43
    +
    
    44
    +# We want to parse the file and rename the IDs we are interested in.
    
    45
    +# If the ID starts with one of the `rename_ids` but the suffix does
    
    46
    +# not match we append an "_UNUSED" suffix to the ID, to keep it in the output
    
    47
    +# but functionally unused in the final build.
    
    48
    +# Otherwise, if the ID starts with one of the `rename_ids` and the suffix
    
    49
    +# matches we will remove the suffix from the ID, so that it is used in the
    
    50
    +# final build.
    
    51
    +# Everything else found in the file, like entry values, comments and blank
    
    52
    +# lines, will be included in the output as it was.
    
    53
    +#
    
    54
    +# NOTE: This script is constructed to be *independent* of the order in which
    
    55
    +# strings are present in the file. Weblate does not guarantee the order of
    
    56
    +# translated files to use the same ordering as the original en-US file.
    
    57
    +#
    
    58
    +# NOTE: This script should work for all locales. In particular, for Fluent files
    
    59
    +# it needs to be able to handle Fluent Terms that are multi-valued (conditional)
    
    60
    +# and Terms with attributes. Therefore, whilst we could have written a script to
    
    61
    +# *remove* unwanted strings, the parsing logic would have been far more complex
    
    62
    +# to be able to handle all these cases. Hence why we only parse for the Fluent
    
    63
    +# IDs and rename them, which is much simpler.
    
    64
    +with open(args.file, "r") as file:
    
    65
    +    if file.name.endswith(".ftl"):
    
    66
    +        # A Fluent ID is the identifier for a Message or Term, which always
    
    67
    +        # starts on a newline, and will be followed by an "=" character.
    
    68
    +        id_pattern = r"^(?P<id>-?[a-zA-Z][a-zA-Z0-9_-]*) *="
    
    69
    +    elif file.name.endswith(".properties"):
    
    70
    +        # A properties ID can be preceded by whitespace, and can be any
    
    71
    +        # character other than whitespace, ":" or "=". The first character also
    
    72
    +        # cannot be "!" or "#" since this starts a comment. Technically the
    
    73
    +        # Java ".properties" spec allows a ID to include one of these characters
    
    74
    +        # if it is escaped by a "\", but we don't expect or care about such IDs.
    
    75
    +        # The Java spec also has a limited set of whitespace, which excludes
    
    76
    +        # "\v", but we do not expect Weblate or any other serialiser to
    
    77
    +        # insert whitespace beyond "\n", "\r", "\t" or " ".
    
    78
    +        id_pattern = r"^\s*(?P<id>[^!#:=\s][^:=\s]*)"
    
    79
    +    else:
    
    80
    +        raise ValueError(f"Unknown file type {file.name}")
    
    81
    +
    
    82
    +    for part, is_id in parse_ids(file.read(), id_pattern):
    
    83
    +        if is_id:
    
    84
    +            for string_id in rename_ids:
    
    85
    +                if part.startswith(string_id):
    
    86
    +                    if part == string_id + suffix:
    
    87
    +                        # This string matches the suffix, so we want to use its
    
    88
    +                        # value. We adjust the ID to remove the suffix before
    
    89
    +                        # printing.
    
    90
    +                        part = string_id
    
    91
    +                    else:
    
    92
    +                        # Keep this entry in the output, but make it unused by
    
    93
    +                        # appending to the ID.
    
    94
    +                        part += "_UNUSED"
    
    95
    +                    break
    
    96
    +        print(part, end="")