Plugin Directory

Changeset 3478054


Ignore:
Timestamp:
03/09/2026 12:13:50 PM (4 weeks ago)
Author:
nakedcatplugins
Message:

Update to version 3.0 from GitHub

Location:
lang-attribute-blocks
Files:
8 added
2 deleted
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • lang-attribute-blocks/tags/3.0/build/index.asset.php

    r3337921 r3478054  
    1 <?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-hooks', 'wp-i18n'), 'version' => '4f65e3d03de63b85e0a0');
     1<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-hooks', 'wp-i18n', 'wp-plugins'), 'version' => '4c50b3542257c21dfef2');
  • lang-attribute-blocks/tags/3.0/build/index.css

    r3337921 r3478054  
    1 :root{--nakedcatplugins-lang-attr-highlight-color:rgba(255,0,0,.75)}.editor-styles-wrapper .naked-cat-plugins-has-lang-attr,body:not(.block-editor-page) [lang]{outline:3px dashed var(--nakedcatplugins-lang-attr-highlight-color)!important;outline-offset:2px}
     1:root{--nakedcatplugins-lang-attr-highlight-color:rgba(255,0,0,.65)}.editor-styles-wrapper .naked-cat-plugins-has-lang-attr,body:not(.block-editor-page) [lang]{outline:3px dashed var(--nakedcatplugins-lang-attr-highlight-color)!important;outline-offset:2px}html.naked-cat-plugins-post-has-lang-attr{outline:3px dashed var(--nakedcatplugins-lang-attr-highlight-color)!important;outline-offset:-3px}
  • lang-attribute-blocks/tags/3.0/build/index.js

    r3337921 r3478054  
    1 (()=>{"use strict";const t=window.React,e=window.wp.i18n,a=window.wp.blockEditor,n=window.wp.components,l=window.wp.compose,i=window.wp.hooks,o=(0,l.createHigherOrderComponent)((l=>i=>{if(window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(i.name))return(0,t.createElement)(l,{...i});const{attributes:o,setAttributes:r}=i,s=o.lang||"",d=o.dir||"ltr";return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(l,{...i}),(0,t.createElement)(a.InspectorControls,null,(0,t.createElement)(n.PanelBody,{title:(0,e.__)("Language Settings","lang-attribute-blocks"),initialOpen:!0},(0,t.createElement)(n.TextControl,{label:(0,e.__)("Language Code","lang-attribute-blocks"),value:s,onChange:t=>r({lang:t}),placeholder:window.nakedCatPluginsLangAttributeBlocks?.placeholderText||"en (default website language)",help:(0,e.__)("Valid language code, like “fr” or “pt-PT”, if different from the website main language (shown as a placeholder)","lang-attribute-blocks")}),(0,t.createElement)(n.SelectControl,{label:(0,e.__)("Text Direction","lang-attribute-blocks"),value:d,options:[{label:(0,e.__)("Left to right","lang-attribute-blocks"),value:"ltr"},{label:(0,e.__)("Right to left","lang-attribute-blocks"),value:"rtl"}],onChange:t=>r({dir:t})}))))}),"addLangAttributesToGroupBlock");(0,i.addFilter)("editor.BlockEdit","lang-attribute-blocks/add-lang-attributes-to-group-block",o);const r=(0,l.createHigherOrderComponent)((e=>a=>window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(a.block.name)?(0,t.createElement)(e,{...a}):a.block.attributes.lang&&""!==a.block.attributes.lang.trim()?(0,t.createElement)(e,{...a,className:"naked-cat-plugins-has-lang-attr"}):(0,t.createElement)(e,{...a})),"withLangAttr");(0,i.addFilter)("blocks.registerBlockType","lang-attribute-blocks/add-lang-and-dir-attributes",(function(t,e){return window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(e)&&(t.attributes={...t.attributes,lang:{type:"string",default:""},dir:{type:"string",default:"ltr"}}),t})),window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.highlightEnabled&&(0,i.addFilter)("editor.BlockListBlock","lang-attribute-blocks/add-lang-and-dir-attributes",r)})();
     1(()=>{"use strict";const t=window.React,e=window.wp.i18n,a=window.wp.blockEditor,l=window.wp.components,n=window.wp.compose,i=window.wp.hooks,o=window.wp.plugins,r=window.wp.editor,s=window.wp.coreData,g=window.wp.data,u=(0,n.createHigherOrderComponent)((n=>i=>{if(window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(i.name))return(0,t.createElement)(n,{...i});const{attributes:o,setAttributes:r}=i,s=(o.lang||"").trim(),g=o.dir||"ltr";return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(n,{...i}),(0,t.createElement)(a.InspectorControls,null,(0,t.createElement)(l.PanelBody,{title:(0,e.__)("Block Language","lang-attribute-blocks"),initialOpen:!0},(0,t.createElement)(l.TextControl,{label:(0,e.__)("Language Code","lang-attribute-blocks"),value:s,onChange:t=>r({lang:t.trim()}),placeholder:window.nakedCatPluginsLangAttributeBlocks?.placeholderText||"en (default website language)",help:(0,e.__)("Valid language code for this block, like “fr” or “pt-PT”, if different from the website's or page's main language (shown as a placeholder)","lang-attribute-blocks")}),(0,t.createElement)(l.SelectControl,{label:(0,e.__)("Text Direction","lang-attribute-blocks"),value:g,options:[{label:(0,e.__)("Left to right","lang-attribute-blocks"),value:"ltr"},{label:(0,e.__)("Right to left","lang-attribute-blocks"),value:"rtl"}],onChange:t=>r({dir:t})}))))}),"addLangAttributesToGroupBlock");(0,i.addFilter)("editor.BlockEdit","lang-attribute-blocks/add-lang-attributes-to-group-block",u);const d=(0,n.createHigherOrderComponent)((e=>a=>window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(a.block.name)?(0,t.createElement)(e,{...a}):a.block.attributes.lang&&""!==a.block.attributes.lang.trim()?(0,t.createElement)(e,{...a,className:"naked-cat-plugins-has-lang-attr"}):(0,t.createElement)(e,{...a})),"withLangAttr");(0,i.addFilter)("blocks.registerBlockType","lang-attribute-blocks/add-lang-and-dir-attributes",(function(t,e){return window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(e)&&(t.attributes={...t.attributes,lang:{type:"string",default:""},dir:{type:"string",default:"ltr"}}),t})),window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.highlightEnabled&&(0,i.addFilter)("editor.BlockListBlock","lang-attribute-blocks/add-lang-and-dir-attributes",d),(0,o.registerPlugin)("nakedcatplugins-page-lang-controls",{render:()=>{var a,n;const i=(0,g.useSelect)((t=>t("core/editor").getCurrentPostType()),[]),[o,u]=(0,s.useEntityProp)("postType",i,"meta"),d=(null!==(a=o?._nakedcatplugins_page_lang)&&void 0!==a?a:"").trim(),c=null!==(n=o?._nakedcatplugins_page_dir)&&void 0!==n?n:"ltr";return(0,t.createElement)(r.PluginDocumentSettingPanel,{name:"nakedcatplugins-page-lang-panel",title:(0,e.__)("Page Language","lang-attribute-blocks")},(0,t.createElement)(l.TextControl,{label:(0,e.__)("Language Code","lang-attribute-blocks"),value:d,onChange:t=>u({...o,_nakedcatplugins_page_lang:t.trim()}),placeholder:window.nakedCatPluginsLangAttributeBlocks?.placeholderText||"en (default website language)",help:(0,e.__)("Valid language code for this page/post, like “fr” or “pt-PT”, if different from the website's main language (shown as a placeholder) - This overrides the HTML language attribute","lang-attribute-blocks")}),(0,t.createElement)(l.SelectControl,{label:(0,e.__)("Text Direction","lang-attribute-blocks"),value:c,options:[{label:(0,e.__)("Left to right","lang-attribute-blocks"),value:"ltr"},{label:(0,e.__)("Right to left","lang-attribute-blocks"),value:"rtl"}],onChange:t=>u({...o,_nakedcatplugins_page_dir:t})}))}})})();
  • lang-attribute-blocks/tags/3.0/includes/class-lang-attribute-blocks.php

    r3342031 r3478054  
    11<?php
    22/**
    3  * Main plugin class for Language Attribute for Container Blocks
     3 * Main plugin class for Language Attribute for Container Blocks and Pages/Posts
    44 *
    55 * This file contains the core functionality for adding language and direction
     
    136136            add_filter( 'render_block_' . $block_name, array( $this, 'process_blocks' ), 10, 2 );
    137137        }
     138        // Register post meta for page-level language settings
     139        add_action( 'init', array( $this, 'register_page_lang_meta' ) );
     140        // Apply page-level language attribute to the <html> element
     141        add_filter( 'language_attributes', array( $this, 'apply_page_lang_attribute' ) );
    138142        // Enqueues JavaScript and CSS assets for the WordPress block editor
    139143        add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
     
    144148        // Add settings link to the plugin action links
    145149        add_filter( 'plugin_action_links_' . plugin_basename( NAKEDCATPLUGINS_LANG_ATTRIBUTE_BLOCKS_FILE ), array( $this, 'add_plugin_action_links' ) );
     150        // Add classic editor metabox for page-level language settings
     151        add_action( 'add_meta_boxes', array( $this, 'add_classic_editor_metabox' ) );
     152        add_action( 'save_post', array( $this, 'save_classic_editor_metabox' ), 10, 2 );
     153    }
     154
     155    /**
     156     * Register post meta fields for page-level language settings.
     157     *
     158     * Registers '_nakedcatplugins_page_lang' and '_nakedcatplugins_page_dir' meta
     159     * for all public post types, exposed via the REST API so the block editor
     160     * can read and write them.
     161     *
     162     * @since 3.0
     163     * @hook init
     164     * @return void
     165     */
     166    public function register_page_lang_meta() {
     167        $args_lang = array(
     168            'show_in_rest'  => true,
     169            'single'        => true,
     170            'type'          => 'string',
     171            'default'       => '',
     172            'auth_callback' => function () {
     173                return current_user_can( 'edit_posts' );
     174            },
     175        );
     176        $args_dir  = array(
     177            'show_in_rest'  => true,
     178            'single'        => true,
     179            'type'          => 'string',
     180            'default'       => 'ltr',
     181            'auth_callback' => function () {
     182                return current_user_can( 'edit_posts' );
     183            },
     184        );
     185        // Register for all public post types
     186        foreach ( get_post_types( array( 'public' => true ) ) as $post_type ) {
     187            register_post_meta( $post_type, '_nakedcatplugins_page_lang', $args_lang );
     188            register_post_meta( $post_type, '_nakedcatplugins_page_dir', $args_dir );
     189        }
     190    }
     191
     192    /**
     193     * Override the HTML lang (and optionally dir) attribute for singular pages/posts.
     194     *
     195     * When a page or post has the '_nakedcatplugins_page_lang' meta set, this method
     196     * replaces the lang attribute on the <html> element with the stored value.
     197     * When '_nakedcatplugins_page_dir' is set to 'rtl', the dir attribute is also applied.
     198     *
     199     * @since 3.0
     200     * @hook language_attributes
     201     * @param string $output The existing language attributes string, e.g. 'lang="en-US"'.
     202     * @return string Modified language attributes string.
     203     */
     204    public function apply_page_lang_attribute( $output ) {
     205        if ( ! is_singular() ) {
     206            return $output;
     207        }
     208        $post_id   = get_queried_object_id();
     209        $page_lang = trim( get_post_meta( $post_id, '_nakedcatplugins_page_lang', true ) );
     210        $page_dir  = trim( get_post_meta( $post_id, '_nakedcatplugins_page_dir', true ) );
     211
     212        if ( ! empty( $page_lang ) ) {
     213            $safe_lang = esc_attr( $page_lang );
     214            if ( strpos( $output, 'lang=' ) !== false ) {
     215                $output = preg_replace( '/lang="[^"]*"/', 'lang="' . $safe_lang . '"', $output );
     216            } else {
     217                $output .= ' lang="' . $safe_lang . '"';
     218            }
     219            // Add our class name
     220            if ( strpos( $output, 'class=' ) !== false ) {
     221                $output = preg_replace( '/class="([^"]*)"/', 'class="$1 naked-cat-plugins-post-has-lang-attr"', $output );
     222            } else {
     223                $output .= ' class="naked-cat-plugins-post-has-lang-attr"';
     224            }
     225        }
     226
     227        if ( ! empty( $page_dir ) && 'rtl' === $page_dir ) {
     228            $safe_dir = esc_attr( $page_dir );
     229            if ( strpos( $output, 'dir=' ) !== false ) {
     230                $output = preg_replace( '/dir="[^"]*"/', 'dir="' . $safe_dir . '"', $output );
     231            } else {
     232                $output .= ' dir="' . $safe_dir . '"';
     233            }
     234        }
     235
     236        return $output;
    146237    }
    147238
     
    196287    public function process_blocks( $block_content, $block ) {
    197288        if ( isset( $block['attrs']['lang'] ) && ! empty( $block['attrs']['lang'] ) ) {
    198             $lang          = esc_attr( $block['attrs']['lang'] );
    199             $dir           = isset( $block['attrs']['dir'] ) ? esc_attr( $block['attrs']['dir'] ) : 'ltr';
     289            $lang          = trim( esc_attr( $block['attrs']['lang'] ) );
     290            $dir           = trim( isset( $block['attrs']['dir'] ) ? esc_attr( $block['attrs']['dir'] ) : 'ltr' );
    200291            $tag_processor = new \WP_HTML_Tag_Processor( $block_content );
    201292            // Depending on the block type, we will set the tag to be processed
     
    251342            'nakedcatplugins-lang-attribute-blocks-script',
    252343            plugins_url( 'build/index.js', NAKEDCATPLUGINS_LANG_ATTRIBUTE_BLOCKS_FILE ),
    253             array( 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post', 'wp-element', 'wp-i18n', 'wp-block-editor' ),
     344            array( 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-block-editor', 'wp-plugins', 'wp-data', 'wp-core-data' ),
    254345            filemtime( plugin_dir_path( NAKEDCATPLUGINS_LANG_ATTRIBUTE_BLOCKS_FILE ) . 'build/index.js' ),
    255346            true
     
    361452        add_settings_section(
    362453            'nakedcatplugins_lang_attr_section',
    363             __( 'Language Attribute for Container Blocks', 'lang-attribute-blocks' ),
     454            __( 'Language Attribute for Container Blocks and Pages/Posts', 'lang-attribute-blocks' ),
    364455            array( $this, 'settings_section_callback' ),
    365456            'writing'
     
    383474     */
    384475    public function settings_section_callback() {
    385         echo '<p>' . esc_html__( 'Configure Language Attribute for Container Blocks plugin settings.', 'lang-attribute-blocks' ) . '</p>';
     476        echo '<p>' . esc_html__( 'Configure Language Attribute for Container Blocks and Pages/Posts plugin settings.', 'lang-attribute-blocks' ) . '</p>';
    386477    }
    387478    /**
     
    405496
    406497    /**
     498     * Register the page language metabox for the classic editor.
     499     *
     500     * Added to all public post types so editors can set the page-level
     501     * lang and dir meta without the block editor.
     502     *
     503     * @since 3.0
     504     * @hook add_meta_boxes
     505     * @return void
     506     */
     507    public function add_classic_editor_metabox() {
     508        // Only register the metabox in the classic editor; the block editor
     509        // provides its own Document Settings panel for the same fields.
     510        $screen = get_current_screen();
     511        if ( $screen && $screen->is_block_editor() ) {
     512            return;
     513        }
     514
     515        foreach ( get_post_types( array( 'public' => true ), 'names' ) as $post_type ) {
     516            add_meta_box(
     517                'nakedcatplugins_page_language',
     518                __( 'Page Language', 'lang-attribute-blocks' ),
     519                array( $this, 'render_classic_editor_metabox' ),
     520                $post_type,
     521                'side',
     522                'default'
     523            );
     524        }
     525    }
     526
     527    /**
     528     * Render the classic editor metabox HTML.
     529     *
     530     * @since 3.0
     531     * @param \WP_Post $post The current post object.
     532     * @return void
     533     */
     534    public function render_classic_editor_metabox( \WP_Post $post ) {
     535        $lang = trim( get_post_meta( $post->ID, '_nakedcatplugins_page_lang', true ) );
     536        $dir  = trim( get_post_meta( $post->ID, '_nakedcatplugins_page_dir', true ) );
     537        if ( empty( $dir ) ) {
     538            $dir = 'ltr';
     539        }
     540
     541        wp_nonce_field( 'nakedcatplugins_page_language_metabox', 'nakedcatplugins_page_language_nonce' );
     542        $placeholder = sprintf(
     543            /* translators: %s: The website's default language code */
     544            __( '%s (default website language)', 'lang-attribute-blocks' ),
     545            get_bloginfo( 'language' )
     546        );
     547        ?>
     548        <p>
     549            <label for="nakedcatplugins_page_lang">
     550                <?php esc_html_e( 'Language Code', 'lang-attribute-blocks' ); ?>
     551            </label>
     552            <input type="text" id="nakedcatplugins_page_lang" name="nakedcatplugins_page_lang" value="<?php echo esc_attr( $lang ); ?>" placeholder="<?php echo esc_attr( $placeholder ); ?>" class="widefat"/>
     553            <span class="description">
     554                <?php esc_html_e( "Valid language code for this page/post, like “fr” or “pt-PT”, if different from the website's main language (shown as a placeholder) - This overrides the HTML language attribute", 'lang-attribute-blocks' ); ?>
     555            </span>
     556        </p>
     557        <p>
     558            <label for="nakedcatplugins_page_dir">
     559                <?php esc_html_e( 'Text Direction', 'lang-attribute-blocks' ); ?>
     560            </label>
     561            <select id="nakedcatplugins_page_dir" name="nakedcatplugins_page_dir" class="widefat">
     562                <option value="ltr" <?php selected( $dir, 'ltr' ); ?>>
     563                    <?php esc_html_e( 'Left to right', 'lang-attribute-blocks' ); ?>
     564                </option>
     565                <option value="rtl" <?php selected( $dir, 'rtl' ); ?>>
     566                    <?php esc_html_e( 'Right to left', 'lang-attribute-blocks' ); ?>
     567                </option>
     568            </select>
     569        </p>
     570        <?php
     571    }
     572
     573    /**
     574     * Save the classic editor metabox values.
     575     *
     576     * Validates the nonce to confirm the metabox was present in the form
     577     * (guards against quick edit, bulk actions, REST and programmatic saves
     578     * that would otherwise wipe the meta), checks capabilities, then saves
     579     * or deletes the page language meta fields.
     580     *
     581     * @since 3.0
     582     * @hook save_post
     583     * @param int      $post_id The post ID being saved.
     584     * @param \WP_Post $post    The post object being saved.
     585     * @return void
     586     */
     587    public function save_classic_editor_metabox( int $post_id, \WP_Post $post ) {
     588        // If our metabox was not present in the request, bail out to avoid
     589        // accidentally wiping the meta (e.g. quick edit, REST, wp_update_post()).
     590        if ( ! isset( $_POST['nakedcatplugins_page_language_nonce'] ) ) {
     591            return;
     592        }
     593
     594        // WordPress has already verified the post nonce, but we verify our own
     595        // as extra confirmation that our metabox submitted these values.
     596        if ( ! wp_verify_nonce( sanitize_key( $_POST['nakedcatplugins_page_language_nonce'] ), 'nakedcatplugins_page_language_metabox' ) ) {
     597            return;
     598        }
     599
     600        // Bail on autosave and revisions.
     601        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
     602            return;
     603        }
     604        if ( wp_is_post_revision( $post_id ) ) {
     605            return;
     606        }
     607
     608        // Check the user has permission to edit this specific post.
     609        $post_type_object = get_post_type_object( $post->post_type );
     610        if ( ! current_user_can( $post_type_object->cap->edit_post, $post_id ) ) {
     611            return;
     612        }
     613
     614        // Save lang — trim and sanitize; delete if empty so the DB stays clean.
     615        if ( isset( $_POST['nakedcatplugins_page_lang'] ) ) {
     616            $lang = trim( sanitize_text_field( wp_unslash( $_POST['nakedcatplugins_page_lang'] ) ) );
     617            if ( ! empty( $lang ) ) {
     618                update_post_meta( $post_id, '_nakedcatplugins_page_lang', $lang );
     619            } else {
     620                delete_post_meta( $post_id, '_nakedcatplugins_page_lang' );
     621                delete_post_meta( $post_id, '_nakedcatplugins_page_dir' );
     622                return; // If lang is empty, we also delete dir and skip saving it since it doesn't make sense to have a dir without a lang.
     623            }
     624        }
     625
     626        // Save dir — whitelist to known values only.
     627        if ( isset( $_POST['nakedcatplugins_page_dir'] ) ) {
     628            $dir = sanitize_text_field( wp_unslash( $_POST['nakedcatplugins_page_dir'] ) );
     629            $dir = in_array( $dir, array( 'ltr', 'rtl' ), true ) ? $dir : 'ltr';
     630            update_post_meta( $post_id, '_nakedcatplugins_page_dir', $dir );
     631        }
     632    }
     633
     634    /**
    407635     * Add settings link to the plugin action links.
    408636     *
    409637     * This function adds a "Settings" link to the plugin's row on the Plugins page
    410      * that points to the Language Attribute for Container Blocks settings section
     638     * that points to the Language Attribute for Container Blocks and Pages/Posts settings section
    411639     * on the Settings > Writing page.
    412640     *
  • lang-attribute-blocks/tags/3.0/lang-attribute-blocks.php

    r3381456 r3478054  
    11<?php
    22/**
    3  * Plugin Name:          Language Attribute for Container Blocks
     3 * Plugin Name:          Language Attribute for Container Blocks and Pages/Posts
    44 * Plugin URI:
    5  * Description:          Add “lang” and “dir” attributes on Group, Columns, and Cover WordPress Blocks
    6  * Version:              2.2
     5 * Description:          Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, or to the whole page/post.
     6 * Version:              3.0
    77 * Author:               Naked Cat Plugins (by Webdados)
    88 * Author URI:           https://nakedcatplugins.com
    99 * Text Domain:          lang-attribute-blocks
    1010 * Requires at least:    5.9
    11  * Tested up to:         6.9
     11 * Tested up to:         7.0
    1212 * Requires PHP:         7.2
    1313 * License:              GPLv3
  • lang-attribute-blocks/tags/3.0/languages/lang-attribute-blocks.pot

    r3381456 r3478054  
    1 # Copyright (C) 2025 Naked Cat Plugins (by Webdados)
     1# Copyright (C) 2026 Naked Cat Plugins (by Webdados)
    22# This file is distributed under the GPLv3.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Language Attribute for Container Blocks 2.2\n"
     5"Project-Id-Version: Language Attribute for Container Blocks and Pages/Posts 2.2\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/lang-attribute-blocks\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-10-20T16:43:04+00:00\n"
     12"POT-Creation-Date: 2026-03-09T12:04:28+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.11.0\n"
     
    1717#. Plugin Name of the plugin
    1818#: lang-attribute-blocks.php
    19 #: includes/class-lang-attribute-blocks.php:363
    20 msgid "Language Attribute for Container Blocks"
     19#: includes/class-lang-attribute-blocks.php:454
     20msgid "Language Attribute for Container Blocks and Pages/Posts"
    2121msgstr ""
    2222
    2323#. Description of the plugin
    2424#: lang-attribute-blocks.php
    25 msgid "Add “lang” and “dir” attributes on Group, Columns, and Cover WordPress Blocks"
     25msgid "Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, or to the whole page/post."
    2626msgstr ""
    2727
     
    3737
    3838#. translators: %s: The website's default language code
    39 #: includes/class-lang-attribute-blocks.php:268
     39#: includes/class-lang-attribute-blocks.php:359
     40#: includes/class-lang-attribute-blocks.php:544
    4041msgid "%s (default website language)"
    4142msgstr ""
    4243
    43 #: includes/class-lang-attribute-blocks.php:371
     44#: includes/class-lang-attribute-blocks.php:462
    4445msgid "Highlight blocks with lang attribute"
    4546msgstr ""
    4647
    47 #: includes/class-lang-attribute-blocks.php:385
    48 msgid "Configure Language Attribute for Container Blocks plugin settings."
     48#: includes/class-lang-attribute-blocks.php:476
     49msgid "Configure Language Attribute for Container Blocks and Pages/Posts plugin settings."
    4950msgstr ""
    5051
    51 #: includes/class-lang-attribute-blocks.php:398
     52#: includes/class-lang-attribute-blocks.php:489
    5253msgid "Show visual outline around blocks that have a language attribute set"
    5354msgstr ""
    5455
    55 #: includes/class-lang-attribute-blocks.php:401
     56#: includes/class-lang-attribute-blocks.php:492
    5657msgid "When enabled, blocks with a language attribute will be visually highlighted with a red dashed outline in both the editor and frontend (only for Administrators and Editors)."
    5758msgstr ""
    5859
    59 #: includes/class-lang-attribute-blocks.php:421
     60#: includes/class-lang-attribute-blocks.php:518
     61#: build/index.js:1
     62#: src/index.js:165
     63msgid "Page Language"
     64msgstr ""
     65
     66#: includes/class-lang-attribute-blocks.php:550
     67#: build/index.js:1
     68#: src/index.js:49
     69#: src/index.js:168
     70msgid "Language Code"
     71msgstr ""
     72
     73#: includes/class-lang-attribute-blocks.php:554
     74#: build/index.js:1
     75#: src/index.js:172
     76msgid "Valid language code for this page/post, like “fr” or “pt-PT”, if different from the website's main language (shown as a placeholder) - This overrides the HTML language attribute"
     77msgstr ""
     78
     79#: includes/class-lang-attribute-blocks.php:559
     80#: build/index.js:1
     81#: src/index.js:56
     82#: src/index.js:175
     83msgid "Text Direction"
     84msgstr ""
     85
     86#: includes/class-lang-attribute-blocks.php:563
     87#: build/index.js:1
     88#: src/index.js:59
     89#: src/index.js:178
     90msgid "Left to right"
     91msgstr ""
     92
     93#: includes/class-lang-attribute-blocks.php:566
     94#: build/index.js:1
     95#: src/index.js:60
     96#: src/index.js:179
     97msgid "Right to left"
     98msgstr ""
     99
     100#: includes/class-lang-attribute-blocks.php:649
    60101msgid "Settings"
    61102msgstr ""
    62103
    63 #: assets/index.js:41
    64104#: build/index.js:1
    65 msgid "Language Settings"
     105#: src/index.js:45
     106msgid "Block Language"
    66107msgstr ""
    67108
    68 #: assets/index.js:45
    69109#: build/index.js:1
    70 msgid "Language Code"
     110#: src/index.js:53
     111msgid "Valid language code for this block, like “fr” or “pt-PT”, if different from the website's or page's main language (shown as a placeholder)"
    71112msgstr ""
    72 
    73 #: assets/index.js:49
    74 #: build/index.js:1
    75 msgid "Valid language code, like “fr” or “pt-PT”, if different from the website main language (shown as a placeholder)"
    76 msgstr ""
    77 
    78 #: assets/index.js:52
    79 #: build/index.js:1
    80 msgid "Text Direction"
    81 msgstr ""
    82 
    83 #: assets/index.js:55
    84 #: build/index.js:1
    85 msgid "Left to right"
    86 msgstr ""
    87 
    88 #: assets/index.js:56
    89 #: build/index.js:1
    90 msgid "Right to left"
    91 msgstr ""
  • lang-attribute-blocks/tags/3.0/readme.txt

    r3381456 r3478054  
    1 === Language Attribute for Container Blocks ===
     1=== Language Attribute for Container Blocks and Pages/Posts ===
    22Contributors: nakedcatplugins, webdados
    3 Tags: language, accessibility, block editor
     3Tags: language, accessibility, block editor, gutenberg, classic editor
    44Requires at least: 5.9
    5 Tested up to: 6.9
     5Tested up to: 7.0
    66Requires PHP: 7.2
    7 Stable tag: 2.2
     7Stable tag: 3.0
    88License: GPLv3
    99License URI: https://www.gnu.org/licenses/gpl-3.0.html
    1010
    11 Add “lang” and “dir” attributes to Group, Columns, Cover, and other specific WordPress Blocks.
     11Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, or to the whole page/post.
    1212
    1313== Description ==
    1414
    15 This plugin aims to provide a way to ensure that any language change in the content of a page is indicated to assistive technologies at the container block level, helping a website comply with WCAG guidelines.
     15This plugin aims to ensure that any language change in a page’s content is indicated to assistive technologies at the container block level, helping a website comply with WCAG guidelines.
    1616
    1717This feature is available on the core block editor only at a text formatting level after code from [Jb Audras plugin “Lang Attribute for the Block Editor”](https://wordpress.org/plugins/lang-attribute/) was merged into core. The objective of this plugin is to provide the same functionality at a container block level (Group - including all its variants, Columns, Cover, and other specific block types) so that the language applies to all child elements, no matter the kind of content inside.
    1818
    19 This plugin is heavily inspired by the Jb Audras plugin (including this readme file), and the development started at WordCamp Europe 2025 Contributor Day, by Marco Almeida from [Naked Cat Plugins](https://profiles.wordpress.org/nakedcatplugins/) / [Webdados](https://profiles.wordpress.org/webdados/), and the help from [Ryan Welcher](https://profiles.wordpress.org/welcher/) on the code side and [Amber Hinds](https://profiles.wordpress.org/alh0319/) on the accessibility compliance side.
     19The plugin also supports setting the language at the page or post level, both on the blocks and classic editor. When an entire page is written in a different language than the website’s default, you can override the HTML `lang` and `dir` attributes for that specific page directly from the Document Settings sidebar, without needing to wrap everything in a container block.
    2020
    21 For more context: this plugin helps you to make your website compliant with the Web Content Accessibility Guidelines (WCAG) success criterion 3.1.2: “Language of Parts”. The purpose of this success Criterion is to ensure that user agents can correctly present content written in multiple languages.
     21This plugin is heavily inspired by the Jb Audras plugin (including this readme file). The development started at WordCamp Europe 2025 Contributor Day, by Marco Almeida from [Naked Cat Plugins](https://profiles.wordpress.org/nakedcatplugins/) / [Webdados](https://profiles.wordpress.org/webdados/), and the help from [Ryan Welcher](https://profiles.wordpress.org/welcher/) on the code side and [Amber Hinds](https://profiles.wordpress.org/alh0319/) on the accessibility compliance side.
    2222
    23 Keep in mind that you should only set the lang and dir attributes to a container block if the content you’re going to insert inside it is written in a different language than that set globally on your website.
     23For more context: this plugin helps you to make your website compliant with the Web Content Accessibility Guidelines (WCAG) success criteria:
    2424
    25 As per Web Content Accessibility Guidelines:
     25* **3.1.1 – Language of Page**: The default human language of each web page can be programmatically determined. Use the page-level setting when an entire page or post is written in a language other than the website’s default.
     26* **3.1.2 – Language of Parts**: The human language of each passage or phrase in the content can be programmatically determined. Use the block-level setting when only specific sections within a page are in a different language.
    2627
    27 This makes it possible for user agents and assistive technologies to present content according to the presentation and pronunciation rules for that language. This applies to graphical browsers as well as screen readers, braille displays, and other voice browsers.
     28The purpose of these success criteria is to ensure that user agents can correctly present content written in multiple languages.
    2829
    29 Both assistive technologies and conventional user agents can render text more accurately if the language of each passage of text is identified. Screen readers can use the pronunciation rules of the language of the text. Visual browsers can display characters and scripts in appropriate ways.
     30Keep in mind that you should set the `lang` and `dir` attributes only on a container block or page if the content is written in a language different from the one set globally on your website.
     31
     32**As per Web Content Accessibility Guidelines:**
     33
     34This enables user agents and assistive technologies to present content according to the presentation and pronunciation rules of that language. This applies to graphical browsers, screen readers, braille displays, and other voice browsers.
     35
     36Both assistive technologies and conventional user agents can render text more accurately if the language of each passage of text is identified. Screen readers can use the language’s pronunciation rules. Visual browsers can display characters and scripts appropriately.
    3037
    3138This is especially important when switching between languages that read from left to right and languages that read from right to left, or when text is rendered in a language that uses a different alphabet. Users with disabilities who know all the languages used in the Web page will be better able to understand the content when each passage is rendered appropriately.
     
    3643
    3744== Supported block types ==
     45
    3846* **Group** (`core/group`): Group contents together and set a language for them
    3947* **Columns** (`core/columns` and `core/column`): Organize content into a set of columns and set a language for all the columns or a specific column
     
    4553
    4654== Features ==
    47 * Add “lang” and “dir” attributes to Group, Columns, Cover, and other specific WordPress Blocks
     55
     56* Set the language and text direction for an entire page or post, both on the blocks and classic editor: a “Page Language” panel in the Document Settings sidebar overrides the HTML `lang` and `dir` attributes for that specific page
     57* Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, mentioned above
    4858* Show visual outline around blocks that have a language attribute set - For easy identification of blocks you have already set to a different language during your editing process, only for Administrators and Editors, and if enabled in Settings - Writing
    4959
     
    5161
    52621. Using the block editor to add a language attribute to a Group block
    53 2. The lang and dir attributes rendered on the frontend
     632. The `lang` and `dir attributes rendered on the frontend
    54643. Using the highlighting option during the editing process
    5565
     
    5767
    58681. Install the plugin and activate it.
    59 2. Insert a Group, Columns, Cover (or other specific) block, and use the “Language Settings” sidebar panel to set the language for all the content inside that container
     692. To set the language for an entire page or post: open the Document Settings sidebar (the panel icon at the top right of the editor) and use the “Page Language” panel.
     703. To set the language for a specific section within a page: insert a Group, Columns, Cover (or other specific) block, and use the “Block Language” sidebar panel to set the language for all the content inside that container.
    6071
    6172== Frequently Asked Questions ==
     73
     74= When should I use the page-level language setting instead of a block-level one? =
     75
     76Use the **Page Language** setting (in the Document Settings sidebar) when the entire page or post is written in a different language than the website default. This overrides the `lang` attribute on the HTML element itself, which corresponds to WCAG 3.1.1 (Language of Page).
     77In this case, we also recommend creating a dedicated template in the Site Editor (Appearance → Editor → Templates) where shared template parts — such as the header and footer — are also in that same language.
     78
     79Use the **Block Language** setting (in the block’s sidebar panel) when only a specific section within a page is in a different language, while the rest of the page remains in the site’s default language. This corresponds to WCAG 3.1.2 (Language of Parts).
    6280
    6381= Why not have the option to set the language attribute on all block types? =
     
    7189
    7290If your are working on a WordCamp website, or you don’t want to mess around with PHP, you can also add custom CSS to change the color, overriding our `--nakedcatplugins-lang-attr-highlight-color` variable.
    73 Here’s a [Gist example](https://gist.github.com/webdados/61197dd2e98f399ba2cfeefbac518851).
     91Here’s a [Gist example](https://gist.github.com/webdados/7179f5be4e224ba84867cf77e9bc9174).
    7492
    7593= How can I contribute to this plugin? =
     
    82100
    83101== Changelog ==
     102
     103= 3.0 - 2026-03-09 =
     104* [NEW] Plugin renamed from “Language Attribute for Container Blocks” to “Language Attribute for Container Blocks and Pages/Posts”
     105* [NEW] Set the page/post language at the document level: a new “Page Language” panel in the Document Settings sidebar allows overriding the HTML `lang` and `dir` attributes for a specific page or post, independently of the website’s default language
     106* [TWEAK] Rename “Language Settings” sidebar block panel to “Block Language”
     107* [FIX] Gist URL for changing the highlight color using plain CSS
     108* [DEV] Tested up to 7.0-beta3-61865
    84109
    85110= 2.2 - 2025-10-20 =
  • lang-attribute-blocks/trunk/build/index.asset.php

    r3337921 r3478054  
    1 <?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-hooks', 'wp-i18n'), 'version' => '4f65e3d03de63b85e0a0');
     1<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-hooks', 'wp-i18n', 'wp-plugins'), 'version' => '4c50b3542257c21dfef2');
  • lang-attribute-blocks/trunk/build/index.css

    r3337921 r3478054  
    1 :root{--nakedcatplugins-lang-attr-highlight-color:rgba(255,0,0,.75)}.editor-styles-wrapper .naked-cat-plugins-has-lang-attr,body:not(.block-editor-page) [lang]{outline:3px dashed var(--nakedcatplugins-lang-attr-highlight-color)!important;outline-offset:2px}
     1:root{--nakedcatplugins-lang-attr-highlight-color:rgba(255,0,0,.65)}.editor-styles-wrapper .naked-cat-plugins-has-lang-attr,body:not(.block-editor-page) [lang]{outline:3px dashed var(--nakedcatplugins-lang-attr-highlight-color)!important;outline-offset:2px}html.naked-cat-plugins-post-has-lang-attr{outline:3px dashed var(--nakedcatplugins-lang-attr-highlight-color)!important;outline-offset:-3px}
  • lang-attribute-blocks/trunk/build/index.js

    r3337921 r3478054  
    1 (()=>{"use strict";const t=window.React,e=window.wp.i18n,a=window.wp.blockEditor,n=window.wp.components,l=window.wp.compose,i=window.wp.hooks,o=(0,l.createHigherOrderComponent)((l=>i=>{if(window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(i.name))return(0,t.createElement)(l,{...i});const{attributes:o,setAttributes:r}=i,s=o.lang||"",d=o.dir||"ltr";return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(l,{...i}),(0,t.createElement)(a.InspectorControls,null,(0,t.createElement)(n.PanelBody,{title:(0,e.__)("Language Settings","lang-attribute-blocks"),initialOpen:!0},(0,t.createElement)(n.TextControl,{label:(0,e.__)("Language Code","lang-attribute-blocks"),value:s,onChange:t=>r({lang:t}),placeholder:window.nakedCatPluginsLangAttributeBlocks?.placeholderText||"en (default website language)",help:(0,e.__)("Valid language code, like “fr” or “pt-PT”, if different from the website main language (shown as a placeholder)","lang-attribute-blocks")}),(0,t.createElement)(n.SelectControl,{label:(0,e.__)("Text Direction","lang-attribute-blocks"),value:d,options:[{label:(0,e.__)("Left to right","lang-attribute-blocks"),value:"ltr"},{label:(0,e.__)("Right to left","lang-attribute-blocks"),value:"rtl"}],onChange:t=>r({dir:t})}))))}),"addLangAttributesToGroupBlock");(0,i.addFilter)("editor.BlockEdit","lang-attribute-blocks/add-lang-attributes-to-group-block",o);const r=(0,l.createHigherOrderComponent)((e=>a=>window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(a.block.name)?(0,t.createElement)(e,{...a}):a.block.attributes.lang&&""!==a.block.attributes.lang.trim()?(0,t.createElement)(e,{...a,className:"naked-cat-plugins-has-lang-attr"}):(0,t.createElement)(e,{...a})),"withLangAttr");(0,i.addFilter)("blocks.registerBlockType","lang-attribute-blocks/add-lang-and-dir-attributes",(function(t,e){return window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(e)&&(t.attributes={...t.attributes,lang:{type:"string",default:""},dir:{type:"string",default:"ltr"}}),t})),window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.highlightEnabled&&(0,i.addFilter)("editor.BlockListBlock","lang-attribute-blocks/add-lang-and-dir-attributes",r)})();
     1(()=>{"use strict";const t=window.React,e=window.wp.i18n,a=window.wp.blockEditor,l=window.wp.components,n=window.wp.compose,i=window.wp.hooks,o=window.wp.plugins,r=window.wp.editor,s=window.wp.coreData,g=window.wp.data,u=(0,n.createHigherOrderComponent)((n=>i=>{if(window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(i.name))return(0,t.createElement)(n,{...i});const{attributes:o,setAttributes:r}=i,s=(o.lang||"").trim(),g=o.dir||"ltr";return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(n,{...i}),(0,t.createElement)(a.InspectorControls,null,(0,t.createElement)(l.PanelBody,{title:(0,e.__)("Block Language","lang-attribute-blocks"),initialOpen:!0},(0,t.createElement)(l.TextControl,{label:(0,e.__)("Language Code","lang-attribute-blocks"),value:s,onChange:t=>r({lang:t.trim()}),placeholder:window.nakedCatPluginsLangAttributeBlocks?.placeholderText||"en (default website language)",help:(0,e.__)("Valid language code for this block, like “fr” or “pt-PT”, if different from the website's or page's main language (shown as a placeholder)","lang-attribute-blocks")}),(0,t.createElement)(l.SelectControl,{label:(0,e.__)("Text Direction","lang-attribute-blocks"),value:g,options:[{label:(0,e.__)("Left to right","lang-attribute-blocks"),value:"ltr"},{label:(0,e.__)("Right to left","lang-attribute-blocks"),value:"rtl"}],onChange:t=>r({dir:t})}))))}),"addLangAttributesToGroupBlock");(0,i.addFilter)("editor.BlockEdit","lang-attribute-blocks/add-lang-attributes-to-group-block",u);const d=(0,n.createHigherOrderComponent)((e=>a=>window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&!window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(a.block.name)?(0,t.createElement)(e,{...a}):a.block.attributes.lang&&""!==a.block.attributes.lang.trim()?(0,t.createElement)(e,{...a,className:"naked-cat-plugins-has-lang-attr"}):(0,t.createElement)(e,{...a})),"withLangAttr");(0,i.addFilter)("blocks.registerBlockType","lang-attribute-blocks/add-lang-and-dir-attributes",(function(t,e){return window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks&&window.nakedCatPluginsLangAttributeBlocks.supportedBlocks.includes(e)&&(t.attributes={...t.attributes,lang:{type:"string",default:""},dir:{type:"string",default:"ltr"}}),t})),window.nakedCatPluginsLangAttributeBlocks&&window.nakedCatPluginsLangAttributeBlocks.highlightEnabled&&(0,i.addFilter)("editor.BlockListBlock","lang-attribute-blocks/add-lang-and-dir-attributes",d),(0,o.registerPlugin)("nakedcatplugins-page-lang-controls",{render:()=>{var a,n;const i=(0,g.useSelect)((t=>t("core/editor").getCurrentPostType()),[]),[o,u]=(0,s.useEntityProp)("postType",i,"meta"),d=(null!==(a=o?._nakedcatplugins_page_lang)&&void 0!==a?a:"").trim(),c=null!==(n=o?._nakedcatplugins_page_dir)&&void 0!==n?n:"ltr";return(0,t.createElement)(r.PluginDocumentSettingPanel,{name:"nakedcatplugins-page-lang-panel",title:(0,e.__)("Page Language","lang-attribute-blocks")},(0,t.createElement)(l.TextControl,{label:(0,e.__)("Language Code","lang-attribute-blocks"),value:d,onChange:t=>u({...o,_nakedcatplugins_page_lang:t.trim()}),placeholder:window.nakedCatPluginsLangAttributeBlocks?.placeholderText||"en (default website language)",help:(0,e.__)("Valid language code for this page/post, like “fr” or “pt-PT”, if different from the website's main language (shown as a placeholder) - This overrides the HTML language attribute","lang-attribute-blocks")}),(0,t.createElement)(l.SelectControl,{label:(0,e.__)("Text Direction","lang-attribute-blocks"),value:c,options:[{label:(0,e.__)("Left to right","lang-attribute-blocks"),value:"ltr"},{label:(0,e.__)("Right to left","lang-attribute-blocks"),value:"rtl"}],onChange:t=>u({...o,_nakedcatplugins_page_dir:t})}))}})})();
  • lang-attribute-blocks/trunk/includes/class-lang-attribute-blocks.php

    r3342031 r3478054  
    11<?php
    22/**
    3  * Main plugin class for Language Attribute for Container Blocks
     3 * Main plugin class for Language Attribute for Container Blocks and Pages/Posts
    44 *
    55 * This file contains the core functionality for adding language and direction
     
    136136            add_filter( 'render_block_' . $block_name, array( $this, 'process_blocks' ), 10, 2 );
    137137        }
     138        // Register post meta for page-level language settings
     139        add_action( 'init', array( $this, 'register_page_lang_meta' ) );
     140        // Apply page-level language attribute to the <html> element
     141        add_filter( 'language_attributes', array( $this, 'apply_page_lang_attribute' ) );
    138142        // Enqueues JavaScript and CSS assets for the WordPress block editor
    139143        add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
     
    144148        // Add settings link to the plugin action links
    145149        add_filter( 'plugin_action_links_' . plugin_basename( NAKEDCATPLUGINS_LANG_ATTRIBUTE_BLOCKS_FILE ), array( $this, 'add_plugin_action_links' ) );
     150        // Add classic editor metabox for page-level language settings
     151        add_action( 'add_meta_boxes', array( $this, 'add_classic_editor_metabox' ) );
     152        add_action( 'save_post', array( $this, 'save_classic_editor_metabox' ), 10, 2 );
     153    }
     154
     155    /**
     156     * Register post meta fields for page-level language settings.
     157     *
     158     * Registers '_nakedcatplugins_page_lang' and '_nakedcatplugins_page_dir' meta
     159     * for all public post types, exposed via the REST API so the block editor
     160     * can read and write them.
     161     *
     162     * @since 3.0
     163     * @hook init
     164     * @return void
     165     */
     166    public function register_page_lang_meta() {
     167        $args_lang = array(
     168            'show_in_rest'  => true,
     169            'single'        => true,
     170            'type'          => 'string',
     171            'default'       => '',
     172            'auth_callback' => function () {
     173                return current_user_can( 'edit_posts' );
     174            },
     175        );
     176        $args_dir  = array(
     177            'show_in_rest'  => true,
     178            'single'        => true,
     179            'type'          => 'string',
     180            'default'       => 'ltr',
     181            'auth_callback' => function () {
     182                return current_user_can( 'edit_posts' );
     183            },
     184        );
     185        // Register for all public post types
     186        foreach ( get_post_types( array( 'public' => true ) ) as $post_type ) {
     187            register_post_meta( $post_type, '_nakedcatplugins_page_lang', $args_lang );
     188            register_post_meta( $post_type, '_nakedcatplugins_page_dir', $args_dir );
     189        }
     190    }
     191
     192    /**
     193     * Override the HTML lang (and optionally dir) attribute for singular pages/posts.
     194     *
     195     * When a page or post has the '_nakedcatplugins_page_lang' meta set, this method
     196     * replaces the lang attribute on the <html> element with the stored value.
     197     * When '_nakedcatplugins_page_dir' is set to 'rtl', the dir attribute is also applied.
     198     *
     199     * @since 3.0
     200     * @hook language_attributes
     201     * @param string $output The existing language attributes string, e.g. 'lang="en-US"'.
     202     * @return string Modified language attributes string.
     203     */
     204    public function apply_page_lang_attribute( $output ) {
     205        if ( ! is_singular() ) {
     206            return $output;
     207        }
     208        $post_id   = get_queried_object_id();
     209        $page_lang = trim( get_post_meta( $post_id, '_nakedcatplugins_page_lang', true ) );
     210        $page_dir  = trim( get_post_meta( $post_id, '_nakedcatplugins_page_dir', true ) );
     211
     212        if ( ! empty( $page_lang ) ) {
     213            $safe_lang = esc_attr( $page_lang );
     214            if ( strpos( $output, 'lang=' ) !== false ) {
     215                $output = preg_replace( '/lang="[^"]*"/', 'lang="' . $safe_lang . '"', $output );
     216            } else {
     217                $output .= ' lang="' . $safe_lang . '"';
     218            }
     219            // Add our class name
     220            if ( strpos( $output, 'class=' ) !== false ) {
     221                $output = preg_replace( '/class="([^"]*)"/', 'class="$1 naked-cat-plugins-post-has-lang-attr"', $output );
     222            } else {
     223                $output .= ' class="naked-cat-plugins-post-has-lang-attr"';
     224            }
     225        }
     226
     227        if ( ! empty( $page_dir ) && 'rtl' === $page_dir ) {
     228            $safe_dir = esc_attr( $page_dir );
     229            if ( strpos( $output, 'dir=' ) !== false ) {
     230                $output = preg_replace( '/dir="[^"]*"/', 'dir="' . $safe_dir . '"', $output );
     231            } else {
     232                $output .= ' dir="' . $safe_dir . '"';
     233            }
     234        }
     235
     236        return $output;
    146237    }
    147238
     
    196287    public function process_blocks( $block_content, $block ) {
    197288        if ( isset( $block['attrs']['lang'] ) && ! empty( $block['attrs']['lang'] ) ) {
    198             $lang          = esc_attr( $block['attrs']['lang'] );
    199             $dir           = isset( $block['attrs']['dir'] ) ? esc_attr( $block['attrs']['dir'] ) : 'ltr';
     289            $lang          = trim( esc_attr( $block['attrs']['lang'] ) );
     290            $dir           = trim( isset( $block['attrs']['dir'] ) ? esc_attr( $block['attrs']['dir'] ) : 'ltr' );
    200291            $tag_processor = new \WP_HTML_Tag_Processor( $block_content );
    201292            // Depending on the block type, we will set the tag to be processed
     
    251342            'nakedcatplugins-lang-attribute-blocks-script',
    252343            plugins_url( 'build/index.js', NAKEDCATPLUGINS_LANG_ATTRIBUTE_BLOCKS_FILE ),
    253             array( 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post', 'wp-element', 'wp-i18n', 'wp-block-editor' ),
     344            array( 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-block-editor', 'wp-plugins', 'wp-data', 'wp-core-data' ),
    254345            filemtime( plugin_dir_path( NAKEDCATPLUGINS_LANG_ATTRIBUTE_BLOCKS_FILE ) . 'build/index.js' ),
    255346            true
     
    361452        add_settings_section(
    362453            'nakedcatplugins_lang_attr_section',
    363             __( 'Language Attribute for Container Blocks', 'lang-attribute-blocks' ),
     454            __( 'Language Attribute for Container Blocks and Pages/Posts', 'lang-attribute-blocks' ),
    364455            array( $this, 'settings_section_callback' ),
    365456            'writing'
     
    383474     */
    384475    public function settings_section_callback() {
    385         echo '<p>' . esc_html__( 'Configure Language Attribute for Container Blocks plugin settings.', 'lang-attribute-blocks' ) . '</p>';
     476        echo '<p>' . esc_html__( 'Configure Language Attribute for Container Blocks and Pages/Posts plugin settings.', 'lang-attribute-blocks' ) . '</p>';
    386477    }
    387478    /**
     
    405496
    406497    /**
     498     * Register the page language metabox for the classic editor.
     499     *
     500     * Added to all public post types so editors can set the page-level
     501     * lang and dir meta without the block editor.
     502     *
     503     * @since 3.0
     504     * @hook add_meta_boxes
     505     * @return void
     506     */
     507    public function add_classic_editor_metabox() {
     508        // Only register the metabox in the classic editor; the block editor
     509        // provides its own Document Settings panel for the same fields.
     510        $screen = get_current_screen();
     511        if ( $screen && $screen->is_block_editor() ) {
     512            return;
     513        }
     514
     515        foreach ( get_post_types( array( 'public' => true ), 'names' ) as $post_type ) {
     516            add_meta_box(
     517                'nakedcatplugins_page_language',
     518                __( 'Page Language', 'lang-attribute-blocks' ),
     519                array( $this, 'render_classic_editor_metabox' ),
     520                $post_type,
     521                'side',
     522                'default'
     523            );
     524        }
     525    }
     526
     527    /**
     528     * Render the classic editor metabox HTML.
     529     *
     530     * @since 3.0
     531     * @param \WP_Post $post The current post object.
     532     * @return void
     533     */
     534    public function render_classic_editor_metabox( \WP_Post $post ) {
     535        $lang = trim( get_post_meta( $post->ID, '_nakedcatplugins_page_lang', true ) );
     536        $dir  = trim( get_post_meta( $post->ID, '_nakedcatplugins_page_dir', true ) );
     537        if ( empty( $dir ) ) {
     538            $dir = 'ltr';
     539        }
     540
     541        wp_nonce_field( 'nakedcatplugins_page_language_metabox', 'nakedcatplugins_page_language_nonce' );
     542        $placeholder = sprintf(
     543            /* translators: %s: The website's default language code */
     544            __( '%s (default website language)', 'lang-attribute-blocks' ),
     545            get_bloginfo( 'language' )
     546        );
     547        ?>
     548        <p>
     549            <label for="nakedcatplugins_page_lang">
     550                <?php esc_html_e( 'Language Code', 'lang-attribute-blocks' ); ?>
     551            </label>
     552            <input type="text" id="nakedcatplugins_page_lang" name="nakedcatplugins_page_lang" value="<?php echo esc_attr( $lang ); ?>" placeholder="<?php echo esc_attr( $placeholder ); ?>" class="widefat"/>
     553            <span class="description">
     554                <?php esc_html_e( "Valid language code for this page/post, like “fr” or “pt-PT”, if different from the website's main language (shown as a placeholder) - This overrides the HTML language attribute", 'lang-attribute-blocks' ); ?>
     555            </span>
     556        </p>
     557        <p>
     558            <label for="nakedcatplugins_page_dir">
     559                <?php esc_html_e( 'Text Direction', 'lang-attribute-blocks' ); ?>
     560            </label>
     561            <select id="nakedcatplugins_page_dir" name="nakedcatplugins_page_dir" class="widefat">
     562                <option value="ltr" <?php selected( $dir, 'ltr' ); ?>>
     563                    <?php esc_html_e( 'Left to right', 'lang-attribute-blocks' ); ?>
     564                </option>
     565                <option value="rtl" <?php selected( $dir, 'rtl' ); ?>>
     566                    <?php esc_html_e( 'Right to left', 'lang-attribute-blocks' ); ?>
     567                </option>
     568            </select>
     569        </p>
     570        <?php
     571    }
     572
     573    /**
     574     * Save the classic editor metabox values.
     575     *
     576     * Validates the nonce to confirm the metabox was present in the form
     577     * (guards against quick edit, bulk actions, REST and programmatic saves
     578     * that would otherwise wipe the meta), checks capabilities, then saves
     579     * or deletes the page language meta fields.
     580     *
     581     * @since 3.0
     582     * @hook save_post
     583     * @param int      $post_id The post ID being saved.
     584     * @param \WP_Post $post    The post object being saved.
     585     * @return void
     586     */
     587    public function save_classic_editor_metabox( int $post_id, \WP_Post $post ) {
     588        // If our metabox was not present in the request, bail out to avoid
     589        // accidentally wiping the meta (e.g. quick edit, REST, wp_update_post()).
     590        if ( ! isset( $_POST['nakedcatplugins_page_language_nonce'] ) ) {
     591            return;
     592        }
     593
     594        // WordPress has already verified the post nonce, but we verify our own
     595        // as extra confirmation that our metabox submitted these values.
     596        if ( ! wp_verify_nonce( sanitize_key( $_POST['nakedcatplugins_page_language_nonce'] ), 'nakedcatplugins_page_language_metabox' ) ) {
     597            return;
     598        }
     599
     600        // Bail on autosave and revisions.
     601        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
     602            return;
     603        }
     604        if ( wp_is_post_revision( $post_id ) ) {
     605            return;
     606        }
     607
     608        // Check the user has permission to edit this specific post.
     609        $post_type_object = get_post_type_object( $post->post_type );
     610        if ( ! current_user_can( $post_type_object->cap->edit_post, $post_id ) ) {
     611            return;
     612        }
     613
     614        // Save lang — trim and sanitize; delete if empty so the DB stays clean.
     615        if ( isset( $_POST['nakedcatplugins_page_lang'] ) ) {
     616            $lang = trim( sanitize_text_field( wp_unslash( $_POST['nakedcatplugins_page_lang'] ) ) );
     617            if ( ! empty( $lang ) ) {
     618                update_post_meta( $post_id, '_nakedcatplugins_page_lang', $lang );
     619            } else {
     620                delete_post_meta( $post_id, '_nakedcatplugins_page_lang' );
     621                delete_post_meta( $post_id, '_nakedcatplugins_page_dir' );
     622                return; // If lang is empty, we also delete dir and skip saving it since it doesn't make sense to have a dir without a lang.
     623            }
     624        }
     625
     626        // Save dir — whitelist to known values only.
     627        if ( isset( $_POST['nakedcatplugins_page_dir'] ) ) {
     628            $dir = sanitize_text_field( wp_unslash( $_POST['nakedcatplugins_page_dir'] ) );
     629            $dir = in_array( $dir, array( 'ltr', 'rtl' ), true ) ? $dir : 'ltr';
     630            update_post_meta( $post_id, '_nakedcatplugins_page_dir', $dir );
     631        }
     632    }
     633
     634    /**
    407635     * Add settings link to the plugin action links.
    408636     *
    409637     * This function adds a "Settings" link to the plugin's row on the Plugins page
    410      * that points to the Language Attribute for Container Blocks settings section
     638     * that points to the Language Attribute for Container Blocks and Pages/Posts settings section
    411639     * on the Settings > Writing page.
    412640     *
  • lang-attribute-blocks/trunk/lang-attribute-blocks.php

    r3381456 r3478054  
    11<?php
    22/**
    3  * Plugin Name:          Language Attribute for Container Blocks
     3 * Plugin Name:          Language Attribute for Container Blocks and Pages/Posts
    44 * Plugin URI:
    5  * Description:          Add “lang” and “dir” attributes on Group, Columns, and Cover WordPress Blocks
    6  * Version:              2.2
     5 * Description:          Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, or to the whole page/post.
     6 * Version:              3.0
    77 * Author:               Naked Cat Plugins (by Webdados)
    88 * Author URI:           https://nakedcatplugins.com
    99 * Text Domain:          lang-attribute-blocks
    1010 * Requires at least:    5.9
    11  * Tested up to:         6.9
     11 * Tested up to:         7.0
    1212 * Requires PHP:         7.2
    1313 * License:              GPLv3
  • lang-attribute-blocks/trunk/languages/lang-attribute-blocks.pot

    r3381456 r3478054  
    1 # Copyright (C) 2025 Naked Cat Plugins (by Webdados)
     1# Copyright (C) 2026 Naked Cat Plugins (by Webdados)
    22# This file is distributed under the GPLv3.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Language Attribute for Container Blocks 2.2\n"
     5"Project-Id-Version: Language Attribute for Container Blocks and Pages/Posts 2.2\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/lang-attribute-blocks\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-10-20T16:43:04+00:00\n"
     12"POT-Creation-Date: 2026-03-09T12:04:28+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.11.0\n"
     
    1717#. Plugin Name of the plugin
    1818#: lang-attribute-blocks.php
    19 #: includes/class-lang-attribute-blocks.php:363
    20 msgid "Language Attribute for Container Blocks"
     19#: includes/class-lang-attribute-blocks.php:454
     20msgid "Language Attribute for Container Blocks and Pages/Posts"
    2121msgstr ""
    2222
    2323#. Description of the plugin
    2424#: lang-attribute-blocks.php
    25 msgid "Add “lang” and “dir” attributes on Group, Columns, and Cover WordPress Blocks"
     25msgid "Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, or to the whole page/post."
    2626msgstr ""
    2727
     
    3737
    3838#. translators: %s: The website's default language code
    39 #: includes/class-lang-attribute-blocks.php:268
     39#: includes/class-lang-attribute-blocks.php:359
     40#: includes/class-lang-attribute-blocks.php:544
    4041msgid "%s (default website language)"
    4142msgstr ""
    4243
    43 #: includes/class-lang-attribute-blocks.php:371
     44#: includes/class-lang-attribute-blocks.php:462
    4445msgid "Highlight blocks with lang attribute"
    4546msgstr ""
    4647
    47 #: includes/class-lang-attribute-blocks.php:385
    48 msgid "Configure Language Attribute for Container Blocks plugin settings."
     48#: includes/class-lang-attribute-blocks.php:476
     49msgid "Configure Language Attribute for Container Blocks and Pages/Posts plugin settings."
    4950msgstr ""
    5051
    51 #: includes/class-lang-attribute-blocks.php:398
     52#: includes/class-lang-attribute-blocks.php:489
    5253msgid "Show visual outline around blocks that have a language attribute set"
    5354msgstr ""
    5455
    55 #: includes/class-lang-attribute-blocks.php:401
     56#: includes/class-lang-attribute-blocks.php:492
    5657msgid "When enabled, blocks with a language attribute will be visually highlighted with a red dashed outline in both the editor and frontend (only for Administrators and Editors)."
    5758msgstr ""
    5859
    59 #: includes/class-lang-attribute-blocks.php:421
     60#: includes/class-lang-attribute-blocks.php:518
     61#: build/index.js:1
     62#: src/index.js:165
     63msgid "Page Language"
     64msgstr ""
     65
     66#: includes/class-lang-attribute-blocks.php:550
     67#: build/index.js:1
     68#: src/index.js:49
     69#: src/index.js:168
     70msgid "Language Code"
     71msgstr ""
     72
     73#: includes/class-lang-attribute-blocks.php:554
     74#: build/index.js:1
     75#: src/index.js:172
     76msgid "Valid language code for this page/post, like “fr” or “pt-PT”, if different from the website's main language (shown as a placeholder) - This overrides the HTML language attribute"
     77msgstr ""
     78
     79#: includes/class-lang-attribute-blocks.php:559
     80#: build/index.js:1
     81#: src/index.js:56
     82#: src/index.js:175
     83msgid "Text Direction"
     84msgstr ""
     85
     86#: includes/class-lang-attribute-blocks.php:563
     87#: build/index.js:1
     88#: src/index.js:59
     89#: src/index.js:178
     90msgid "Left to right"
     91msgstr ""
     92
     93#: includes/class-lang-attribute-blocks.php:566
     94#: build/index.js:1
     95#: src/index.js:60
     96#: src/index.js:179
     97msgid "Right to left"
     98msgstr ""
     99
     100#: includes/class-lang-attribute-blocks.php:649
    60101msgid "Settings"
    61102msgstr ""
    62103
    63 #: assets/index.js:41
    64104#: build/index.js:1
    65 msgid "Language Settings"
     105#: src/index.js:45
     106msgid "Block Language"
    66107msgstr ""
    67108
    68 #: assets/index.js:45
    69109#: build/index.js:1
    70 msgid "Language Code"
     110#: src/index.js:53
     111msgid "Valid language code for this block, like “fr” or “pt-PT”, if different from the website's or page's main language (shown as a placeholder)"
    71112msgstr ""
    72 
    73 #: assets/index.js:49
    74 #: build/index.js:1
    75 msgid "Valid language code, like “fr” or “pt-PT”, if different from the website main language (shown as a placeholder)"
    76 msgstr ""
    77 
    78 #: assets/index.js:52
    79 #: build/index.js:1
    80 msgid "Text Direction"
    81 msgstr ""
    82 
    83 #: assets/index.js:55
    84 #: build/index.js:1
    85 msgid "Left to right"
    86 msgstr ""
    87 
    88 #: assets/index.js:56
    89 #: build/index.js:1
    90 msgid "Right to left"
    91 msgstr ""
  • lang-attribute-blocks/trunk/readme.txt

    r3381456 r3478054  
    1 === Language Attribute for Container Blocks ===
     1=== Language Attribute for Container Blocks and Pages/Posts ===
    22Contributors: nakedcatplugins, webdados
    3 Tags: language, accessibility, block editor
     3Tags: language, accessibility, block editor, gutenberg, classic editor
    44Requires at least: 5.9
    5 Tested up to: 6.9
     5Tested up to: 7.0
    66Requires PHP: 7.2
    7 Stable tag: 2.2
     7Stable tag: 3.0
    88License: GPLv3
    99License URI: https://www.gnu.org/licenses/gpl-3.0.html
    1010
    11 Add “lang” and “dir” attributes to Group, Columns, Cover, and other specific WordPress Blocks.
     11Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, or to the whole page/post.
    1212
    1313== Description ==
    1414
    15 This plugin aims to provide a way to ensure that any language change in the content of a page is indicated to assistive technologies at the container block level, helping a website comply with WCAG guidelines.
     15This plugin aims to ensure that any language change in a page’s content is indicated to assistive technologies at the container block level, helping a website comply with WCAG guidelines.
    1616
    1717This feature is available on the core block editor only at a text formatting level after code from [Jb Audras plugin “Lang Attribute for the Block Editor”](https://wordpress.org/plugins/lang-attribute/) was merged into core. The objective of this plugin is to provide the same functionality at a container block level (Group - including all its variants, Columns, Cover, and other specific block types) so that the language applies to all child elements, no matter the kind of content inside.
    1818
    19 This plugin is heavily inspired by the Jb Audras plugin (including this readme file), and the development started at WordCamp Europe 2025 Contributor Day, by Marco Almeida from [Naked Cat Plugins](https://profiles.wordpress.org/nakedcatplugins/) / [Webdados](https://profiles.wordpress.org/webdados/), and the help from [Ryan Welcher](https://profiles.wordpress.org/welcher/) on the code side and [Amber Hinds](https://profiles.wordpress.org/alh0319/) on the accessibility compliance side.
     19The plugin also supports setting the language at the page or post level, both on the blocks and classic editor. When an entire page is written in a different language than the website’s default, you can override the HTML `lang` and `dir` attributes for that specific page directly from the Document Settings sidebar, without needing to wrap everything in a container block.
    2020
    21 For more context: this plugin helps you to make your website compliant with the Web Content Accessibility Guidelines (WCAG) success criterion 3.1.2: “Language of Parts”. The purpose of this success Criterion is to ensure that user agents can correctly present content written in multiple languages.
     21This plugin is heavily inspired by the Jb Audras plugin (including this readme file). The development started at WordCamp Europe 2025 Contributor Day, by Marco Almeida from [Naked Cat Plugins](https://profiles.wordpress.org/nakedcatplugins/) / [Webdados](https://profiles.wordpress.org/webdados/), and the help from [Ryan Welcher](https://profiles.wordpress.org/welcher/) on the code side and [Amber Hinds](https://profiles.wordpress.org/alh0319/) on the accessibility compliance side.
    2222
    23 Keep in mind that you should only set the lang and dir attributes to a container block if the content you’re going to insert inside it is written in a different language than that set globally on your website.
     23For more context: this plugin helps you to make your website compliant with the Web Content Accessibility Guidelines (WCAG) success criteria:
    2424
    25 As per Web Content Accessibility Guidelines:
     25* **3.1.1 – Language of Page**: The default human language of each web page can be programmatically determined. Use the page-level setting when an entire page or post is written in a language other than the website’s default.
     26* **3.1.2 – Language of Parts**: The human language of each passage or phrase in the content can be programmatically determined. Use the block-level setting when only specific sections within a page are in a different language.
    2627
    27 This makes it possible for user agents and assistive technologies to present content according to the presentation and pronunciation rules for that language. This applies to graphical browsers as well as screen readers, braille displays, and other voice browsers.
     28The purpose of these success criteria is to ensure that user agents can correctly present content written in multiple languages.
    2829
    29 Both assistive technologies and conventional user agents can render text more accurately if the language of each passage of text is identified. Screen readers can use the pronunciation rules of the language of the text. Visual browsers can display characters and scripts in appropriate ways.
     30Keep in mind that you should set the `lang` and `dir` attributes only on a container block or page if the content is written in a language different from the one set globally on your website.
     31
     32**As per Web Content Accessibility Guidelines:**
     33
     34This enables user agents and assistive technologies to present content according to the presentation and pronunciation rules of that language. This applies to graphical browsers, screen readers, braille displays, and other voice browsers.
     35
     36Both assistive technologies and conventional user agents can render text more accurately if the language of each passage of text is identified. Screen readers can use the language’s pronunciation rules. Visual browsers can display characters and scripts appropriately.
    3037
    3138This is especially important when switching between languages that read from left to right and languages that read from right to left, or when text is rendered in a language that uses a different alphabet. Users with disabilities who know all the languages used in the Web page will be better able to understand the content when each passage is rendered appropriately.
     
    3643
    3744== Supported block types ==
     45
    3846* **Group** (`core/group`): Group contents together and set a language for them
    3947* **Columns** (`core/columns` and `core/column`): Organize content into a set of columns and set a language for all the columns or a specific column
     
    4553
    4654== Features ==
    47 * Add “lang” and “dir” attributes to Group, Columns, Cover, and other specific WordPress Blocks
     55
     56* Set the language and text direction for an entire page or post, both on the blocks and classic editor: a “Page Language” panel in the Document Settings sidebar overrides the HTML `lang` and `dir` attributes for that specific page
     57* Add `lang` and `dir` attributes to Group, Columns, Cover, and other specific WordPress Blocks, mentioned above
    4858* Show visual outline around blocks that have a language attribute set - For easy identification of blocks you have already set to a different language during your editing process, only for Administrators and Editors, and if enabled in Settings - Writing
    4959
     
    5161
    52621. Using the block editor to add a language attribute to a Group block
    53 2. The lang and dir attributes rendered on the frontend
     632. The `lang` and `dir attributes rendered on the frontend
    54643. Using the highlighting option during the editing process
    5565
     
    5767
    58681. Install the plugin and activate it.
    59 2. Insert a Group, Columns, Cover (or other specific) block, and use the “Language Settings” sidebar panel to set the language for all the content inside that container
     692. To set the language for an entire page or post: open the Document Settings sidebar (the panel icon at the top right of the editor) and use the “Page Language” panel.
     703. To set the language for a specific section within a page: insert a Group, Columns, Cover (or other specific) block, and use the “Block Language” sidebar panel to set the language for all the content inside that container.
    6071
    6172== Frequently Asked Questions ==
     73
     74= When should I use the page-level language setting instead of a block-level one? =
     75
     76Use the **Page Language** setting (in the Document Settings sidebar) when the entire page or post is written in a different language than the website default. This overrides the `lang` attribute on the HTML element itself, which corresponds to WCAG 3.1.1 (Language of Page).
     77In this case, we also recommend creating a dedicated template in the Site Editor (Appearance → Editor → Templates) where shared template parts — such as the header and footer — are also in that same language.
     78
     79Use the **Block Language** setting (in the block’s sidebar panel) when only a specific section within a page is in a different language, while the rest of the page remains in the site’s default language. This corresponds to WCAG 3.1.2 (Language of Parts).
    6280
    6381= Why not have the option to set the language attribute on all block types? =
     
    7189
    7290If your are working on a WordCamp website, or you don’t want to mess around with PHP, you can also add custom CSS to change the color, overriding our `--nakedcatplugins-lang-attr-highlight-color` variable.
    73 Here’s a [Gist example](https://gist.github.com/webdados/61197dd2e98f399ba2cfeefbac518851).
     91Here’s a [Gist example](https://gist.github.com/webdados/7179f5be4e224ba84867cf77e9bc9174).
    7492
    7593= How can I contribute to this plugin? =
     
    82100
    83101== Changelog ==
     102
     103= 3.0 - 2026-03-09 =
     104* [NEW] Plugin renamed from “Language Attribute for Container Blocks” to “Language Attribute for Container Blocks and Pages/Posts”
     105* [NEW] Set the page/post language at the document level: a new “Page Language” panel in the Document Settings sidebar allows overriding the HTML `lang` and `dir` attributes for a specific page or post, independently of the website’s default language
     106* [TWEAK] Rename “Language Settings” sidebar block panel to “Block Language”
     107* [FIX] Gist URL for changing the highlight color using plain CSS
     108* [DEV] Tested up to 7.0-beta3-61865
    84109
    85110= 2.2 - 2025-10-20 =
Note: See TracChangeset for help on using the changeset viewer.