mathieumaingret / drup_csv2po
Generates the PO files of a module or a theme from a CSV translation file.
Package info
github.com/mathieumaingret/drup_csv2po
Type:drupal-module
pkg:composer/mathieumaingret/drup_csv2po
Requires
- php: ^8.1
- gettext/gettext: ^5.7
- league/csv: ^9.14
This package is auto-updated.
Last update: 2026-07-28 08:48:18 UTC
README
Generates the PO files of a module or a theme from a CSV translation file, typically a Google Sheet exported as CSV. One PO file is written per language column found in the CSV.
Requirements
- Drush
- The
languageandlocalecore modules, both declared as dependencies.
Setup
-
Tell Drupal where the translation files of the module or theme live, in its own
.info.yml:'interface translation project': my_module 'interface translation server pattern': modules/custom/my_module/translations/%project.%language.po
-
At
/admin/config/regional/translate/settings, set Translation source overwrite to All. -
Declare the CSV URL in
settings.php:$settings['drup_csv2po']['csv_remote_url'] = 'https://docs.google.com/spreadsheets/d/[ID]/gviz/tq?tqx=out:csv'; $settings['drup_csv2po']['extension_name'] = 'my_module';
Usage
drush csv2po
The command downloads the CSV, writes one PO file per language next to it, and
points you to /admin/reports/translations to import them.
Which extension is translated
extension_name is looked up in the modules first, then in the themes. Without
a value, the site's default theme is used. A name matching neither is rejected.
# A theme. drush csv2po --extension_name=backend # A module. drush csv2po --extension_name=my_module # Overriding the CSV URL for one run. drush csv2po --csv_remote_url='https://docs.google.com/spreadsheets/d/XXX/gviz/tq?tqx=out:csv'
Options
Every option can be set in settings.php under $settings['drup_csv2po'], or
passed to the command. The command line wins over settings.php, which wins
over the defaults.
| Option | Default | Description |
|---|---|---|
extension_name |
the default theme | Machine name of the module or theme to translate. |
extension_translations_directory |
translations |
Directory, inside the extension, the files are written to. |
csv_remote_url |
none | URL the CSV is downloaded from. Required. |
csv_output_filename |
translations.csv |
Name the downloaded CSV is saved under. |
plural_value_separator |
PHP_EOL |
Separator between the singular and the plural value of a cell. |
check_enabled_languages |
TRUE |
Only generate files for languages enabled on the site. |
translations_source_langcode |
en |
Langcode of the column strings are translated from. |
The canonical list is ConverterOptions::DEFAULTS.
CSV format
Column names are matched case insensitively.
| Column | Required | Description |
|---|---|---|
PAGE |
yes | Grouping label. A comment banner is written whenever it changes. May be left empty on a row. |
CONTEXT |
yes | Translation context. May be left empty on a row. |
PLURAL |
yes | When filled, the source and translation cells hold a singular and a plural value, separated by plural_value_separator. |
| source langcode | yes | The strings to translate. EN unless translations_source_langcode says otherwise. |
[LANGCODE] |
— | One column per translation, named after the langcode. |
A row is skipped when its source or its translation is empty, so a language column can be filled progressively.
Example
"PAGE","CONTEXT","PLURAL","EN","FR","DE" "FAQ","","","Frequently asked questions","Questions fréquentes","Häufig gestellte Fragen" "FAQ","","","Search by keywords","Rechercher par mots-clés","Nach Stichwörtern suchen" "SEARCH","","1","@count result @count results","@count résultat @count résultats","@count Ergebnis @count Ergebnisse"
Safeguards
- A CSV missing a required column aborts the run, naming the columns.
- A language whose column holds no translation at all leaves its PO file untouched, so an emptied column cannot wipe the translations of a site.
- Two rows sharing a context and a source string are reported: the last one wins.
- A malformed plural value is imported as a singular translation, with a warning.