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

ku-enza commented Apr 25, 2023

Copy link
Copy Markdown
Author

Updated regex and extract_strings() function

@ku-enza

ku-enza commented Apr 25, 2023

Copy link
Copy Markdown
Author

Manage duplicate entry of the final result

@ku-enza

ku-enza commented Apr 26, 2023

Copy link
Copy Markdown
Author

change first msgid msgstr position

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