Skip to content

Instantly share code, notes, and snippets.

@ku-enza
Last active June 2, 2025 05:36
Show Gist options
  • Select an option

  • Save ku-enza/50fbfc73a7510bc2ff86adeb761bdf42 to your computer and use it in GitHub Desktop.

Select an option

Save ku-enza/50fbfc73a7510bc2ff86adeb761bdf42 to your computer and use it in GitHub Desktop.
Shell script to extract t() function translations in drupal custom module and generate .pot file
#!/bin/bash
# Shell script to extract $this->t() function translations in drupal 8+ custom module and generate .pot file
# Extract from .php .module .js .twig from current custom module folder
# Exclude .min.js for js libraries
# Put this in your module folder, make it executable : chmod +x generate_pot.sh , run it
# Feel free to improve it
# Define the regex patterns for each file type
php_t_regex="\$this->t\(\s*'([^']*(?:@[a-zA-Z0-9_]+[^']*)*)'\s*(?:,\s*\[[^\]]*\])?\s*\)"
twig_t_regex="{{\s*['\"]([^'\"]*(?:@[a-zA-Z0-9_]+[^'\"]*)*)['\"]\s*\|?\s*t\s*(?:\(\s*\{(?:[^\}]*)\}\s*\)|\(\s*\{[^\}]*\}?\s*\))?(?:\.\s*t\(\s*\{(?:[^\}]*)\}\s*\))?\s*}}"
twig_trans_regex="{{\s*['\"]([^'\"]*)['\"]\s*\|\s*trans\s*}}|{%\s*trans\s*%}\s*((?:(?!{%\s*endtrans\s*%}).)*)\s*{%\s*endtrans\s*%}|{%\s*trans\s*%}\s*((?:(?!{%\s*plural\s*[^%]*%\s*).)*)\s*{%\s*plural\s*([^%]*)%\s*}\s*((?:(?!{%\s*endtrans\s*%}).)*)\s*{%\s*endtrans\s*%}"
js_regex="Drupal\.t\(\s*['\"](.+?)['\"]\s*\)"
js_regex_a="Drupal\.t\(\s*['\"](.+?)['\"],\s*{\s*['\"]@[^'\"]*['\"]:\s*[^,}]*[,\s}]"
js_regex_p="Drupal\.formatPlural\(\s*[^,]*\s*,\s*['\"](.+?)['\"]\s*,\s*['\"](.+?)['\"]\s*\)"
# Initialize the .pot file
output_file="translations.pot"
# Function to list all files used to extract translations
function list_files() {
file_type=$1
name_pattern=$2
find . -type f -name "$name_pattern" -print0 | sort -z | xargs -0 -I {} echo "# {}"
}
# Get the custom module name from the .info.yml file
module_name=$(grep -oP "name:\s*\K[^\n]+" *.info.yml | tr '[:lower:]' '[:upper:]' | tr ' ' '_' | sed 's/_$//')
# Get the current date and time
current_date=$(date +"%Y-%m-%d %H:%M%z")
# Write the header to the .pot file
{
echo "# \$Id$"
echo "#"
echo "# LANGUAGE translation of Drupal 9 module"
echo "# Copyright YEAR NAME <EMAIL@ADDRESS>"
echo "# Generated from files:"
list_files "php" "*.php"
list_files "php" "*.module"
list_files "twig" "*.twig"
list_files "js" "*.js" "! -name *.min.js"
echo
echo "# xx translation of $module_name"
echo
echo "\"Project-Id-Version: $module_name v1\\n\""
echo "\"POT-Creation-Date: $current_date\\n\""
echo "\"PO-Revision-Date: $current_date\\n\""
echo "\"Last-Translator: NAME <EMAIL@ADDRESS>\\n\""
echo "\"Language-Team: LANGUAGE <EMAIL@ADDRESS>\\n\""
echo "\"MIME-Version: 1.0\\n\""
echo "\"Content-Type: text/plain; charset=utf-8\\n\""
echo "\"Content-Transfer-Encoding: 8bit\\n\""
echo "\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\""
echo "\"X-Generator: Custom script v.01\\n\""
echo
echo "msgid \"\""
echo "msgstr \"\""
echo
} > "$output_file"
# Helper function to extract the strings and append them to the .pot file
function extract_strings() {
file_type=$1
regex=$2
name_pattern=$3
find . -type f -name "$name_pattern" ! -name "*.min.js" -print0 | while IFS= read -r -d '' file; do
matches=$(perl -ne "print \"\$1\n\" while (/$regex/g);" "$file" | sort -u)
if [ -n "$matches" ]; then
echo -e "# ${file}\n# $(printf '%0.s-' $(seq 1 ${#file}))\n" >> "$output_file"
echo "$matches" | while read -r match; do
echo -e "msgid \"$match\"\nmsgstr \"\"\n" >> "$output_file"
done
fi
done
}
# Helper function to remove duplicate msgid entries
function remove_duplicates() {
awk '
/^msgid/ {
if (!msgid[$0]++)
print
else
getline; getline
}
/^msgstr/ { print }
!/^(msgid|msgstr)/ { print }
' "$output_file" > "$output_file.tmp" && mv "$output_file.tmp" "$output_file"
}
# Extract strings from each file type
extract_strings "php" "$php_t_regex" "*.php"
extract_strings "php" "$php_t_regex" "*.module"
extract_strings "twig" "$twig_t_regex" "*.twig"
#extract_strings "twig" "$twig_trans_regex" "*.twig"
extract_strings "js" "$js_regex" "*.js"
#extract_strings "js" "$js_regex_a" "*.js"
#extract_strings "js" "$js_regex_p" "*.js"
# Remove duplicate lines except for those that start with 'msgstr ""', except empty lines \n and line starting with #
remove_duplicates
# Remove double empty lines
sed -i '/^$/N;/^\n$/D' "$output_file"
@ku-enza
Copy link
Author

ku-enza commented Apr 25, 2023

Updated regex and extract_strings() function

@ku-enza
Copy link
Author

ku-enza commented Apr 25, 2023

Manage duplicate entry of the final result

@ku-enza
Copy link
Author

ku-enza commented Apr 26, 2023

change first msgid msgstr position

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment