The 7 Cardinal Sins of Localizing WordPress Plugins and Themes

There’s a lot of awesome things going on in the WordPress land. This CMS is just a brilliant ecosystem and more and more devs jumping on the bandwagon. Still, there are basic things – call them standard – which aren’t addressed with the attention they’d actually need. And there’s this need, definitely. Read on, about some nightmares I’ve seen within WordPress code broken down to seven cardinal sins regarding the localizing/internationalization of WordPress plugins and themes.


1.) Not Localizing At All

You got it. This is the biggest sin at all. In the last months I’ve seen SO MANY themes and plugins – including from big premium theme/plugin shops – that were not translateable at all. Or even if they’ve tried to implement localizing they’ve failed at it big time. Yes, I speak of some of the so-called premium elite of WordPress developers. It’s surprising but it’s a reality.

Localizing your plugin or theme is NOT an option. It is a decision BEFORE you even begin to write the first line of code. Not thinking about the majority of your future users will also effect your future sales. The majority of all WordPress users worldwide does NOT speak any English. No matter if they use self-hosted or hosted taste of WP.

Don’t do international users „a little benefit“, just make your coded work useful at all for them. You can come up with the greatest feature set, the most awesome design or an impressive UI. As long as your product cannot be translated it’s not half worth it!

Implementing of Gettext is not a WordPress thing at all. Gettext is a PHP feature/function and you should use it. It belongs to proper coding standards. So, learning this little Gettext syntax should be a developer standard not an add-on.

Having all strings in your own language is not an option, it’s part of the natural user experience from the beginning. Come on, just do it.


2.) No Loading of The Textdomain

Oh, this is a big one. Biggest error – should I say fail? – I’ve seen so far! This function has to be loaded at all AND at first, before anything else. Reason? Strings will effect anything also your error messages and other user notifications. If you load the translated strings somewhere in the middle it’s almost sure your users will miss something important before!

The proper WordPress functions for loading the textdomains are:

For Plugins:


For Themes/ Parent Themes/ Frameworks:


For Child Themes:


These go just after the plugin’s header info or in your theme’s functions.php just as the first function. Period.

Just implement these with the correct parameters. Yes, it’s that easy.
And please create a folder for the translations by default. Most popular use is /languages/ in the first level hierarchy of your plugin or theme folder. Please create it even if it’s empty at first. If this folder is there users later can add their language packs here and all gets loaded out of the box. This way you’ll make your users happy once again.


3.) No Textdomain Attached to the Gettext Strings

Another frustrating one: they’ve implemented the loading call for the textdomain, they did Gettext strings but no textdomain in the end. Maybe because WordPress itself has no textdomain attached? Don’t know yet.

WordPress itself knows its stuff and gets it loaded. In this post here, I am speaking of plugins and themes which are add-ons for WordPress and therefore need some other handling so WordPress can determine a difference from its core files/strings.

So, please, please, please add ONE UNIQUE textdomain to ALL your strings. It’s no magic. So if your plugin’s folder path name is foo-test-plugin and it’s proper Name is "Foo Test Plugin" and it has 587 strings to translate your textdomain will most definitely be named 'foo-test-plugin' and all in all we will have 587 appearances of this domain – at each and every string. No exception.


4.) Using A Constant As Textdomain

Some developers think they’re the most clever WP devs out there. Nah, they aren’t. Using of constants in many cases leads to NON-displayed translated strings because they implemented it all the wrong way. To me as a translator and user it just seems they wanted to re-implement the whole loading functions WordPress itself just provides as API/ functions for the developers. WordPress core provides all you need, just USE it as it will make your work easy and gets proper results for your end users.

Don’t re-implement things here and there WordPress has already APIs for! Don’t get too clever, just don’t use any constants for localizing things, use a proper textdomain which itself is a regular string. And, it all goes in single quotes.

The wrong example seen so often:

__( 'Foo text', TOO_CLEVER_DEV_CONSTANT );

The right way – use that:

__( 'Foo text', 'foo-test-plugin' );

This is such a little „mistake“ a lot of coders make but with huge impact. It’s surprising sometimes people think they have to do more clever than going the REAL clever way and making it easy, simple and beautiful. Code is poetry – at least regarding the localization and textdomains. Constant is no poetry in this case…

FYI, Mark Jaquith, WordPress core developer, has spoken out on the constants issue a lot better than I could do, so, go and read his article too!


5.) Mixing of Double and Single Quotes in Gettext Strings/ Textdomains

This is a bit more special and it is more tricky. Some devs mixing up double and single quotes in Gettext calls. This ist NOT recommended as it can lead to crazy things. I’ve had themes with such implemented strings and widgets got no longer displayed on the frontend because something was blocked. As of my experience, my own coding and testing the using of single quotes in the whole thing is the best practice and would lead to correct results.

The wrong example seen a lot of times:

__( "Foo text", 'foo-test-plugin' );

The right way – use that:

__( 'Foo text', 'foo-test-plugin' );


6.) Not ONE Unique Textdomains but A Lot of Them…

This one is spreaded like a virus already… I’ve seen plugins with seven (yes, 7!) different textdomains. Whoa! This is not poetry in the code, this is waste of time and end users get these not displayed properly in THEIR language. So, just use ONE, and I say only ONE textdomain for all your strings. Please test it!

So why is this really important? In almost all cases the only textdomain that will lead to diplayed results is the defined textdomain in the loading call! So when you load ‘foo-test-plugin’ in your call at the beginning you cannot add a textdomain like ‘clever-test-plugin’ to any of your strings. In most circumstances this particularly string will NOT get displayed in the translated language.

To test and verify that you only have one domain in use just use the awesome plugin „Codestyling Localization“. It has an in-built counter and drop-down menu for choosing which string has which domain. So do yourself a favor, install that plugin in your sandbox install and look at your plugin or theme as a real clever dev – with the international user in mind.

Count all „third-party“ textdomains in your plugin or theme down to ZERO! Do not release anything before this task! You’ll make translators and users even more happy!


7.) Not Localizing ALL Strings

Yeah, it happens to all of us. We tend to forget some things sometimes. So is with localizing strings. No problem, release an update of your work after you’ve added Gettext strings to all remaining contents/texts of your plugin or theme.

I mean each and every word or „syntax“ of your plugin and theme. Make it ALL translateable. To test and verify this just set the locale of your test install to something different than English – most definitely to a language where there’s already a completely translated language file available. Install this language pack and look at your plugin or theme if you still see any English you definitely forgot something to localize. Don’t release your work if not all is translateable. Otherwise you and your translators have to update very often and that is more time consuming in the end than some more testing before.

And did I mention it already, help texts, error messages, notifications and even your promotional info and links about your plugin in the backend – it all should be translateable. Especially properly translated help texts and user guidance is very important for your users as to some of them this will be the only documentation/ help/ info within your work. So if you want YOUR HARD WORK getting used please make it accessable for as many users as you could.

With localizing you might not get the most applause at the beginning. But in the long run you will succeed if you do the heavy lifting right from the start. Correct localizing is getting more and more an important factor to get your premium plugins or themes sold and also for free work to get more users, downloads and even user feedback.

Localizing your stuff is absolutely worth it. Getting in touch with your users and give them the best possible user experience. This is the real clever way and it’s win/win in the end. So just think twice.

Happy localizing :)
Dave, some WordPress translator from Germany

P.S. You can blame me for my bad English of course but these things were on my heart for a long time and had to be pointed out finally.

Please join in with your comments and experiences – happy discussion ;-)

About David Decker

WordPress-Enthusiast und Webworker aus dem Erzgebirge. Ich arbeite seit 2010 mit dem Genesis Framework; u.a. Übersetzer der deutschen Sprachdateien dafür. DECKERWEB betreibe ich seit 2000. Ansonsten liebe ich Wandern, Radfahren, jede Menge großartiger Musik und als Sachse natürlich immer gern einen starken Kaffee ;-) — Folge mir bei Twitter @deckerweb oder bei Facebook oder lese in meinem Blog.

» runs on the Genesis Framework

Genesis Framework

Genesis empowers you to quickly and easily build incredible websites with WordPress. Whether you're a novice or advanced developer, Genesis provides the secure and search-engine-optimized foundation that takes WordPress to places you never thought it could go. It's that simple - start using Genesis now!

Take advantage of the 6 default layout options, comprehensive SEO settings, rock-solid security, flexible theme options, cool custom widgets, custom design hooks, and a huge selection of child themes ("skins") that make your site look the way you want it to. With automatic theme updates and world-class support included, Genesis is the smart choice for your WordPress website or blog.


  1. Excellent post, Dave! Every dev should read this.

    I know that I for one, as you have pointed out a few times ;), am one of those devs that forgets to localize a little too frequently.

    • Thank you, Pippin :-) Much appreciated!

      Yeah, I know you could do it – I’ve already have your ECT plugin translated, nearly complete. So you have some example then :)

      And another reason for writing was I just needed some post to link and/or show some people some time when there are discussions…

  2. Okay, now what about beginners? I don’t even know where to start with localizing.

    • Good question! I already am planning some posts about how to start localizing a plugin or theme. So your question will lead to some great tips and tutorials in the very near future :-) So just stay tuned!

  3. Hi,

    great article.

    But I must add, that the reason for 4) seems to be a bad parser, which does not allow bulk renaming of a textdomain, so no PHP error, but rather a tool mistake.

    To 6):
    This is clearly a tool flaw…

    • Thanx, Jannik!
      To 4) this a good tip thanx for mentioning. When I update my article – or in a follow up post – I’ll add this!

      To 6) This could be but more obviously and based on my experience and conversation with devs it comes from not fully understanding and actually testing the localized files. Most devs seem to do no testing and so cannot imagine where translations load and where not.

      Thanx, Dave :)

  4. I’m always a fan of people posting tutorials on how to properly internationalize the strings in their plugins and themes. But I take a certain kind of offense at people who vilify developers who failed to do so in the first place. So thank you for not painting those developers in a negative light!

    I was called out today for not properly internationalizing one of my more popular plugins. I understand the end users’ frustration, but I want everyone to take a second to look at things from a developers’ perspective, too.

    I built the plugin originally for personal use, but decided to post it in the repo for anyone else to use. The first release had 0 UI, so there was no reason to load a text domain. As time wore on, more and more feature requests began to come in. And end users became more and more impatient with how long it took me to implement the changes.

    It was actually hurting my reputation as a developer to have that kind of negative feedback floating around in public forums, so I slapped a few quick changes on the system to appease my detractors and get a newer version out. But it was a set of quick, “fix my specific issue” changes … not a major overhaul. I fully intended to clean things up, but haven’t had the chance. As a result, I’ve had a stale, un-translatable plugin sitting out there for months. And someone called me on it today.

    There are 3 dimensions to any development project: good, fast, or cheap. Pick two. With free themes/plugins, you’ve already picked “cheap.” So you can either have frequent, quick updates in response to user requests, or you can have everything done right the first time. In my experience, the user community is far too impatient with solo developers and small shops to wait for them to “do it right” the first time.

    So will I go back and internationalize my plugin? Absolutely! But it’s a question of balancing my time – time I spend at my regular paying job, time I spend with my family NOT working, and time I spend maintaining a free system. A lot of other developers are in the same boat. So while I empathize with non-English speaking users of my plugins, I also have to ask them for patience and understanding while I try to keep up.

    • As a free-time maintainer of a free GPL plugin, I certainly would accept a patch that helps with L10n and i18n :) (I work on the Good and Cheap model… I tried Fast and introduced bugs, LOL.)

  5. Thanks David,
    I have been the culprint of No 5 sin.

  6. All good points, and it really is fairly trivial to internationalise* theme and plugin code. I disagree with 4) though – I’ve used both defined constants and calls to static methods in place of the text domain argument, and a tool like PO Edit can detect all of the strings just fine.

    Another sin would be to do all the tasks you’ve mentioned, then not including a .pot file in the languages directory so people can get straight on with translating.

    * Internationali(s|z)ing and locali(s|z)ing are two different things – your post title here is wrong, since all of the sins relate to internationalisation. I18n is the part which makes the strings detectable as being translatable (i.e. writing the code), where as l10n is taking the .pot files and creating the translated strings for .po files usable in their own locale.

  7. I never use the italian localization of WP, they have translated the dasboard and nothing make sense…
    People really need few items localized and always when for end user…..
    We are speaking of free stuff.

  8. You’d be surprised how many developers get it wrong, even down to simple HTML, especially with using quotation. I hope your message is heard by a lot of people. I am still seeing International freelancers using kubrick and alternative means to coding that are not as flexible for their users/clients.

    I have started to touch on and speak at WordCamps based on tweaking your theme, and plugin development, however, I have many more presentations to go through and would like to see more developers cover topics like localization.

    Aside that- I will have to work on my plugins and translate them and I am guilty of not being nice… which is sad considering I speak a couple languages. Most of my clients are primarily English speakers, but I have a theme I am about ready to release as a premium, so definitely a translatable theme, especially for documentation and usage would be important.

  9. Useful article, Dave, thanks for writing it up.

    I’ll take issue with a couple of points, though:

    1. As mentioned by Garyj, your article discussed internationalisation, not localisation. :-)

    2. I don’t agree with your #4 either. Mark Jaquith’s original article hinted that new translation tools are on the horizon which won’t work with textxdomain as a constant. But today, those tools don’t exist, and constants work absolutely fine.

    Finally, don’t be too hard on plugin developers. The situation re I18n in plugins is much better today than it was only a couple of years ago, and the trend is in the right direction. Let’s cheer on developers, not knock them. :-)

  10. I had to read Mark’s comments on constants a couple of times before “getting” his point. What I think is that the repo could one day have a tool that spits out a list of translatable phrases across the entire directory, for a team of translators to work on.

    If we (developers) use constants, those phrases wouldn’t be able to have an association. If we leave ‘my-plugin-name’ as the string in the translation function, it’ll work in bulk like that. Which is pretty cool.

    Now, if you’ll excuse me, I have some constants to replace.

  11. Loved #5 – it happens quite a lot.

  12. Great tips! I’ve been struggling a little with my WordPress account, but now I realize what I’m doing wrong. And I’ll admit, I’m one of those who’s using a constant as my text domain. Now I know better. Thanks a lot for sharing these tips! Really helpful stuff!

  13. Hi there Dave,

    Interesting insights. I didn’t really think about localizing before. Its true that many don’t speak English. I am a self thought Genesis Child Theme developer, How much do you think it would cost to localize a genesis child theme?