mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-04-22 10:11:13 -03:00
Multiple gettext-extraction proc macro instances can run at the same time due to Rust's compilation model. In the previous implementation, where every instance appended to the same file, this has resulted in corruption of the file. This was reported and discussed in https://github.com/fish-shell/fish-shell/pull/11928#discussion_r2488047964 for the equivalent macro for Fluent message ID extraction. The underlying problem is the same. The best way we have found to avoid such race condition is to write each entry to a new file, and concatenate them together before using them. It's not a beautiful approach, but it should be fairly robust and portable. Closes #12125
155 lines
5.6 KiB
Fish
Executable File
155 lines
5.6 KiB
Fish
Executable File
#!/usr/bin/env fish
|
|
|
|
# Updates the files used for gettext translations.
|
|
# By default, the whole xgettext + msgmerge pipeline runs,
|
|
# which extracts the messages from the source files into $template_file,
|
|
# and updates the PO files for each language from that.
|
|
#
|
|
# Use cases:
|
|
# For developers:
|
|
# - Run with no args to update all PO files after making changes to Rust/fish sources.
|
|
# For translators:
|
|
# - Specify the language you want to work on as an argument, which must be a file in the po/
|
|
# directory. You can specify a language which does not have translations yet by specifying the
|
|
# name of a file which does not yet exist. Make sure to follow the naming convention.
|
|
# For testing:
|
|
# - Specify `--dry-run` to see if any updates to the PO files would by applied by this script.
|
|
# If this flag is specified, the script will exit with an error if there are outstanding
|
|
# changes, and will display the diff. Do not specify other flags if `--dry-run` is specified.
|
|
#
|
|
# Specify `--use-existing-template=DIR` to prevent running cargo for extracting an up-to-date
|
|
# version of the localized strings. This flag is intended for testing setups which make it
|
|
# inconvenient to run cargo here, but run it in an earlier step to ensure up-to-date values.
|
|
# This argument is passed on to the `fish_xgettext.fish` script and has no other uses.
|
|
# `DIR` must be the path to a gettext template file generated from our compilation process.
|
|
# It can be obtained by running:
|
|
# set -l DIR (mktemp -d)
|
|
# FISH_GETTEXT_EXTRACTION_DIR=$DIR cargo check --features=gettext-extract
|
|
|
|
# The sort utility is locale-sensitive.
|
|
# Ensure that sorting output is consistent by setting LC_ALL here.
|
|
set -gx LC_ALL C.UTF-8
|
|
|
|
set -l build_tools (status dirname)
|
|
set -l po_dir $build_tools/../po
|
|
|
|
set -l extract
|
|
|
|
argparse dry-run use-existing-template= -- $argv
|
|
or exit $status
|
|
|
|
if test -z $argv[1]
|
|
# Update everything if not specified otherwise.
|
|
set -g po_files $po_dir/*.po
|
|
else
|
|
set -l po_dir_id (stat --format='%d:%i' -- $po_dir)
|
|
for arg in $argv
|
|
set -l arg_dir_id (stat --format='%d:%i' -- (dirname $arg) 2>/dev/null)
|
|
if test $po_dir_id != "$arg_dir_id"
|
|
echo "Argument $arg is not a file in the directory $(realpath $po_dir)."
|
|
echo "Non-option arguments must specify paths to files in this directory."
|
|
echo ""
|
|
echo "If you want to add a new language to the translations not the following:"
|
|
echo "The filename must identify a language, with a two letter ISO 639-1 language code of the target language (e.g. 'pt' for Portuguese), and use the file extension '.po'."
|
|
echo "Optionally, you can specify a regional variant (e.g. 'pt_BR')."
|
|
echo "So valid filenames are of the shape 'll.po' or 'll_CC.po'."
|
|
exit 1
|
|
end
|
|
if not basename $arg | grep -qE '^[a-z]{2,3}(_[A-Z]{2})?\.po$'
|
|
echo "Filename does not match the expected format ('ll.po' or 'll_CC.po')."
|
|
exit 1
|
|
end
|
|
end
|
|
set -g po_files $argv
|
|
end
|
|
|
|
set -g template_file (mktemp)
|
|
# Protect from externally set $tmpdir leaking into this script.
|
|
set -g tmpdir
|
|
|
|
function cleanup_exit
|
|
set -l exit_status $status
|
|
|
|
rm $template_file
|
|
|
|
if set -g --query tmpdir[1]
|
|
rm -r $tmpdir
|
|
end
|
|
|
|
exit $exit_status
|
|
end
|
|
|
|
if set -l --query extract
|
|
set -l xgettext_args
|
|
if set -l --query _flag_use_existing_template
|
|
set xgettext_args --use-existing-template=$_flag_use_existing_template
|
|
end
|
|
$build_tools/fish_xgettext.fish $xgettext_args >$template_file
|
|
or cleanup_exit
|
|
end
|
|
|
|
if set -l --query _flag_dry_run
|
|
# On a dry run, we do not modify po/ but write to a temporary directory instead and check if
|
|
# there is a difference between po/ and the tmpdir after re-generating the PO files.
|
|
set -g tmpdir (mktemp -d)
|
|
|
|
# Ensure tmpdir has the same initial state as the po dir.
|
|
cp -r $po_dir/* $tmpdir
|
|
end
|
|
|
|
# This is used to identify lines which should be set here via $header_lines.
|
|
# Make sure that this prefix does not appear elsewhere in the file and only contains characters
|
|
# without special meaning in a sed pattern.
|
|
set -g header_prefix "# fish-note-sections: "
|
|
|
|
function print_header
|
|
set -l header_lines \
|
|
"Translations are divided into sections, each starting with a fish-section-* pseudo-message." \
|
|
"The first few sections are more important." \
|
|
"Ignore the tier3 sections unless you have a lot of time."
|
|
for line in $header_lines
|
|
printf '%s%s\n' $header_prefix $line
|
|
end
|
|
end
|
|
|
|
function merge_po_files --argument-names template_file po_file
|
|
msgmerge --no-wrap --update --no-fuzzy-matching --backup=none --quiet \
|
|
$po_file $template_file
|
|
or cleanup_exit
|
|
set -l new_po_file (mktemp) # TODO Remove on failure.
|
|
# Remove obsolete messages instead of keeping them as #~ entries.
|
|
and msgattrib --no-wrap --no-obsolete -o $new_po_file $po_file
|
|
or cleanup_exit
|
|
|
|
begin
|
|
print_header
|
|
# Paste PO file without old header lines.
|
|
sed '/^'$header_prefix'/d' $new_po_file
|
|
end >$po_file
|
|
rm $new_po_file
|
|
end
|
|
|
|
for po_file in $po_files
|
|
if set --query tmpdir[1]
|
|
set po_file $tmpdir/(basename $po_file)
|
|
end
|
|
if test -e $po_file
|
|
merge_po_files $template_file $po_file
|
|
else
|
|
begin
|
|
print_header
|
|
cat $template_file
|
|
end >$po_file
|
|
end
|
|
end
|
|
|
|
if set -g --query tmpdir[1]
|
|
diff -ur $po_dir $tmpdir
|
|
or begin
|
|
echo ERROR: translations in ./po/ are stale. Try running build_tools/update_translations.fish
|
|
cleanup_exit
|
|
end
|
|
end
|
|
|
|
cleanup_exit
|