Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits: 858ee2ee by Henry Wilkes at 2025-02-18T11:35:44+00:00 Bug 41372: Handle branding strings for tor-browser build.
- - - - -
3 changed files:
- projects/firefox/build - projects/firefox/config - + projects/firefox/rename-branding-strings.py
Changes:
===================================== projects/firefox/build ===================================== @@ -136,15 +136,50 @@ branding_dir=browser/branding/[% c("var/branding_directory_prefix") %]-[% c("var
[% IF c("var/tor-browser") -%] tar -C "$rootdir" -xf "$rootdir/[% c('input_files_by_name/translation-tor-browser') %]" + + # For the purpose of Weblate, all releases share a single brand.ftl and + # brand.properties file per locale in the translations repository. + # See tor-browser-build#41372. + # In brand.ftl, both `-brand-short-name` and `-brand-full-name` should + # differ between releases. As such, they have additional entries in the + # translations repository file (Weblate): + # -brand-short-name for the stable release. + # -brand-short-name_alpha for the alpha release. + # -brand-short-name_nightly for the nightly release. + # And similarly for -brand-full-name. + # For the final build, we only want to keep the string that matches the + # built release, and remove its suffix if it has one. So for the stable + # release we want to keep -brand-short-name. For the alpha release we want + # to keep -brand-short-name_alpha instead, and rename it to be + # -brand-short-name. + # + # As such, we parse the brand.ftl file to rename these strings to keep the + # version we want using rename-branding-strings.py. + # + # We do a similar thing with brandShortName and brandFullName in + # brand.properties. + + # Instructions for the script to perform the renames. + brand_ftl_renames='{ + "suffix": "[% c("var/branding_string_suffix") %]", + "ids": ["-brand-short-name", "-brand-full-name"] + }' + brand_properties_renames='{ + "suffix": "[% c("var/branding_string_suffix") %]", + "ids": ["brandShortName", "brandFullName"] + }' + pushd "$rootdir/translation-tor-browser" ln -s ja ja-JP-mac for lang in $supported_locales; do mv $lang/tor-browser.ftl "$l10ncentral/$lang/toolkit/toolkit/global/" - # Branding. Currently all releases use the same branding. + # Branding. l10n_branding_dir="$l10ncentral/$lang/$branding_dir/" mkdir -p "$l10n_branding_dir" - mv $lang/branding/brand.ftl "$l10n_branding_dir" - mv $lang/brand.properties "$l10n_branding_dir" + # Convert the translations repository branding files into files that work + # for this specific build. + python3 rename-branding-strings.py $lang/branding/brand.ftl "$brand_ftl_renames" > "$l10n_branding_dir/brand.ftl" + python3 rename-branding-strings.py $lang/brand.properties "$brand_properties_renames" > "$l10n_branding_dir/brand.properties" done popd
===================================== projects/firefox/config ===================================== @@ -54,6 +54,10 @@ var: rm -Rf "$rezip_tmpdir"
l10n-changesets: '[% exec("git --no-pager show " _ c("git_hash") _ ":browser/locales/l10n-changesets.json", { exec_noco => 1 }) %]' + # The branding_string_suffix for the alpha and nightly should be + # '_alpha' and '_nightly', matching the "suffix" chosen in the + # tor-browser:update-translations.yml file. + branding_string_suffix: '_[% c("var/channel") %]'
steps: src-tarballs: @@ -94,6 +98,12 @@ targets: var: nightly_updates_publish_dir_prefix: basebrowser-
+ release: + var: + # For the stable release, the suffix is empty. + # I.e. we want to select `-brand-short-name` directly. + branding_string_suffix: '' + nightly: git_hash: '[% c("var/project-name") %]-[% c("var/firefox_version") %]-[% c("var/browser_branch") %]' tag_gpg_id: 0 @@ -183,6 +193,8 @@ input_files: - project: binutils name: binutils enable: '[% c("var/linux") && ! c("var/linux-cross") %]' + - filename: rename-branding-strings.py + enable: '[% c("var/has_l10n") && c("var/tor-browser") %]' - filename: fix-info-plist.py enable: '[% c("var/macos") %]' - filename: nsis-uninstall.patch
===================================== projects/firefox/rename-branding-strings.py ===================================== @@ -0,0 +1,96 @@ +import argparse +import json +import re + +arg_parser = argparse.ArgumentParser( + description="Filter a branding file to only include the expected strings" +) +arg_parser.add_argument("file", metavar="<file>", help="branding file to process") +arg_parser.add_argument( + "details", metavar="<details>", help="JSON specification for renaming" +) + +args = arg_parser.parse_args() +details_dict = json.loads(args.details) +# The suffix we want to search for or remove. +# Can be empty if we want to select the IDs that have no suffix. +suffix = details_dict["suffix"] +# The string IDs we want to rename. +rename_ids = details_dict["ids"] + + +def parse_ids(string, pattern): + """ + Extract the IDs found in a string. + + :param string: The string to parse. + :param pattern: The pattern to capture IDs. + + :yields: A tuple containing a chunk of string and whether the chunk + is an ID. + """ + regex = re.compile(pattern, flags=re.MULTILINE + re.ASCII) + while True: + match = regex.search(string) + if not match: + yield string, False + return + + yield string[: match.start("id")], False + yield match.group("id"), True + string = string[match.end("id") :] + + +# We want to parse the file and rename the IDs we are interested in. +# If the ID starts with one of the `rename_ids` but the suffix does +# not match we append an "_UNUSED" suffix to the ID, to keep it in the output +# but functionally unused in the final build. +# Otherwise, if the ID starts with one of the `rename_ids` and the suffix +# matches we will remove the suffix from the ID, so that it is used in the +# final build. +# Everything else found in the file, like entry values, comments and blank +# lines, will be included in the output as it was. +# +# NOTE: This script is constructed to be *independent* of the order in which +# strings are present in the file. Weblate does not guarantee the order of +# translated files to use the same ordering as the original en-US file. +# +# NOTE: This script should work for all locales. In particular, for Fluent files +# it needs to be able to handle Fluent Terms that are multi-valued (conditional) +# and Terms with attributes. Therefore, whilst we could have written a script to +# *remove* unwanted strings, the parsing logic would have been far more complex +# to be able to handle all these cases. Hence why we only parse for the Fluent +# IDs and rename them, which is much simpler. +with open(args.file, "r") as file: + if file.name.endswith(".ftl"): + # A Fluent ID is the identifier for a Message or Term, which always + # starts on a newline, and will be followed by an "=" character. + id_pattern = r"^(?P<id>-?[a-zA-Z][a-zA-Z0-9_-]*) *=" + elif file.name.endswith(".properties"): + # A properties ID can be preceded by whitespace, and can be any + # character other than whitespace, ":" or "=". The first character also + # cannot be "!" or "#" since this starts a comment. Technically the + # Java ".properties" spec allows a ID to include one of these characters + # if it is escaped by a "", but we don't expect or care about such IDs. + # The Java spec also has a limited set of whitespace, which excludes + # "\v", but we do not expect Weblate or any other serialiser to + # insert whitespace beyond "\n", "\r", "\t" or " ". + id_pattern = r"^\s*(?P<id>[^!#:=\s][^:=\s]*)" + else: + raise ValueError(f"Unknown file type {file.name}") + + for part, is_id in parse_ids(file.read(), id_pattern): + if is_id: + for string_id in rename_ids: + if part.startswith(string_id): + if part == string_id + suffix: + # This string matches the suffix, so we want to use its + # value. We adjust the ID to remove the suffix before + # printing. + part = string_id + else: + # Keep this entry in the output, but make it unused by + # appending to the ID. + part += "_UNUSED" + break + print(part, end="")
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/85...