9.8 KiB
L10n / I18N Improvements
- Status: accepted
- Deciders: Lauren Zugai, Dan Schomburg, Barry Chen, Vijay Budhram, Wil Clouser
- Date: 2022-09-22
Technical Story
This document was a RFC from 2022-07-09 to 2022-09-19 and contains Jira links, more information, and more context.
Context and Problem Statement
As Firefox Accounts has migrated from gettext to Fluent over the last 2-3 years, several questions around l10n, including infrastructure, package inconsistencies, and general improvements have surfaced.
While discussions occurred in the linked document above, this ADR captures major decisions from that doc, mentions other relevant past decisions, and only lists pros/cons, or negative consequences, of new decisions that have reasonable alternatives.
Note that most decisions cover Fluent packages - fxa-settings
, fxa-payments-server
, fxa-react
, and fxa-auth-server
. As noted in the RFC, fxa-content-server
still uses gettext and will share our Fluent infrastructure when we refactor it to React in 2023.
Decision Drivers
- Consistency across packages
- Reliability
- More robust and complete testing
- Allowing
fxa-react
to manage its own l10n - More straightforward l10n in emails
Decision outcome 1: Use consistent FTL paths, names, and setup across packages
en-US
was FxA's default locale until early 2021 when the l10n team recommended we switch to en
. fxa-settings
still contains en-US.ftl
files that will be updated to en.ftl
.
Historically, we did not deploy our en
or en-US
Fluent bundles, but we have since May 2022 to support any missing fallback text and for consistency across locales and environments.
fxa-payments-server
setup changes
fxa-payments-server
commits a single file to public/locales/en-US/main.ftl
which is copied to the l10n repo. This differs from fxa-settings
and fxa-auth-server
, wherein we separate FTL files per component and then concatenate the files together to copy into the l10n repo.
For consistency, better maintainability, and because we need to set up concatenation anyway (see the fxa-react
decision), we'll split fxa-payments-server
's FTL file into per-component en.ftl
files. This will require setting up something similar to fxa-auth-server
's merge-ftl-test
script for test, and we can make sure those reference the same relative path. We can also rename main.ftl
to become payments.ftl
.
Negative consequences
Keeping strings in a single file that doesn't need an additional build step for testing or pushing to the l10n repo means the final output could feel more clear since a single committed file would reflect exactly what's going out.
Fluent configuration files
Fluent configuration files are useful when the same repository needs to support different locales for different files or when there are complex paths involved, but because FxA manages its translations in a separate repository, it won't benefit. We'll remove fxa-payments-server
's config file.
Decision outcome 2: continue using fallback text and set up better testing strategies
In theory, Fluent should always insert translated strings found in its bundles for us, including English strings. Because of this, we considered dropping our fallback text in favor of relying on Fluent.
Pros of dropping fallback text
- Better maintainability and guarantee of consistency due to not needing duplicate strings (one for fallback text and one in an FTL file), in the codebase
- It might feel more i18n-friendly to depend on Fluent instead of prioritizing English speaking users by explicitly setting English fallback text
Cons of dropping fallback text
- String extraction timing considerations; there is currently a delay between when FxA lands PRs and when we can reference the latest compiled FTL files, including
en
@fluent/react
docs actually recommend fallback text and state that in the future, it may be used for automatic extraction of source copy- We ran a small test (see technical story doc) that showed at least on rare occasions, Fluent may fail to retrieve strings or the browser can't always load the Fluent bundle files after loading the page successfully, wherein fallback text is displayed
- It would take at least two searches to find where a string should ultimately end up in a component, e.g. finding the corresponding FTL ID then searching for it
Solutions
One of the primary concerns around using fallback text is maintainability and consistency guarantee. We should be testing:
- All provided FTL IDs exist in the source-of-truth
en
bundle - Fallback text matches the message tied to the ID in the
en.ftl
bundle, and validate that variables referenced in the message string are available - The message doesn’t contain straight quotes (nice to have)
React-based packages
We will create two wrappers, one for Localized
and one for l10n.getString()
, to enforce fallback text is always provided, set up a merge:ftl-test
script for when tests run, and mock the wrappers to test what's outlined above.
fxa-auth-server
We will create a helper function to send into our templates to more easily grab messages from Fluent bundles for things like alt text that otherwise require additional complexities due to our MJML and @fluent/dom
set up. We can also automatically apply data-l10n-args
.
We test our email templates in an enormous, single test file of email strings. We will adjust our email test set up and separate these out per component for better maintainability and easier testing.
Decision outcome 3: concat fxa-react
FTL files to other packages, use a global branding file
When we use components from fxa-react
in another package, we have to add the FTL ID and string into the package using the component rather than in fxa-react
. This can be easily forgotten or lead to duplication of IDs/messages across our packages.
Instead, we can concat files from fxa-react
into the existing Fluent bundles. Additionally, to help with consistency and maintainability across the board, we'll create a "global" FTL file with our license and branding to be shared across our packages to be used first to build our bundles.
Other considered options
We could create a new bundle for fxa-react
similar to other packages. However, we'd need to ship the outputted file with our other packages which would create another network request and more importantly we'd have to reconfigure our Fluent set up to check for translations in two different bundles.
Decision outcome 4: Clone fxa-content-server-l10n
once, instead of per-package
We currently clone the l10n repo into each package via a clone-l10n.sh
script at the postinstall
step.
Instead of every package cloning the repo, we should have our script pull the repo into a central location so each package can skip that script, and then update build steps per package accordingly. We know this script works and can tweak it to our needs, and it doesn't require any management from engineers when new strings land.
While subtrees may be a good option, we would need to heavily modify and still maintain a script introducing a new-to-FxA git concept.
Other considered options
Use a git submodule
Git submodules are essentially gitlinks with a reference to a commit. Locally, the link looks no different than a clone (e.g. you can see and poke around fxa-content-server-l10n
within packages), but git tracks it as a reference to that commit and uses a .gitmodules
config file.
Pros
- We could ditch our
clone-l10n.sh
script in favor of a native git feature - Can make pushing to the l10n repo easier (which is not a feature we would use often) if
submodule
commands are known - Submodules can be useful for switching between different states for comparison
Neutral
- We'll need to maintain the
.gitmodules
configuration file
Cons
- All engineers will need to run
git submodule init
once - While engineers won't have to know much, submodules are one more thing to read about and understand and will be more visible, vs our clone script that is essentially hidden from developers
- While we could add a
git submodule update --remote
call at the build and postinstall step to fetch latest, we would still have to commit an update to the FxA repo to update gitlink commit SHA. At least one Mozilla project does this with a bot. - We may need to tweak our build steps and CI set up
Use a git subtree
A git subtree is a replica or a copy of a git repository and creates a relationship between it and its parent repository (FxA).
Pros
- Similar to our existing setup and unlike submodules, complexity is hidden from engineers
- We may be able to remove copying directories from build steps in our packages in favor of using
git-subtrees-split
andgit-subtree-merge
Cons
- While a subtree wouldn't add a new metadata file like a git module would, we would need to modify or create a new version of our
clone-l10n.sh
script togit subtree add
the tree(s) alongside other checks. Updating asubtree
requires the commandgit subtree pull
and since we want to.gitignore
the output and have this update onpostinstall
, we may need to always run an additional command to first remove the subtree so we can useadd
every time, or have some extra checks to see ifpull
oradd
should be used. - While engineers won't have to know much, subtrees are one more thing to read about and understand
Links
- Original RFC that was created before this ADR