jjgrainger / PostTypes

Simple WordPress custom post types.
https://posttypes.jjgrainger.co.uk/
MIT License
373 stars 47 forks source link

Add translation support with textdomains #69

Closed dweipert-3138720606 closed 2 years ago

dweipert-3138720606 commented 3 years ago

In light of https://github.com/jjgrainger/PostTypes/issues/66 and having a similar issue, I was thinking how to add translation support to the library. So I've extended the PostType in one of my projects to add translation support with loading a textdomain.

https://developer.wordpress.org/reference/functions/load_textdomain/

PostType.php

class PostType extends \PostTypes\PostType
{
    // I don't know whether we'd have to introduce that many new properties.
    // It's just what I came up with for now
    public string $textdomain = '';
    public string $textdomainDir;
    public string $textdomainFile;
    public static $defaultTextdomain = 'PostTypes/PostType';

    public function textdomain($textdomain, $textdomainDir, $textdomainFile = '')
    {
        $this->textdomain = $textdomain;
        $this->textdomainDir = $textdomainDir;
        $this->textdomainFile = $textdomainFile ?: get_locale() . '.mo';

        return $this;
    }

    public function register()
    {
        add_action('init', [$this, 'loadTextdomain']);
        parent::register();
    }

    public function loadTextdomain()
    {
        // loading the default textdomain loads all the string below in "createLabels".
        // we'd have to add the translations to the project then to provide those as translated defaults
        load_textdomain(self::$defaultTextdomain, dirname(__DIR__) . '/languages/' . get_locale() . '.mo');

        if (! empty($this->textdomain)) {
            load_textdomain($this->textdomain, trailingslashit($this->textdomainDir) . $this->textdomainFile);
        }
    }

    public function createLabels()
    {
        // the singular and plural names have to be translated by the plugin's author but
        // we can provide default translations for "Add New" and the other labels if we use sprintf
        return array_replace_recursive([
            'name'               => __($this->plural, $this->textdomain),
            'singular_name'      => __($this->singular, $this->textdomain),
            'menu_name'          => __($this->plural, $this->textdomain),
            'all_items'          => __($this->plural, $this->textdomain),
            'add_new'            => __('Add New', self::$defaultTextdomain),
            'add_new_item'       => sprintf(__('Add New %s', self::$defaultTextdomain), __($this->singular, $this->textdomain)),
            'edit_item'          => sprintf(__('Edit %s', self::$defaultTextdomain), __($this->singular, $this->textdomain)),
            'new_item'           => sprintf(__('New %s', self::$defaultTextdomain), __($this->singular, $this->textdomain)),
            'view_item'          => sprintf(__('View %s', self::$defaultTextdomain), __($this->singular, $this->textdomain)),
            'search_items'       => sprintf(__('Search %s', self::$defaultTextdomain), $this->plural, $this->textdomain),
            'not_found'          => sprintf(__('No %s found', self::$defaultTextdomain), __($this->plural, $this->textdomain)),
            'not_found_in_trash' => sprintf(__('No %s found in Trash', self::$defaultTextdomain), __($this->plural, $this->textdomain)),
            'parent_item_colon'  => sprintf(__('Parent %s:', self::$defaultTextdomain), __($this->singular, $this->textdomain)),
        ], $this->labels);
    }
}

index.php

$books = (new PostType('books'))
    ->textdomain('books', dirname(__DIR__) . '/languages');

# You have to load textdomains manually before using the translation function
# so you'd have to do something like this to add a custom label with the "labels" function to translate it
# since the loading of the textdomain is done in the "register" function.
# But I guess it might as well be loaded when calling
# ->textdomain('books', ...)
$books->loadTextdomain();
$books->labels(['name' => __($books->singular, $books->textdomain)]);

$books->register();

What do you think?

jjgrainger commented 2 years ago

Thanks @DRogueRonin

This was similar to an approach PostTypes used in earlier version but was dropped based on the WordPress Documentation. It advises not to pass a variable names or constants for the text domain parameter in gettext functions. I believe this is because it can interfere in automatic parsing of your plugin/theme’s files for translation.

When using PostTypes it's recommended to follow the WordPress guidance and use a directly passed string literal. This is noted in the full documentation.

I am aware there are some issues to fix within the code to make translations better and looking to resolve those soon.

However, I think the example you've provided is a great to show how to extend PostTypes and implement that translation solution if it works for your project.

Many thanks!