If you have been using WordPress for some time, you would eventually come into a scenario where you need to translate a plugin or a theme. WordPress, as well as most PHP-based projects use .po files to translate strings. Manual translation is a tedious job and come on, it is 2026, can’t we just ask Chat GPT or other AI tool to do the job for us? The answer, as usual, is “it depends”. You can surely use Chat GPT, DeepL or Google Translate but if the file consists of thousands of lines, it is still too much work and can be prone to errors. You can also use the Poedit Translation Editor, which is the standard way to translate WordPress themes and plugins but the automatic translation is limited to the first 10,000 characters only. Luckily, there are some alternatives to Poedit to generate locales for different languages that will allow you to use the power of AI to translate the strings completely for free. Lets explore the different options.

Translate .po files for Free using Google Translate API
This approach requires Google Translate API in order to work. To get access, you typically need to register for Google CLoud an obtain an API key. Moreover, you are limited to 500,000 characters per month. However, there is a workaround that lets you create unlimited translations – by using Googletrans, a python script that acts as an unofficial wrapper to the Google Translate API. The advantage of this method is that you don’t need to go through the somewhat tedious registration process in Google Cloud in order to obtain an API key and you are not restricted. The downside is that the API is somewhat unstable, as the software works based on reverse engineering and can be blocked by Google at any time. With that said, I have found it to work reasonably well for its purpose to provide automatic translation in a specific language. Here is what you need to do.
Generate .pot tempate file and .po file for the specific local
First, you need to have .pot file (Portable Object Template) that serves as a language template for the different locales. If you have wp-cli installed on your machine, in the root of your theme folder, you can run:
wp i18n make-pot . languages/languages.pot
If you don’t have wp-cli, you can use a plugin like Loco Translate or Poedit to do that.
If you use Mac or Linux, you can use the gettext toolset to generate the .po file. For Windows, the easiest way is to use Loco Translate, just make sure to save the translations inside the languages theme folder.
msginit --locale=de_DE --input=languages/languages.pot --output-file=languages/de_DE.po
The above code will generate a German locale but you will notice that the strings are not translated yet. The traditional way is to use a web interface like Loco Translate to open the file and to translate all the strings manually (or you can even use any text editor like Gedit (Ubuntu) or Notepad (Windows) but you can also use an AI-powered API to do the tedious job for you. We will use a simple python script to do the job for us.
Create a python script to translate all the strings
First make sure python is installed on your machine, then run
pip install googletrans==4.0.0-rc1 polib==1.2.0 black==23.1.0 tqdm==4.65.0
It is important to use the above versions, as I found that the latest version of Googletrans was not working. Finally, copy the below code and save it under a file in the same folder as the de_DE.po file that we have generated before.
languages/translate.py
import argparse
import polib
from googletrans import Translator
from tqdm import tqdm
import os
# Parse command-line arguments
parser = argparse.ArgumentParser(description="Translate .po files using Google Translate")
parser.add_argument("-f", "--file", required=True, help="Path to the .po file")
parser.add_argument("-l", "--lang", required=True, help="Target language code")
args = parser.parse_args()
po_file = args.file
language = args.lang
# Load the .po file
po = polib.pofile(po_file)
translator = Translator()
# Translate each message
for entry in tqdm(po, desc="Translating messages"):
if not entry.msgstr: # Only translate empty translations
try:
entry.msgstr = translator.translate(entry.msgid, dest=language).text
except Exception as e:
print(f"\nError translating '{entry.msgid}': {e}")
# Save the translated PO file
translated_filename = f"{os.path.splitext(po_file)[0]}_{language}.po"
po.save(translated_filename)
print(f"\nTranslation completed: {translated_filename}")
Finally, run the following command in the terminal. Make sure the translation file and the script are in the same folder:
python translate.py -f de_DE.po -l "de"
In this example, we used German, but you can use any language that is listed here. You can check Po FIle Translator Git repo for more information.
Translate .po files for Free using DeepL API
This is the most reliable way I have found so far to translate PHP projects. The downside is that you need to register on DeepL website and you need to go through an additional registration for the DeepL API that includes user confirmation with a credit card. The good news is they will not charge you unless you decide to upgrade to their Pro plan. However, once you hit the 500,000 characters per month treshold, you will be blocked from using it until you upgrade or wait until it resets.
Again, we will need to generate .po file and create a python script to do the heavy lifting for us. Here is the code that I have used:
pip install polib deepl
languages/translate.py
import argparse
import polib
import deepl
import time
# Parse command-line arguments
parser = argparse.ArgumentParser(description="Translate .po files using DeepL")
parser.add_argument("-f", "--file", required=True, help="Path to the .po file")
parser.add_argument("-l", "--lang", required=True, help="Target language code")
args = parser.parse_args()
po_file = args.file
lang = args.lang.upper() # Convert to uppercase
# DeepL API Key
AUTH_KEY = "your-deepl-api-key-goes-here" # Replace with your actual DeepL API key
translator = deepl.Translator(AUTH_KEY)
# Load the .po file
po = polib.pofile(po_file)
total_entries = len([entry for entry in po if entry.msgid and not entry.msgstr])
translated_count = 0
# Translate entries with progress
for i, entry in enumerate(po):
if entry.msgid and not entry.msgstr: # Only translate empty translations
try:
translation = translator.translate_text(entry.msgid, target_lang=lang)
entry.msgstr = translation.text
translated_count += 1
percent_done = (translated_count / total_entries) * 100
print(f"Progress: {translated_count}/{total_entries} ({percent_done:.2f}%)", end="\r")
time.sleep(0.1) # Optional delay to avoid hitting API limits
except Exception as e:
print(f"\nError translating '{entry.msgid}': {e}")
# Save the translated .po file
translated_file = po_file.replace(".po", f"_translated_{lang}.po")
po.save(translated_file)
print(f"\nTranslation completed: {translated_file}")
Finally, execute the code:
python translate.py -f de_DE.po -l de
The above command will translate the theme to German but you can change the language code to any supported language. My observation is that DeepL did a better job compared to Googletrans. Some of the strings were translated with capital letters for some reason using the Google translate API. Also, some strings failed to translate and some weird spaces have appeared in the middle of dynamic placeholders like %1$s.
Conclusion
While both of the tools are saving time for the translator, a manual editing is still necessary. The good news is it really saves time and empowers the content creator to focus on improving the work rather than wasting time on tedious and boring things that can surely be automated.
Bonus: Submit your language pack to WordPress.org
A little known fact is that you can share your translation with the others by uploading the .po or .mo file to WordPress.org, given the fact that the plugin or theme that you have translated is hosted there. In this way, you will become a contributor and you will help other people. All you need is a profile there, go to the translation page of the theme or the plugin and import the translation from the bottom of the page. Happy translations!


