Can posts or terms share the same URL slug across translations?

Can posts or terms share the same URL slug across translations?

With Polylang Pro comes the possibility to share slugs between posts and pages.
By default WordPress will not allow two pages or posts to share the same slug. That is to say if two posts are created with the same slug, WP will automatically add a 「-2」 to the slug of the second post created, 「-3」 to the third etc.
URLs contribute to the first impression visitors will have of your site. Long URLs that contain random numbers and/or letters appear less trustworthy than URLs that convey accurate information related to the content of the page. This is where sharing slugs can come in handy.

This feature allows you to share the same slug between translations for all types of content, pages, posts, categories, tags, media, custom taxonomies… You need to use pretty permalinks and the language must not be set from the content for it to be activated.
For posts, pages, custom post types
Taken an author is presented in a post (Agatha Christie), it is useful to share the same slug between languages as the post name showing in the URL should be the same regardless of the language. If you have two languages (English and French), with Polylang Pro you will get this result:

For categories, tags, custom taxonomies
If a site references books, movies and authors. While the title of the books and the movies may vary between languages, authors』 names are unlikely to change. Taken each author corresponds to a category, it becomes possible with Polylang Pro to keep the same slug for each translation of the category
So with Polylang Pro you will get this result:

/en/category/agatha-christie
/fr/category/agatha-christie

Instead of having with Polylang:

/en/category/agatha-christie
/fr/category/agatha-christie-fr

Note that it is also possible to translate the category base in the Languages => Strings Translations tab. See translating URLs slugs.
 
Note: It』s a known issue that when using the WordPress Importer plugin, the content having a shared slug is not imported.
Note: If you deactivate Polylang Pro, only one item among all sharing the same slug will be displayed.

The wpml-config.xml file

The wpml-config.xml file

The WordPress multilingual plugin WPML has been created far before Polylang and thus some plugins and themes have been written to play nicely with it. Polylang does support the WPML language configuration file wpml-config.xml to avoid double work for themes and plugins author.
Here is an example which is pretty much self explanatory:
123456789101112131415161718192021222324            quantity        custom-title                book        DVD                genre                                                                                                                    
custom-fields: the custom field name needs to be provided and also the action that Polylang is expected to take:

「ignore」: no action from Polylang
「translate」: the custom field is copied from the source post but may be modified
「copy」: the custom field is copied from the source post and synchronized accross translations

custom-types: the custom post types that Polylang should manage. Allowed values for the 「translate」 attribute are 1 (managed by Polylang) and 0 (not managed by Polylang). In both cases, users cannot change this choice in Polylang settings.
taxonomies: the custom taxonomies that Polylang should manage. Allowed values for the 「translate」 attribute are 1 (managed by Polylang) and 0 (not managed by Polylang). In both cases, users cannot change this choice in Polylang settings.
admin-texts: When themes and plugins use 『get_option』, Polylang can filter these calls and provide translation to the values of these options. To translate a single option, add a key entry under admin-texts (as simple_string_option in the example above). To translate a serialized array, add several keys under a key (as in my_plugin_options in the example above).
Polylang does not support the section.
Developpers must place the wpml-config.xml file in the root directory of the plugin or theme. It is also possible for users to create their own wpml-config.xml file and to upload it in /wp-content/polylang/ (create the directory if it does not exist).

Is Polylang compatible with the EU cookie law?

Is Polylang compatible with the EU cookie law?

Polylang uses a cookie to remember the language selected by the user when he comes back to visit again the website. This cookie is also used to get the language information when not available in another way. Examples are ajax requests or the login page.
According to the section 3.6 of the  Opinion 04/2012 on Cookie Consent Exemption, this cookie is part of the user interface customization and may be considered as requested by the user. Whether it requires the explicit consent of the user seems to depend on the expiration time or the information provided on your website. Moreover European countries have all their own law and do not apply the European directive the same way. Please check if this cookie requires an explicit user consent in your own country.
Here are the information about the cookie used by Polylang:

Default name: 『pll_language』, can be changed by setting the constant PLL_COOKIE
Value: the language code of the last browsed page
Default expiration time: 1 year, can be changed with the filter 『pll_cookie_expiration』

It is possible not to use the cookie (be aware however that in this case and as stated above, not everything will work correctly)  by putting the code below for example in your wp-config.php file:
1define( 'PLL_COOKIE', false);

How to translate options with a wpml-config.xml file?

How to translate options with a wpml-config.xml file?

Adding a simple option in the wpml-config.xml
Writing the wpml-config.xml file
Adding a serialized option in the wpml-config.xml
My wpml-config.xml is written, what should I do now ?
I already have a wpml-config.xml, may I merge two in one ?

Introduction
The wpml-config.xml file is a powerful tool which allows to add WordPress themes and plugins options to the string translations.
This tutorial explains how to find the information to add in this file to translate option strings easily.
Prerequisite
To follow this tutorial you』ll need a PhpMyAdmin access to find how options are stored and named. We suggest you to test it in a development environment before using it on your production website.
If you are not sure about your ability to manage this tutorial, do not hesitate to contact us in our Polylang Pro help desk.
Warning
In this tutorial, we』ll access to PhpMyAdmin which is a tool to manage databases. A wrong manipulation of data may break your website.
Always make a database backup before manipulating it.
Adding a simple option in the wpml-config.xml
To illustrate we』ll use the plugin WooCommerce. Thanks to Polylang for WooCommerce you』ll be able to send emails to your customer in the language they purchased.
That said, you may want to translate the email sender options in each language that you have in your website:

Now our goal is to find how WooCommerce stores these options and which names it uses.

Fill each fields and save the options, to store them in the database.
Open PhpMyAdmin and go to the wp_options table
click on 「Search」 tab

Fill the search fields with:

「Option value」 selected on 「LIKE %…%」. The % sign will allows to hav characters before and after the searched string.
Paste the value on the searched option: 「Polylang Helpdesk」 in our case.

Click on 「Execute」
You should have something like:

The info needed here is 「woocommerce_email_from_name」. Copy the data (Do not cut).

Writing the wpml-config.xml file
In your preferred text editor, add the code below in a new file called wpml-config.xml:

must be the first tag in your wpml-config.xml file, and must be the last one. Polylang will only process instructions between these tags.
... will contain the options we want to translate.
Adds a simple option (not serialized) to our string translation. The name 『woocommerce_email_from_name』 is the option name found earlier in PhpMyAdmin.

Of course, you can have several inside your admin-texts section.
Adding a serialized option in the wpml-config.xml
Some themes or plugins are storing an array of options in the same option key in the database. WordPress serializes the data to store them correctly.
To illustrate this chapter, we』ll use the plugin WPFront Notification Bar. This plugin allows to spread a message in a bar in your front-end website. In the settings of this plugin, you』ll find several textareas and input fields for text.

Here the goal is to translate 「My great text」, 「toto」,  「https://polylang.pro」.
As in the previous chapter, we』ll search one of the string in the databases:

At this point, we can start to write (or edit an existing) wpml-config.xml:

Here the important information is the syntax that is used for serialized options. Now, let』s unserialize 「option_value」.

Copy the 「option_value」 content
Paste it in the field present on this URL https://www.unserialize.com/
click on 「Unserialize」

Here a screenshot of what you should have :

The information we need here are the option key:

message
button_text
button_action_url

Which are sub-keys of our main option_name 「wpfront-notification-bar-options」. Our wpml-config.xml should be modified as follow:

My wpml-config.xml is written, what should I do now ?
Simply upload it to your FTP in
wp-content/polylang
(you may need to create this folder)
Go to Polylang』s Strings Translations page and save your plugins settings again. You should now have a new group called 「Polylang」 in your strings translations with your new strings.

I already have a wpml-config.xml, may I merge two in one ?
Of course, be sure to copy the content inside the

tags
Let』s say you already have:

et_pb_layout

and need to add the previous instructions, you can merge both wpml-config.xml like below:

et_pb_layout

How to

How to

How to know the current language in the theme ?
WordPress provides at least two functions for the themes or plugins authors to know the current language:

get_locale() returns the WordPress locale in the format 'en_US'
get_bloginfo('language') returns the locale in the format 'en-US'

Note the difference between '_' and '-' in the two functions. You can have a look at the following forum topics:

Return the current language as variable for your template
How to translate/switch specific contents on templates

Additionaly, Polylang now provides the function 'pll_current_language' which can return either the language code, the locale or the language name.
How to make translatable user defined strings in my plugin or theme ?
You have to register strings on the admin side with the function 'pll_register_string' and display them on frontend with 'pll__' or 'pll_e'.
How to make my custom post types and taxonomies multilingual?
You must register your custom post type (or taxonomy) in a function hooked to the 'init' action as usual.
The user will have access to an option to enable languages and translations for the custom post type (or taxonomy) in the Polylang settings. You can however use the 'pll_get_post_types' or 'pll_get_taxonomies' filters to get full control on this.
How to query content in a different language than the current one?
Polylang does set the language of the theme based on the main query, but it is possible to query content in a different language. For example, you can display the list of the five most recent French posts on an English page. Your custom query just needs to add the 'lang' parameter.
Example:
12345$posts = get_posts( array(    'post_type' => 'post',    'lang' => 'fr', // use language slug in the query    'showposts' => 5,) );
This 'lang' parameter is not only available for posts but also for terms using the function 'get_terms' and comments using the function 'get_comments'.
How to query multiple languages?
Example:
12345$posts = get_posts( array(    'post_type' => 'post',    'lang' => 'de,fr', // query German and French posts    'showposts' => 5,) );
How to deactivate the current language filter?
Example:
12345$posts = get_posts( array(    'post_type' => 'post',    'lang' => '', // deactivates the Polylang filter    'showposts' => 5,) );
How to display links to posts translations within the loop?
Example:
1234

    $post->ID ) ); ?>

How to load the Polylang API for ajax requests on frontend ?
Polylang should automatically detect AJAX requests on frontend and load the current language. You can optionally set the 'lang' variable (with the language code) in the request (POST or GET) to load a specific language instead of the current language. The variable 'pll_load_front' which was necessary in old versions is useless since v1.4.
When Polylang does load the language?
There are two cases:

The language is set from the content: Polylang needs to defer the language loading and does it in a function hooked to the action 'wp' action with priority 5.
The language code is added to all urls (default): there is no need to defer the language loading and it is done as if Polylang were not active.

Due to the first case, plugin authors should not attempt to translate strings before the 'wp' action has been fired. Polylang provides a new action 'pll_language_defined' which is fired as soon as the language is defined. It works whatever the option chosen by the user to set the language.
How to give access to strings translations to non-administrators?
As the main purpose of the strings translations is to translate options, Polylang checks for the 『manage_options』 capability, which is assigned to administrators by default, to control the access to the strings translations table. You can modify the required capability with the following snippet:
12345add_action( 'admin_menu', function() {    if ( ! current_user_can( 'manage_options' ) && function_exists( 'PLL' ) ) {        add_menu_page( __( 'Strings translations', 'polylang' ), __( 'Languages', 'polylang' ), 'edit_pages', 'mlang_strings', array( PLL(), 'languages_page' ), 'dashicons-translation' );    }} );
Here the capability was changed to 『edit_pages』, which is assigned to administrators and editors by default. See the codex to discover which capability you can use to target other roles.

Is Polylang GDPR compliant?

Is Polylang GDPR compliant?

Since the version 4.9.6, WordPress allows to export personal data. This includes the biographical info. As Polylang and Polylang Pro allow the users to translate their biographical info, the translations are added to the exported data since the version 2.3.6.
None of our plugins collect other personal data.

PHP Constants

PHP Constants

It is possible to change the default way Polylang works by setting some options in wp-config.php. You can add a line such as:
1define('OPTION', false);
above the comment:
/* That』s all, stop editing! Happy publishing. */
Alternatively, it is possible to create a file named 『pll-config.php』 in the directory 『/wp-content/polylang/』 (you have to create the directory too) and set the options in this file instead of 『wp-config.php.』
PLL_FILTER_HOME_URL
Defaults to true.
This option allows Polylang to return the url of the homepage in the right language instead of the default homepage. Although the feature allows Polylang working with a lot of themes without any modification, it may break some themes. If you set it to false, you will need to modify your theme and replace calls to home_url(), home_url(『/』), bloginfo(『url』), get_bloginfo(『url』) by pll_home_url() if you want a link to the homepage in the right language.
PLL_SEARCH_FORM_JS
Defaults to true.
Prior to WordPress 3.6, adds javascript code to modify the search form when using default permalinks.
PLL_MEDIA_SUPPORT (deprecated)
Removed in v1.0 as it is now useless. Use the corresponding option in Polylang settings instead.
PLL_COOKIE
Defaults to 『pll_language』.
Defines the name of the cookie used by Polylang to store the visitor』s language.
When PLL_COOKIE is set to false, Polylang does not set any cookie. Be aware that in this case, not everything will work correctly. For example, the login page will not translate.
PLL_WPML_COMPAT
Defaults to true.
Wether to load the WPML API.
PLL_PLUGINS_COMPAT
Defaults to true.
Wether to load support of some 3rd party plugins. Currently concerns WordPress SEO by Yoast, YARPP, Custom field template, Jetpack (infinite scroll)
PLL_WIDGET_CALENDAR
Defaults to true.
Wether to load the calendar widget modified by Polylang.
PLL_AUTO_TRANSLATE
Defaults to true.
Some themes query a specific category for a specific usage (such as a slider). By default Polylang automatically queries the translation of this specific category when it exists. The option allows to enable / disable the feature.
PLL_CACHE_HOME_URL
Defaults to true.
By default, Polylang caches the urls of homepages in all languages. This is not compatible with websites accessible from more than one domain (as only one domain is cached). The option allows to disable the cache and thus make Polylang compatible with multiple domains.
PLL_ENCODED_FLAGS
Defaults to true.
By default, Polylang encodes the flags (only those provided with the plugin) directly in the html request instead of linking to image files. This is nice for performances as it avoids one http request per flag, but is no compatible with Internet Explorer 6 & 7. The option allows to disable the flags encoding for websites needing to be compatible with these old browsers.

How to translate emails?

How to translate emails?

Since the version 4.7, WordPress introduced the function switch_to_locale(). This function unloads all translations in the previous locale and loads the translations of WordPress in the new locale passed as argument. WordPress uses this function to send emails in the user language, for example, the new user notification email. Once the email is sent, the previous locale is restored with restore_previous_locale().
It』s however important to know that these functions don』t load the theme or plugins translations. This is why the plugins and themes need to load their own translations with load_plugin_textdomain() or load_theme_textdomain(). This should be done just after the call to switch_to_locale(). Alternatively, it』s possible to hook to the action change_locale fired each time switch_to_locale() and restore_previous_locale().
Step 1: Get the locale the email must be sent – possibly with get_user_locale() which returns the locale set in the user profile.
Step 2: Call switch_to_locale() .
Step 3: Call load_plugin_textdomain to load your plugin』s translations if you did not hook to change_locale.
Step 4: Construct and send the email, using usual internationalization functions such as __().
Step 5: Call restore_previous_locale()
Step 6: Call load_plugin_textdomain to load your plugin』s translations if you did not hook to change_locale.
See also the post about locale switching on Make WordPress Core.