-
Notifications
You must be signed in to change notification settings - Fork 3
[Tooling] Add localization automation #765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
6c68054
to
b15d9ee
Compare
{ glotpress: 'sv', project: 'sv' }, | ||
{ glotpress: 'tr', project: 'tr-TR' }, | ||
{ glotpress: 'zh-cn', project: 'zh-CN' }, | ||
{ glotpress: 'zh-tw', project: 'zh-TW' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is shorter than I thought it'd be. The translations in this library should be a combination of the locales supported in the iOS and Android apps. Here is the list that I gathered a while ago:
ar
az
bg
cs
cy
da
de
el
en-AU
en-CA
en-GB
en-US
es
es-CL
es-CO
es-MX
es-VE
eu
fr
fr-CA
gd
gl
he
hi
hr
hu
id
is
it
ja
kmr
ko
lv
mk
ms
nb
nl
pl
pt
pt-BR
ro
ru
sk
sq
sr
sv
th
tr-TR
uz
vi
zh-CN
zh-HK
zh-TW
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the list of supported locales on 51af12c (for the record, I also had to add fr-CA
in GlotPress). Thanks @crazytonyli!
Thanks for working on this! The result looks great! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Left a couple of nitpicks but just mostly form and code adjustments, nothing major.
Approving to unblock (though reminder not to merge this until the fluent-tools
gem is finalized and published as a tagged version so we can point to it instead of the branch)
gem 'fastlane-plugin-wpmreleasetoolkit', '~> 13.2' | ||
gem 'fluent-tools', '~> 0.1', git: 'https://github.com/Automattic/fluent-rust-tools.git', branch: 'iangmaia/ruby-gem-support' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎗️ As you mentioned in the PR description, reminder to update this once the gem is published before merging this PR
wp_localization/glotpress/en-US.pot
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💄 I wonder if it would be worth adding a README.md
in that wp_localization/glotpress/
folder, even a very simple one, to explain what it's for?
### What is this folder?
We use GlotPress as a platform/service to have translators translate our strings from English to other languages.
But GlotPress does not support Rust's Fluent `.ftl` format as an input/output file format.
To circumvent that, during the localization automation process, we convert the `localization/en-US/main.ftl` file to the PO format in `glopress/en-US.pot` so that a cron job can then later pick up that `.pot` file[^1] and upload it to GlotPress and send it to translators. This transformation is handled by `bundle exec fastlane generate_source_po_file`.
Later we then download the translations from GlotPress (which are exported in the `.po` format), then regenerate the `localization/*/main.ftl` files for each language based on those downloaded translated `.po` files. This is handled by `bundle exec fastlane download_translations`
[^1]: Note that we have to commit the `glotpress/en-US.pot` file here because that file is picked up by a cron job in our systems on a regular basis (as opposed to the `.pot` being sent via API on demand), given how those imports are integrated in the company's larger localization system (with import logs and packages and pings sent to translators etc. that a simple API upload to GlotPress wouldn't cover otherwise)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, thanks!
I've added it to the sync job PR as it refers to the automated stuff, but I tried to add the process and lanes description to the README as well: d69ebf3
fastlane/Fastfile
Outdated
# Converts a PO file for a given locale back to Fluent format | ||
# | ||
# This lane takes a PO file and converts it to the corresponding Fluent format file. | ||
# The locale is extracted from the PO filename (e.g., 'fr-FR.po' becomes 'fr-FR'). | ||
# The resulting Fluent file is saved in the appropriate locale directory. | ||
# | ||
# @param file_path [String] The PO file path to convert (e.g., 'path/to/fr-FR.po') | ||
# @return [String] The path to the generated Fluent file | ||
# | ||
lane :generate_fluent_file_from_po do |file_path:| | ||
locale = File.basename(file_path, '.po') | ||
fluent_file_path = File.join(LOCALIZATION_FLUENT_FILES_DIR, locale, MAIN_FLUENT_FILE_NAME) | ||
|
||
UI.user_error!("❌ PO file not found: #{file_path}") unless File.exist?(file_path) | ||
|
||
FileUtils.mkdir_p(File.dirname(fluent_file_path)) | ||
|
||
FluentTools.po_to_fluent( | ||
file_path, | ||
fluent_file_path | ||
) | ||
|
||
next if !File.exist?(fluent_file_path) || File.empty?(fluent_file_path) | ||
|
||
UI.message("✅ #{File.basename(file_path)} → #{fluent_file_path}") | ||
|
||
fluent_file_path | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💄 / 💡 Opinionated: I'd find it easier to read if that whole helper lane was moved to after the download_translations
and download_po_files_from_glotpress
lanes in the Fastfile
.
This simple move would allow the reader of the Fastfile
to better understand that generate_source_po_file
and download_translations
lanes, that would then appear first, are the main lanes one is supposed to call, while download_po_files_from_glotpress
and generate_fluent_file_from_po
are helper lanes called by the one above it.
This also helps organizing the lanes in the Fastfile
by the order in which they'd typically be called by the automation, with download_translations
calling download_po_files_from_glotpress
first then generate_fluent_file_from_po
next on (each locale).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed! Updated in 1d98854
fastlane/Fastfile
Outdated
locale = File.basename(file_path, '.po') | ||
fluent_file_path = File.join(LOCALIZATION_FLUENT_FILES_DIR, locale, MAIN_FLUENT_FILE_NAME) | ||
|
||
UI.user_error!("❌ PO file not found: #{file_path}") unless File.exist?(file_path) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💄 Might make more sense to do the guard statement earlier, since it's checking the input param?
locale = File.basename(file_path, '.po') | |
fluent_file_path = File.join(LOCALIZATION_FLUENT_FILES_DIR, locale, MAIN_FLUENT_FILE_NAME) | |
UI.user_error!("❌ PO file not found: #{file_path}") unless File.exist?(file_path) | |
UI.user_error!("❌ PO file not found: #{file_path}") unless File.exist?(file_path) | |
locale = File.basename(file_path, '.po') | |
fluent_file_path = File.join(LOCALIZATION_FLUENT_FILES_DIR, locale, MAIN_FLUENT_FILE_NAME) | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Updated on 98947d6
fastlane/Fastfile
Outdated
updated_fluent_files = [] | ||
|
||
# Convert PO files back to Fluent format | ||
if downloaded_files.any? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💄 I'd suggest to instead use a guard statement to reduce indentation and exit early:
if downloaded_files.empty?
UI.message("No .po files were downloaded from GlotPress")
next
end
UI.header('🔄 Converting PO files to Fluent format')
# … and the rest of the code, without the need for the extra indentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Updated in 55c1118
Dir.mktmpdir do |temp_download_dir| | ||
downloaded_files = download_po_files_from_glotpress(download_dir: temp_download_dir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️ Nice touch using a temp dir for the download and processing here, will not only prevent any intermediate file from being in the repo (even if we could have gitignored them) and also prevent any previous runs and translations downloads from impacting future ones (e.g. a fr.po
file downloaded on first run but not anymore on the 2nd run for any reason, which would lead to the previous fr.po
file to not be replaced and its old content to be used if you were not using a mktmpdir
) 👍
…o downloaded files
h/t to @crazytonyli for highlighting that the supported locales should be a combination of the locales supported in the iOS and Android apps #765 (comment)
…the latest version
Related: AINFRA-765: Integrate new Fluent conversion tool into wordpress-rs
Note: The
fluent-tools
Gem used in the PR is currently using the Gem directly from the branch Add Ruby Gem wrapper / CLI interface and CI setup. 🎗️ We need to update it once the Rust tool is fully merged.This PR supersedes #756.
What does it do?
This PR integrates the new Fluent conversion tool Gem into
wordpress-rs
to enable a complete translation workflow between the project's Fluent localization files (.ftl) and GlotPress, allowing for:New lanes
generate_source_po_file
lane - Convertsen-US/main.ftl
toen-US.pot
for GlotPress uploaddownload_translations
lane - Downloads all available translations from GlotPress following the supported locales list and updates local Fluent filesgenerate_fluent_file_from_po
lane - Converts individual PO files back to Fluent formatdownload_po_files_from_glotpress
lane - Downloads PO files for all supported localesProposed localization workflow
A day-to-day workflow can look like this:
wp_localization/localization/en-US/main.ftl
.trunk
or a daily scheduled build), we rungenerate_source_po_file
and commit the updatedwp_localization/glotpress/en-US.pot
.wpcom
job uploads the updateden-US
source file to GlotPress (see 184627-ghe-Automattic/wpcom )download_translations
.Update: The PR #770 integrates the automation using the Nightly schedule as the trigger mentioned above.