Woo: You Too Have Woes
How do I put this?
Dear WooThemes: to me, you have become one of the references on how to run a successful business, based solely on WordPress. Not only do you offer fantastic, pixel-perfect themes, but also excellent plugins, most visible of which are WooCommerce and Sensei. I’ve used your themes and plugins a few times in the past, and only have good things to say about the structure, performance and robustness of the code. What’s more, and keeping in mind that code quality alone does not a perfect WordPress business make, you truly make a difference in what you contribute to core, sponsor almost every WordCamp in sight, and, most important of all, provide world class customer support.
The only thing left to do was to translate the theme’s strings to Portuguese. This isn’t a daunting task anymore: by having translated so much of WordPress itself, and also many plugins and themes, my PoEdit installation has accumulated a very large translation memory, which normally takes care of a significant amount of the work.
And so, trouble began…
.pot is not only legal, but actually mandatory
The first surprise is that there is no .pot file — Seriously? What’s with all you people? Is it the file extension that scares you off? Let me, if I may, give you a very quick reminder of language file formats: we have
- .POT file — This file contains the original strings (in English) in your theme (or plugin). POT stands for Portable Object Template; notice that “Template” there? More on that later on…
- .PO file(s) — One per language, they contain the translation of said originals. Did you notice the missing “T”? Good one, it’s because this file isn’t a template anymore, it contains the actual, translated objects now. So, if I want to translate your (sadly inexistent) theme’s .POT file, I’d create a
pt_PT.pofile and translate that (still no “T”, get it?).
- .MO file(s) — Again, one per language. These are machine-readable, binary files that the
gettextfunctions actually use (they don’t care about .POT or .PO files), and are a “compiled” version of the .PO file, discussed before. Again, because (surprisingly) it bears repeating, this is the only file WordPress will read when looking for translations, nothing else.
So the first fix you’d have to implement is to actually supply a proper .POT file with every single theme, named after the theme’s slug, like so:
canvas.pot, in the
lang folder. You can do this by running
makepot.php before every code commit to that theme’s repository, see here how Mike did it. I’m not even going to address the odd presence of a single, lonely
en_GB.po file in the
/lang folder, for fear of finding out exactly which reasoning led to that…
I did run
makepot.php on Canvas, which brings us to the second surprise:
The textdomain parameter is not an arbitrary decision
Why, oh why, do all your themes load the same ‘woothemes’ textdomain? I understand that there is nothing formally wrong with this, but you could run the risk of seeing mixups in loaded translations. Here’s what the Theme Developers Handbook has to say about it:
You need to use a text domain to denote all text belonging to that theme. The text domain is a unique identifier, which makes sure WordPress can distinguish between all loaded translations. This increases portability and plays better with already existing WordPress tools. The text domain must match the slug of the theme. If your theme’s name My Theme is defined in the style.css or it is contained in a folder called my-theme the domain name should be my-theme. The text domain name must use dashes and not underscores.
So, the second fix would be to correct the textdomain on every
gettext call (those
_e()‘s and what have you). You know, not
the_content( __( 'Continue Reading →', 'woothemes' ) ); but rather
the_content( __( 'Continue Reading →', 'canvas' ) );. Everywhere. Tough, I know.
I thought that would be pretty much all, I mean I only needed to check that the call to
load_theme_textdomain was present and needed fixing, and… oh, look, not only is it there, it’s being called twice. What?
Load ALL the textdomains!
You do realize that the first call to the function will look for an .MO file in the theme’s directory, don’t you? Why would it find anything there, if you have kindly supplied a
/lang folder? The call looks unnecessary to me… By the way, the same applies to
load_child_theme_textdomain… It will look in the child theme’s directory, not its
/lang folder. I further suspect that
load_child_theme_textdomain is a call that should be made by the child theme and not its parent.
Ergo, the third fix would be to simplify the loading of translations with the correct textdomain, like so:
Two fewer disk reads, times millions (millions, I tell you!) of visits to the website, it should help with the overall performance.
Are we there yet? Not quite.
Sharing is caring
After all this, I ventured a quick glance at your documentation, to see if there was anything I was missing, if, for some reason, there was a compelling argument for having implemented i18n this way. What I found was, to say the least, surprising.
I’m not usually given to internet memes, but this is the one instance where I feel an exception can be made:
Where do I even begin? Let me try:
You’re encouraging every user to start a brand new translation from scratch. This means that, instead of having centralized translation, everyone is told to do it themselves! I get that you could use Codestyling Localization to adapt an existing translation to your own needs, but telling me, the user, the not-translator, “No. Go away. Do it yourself” isn’t exactly gaining you points, you know? Here’s your fourth fix: create or use an environment where strings can be translated publicly and collaboratively. Install GlotPress, use WP Translations, anything… just not this. I’ll even let you in on a little polyglots’ secret: .POT files to us are like honey to bears; the moment we see one that’s not complete, you can be sure that someone is going to rush in and translate it. Maybe not all of it, maybe not to all languages, but it’ll mark it, if available publicly, as active, alive; someone else will invariably pick up the torch.
And then there’s this nugget: let’s assume that the above point isn’t valid and I decide to use Codestyling Localization, after all, as recommended. Did you ever actually try to do it? Did you see how many strings the plugin offers for translation? That’s right, zero. Nix. Nada. Zip.
So, the fifth and final fix would be to stop recommending Codestyling Localization as the tool for translating the theme, and only mention it as a tool for adapting existing translations (heck, even create new ones, assuming the previous fixes have been properly implemented, but only then)
I still need you around
In closing I’d like to just say this:
- The above considerations probably apply to most, if not all of your themes. I only own a few and can confirm that they all suffer the exact same issues.
- I haven’t gone deeper into considerations of translations of individual strings (a few odd cases flashed by, but this post is long enough as it is), or even language packs. I strongly recommend you read Otto’s take on it all. He said it much better than I ever could.
- The purpose of this post is most definitely not to abuse, insult or berate; were I to have a lesser opinion of WooThemes, I wouldn’t have bothered writing it at all. It is precisely because I think highly of you that I’ve written it: because I know you will listen.
Finally, should you want to discuss this further, and ways to make it a process as flawless as your entire operation, I am at your disposal.
Thank you for listening
I feel your pain! Quite a few WooThemes installations over here. It’s a pain in the ass.
How do you manage and create a translation memory?
Open PoEdit, go to Preferences → Translation Memory, check both the Use translation memory and the Consult TM when updating from sources. That screen will additionally give you the option of augmenting the translation memory by reading in .PO’s that have been already translated. Just click Learn from files….
I’ve been using poEdit for many many moons and I didn’t even know that. The insane things you learn when you read the features list…
In that case you are going to love this little nugget in PoEdit Pro (15€):
That’s freakin’ fantastic. Singing and dancing here. Cheers!
I would love to test these new features of the “Pro” variant – but I am not able to! I am on Linux – which is supported by the Pro version “in general” – but the release is not available on Linux because of Licensing/Handling issues with the “Ubuntu Software Center”.
Had a conversation with the Poedit developer already. It’s a shame that I get punished for wanting to use open source software on an open source OS – but not able because too few users have interest in that, so further engagement with their “software center” is not worth it for the developer.
I pay a lot for open source software – if there are worthy premium products out there – but this case is a bit strange for me…. to say the least.
Can someone who owns and uses the Pro add-on tell me if it is worth it – does it scan better or what is it doing in detail?
Thanks, Dave 🙂
It is worth the 20$ but I am not sure it is worth the trouble setting up a Windows PC. 🙂
You do not need a POT file to start translating and looks for comments. It is as simple as click on button ” Translate WordPress theme or plugin”, select the folder with the code and then you get a list of all of the strings, choose your language and start translating.
Thanks for your feedback on this, and for compiling this post.
We’ve taken your feedback to heart and will be exploring how we can apply these, and other, improvements to how we handle translations within our themes, in a way that is efficient and sensible for our roadmap, going forward.
If you’d like to discuss further, or have any additional feedback (or would like to test out our improvements), please don’t hesitate to drop an email in my direction and we can get the updated code to you. 🙂
Thanks and regards,
Chief Product Officer at WooThemes
I’ll be in touch 😉
I love WooThemes for all the reasons you’ve already explained. In fact, at the company I work for, WooThemes are the only themes we use when we build WordPress sites.
With that said, most of the time we need to set up the sites in Spanish or Catalan, however we didn’t encounter the pain you’re describing (but perhaps it’s just us).
When we translate a site we just work on the front-end strings, we leave out the WooFramework and all the admin goodness (is that what you also wanted to translate to PT?).
For the front-end strings it not really that much that I can not live without a .pot file. We duplicate the en_GB.po and start working on it with PoEdit. It just takes a few minutes since we already did on a previous site and we know what we have to translate.
But hey, I’m not saying they’re perfect, In fact I’d like to see them adopt your suggestions and practices. Like you, I also think a public GlotPress (or similar) would be a huge win for WooThemes.
Maybe, but the flow I was trying to reproduce here is one where a user, (not a developer), purchases a theme and then tries to translate it using the documentation; he won’t look at PHP code, or even know the distinction between WooFramework and the theme itself.
I wonder if it’s possible to share that large translation memory somehow. I imagine it would be useful as a seed for a GlotPress install, etc.
There is a translation memory exchange format listed on the OpenTag.com page that the Poedit features list points to. Now to check that Poedit does allow such export…
Well, PoEdit, known for its spartanian documentation, hints that it might be using a TMX file, which is just a XML format. I’ll keep digging to see if I can find it.
In the meantime, if C doesn’t give you headaches, there’s always the source code 😛
Merci beaucoup Zé pour cet article ! Very thorough and timely!
To be fair to WooThemes, it is not limited to them: I’m having some of the very same issues with a ThemeForest theme that I bought for a friend’s website… to the point were I pointed the author to your article (Hi Peerapong!) 🙂
To be honest, I had a good laugh when reading this post. I was there 🙂
Thanks for this post — that would apply to WAY TOO MANY other plugin and theme shops around! Sadly!
Every time a theme shop has “issues” in that field, I may refer them here 🙂
However, you’re suggesting to avoid “Codestyling Localization” plugin. I understand where you’re coming from but it may sound a bit “strict” overall. Still, a lot of plugins and themes don’t have any translations packaged but do most i18n implementation quite in the right direction. Users that use CL with those ones will have success, of course.
One of the pain points with CL is, that it does not protect against auto updates or language packs or anything in that field. So users are likely to lost their stuff after an update for specific plugin/ theme.
For any users who know what they’re doing it’s quite a nice tool. I can say that because I use it for years on a daily basis – and also given its (many) faults.
The way you are suggesting with “community powered translations” can work quite well, but only “can”. For example packaged Jetpack translations will also overwrite anything on update — so you always get what the community has prepared for you. And there are quite some changes every time a new version releases. May still be better than no translations at all but it’s quite annoying to have unexpected string changes a lot, often for the worse…
Ok, that field is endless. I guess I’ll stop here for now… 🙂
I don’t think I’ve ever seen the whole .pot, .po and .mo differentiation explained so clearly! I’m going to save this as a reference for anyone who asks in the future.
And I love how you had to demean yourself to using a meme to express your pain. Hilarious.
The request for easy translations of Woo Themes must be as old as Woo itself, but no solution has been provided until now. I really hope we see that in the future, but I doubt it…
After hours of testing, doing everything in every possible documented and recommended way to get my translation to work I fortunately found your post. It saved me from pulling my hair out.
Mission accomplished, glad I could be of help!