{"id":153860,"date":"2016-04-11T11:00:49","date_gmt":"2016-04-11T15:00:49","guid":{"rendered":"http:\/\/premium.wpmudev.org\/blog\/?p=153860"},"modified":"2022-02-11T12:06:05","modified_gmt":"2022-02-11T12:06:05","slug":"ultimate-guide-wordpress-localization","status":"publish","type":"post","link":"https:\/\/wpmudev.com\/blog\/ultimate-guide-wordpress-localization\/","title":{"rendered":"Ultimate Guide to WordPress Translation and Localization"},"content":{"rendered":"<p>WordPress powers more than 15 million websites across the web and I\u2019ve got news for you \u2013 not all of them are in English. In fact, one of the reasons the \u2018Press is so popular is due to its availability in many languages and the ease with which it can be translated.<\/p>\n<p>What&#8217;s even more interesting is the fact that in 2014, the number of non-English downloads of WordPress surpassed the number of English downloads for the first time.<\/p>\n<p>Pair that with the <a href=\"https:\/\/ma.tt\/2014\/10\/sotw-2014\/\" target=\"_blank\">announcement that WordPress plugin and theme directories will be fully localized<\/a>, making them more accessible and fully translatable for non-English speakers, and it&#8217;s easy to see why it&#8217;s important to take the localization of WordPress seriously.<\/p>\n<p>If you make your living from WordPress, either by selling themes or plugins, then your work needs to support multiple languages. No ifs, ands, or buts.<\/p>\n<p>And if you happen to be the end-user of WordPress themes and plugins, knowing they include support for your native language is an added bonus.<\/p>\n<p>Today, we\u2019re going to explore just about everything under the sun related to WordPress localization, including:<\/p>\n<ol>\n<li><a href=\"#understanding\">Understanding i18n and l10n<\/a><\/li>\n<li><a href=\"#install\">How to Install a Localized Version of WordPress<\/a><\/li>\n<li><a href=\"#turn-existing\">How to Localize an Existing WordPress Site<\/a><\/li>\n<li><a href=\"#contribute\">How to Contribute to WordPress Localization<\/a><\/li>\n<li><a href=\"#plugins\">How to Prepare Your Plugin for Translation<\/a><\/li>\n<li><a href=\"#themes\">How to Prepare Your Theme for Translation<\/a><\/li>\n<li><a href=\"#translate-themes-plugins\">How to Use the Translated Themes and Plugins<\/a><\/li>\n<li><a href=\"#plugins-localization\">Plugins for Theme and Plugin Localization<\/a><\/li>\n<\/ol>\n<p>So buckle up and get your translation tools ready. It\u2019s about to get linguistic in here!<\/p>\n<h2><a name=\"understanding\" target=\"_blank\"><\/a>Understanding i18n and l10n<\/h2>\n<p>When it comes to WordPress and the support for your language, there are two key terms you need to understand:<\/p>\n<p><strong>The first is internationalization.<\/strong> Internationalization, or i18n for short (because there are 18 letters between i and n), is the process by which you as a theme or plugin developer prepare your theme or plugin for translation.<\/p>\n<p>WordPress uses the <a href=\"https:\/\/codex.wordpress.org\/Plugin_API\/Filter_Reference\/gettext\" target=\"_blank\">gettext<\/a> libraries and tools for i18n.<\/p>\n<p>Here is how it works in short:<\/p>\n<ul>\n<li>Developers wrap translatable strings in gettext functions<\/li>\n<li>Source code files are parsed and translatable strings are extracted into POT (Portable Objects Template) file<\/li>\n<li>POT files are then fed to GlotPress, a collaboration tool for translators<\/li>\n<li>Translators translate and the result is a PO file<\/li>\n<li>PO files are compiled into binary MO files, which give faster access to the strings at run-time<\/li>\n<\/ul>\n<p>This means that no matter what language you use to develop your work, future users (or even developers) can easily translate it into whatever language is required.<\/p>\n<p><strong>The second important term is localization or l10n<\/strong> for short (because there are 10 letters between l and n).<\/p>\n<p>Localization generally happens after internationalization and it&#8217;s the process in which your theme or plugin gets translated and adapted for use in a specific language.<\/p>\n<p>As a developer, you will only need to concern yourself with internationalization \u2013 making your theme or plugin ready for translation.<\/p>\n<p>While it&#8217;s not necessary for you to provide the translation, if you are multilingual, then by all means have a go at it.<\/p>\n<p>With these key definitions out of the way, we can move onto the nitty-gritty of today\u2019s post, including how to install a localized WordPress version or how to convert your existing installation to a localized one; how to prepare your themes and plugins for translation; how to contribute to WordPress localization; and finally, we&#8217;ll take a look at some of the best plugins that can help you with localization.<\/p>\n<div  class=\"wpdui-pic-large   \" >\n<figure class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-1364x1364 size-1364x1364\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/04\/language-large.png\" alt=\"The WordPress core software has been translated into 75 different languages.\" width=\"1364\" height=\"682\" \/><figcaption class=\"wp-caption-text\">The WordPress core software has been translated into 75 different languages.<\/figcaption><\/figure>\n<\/div>\n<h2><a name=\"install\" target=\"_blank\"><\/a>How to Install a Localized Version of WordPress<\/h2>\n<p>The easiest way to install a localized version of WordPress is through your web host&#8217;s cPanel.<\/p>\n<p>Plenty of hosts allow you to choose the language WordPress is installed in. For most users, this option is usually the easiest one.<\/p>\n<p>If for some reason your host doesn&#8217;t allow for this, you will have to do the work yourself.<\/p>\n<p>To see if WordPress is available in your language, visit WordPress.org. If it is available in your language, you will see a yellow notification bar telling you so.<\/p>\n<p>For the purposes of this article, let&#8217;s assume you need the French version of WordPress.<\/p>\n<p>The process of installing it is the same as it is for the regular WordPress version so let&#8217;s briefly run through the steps:<\/p>\n<ul>\n<li>Head over to <a href=\"https:\/\/fr.wordpress.org\" target=\"_blank\">fr.wordpress.org<\/a> and download the French version of WordPress.<\/li>\n<li>Using Filezilla (or your preferred FTP client), connect to your web server and unzip the WordPress package to your preferred installation directory &#8211; usually <em>public_html<\/em><\/li>\n<li>Create a database for WordPress on your web server and a MySQL user with all privileges.<\/li>\n<li>Edit the <em>wp-config.php<\/em> file and add your database information.<\/li>\n<li>Run the WordPress installation script by accessing the URL in a web browser.<\/li>\n<\/ul>\n<p>WordPress should now be installed in the French language. If you need more guidance, be sure to check out our more detailed post on the subject, <a href=\"https:\/\/wpmudev.com\/blog\/guide-installing-wordpress\/\" target=\"_blank\">A Guide to the Best Ways to Install WordPress<\/a>.<\/p>\n<h2><a name=\"turn-existing\" target=\"_blank\"><\/a>How to Localize an Existing WordPress Site<\/h2>\n<p>If you already have a WordPress website, chances are you don&#8217;t want to be bothered by installing WordPress from scratch.<\/p>\n<p>The good news is, you don&#8217;t have to.<\/p>\n<p>The easiest way to do this is to log into your dashboard, click on<strong>\u00a0Settings &gt; General<\/strong>, then scroll down to the bottom of your page to\u00a0<strong>Site Language<\/strong>\u00a0and select your desired language from the dropdown.<\/p>\n<figure class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-490x490\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/04\/Change_Language_Settings.jpg\" alt=\"Change_Language_Settings\" width=\"490\" height=\"312\" \/><figcaption class=\"wp-caption-text\">Changing your site&#8217;s language in the dashboard.<\/figcaption><\/figure>\n<p>Note that this will only change the language used in the backend of your WordPress site. If your posts are in English, they will remain in English.<\/p>\n<p>Your theme and any plugins you may be using will still be in English.<\/p>\n<p>An alternative way of localizing an existing WordPress installation is by downloading and uploading the <em>.mo<\/em> language file to your <em>\/wp-content\/languages\/<\/em> or <em>\/wp-includes\/languages\/<\/em> folder.<\/p>\n<p>You will have to create a new folder called languages in the <em>wp-content<\/em> directory.<\/p>\n<p>Once you have uploaded all the .mo and .po files that came with your language, the next step is to tell WordPress to use these language files. To do so, open your <code><em>wp-config.php<\/em><\/code> file and change the following line:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"ffb7a1f2921c6c6f10b82faafb52bee8\" data-gist-file=\"config\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/ffb7a1f2921c6c6f10b82faafb52bee8.js?file=config\">Loading gist ffb7a1f2921c6c6f10b82faafb52bee8<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>Replace <em>fr_FR<\/em> with your language and country code. The first two letters are for the language code and the other two letters are for the country code. Check out the <a href=\"https:\/\/i18n.svn.wordpress.org\/\" target=\"_blank\">full list of language and country codes<\/a>.<\/p>\n<p>Once you&#8217;ve added that text to your <code><em>wp-config.php<\/em><\/code>\u00a0file, WordPress will display the admin area in your language.<\/p>\n<p>As with the previous method of changing the language in the <strong>Settings<\/strong> menu, only the WordPress administration areas will be in your language. You may still need to translate your WordPress theme or other plugins.<\/p>\n<div  class=\"wpdui-pic-large   \" >\n<figure class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-1364x1364 size-1364x1364\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/04\/translate-wordpress.png\" alt=\"Translate WordPress is the place to go if you want to contribute to the polyglots team.\" width=\"1364\" height=\"496\" \/><figcaption class=\"wp-caption-text\">Translate WordPress is the place to go if you want to contribute to the polyglots team.<\/figcaption><\/figure>\n<\/div>\n<h2><a name=\"contribute\" target=\"_blank\"><\/a>How to Contribute to WordPress Localization<\/h2>\n<p>While WordPress is available in many languages, some of them haven&#8217;t been fully translated yet. If you are multilingual, why not use your skills to contribute to WordPress localization.<\/p>\n<p>The first thing you want to do is head over to <a href=\"https:\/\/make.wordpress.org\/polyglots\/\" target=\"_blank\">Translate WordPress<\/a>. If you have an existing WordPress.org account, all you need to do is log in and start contributing to your language.<\/p>\n<p>Before diving into translation, you will want to check out the <a href=\"https:\/\/make.wordpress.org\/polyglots\/handbook\/\" target=\"_blank\">Translator&#8217;s Handbook<\/a>, which will teach you everything you need to know about translating WordPress, from how to get started to best practices and expectations.<\/p>\n<p>After you have familiarized yourself with the handbook, there are a few different ways you can contribute.<\/p>\n<p>You can become a part of your local team if one exists already for your language. Or you can create a team.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/01\/translation.png\" alt=\"Choose the language you want to use WordPress in.\" width=\"735\" height=\"390\" \/><figcaption class=\"wp-caption-text\">Choose the language you want to use WordPress in.<\/figcaption><\/figure>\n<\/div>\n<p>You can help translate WordPress itself, themes, plugins, or apps. Once you&#8217;ve decided on your translation project, you can start contributing to it by clicking on <strong>Contribute<\/strong>.<\/p>\n<p>You will then be presented with the strings that still need translating. So go forth and translate!<\/p>\n<h2>How to Prepare Your Plugin for Translation<\/h2>\n<p>Preparing your plugin for translation gives you a far wider audience than simply restricting it to one language or assuming that because it&#8217;s in English everyone will know how to use it.<\/p>\n<p>Here&#8217;s a look at how to prep your plugin for translation:<\/p>\n<h3>1. Set Translation Headers<\/h3>\n<p>The first step is adding the translation headers to the plugin headers. The translation headers are the <strong>Text Domain<\/strong> and the <strong>Domain Path<\/strong>.<\/p>\n<p>The Text Domain denotes all text belonging to a plugin. It&#8217;s a unique identifier that ensures WordPress can distinguish between all loaded translations.<\/p>\n<p>The Text Domain must match the slug of the plugin.<\/p>\n<p>Essentially, this means if your plugin is a single file called <em>sample-plugin.php<\/em> or if the plugin is in a folder called <em>sample-plugin<\/em> the text domain should be <em>sample-plugin<\/em>.<\/p>\n<p>It&#8217;s worth mentioning that the text domain name must use dashes and not underscores.<\/p>\n<p>The Domain Path is the folder WordPress will search for the <em>.mo<\/em> translation files.<\/p>\n<p>By default, WordPress searches the plugin directory for the translation files to use. If you leave the translation file at the root folder of your plugin you could wind up with a disorganized plugin structure.<\/p>\n<p>That&#8217;s why it&#8217;s recommended to create a separate folder for the translation files such as <em>\/languages<\/em>. To inform WordPress about it, you need to use the Domain Path header.<\/p>\n<p>For example, a typical header of a WordPress plugin that has been internationalized would look like this:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"65e632280c4ddab2962b0188c1ee1841\" data-gist-file=\"international plugin header\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/65e632280c4ddab2962b0188c1ee1841.js?file=international+plugin+header\">Loading gist 65e632280c4ddab2962b0188c1ee1841<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<h3>2. Load Text Domain<\/h3>\n<p>After adding translation headers, we need to load the text domain by using the <code>load_plugin_textdomain()<\/code> function. This function tells WordPress to load a translation file if it exists for the user\u2019s language. It looks like this:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"7c4e1fd81c168eb5a0a4b2fc23c00889\" data-gist-file=\"load plugin text domain\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/7c4e1fd81c168eb5a0a4b2fc23c00889.js?file=load+plugin+text+domain\">Loading gist 7c4e1fd81c168eb5a0a4b2fc23c00889<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>The first parameter <code>$domain<\/code> should be the text domain; the <code>$abs_rel_path<\/code> has been deprecated and should be set to <code>false<\/code>; finally, <code>$plugin_rel_path<\/code> is the relative path to translation files.<\/p>\n<p>In the case of our sample plugin, the function would look like this:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"204bc0d9bfde475c577c60e7f77a51e3\" data-gist-file=\"load plugin text domain\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/204bc0d9bfde475c577c60e7f77a51e3.js?file=load+plugin+text+domain\">Loading gist 204bc0d9bfde475c577c60e7f77a51e3<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>The function should be called in your plugin as early as the <code>plugins_loaded<\/code> action like this:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"f2546f400864ab826308178546dfe787\" data-gist-file=\"load text domain\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/f2546f400864ab826308178546dfe787.js?file=load+text+domain\">Loading gist f2546f400864ab826308178546dfe787<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>Now that the Text Domain and the Domain Path header are set, let&#8217;s look at how to internationalize a plugin.<\/p>\n<p>We&#8217;ll cover translating strings, using placeholders, HTML translation, handling plurals, dealing with disambiguation, and escaping translation strings.<\/p>\n<h3>3. Strings Translation<\/h3>\n<p>To make a string translatable in your plugin, wrap the original string in a <code>__()<\/code> function call:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"b976cf2e27613eb427c5e10829c4c0d8\" data-gist-file=\"make string transmissible\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/b976cf2e27613eb427c5e10829c4c0d8.js?file=make+string+transmissible\">Loading gist b976cf2e27613eb427c5e10829c4c0d8<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>If you want to echo the string to the browser simply use the <code>_e<\/code> function instead:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"98bc53df835474b7079e3b8deff67c29\" data-gist-file=\"efunction\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/98bc53df835474b7079e3b8deff67c29.js?file=efunction\">Loading gist 98bc53df835474b7079e3b8deff67c29<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>Repeat this for every string that you want to translate.<\/p>\n<h3>4. Using Placeholders<\/h3>\n<p>If you are using variables in strings like the example below, you should use placeholders:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"c3acd65e239489015db6f5ab460419b0\" data-gist-file=\"echo color\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/c3acd65e239489015db6f5ab460419b0.js?file=echo+color\">Loading gist c3acd65e239489015db6f5ab460419b0<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>The right way is to use the <code>printf()<\/code> function:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"31f42b3bd428ba0c0c5eefeaa847f0a6\" data-gist-file=\"placeholder print placement\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/31f42b3bd428ba0c0c5eefeaa847f0a6.js?file=placeholder+print+placement\">Loading gist 31f42b3bd428ba0c0c5eefeaa847f0a6<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>If you don&#8217;t use placeholders, then you are leaving your plugin open to various vulnerabilities, such as translators mistakenly altering the variables or worse, replacing them with malicious code, which could ultimately lead to plugin malfunctions and overall site vulnerability.<\/p>\n<h3>5. Translating HTML<\/h3>\n<p>One of the biggest areas of confusion when it comes to HTML translations is translating links.<\/p>\n<p>How you handle the translation of HTML links depends on the context the link is in. If the link is separated from the rest of the text then you can wrap it into an <code>_e()<\/code> function:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"addfdb2bc0ccb79ac0db92cf481ae0f6\" data-gist-file=\"translating html\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/addfdb2bc0ccb79ac0db92cf481ae0f6.js?file=translating+html\">Loading gist addfdb2bc0ccb79ac0db92cf481ae0f6<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>If, on the other hand, the link is a part of the paragraph (not separated from text surrounding it), then you can translate it as follows:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"2a5a0c70fa216d17a58d33d8836bd572\" data-gist-file=\"link in paragraph translation\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/2a5a0c70fa216d17a58d33d8836bd572.js?file=link+in+paragraph+translation\">Loading gist 2a5a0c70fa216d17a58d33d8836bd572<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<h3>6. Handling Plurals<\/h3>\n<p>In some languages, you can have multiple plural forms unlike in English where you have only one plural form. This is where the<code> _n()<\/code> function comes in handy.<\/p>\n<p>This function accepts four arguments:<\/p>\n<ul>\n<li><strong>Singular \u2013<\/strong>\u00a0the singular form of the string<\/li>\n<li><strong>Plural \u2013<\/strong>\u00a0the plural form of the string<\/li>\n<li><strong>Count \u2013<\/strong>\u00a0the number of objects which determine whether the singular or the plural form should be returned<\/li>\n<li><strong>Text Domain \u2013<\/strong>\u00a0the plugin\u2019s text domain<\/li>\n<\/ul>\n<p>An example of the <code>_n()<\/code> function is below:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"c577fb0308fc8e529b8e95b9857db2e1\" data-gist-file=\"handling plurals\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/c577fb0308fc8e529b8e95b9857db2e1.js?file=handling+plurals\">Loading gist c577fb0308fc8e529b8e95b9857db2e1<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>Now, let&#8217;s break down what all of this means.<\/p>\n<p>The first argument we pass to the <code>_n<\/code> function is the text that will display when we only have one comment.<\/p>\n<p>The second argument displays the text when the number of comments is greater than one. The third argument <code>get_comments_number()<\/code> is a function that returns the comment count.<\/p>\n<p>Finally, the fourth argument is the translation text domain.<\/p>\n<p>The function <code>number_format_i18n()<\/code> converts the comment count to format based on the locale.<\/p>\n<p>Similarly, the <code>date_i18n<\/code> retrieves the date in localized format, based on timestamp.<\/p>\n<h3>7. Handling Disambiguation<\/h3>\n<p>In some cases, one term can carry several different meanings and although it may be one and the same word in English it may not be translated the same way in a different language.<\/p>\n<p>In such cases, the <code>_x<\/code> or <code>_ex<\/code> function should be used.<\/p>\n<p>The <code>_x()<\/code> and <code>_ex()<\/code> functions come with an extra argument: <code>$context<\/code>.<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"6adf21827c2d076f094814c9e7ef3dda\" data-gist-file=\"translation functions\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/6adf21827c2d076f094814c9e7ef3dda.js?file=translation+functions\">Loading gist 6adf21827c2d076f094814c9e7ef3dda<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>Using this method you will ensure that the translators see the two comment strings each in a different context and avoid the confusion.<\/p>\n<h3>8. Escaping Translation Strings<\/h3>\n<p>Translation strings can be escaped by using following functions:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"82919e439d368887b4560fe4ca57eabb\" data-gist-file=\"escaping translation\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/82919e439d368887b4560fe4ca57eabb.js?file=escaping+translation\">Loading gist 82919e439d368887b4560fe4ca57eabb<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>A full list of sanitization and validation functions and their explanation is available at the <a href=\"http:\/\/codex.wordpress.org\/Data_Validation\" target=\"_blank\">WordPress Codex<\/a>.<\/p>\n<p>Once you have gone through every string in your plugin, the only thing left to do is to create the <em>.pot<\/em> file, which will allow other users to translate the plugin into their own language.<\/p>\n<p>By default, the official plugin repository has a tool for generating the POT file of a plugin which is located on the Admin page of every plugin listing.<\/p>\n<p>Once you upload your plugin to the repository you can click on <strong>Admin &gt; Generate POT file<\/strong> and then <strong>Get the POT file<\/strong>.<\/p>\n<p>If you don&#8217;t want to use the official tool, you can use <a href=\"https:\/\/poedit.net\/download\" target=\"_blank\">POEdit<\/a>. Once you&#8217;ve installed it, you can create your <em>.pot<\/em> file. To do this, go to <strong>File &gt; New Catalog<\/strong>.<\/p>\n<p>A dialog box will appear where you need to enter the information for your project, specifically the project name and your language\/country as well as the following in the &#8220;Plural Forms&#8221; box:<\/p>\n<p><em>Plural Forms: nplurals=2; plural=n != 1;<\/em><\/p>\n<p>On the <em>Paths<\/em> tab, enter the path where the files can be found. Since we used the <em>\/languages<\/em> folder in our example, you&#8217;ll need to enter <em>..\u00a0<\/em>(two periods).<\/p>\n<p>Next, you need to tell POEdit which keywords to look for when scanning your files. Enter the following:<\/p>\n<p><em>__<br \/>\n_e<br \/>\n_n:1,2<br \/>\n_x:1,2c<br \/>\n_ex:1,2c<\/em><\/p>\n<p>The <em>:1,2<\/em> extension tells POEdit that these keywords consist of two parts: the second argument is the plural. When you include the &#8220;c&#8221; you\u2019re telling POEdit the second argument is a comment.<\/p>\n<p>After that click &#8220;OK&#8221; and choose a place to save your <em>.pot<\/em> file.<\/p>\n<p>Bear in mind that it has to relate to the path you defined earlier.<\/p>\n<p>POEdit will now scan through your files and find all the occurrences of your translation functions and save them into your <em>.pot<\/em> file.<\/p>\n<p>Now you have the bare minimum for the internationalization of your plugin.<\/p>\n<p>If you know a different language and want to go a step further, you can translate all the strings that POEdit found and save the translation as the <em>.po<\/em> file.<\/p>\n<p>Be careful in naming your <em>.po<\/em> file, however. Since Gettext uses the ISO 639 standard for language abbreviations and ISO 3166 for locales you have to keep in mind the language and country codes, as well as the capitalization.<\/p>\n<p>You can find a full list of language and country codes at the following links:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.gnu.org\/software\/gettext\/manual\/gettext.html#Language-Codes\" target=\"_blank\">Gettext language codes<\/a><\/li>\n<li><a href=\"http:\/\/www.gnu.org\/software\/gettext\/manual\/gettext.html#Country-Codes\" target=\"_blank\">Gettext country codes<\/a><\/li>\n<\/ul>\n<p>Once you save, POEdit will automatically create a <em>.mo<\/em> file alongside your <em>.po<\/em> file.<\/p>\n<h2><a name=\"themes\" target=\"_blank\"><\/a>How to Prepare Your Theme for Translation<\/h2>\n<p>The process for preparing your theme for translation follows the same principles as those for the plugins we described above. The difference is that you need to load the text domain in your <em>functions.php<\/em> file:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"ceb824d36633e610de004e49ae725990\" data-gist-file=\"load theme text\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/ceb824d36633e610de004e49ae725990.js?file=load+theme+text\">Loading gist ceb824d36633e610de004e49ae725990<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<h2><a name=\"translate-themes-plugins\" target=\"_blank\"><\/a>How to Use the Translated Themes and Plugins<\/h2>\n<p>Once you&#8217;ve prepared your theme or a plugin for installation and you want to use them on your site, you need to make a small edit to your <em>wp-config<\/em> file.<\/p>\n<p>To do so, open up <em>wp-config.php<\/em> and find the line that says:<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"c5231c9d930fa604ca4ac437a890d5ae\" data-gist-file=\"wp config language\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/c5231c9d930fa604ca4ac437a890d5ae.js?file=wp+config+language\">Loading gist c5231c9d930fa604ca4ac437a890d5ae<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>In the empty space add the country code and the locale code for your translated language. In the case of French, this bit of code would become&#8221;<\/p>\n<p><span style=\"font-weight: 400;\"><div class=\"gist\" data-gist=\"f7ad2486d7fd968f4e9c29a48b13585d\" data-gist-file=\"define language\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/f7ad2486d7fd968f4e9c29a48b13585d.js?file=define+language\">Loading gist f7ad2486d7fd968f4e9c29a48b13585d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/span><\/p>\n<p>Save the file and you&#8217;re done.<\/p>\n<h2><a name=\"plugins-localization\" target=\"_blank\"><\/a>Plugins for\u00a0Theme and Plugin Localization<\/h2>\n<p>We&#8217;ve already covered <a href=\"https:\/\/wpmudev.com\/blog\/top-6-translation-plugins-for-your-wordpress-site\/\" target=\"_blank\">translation plugins<\/a> here at WPMU DEV, but this time, let&#8217;s focus on plugins that help with <em>preparing<\/em> themes and plugins for translation as well.<\/p>\n<p>While POEdit is a great tool, there are a few plugins that allow you to translate, well, plugins, in your WordPress admin.<\/p>\n<ul class=\"dev-tutorial-list\"><li class=\"dev-tutorial-list__item\"><header class=\"dev-tutorial-list__item__header\"><h3 class=\"dev-tutorial-list__item__title\">WPML<\/h3><\/header><section class=\"dev-tutorial-list__item__image\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"260\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/04\/WPML-plugin.png\" class=\"attachment-ratio-large size-ratio-large\" alt=\"WPML image\" aria-hidden=\"true\" \/><\/section><!-- end dev-tutorial-list__item__image --><section class=\"dev-tutorial-list__item__content\"><p class=\"lead\">WPML enables you to translate the texts coming from themes and plugins you use in your sites.<\/p>\n<p>By default, WPML doesn\u2019t scan or load these translation files into the database. Therefore, if you want to translate or edit these strings, you first need to scan the translation files of the related theme or a plugin.<\/p>\n<p>Once the theme or plugin strings are scanned you can translate them on the <strong>WPML -&gt; String Translation <\/strong>page.<\/p>\n<p>WPML also doesn\u2019t need to access the database to display translations of theme and plugin texts. Because of this, translating theme and plugin texts will have no impact on your site\u2019s performance.<\/p>\n<p>Another great thing about WPML is that it&#8217;s fully compatible with a number of plugins &#8212; including our own <a href=\"https:\/\/wordpress.org\/plugins\/hummingbird-performance\/\" rel=\"noopener\" target=\"_blank\">Hummingbird<\/a>.<\/p>\n<p>Even better, <a href=\"https:\/\/wpml.org\/2019\/10\/wpml-4-3-with-revamped-string-translation\/\" rel=\"noopener\" target=\"_blank\">as of release 4.3<\/a>, WPML has changed the way string translation works. As a result, when used with Hummingbird this translation plugin won&#8217;t slow down your site one bit.<\/p>\n<p>WPML comes with three pricing plans \u2013 Multilingual Blog, Multilingual CMS, and Multilingual Agency. Prices range from $29 &#8211; $159.<\/p>\n<\/section><!-- end dev-tutorial-list__item__content --><footer class=\"dev-tutorial-list__item__footer\"><p>Interested in WPML?<\/p><div class=\"dev-tutorial-list__item__cta\"><a target=\"_blank\" href=\"https:\/\/wpml.org\/\" class=\"dui-btn dui-btn--sm dui-btn--brand dev-btn--Details\">Details<\/a><\/div><!-- end dev-tutorial-list__item__cta --><\/footer><!-- end dev-tutorial-list__item__footer --><\/li><!-- end dev-tutorial-list__item --><li class=\"dev-tutorial-list__item\"><header class=\"dev-tutorial-list__item__header\"><h3 class=\"dev-tutorial-list__item__title\">POEditor WordPress Translation Plugin<\/h3><\/header><section class=\"dev-tutorial-list__item__image\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"171\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/04\/POEditor-600x171.jpg\" class=\"attachment-ratio-large size-ratio-large\" alt=\"POEditor WordPress Translation Plugin image\" aria-hidden=\"true\" \/><\/section><!-- end dev-tutorial-list__item__image --><section class=\"dev-tutorial-list__item__content\"><p>For a more streamlined localization of WordPress themes and plugins, you can use POEditor&#8217;s WordPress translation plugin. With this plugin, you can manage the import and export in your POEditor translation projects directly from your WordPress dashboard.<\/p>\n<p>To use the plugin you will need a POEditor.com account which you will need to connect to the plugin after you have installed it on your site. Then enter the API key and you&#8217;re ready to start translating by creating a new project, adding a language, and assigning a language file.<\/p>\n<p>The plugin is free and there is a free account option on POEditor, however, you are limited to 1000 strings. Paid account plans start at $14.99\/month.<\/p>\n<\/section><!-- end dev-tutorial-list__item__content --><footer class=\"dev-tutorial-list__item__footer\"><p>Interested in POEditor WordPress Translation Plugin?<\/p><div class=\"dev-tutorial-list__item__cta\"><a target=\"_blank\" href=\"https:\/\/wordpress.org\/plugins\/poeditor\/\" class=\"dui-btn dui-btn--sm dui-btn--brand dev-btn--Details\">Details<\/a><\/div><!-- end dev-tutorial-list__item__cta --><\/footer><!-- end dev-tutorial-list__item__footer --><\/li><!-- end dev-tutorial-list__item --><li class=\"dev-tutorial-list__item\"><header class=\"dev-tutorial-list__item__header\"><h3 class=\"dev-tutorial-list__item__title\">TranslatePress<\/h3><\/header><section class=\"dev-tutorial-list__item__image\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"194\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2019\/09\/translatepress-banner.png\" class=\"attachment-ratio-large size-ratio-large\" alt=\"TranslatePress image\" aria-hidden=\"true\" \/><\/section><!-- end dev-tutorial-list__item__image --><section class=\"dev-tutorial-list__item__content\"><p><a href=\"https:\/\/wordpress.org\/plugins\/translatepress-multilingual\/\" rel=\"noopener\" target=\"_blank\">TranslatePress<\/a> is an intuitive translation plugin due to its visual translation interface.<\/p>\n<p>You can translate everything you see (text, images, forms, etc.) directly from the front-end of your site.<\/p>\n<p>TranslatePress automatically detects gettext strings coming from themes or plugins.\u00a0The nice thing is that once you translate gettext strings, these translations will automatically apply to all instances where that string appears.<\/p>\n<p>Also, if a certain plugin has a language pack available, TranslatePress will automatically pre-fill the translations of these strings and display them in the front-end. You can also go through and manually edit them.<\/p>\n<p>TranslatePress is free and available at wp.org. The premium packages include addons like SEO Pack, Automatic User Language Detection, Translator Accounts, and more, and starts at 79 euros.<\/p>\n<\/section><!-- end dev-tutorial-list__item__content --><footer class=\"dev-tutorial-list__item__footer\"><p>Interested in TranslatePress?<\/p><div class=\"dev-tutorial-list__item__cta\"><a target=\"_blank\" href=\"https:\/\/wordpress.org\/plugins\/translatepress-multilingual\/\" class=\"dui-btn dui-btn--sm dui-btn--brand dev-btn--Details\">Details<\/a><\/div><!-- end dev-tutorial-list__item__cta --><\/footer><!-- end dev-tutorial-list__item__footer --><\/li><!-- end dev-tutorial-list__item --><li class=\"dev-tutorial-list__item\"><header class=\"dev-tutorial-list__item__header\"><h3 class=\"dev-tutorial-list__item__title\">Loco Translate<\/h3><\/header><section class=\"dev-tutorial-list__item__image\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"171\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/04\/Loco_Translate-600x171.jpg\" class=\"attachment-ratio-large size-ratio-large\" alt=\"Loco Translate image\" aria-hidden=\"true\" \/><\/section><!-- end dev-tutorial-list__item__image --><section class=\"dev-tutorial-list__item__content\"><p>Loco Translate gives you a built-in translation editor in your WordPress dashboard.<br \/>\nAfter the installation, you will see a list of all the themes and plugins you have installed as well as any existing translations. Once you find the theme or plugin that you want to translate, simply click on <strong>New Language<\/strong>, and then\u00a0<strong>Start Translating<\/strong>.<\/p>\n<p>Loco Translate is free for up to 2000 translations. Paid plans start at $5.95\/month<\/p>\n<\/section><!-- end dev-tutorial-list__item__content --><footer class=\"dev-tutorial-list__item__footer\"><p>Interested in Loco Translate?<\/p><div class=\"dev-tutorial-list__item__cta\"><a target=\"_blank\" href=\"https:\/\/wordpress.org\/plugins\/loco-translate\/\" class=\"dui-btn dui-btn--sm dui-btn--brand dev-btn--Details\">Details<\/a><\/div><!-- end dev-tutorial-list__item__cta --><\/footer><!-- end dev-tutorial-list__item__footer --><\/li><!-- end dev-tutorial-list__item --><\/ul><!-- end dev-tutorial-list -->\n<h2>Wrapping Up<\/h2>\n<p>The number of WordPress users is growing every day. And while a fair number of WordPress users understand English, ignoring other languages is downright foolish.<\/p>\n<p>Preparing your themes and plugins for localization ensures you reach a wider audience and it earns you bonus points with the end-users. And that is a net win.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Did you know more people download WordPress in languages other than English than, well, English? Neglecting site visitors who speak English as a second language (or don&#8217;t speak English at all) isn&#8217;t a great idea, so we&#8217;ve put together this mega guide to give you a head start.<\/p>\n","protected":false},"author":344989,"featured_media":153958,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"blog_reading_time":"","wds_primary_category":0,"wds_primary_tutorials_categories":0,"footnotes":""},"categories":[263],"tags":[10458,10454,64],"tutorials_categories":[],"class_list":["post-153860","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-language","tag-localization","tag-translation"],"_links":{"self":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/153860","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/users\/344989"}],"replies":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/comments?post=153860"}],"version-history":[{"count":32,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/153860\/revisions"}],"predecessor-version":[{"id":224119,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/153860\/revisions\/224119"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media\/153958"}],"wp:attachment":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media?parent=153860"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/categories?post=153860"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tags?post=153860"},{"taxonomy":"tutorials_categories","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tutorials_categories?post=153860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}