확장
확장추가 Gutenberg 블록 번역하기

추가 Gutenberg 블록 번역하기

Gato AI Translations for Polylang은 블록 기반 게시물을 번역할 수 있습니다.

이 플러그인은 많은 블록을 기본으로 지원합니다. 그 외의 경우——직접 만든 커스텀 블록이나 wpml-config.xml을 제공하지 않는 서드파티 플러그인의 블록——에는 PHP 훅을 통해 지원을 확장할 수 있습니다.

문자열 번역

블록에 추가 번역 가능한 속성을 등록하려면 gatompl:gutenberg_block_type_translatable_attribute_regexes 필터를 사용하세요.

왜 정규식을 사용하나요?

Gutenberg 블록은 블록의 JSON 속성을 담은 HTML 주석과 그 뒤에 렌더링된 HTML이 이어지는 형태로 post_content에 저장됩니다. 예를 들면:

<!-- wp:my-plugin/my-block {"title":"Hello"} -->
<div class="wp-block-my-plugin-my-block">Hello</div>
<!-- /wp:my-plugin/my-block -->

블록을 번역한다는 것은 해당 마크업 내에서 번역해야 할 특정 부분 문자열을 찾아 번역으로 교체하고, 나머지 모든 것(블록 이름, 다른 속성, HTML 구조, 주변 블록)은 그대로 유지하는 것을 의미합니다. 정규식은 플러그인이 교체해야 할 부분 문자열을 정확히 찾아내는 수단입니다. 값 앞뒤의 보일러플레이트는 캡처 그룹으로 처리되고, 값 자체가 교체되는 부분입니다.

표준 문자열 속성 (블록의 JSON에 저장된 경우)

속성이 블록의 JSON 속성에 저장된 일반 문자열인 경우, true를 전달하면 플러그인이 기본 정규식을 사용합니다.

예를 들어, kadence/countdown 블록의 daysLabel, hoursLabel, minutesLabel, secondsLabel 속성을 번역하려면——해당 마크업은 다음과 같습니다——:

<!-- wp:kadence/countdown {"uniqueID":"_abc123","date":"2026-12-31 00:00:00","daysLabel":"Days","hoursLabel":"Hours","minutesLabel":"Minutes","secondsLabel":"Seconds"} -->
<div class="wp-block-kadence-countdown">…</div>
<!-- /wp:kadence/countdown -->

…다음과 같이 속성을 등록합니다:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        $regexes['kadence/countdown'] = [
            'daysLabel'    => true,
            'hoursLabel'   => true,
            'minutesLabel' => true,
            'secondsLabel' => true,
        ];
        return $regexes;
    }
);

true 값은 내부적으로 다음의 기본 정규식으로 확장됩니다:

#(<!-- wp:%3$s \{.*?\"%2$s\":\")%1$s(\".*?\}/?-->)#

…플레이스홀더는 다음과 같습니다:

  1. %1$s → 속성 값
  2. %2$s → 속성 이름
  3. %3$s → 블록 이름

kadence/countdowndaysLabel 속성의 경우, 플레이스홀더는 %3$skadence/countdown, %2$sdaysLabel, %1$sDays로 치환되어 다음이 생성됩니다:

#(<!-- wp:kadence/countdown \{.*?\"daysLabel\":\")Days(\".*?\}/?-->)#

Days만 교체되고, 블록 이름, 다른 속성, 닫는 주석은 캡처 그룹에 의해 유지됩니다.

정규식의 형태는 다음과 같습니다:

#(값 이전의 모든 것)속성 값(값 이후의 모든 것)#

블록의 HTML 내에 저장된 문자열

값이 JSON 속성이 아닌 렌더링된 HTML 내에 저장된 경우에는 직접 정규식을 제공하세요. 속성 값이 들어갈 위치에 %s(%1$s 대신)를 사용할 수 있으며, 블록 이름과 속성 이름은 정규식에 하드코딩할 수 있습니다.

예——generateblocks/text 블록의 content 속성 번역. 해당 마크업은 다음과 같습니다——Hello world가 JSON 안이 아닌 렌더링된 태그 사이에 있음에 유의하세요——:

<!-- wp:generateblocks/text {"uniqueId":"abc123","tagName":"p"} -->
<p class="gb-text">Hello world</p>
<!-- /wp:generateblocks/text -->

기본 정규식으로는 해당 부분 문자열을 찾을 수 없으므로, 직접 정규식을 지정합니다:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        $regexes['generateblocks/text'] = [
            'content' => '#(<!-- wp:generateblocks/text [^>]*?-->\n?<[a-z0-9]+ ?[^>]*?>)%s(</[a-z0-9]+>\n?<!-- /wp:generateblocks/text -->)#',
        ];
        return $regexes;
    }
);

같은 값이 여러 곳에 나타나는 경우

같은 속성이 JSON 속성 HTML(또는 두 개의 다른 위치) 양쪽에 모두 나타나는 경우, 정규식 배열을 전달하세요——문자열의 각 복사본을 번역하기 위해 각각의 정규식이 실행되어야 합니다.

예를 들어, generateblocks/media 블록에서 alttitle은 JSON의 htmlAttributes 내부와 렌더링된 <img>의 HTML 속성 양쪽 모두에 저장됩니다:

<!-- wp:generateblocks/media {"mediaId":42,"htmlAttributes":{"alt":"Cat sitting","title":"My cat"}} -->
<figure class="gb-media"><img src="…" alt="Cat sitting" title="My cat"></figure>
<!-- /wp:generateblocks/media -->

속성마다 두 개의 정규식——JSON을 대상으로 하는 것과 <img>를 대상으로 하는 것——을 준비하면 번역 후에도 두 복사본이 동기화된 상태를 유지합니다:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        $regexes['generateblocks/media'] = [
            'htmlAttributes.alt' => [
                '#(<!-- wp:generateblocks/media \{.*?\"htmlAttributes\":\{.*?\"alt\":\")%s(\".*?\}.*?\} -->)#',
                '#(<!-- wp:generateblocks/media [^>]*?-->\n?.*<img [^>]*alt=\")%s(\"[^>]*?>.*\n?<!-- /wp:generateblocks/media -->)#',
            ],
            'htmlAttributes.title' => [
                '#(<!-- wp:generateblocks/media \{.*?\"htmlAttributes\":\{.*?\"title\":\")%s(\".*?\}.*?\} -->)#',
                '#(<!-- wp:generateblocks/media [^>]*?-->\n?.*<img [^>]*title=\")%s(\"[^>]*?>.*\n?<!-- /wp:generateblocks/media -->)#',
            ],
        ];
        return $regexes;
    }
);

속성 값이 JSON 객체인 경우, generateblocks/mediahtmlAttributes.althtmlAttributes.title처럼 속성 이름에 .(점)을 사용하여 특정 하위 속성을 지정할 수 있습니다.

자동 번역되는 속성의 번역 비활성화

false 또는 null을 전달하면 플러그인이 자동으로 번역하는 속성의 번역을 제거합니다. 이는 예를 들어 PHP 전용 블록에서 특정 문자열 속성을 자동 번역에서 제외하거나, 번역하고 싶지 않은 선언된 속성을 가진 wpml-config.xml에서 가져온 블록에 유용합니다:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        // Disable translation of the `header` attribute on the
        // `my-plugin/duplicate-alert` block (either form works)
        unset($regexes['my-plugin/duplicate-alert']['header']);
        $regexes['my-plugin/duplicate-alert']['implications'] = false;
        return $regexes;
    }
);

엔티티 참조 번역

엔티티 참조(블록 속성에 저장된 게시물·미디어·택소노미·메뉴 ID)는 번역 시 대상 언어의 해당 엔티티로 재매핑할 수 있습니다. 참조 유형에 따라 다음 필터 중 하나를 사용하세요:

참조 유형필터
커스텀 게시물과 미디어gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes
택소노미 텀gatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes
ID로 메뉴gatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes
슬러그로 메뉴gatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes

각 필터는 번역 가능 속성 필터와 동일한 구조(기본 정규식에는 true, 커스텀 정규식에는 문자열 또는 배열)를 받습니다.

예를 들어, woocommerce/single-product 블록은 연결된 상품을 숫자 productId로 저장합니다:

<!-- wp:woocommerce/single-product {"productId":42} /-->

게시물이 번역될 때, 해당 42(소스 언어 상품)를 대상 언어의 해당 상품(예: 87)으로 재매핑해야 합니다. 플러그인이 번역 시 ID를 캡처하여 교체할 수 있도록 productId를 커스텀 게시물 참조로 표시합니다:

add_filter(
    'gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes',
    static function (array $regexes): array {
        $regexes['woocommerce/single-product'] = [
            'productId' => true,
            // …or a custom regex if `productId` is not stored in the standard JSON shape:
            // 'productId' => '#(<!-- wp:woocommerce/single-product \{.*?\"productId\":)%s([,\}].*? /?-->)#',
        ];
        return $regexes;
    }
);

다른 참조 유형에도 동일한 패턴을 사용합니다. 블록 마크업에서의 모습은 모두 같습니다——JSON에 포함된 숫자 ID 또는 슬러그——다른 점은 플러그인이 대상 언어로 변환하는 방식입니다:

<!-- wp:my-plugin/related-category {"categoryId":17} /-->
<!-- wp:my-plugin/menu-picker {"menuId":5} /-->
<!-- wp:my-plugin/menu-picker {"menuSlug":"main-nav"} /-->
// Taxonomy term reference
add_filter(
    'gatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes',
    static function (array $regexes): array {
        $regexes['my-plugin/related-category'] = [
            'categoryId' => true,
        ];
        return $regexes;
    }
);
 
// Menu reference by ID
add_filter(
    'gatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes',
    static function (array $regexes): array {
        $regexes['my-plugin/menu-picker'] = [
            'menuId' => true,
        ];
        return $regexes;
    }
);
 
// Menu reference by slug
add_filter(
    'gatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes',
    static function (array $regexes): array {
        $regexes['my-plugin/menu-picker'] = [
            'menuSlug' => true,
        ];
        return $regexes;
    }
);

속성 이름 찾는 방법

속성 이름과 그 저장 방식을 가장 빠르게 찾으려면 Translate custom posts GraphQL 쿼리를 실행하고 해당 블록의 blockFlattenedDataItems 응답 필드를 확인하세요.

해당 쿼리를 실행하고 결과를 읽는 방법은 번역할 페이지 빌더 데이터 가져오기 가이드를 참고하세요.

속성 처리가 필요한 블록 대응하기

위의 훅들은 blockFlattenedDataItems를 통해 노출된 속성 값이 이미 번역 대상 값(스칼라 또는 배열)이라고 가정합니다.

값이 래핑되어 있는 경우——예를 들어, 속성이 <li>Some text</li>를 저장하고 있고 Some text만 번역하고 싶은 경우——먼저 gatompl:gutenberg_block_flattened_data_item_attributes 필터를 사용하여 추출해야 합니다.

generateblocks/image 블록이 실제 예시입니다. 해당 블록의 alttitle은 독립적인 속성으로 노출되지 않고 innerContent의 HTML 내에 존재하며, 정규식으로 추출해야 합니다.

add_filter(
    'gatompl:gutenberg_block_flattened_data_item_attributes',
    static function (?\stdClass $attributes, string $blockTypeName, \stdClass $blockDataItem): ?\stdClass {
        if ($attributes === null || $blockTypeName !== 'generateblocks/image') {
            return $attributes;
        }
 
        $innerContent = $blockDataItem->innerContent ?? null;
        if (!is_array($innerContent) || !isset($innerContent[0]) || !is_string($innerContent[0])) {
            return $attributes;
        }
        $html = $innerContent[0];
 
        if (preg_match('#<img [^>]*alt="([^"]*)"[^>]*?>#', $html, $matches) === 1 && $matches[1] !== '') {
            $attributes->alt = $matches[1];
        }
        if (preg_match('#<img [^>]*title="([^"]*)"[^>]*?>#', $html, $matches) === 1 && $matches[1] !== '') {
            $attributes->title = $matches[1];
        }
        return $attributes;
    },
    10,
    3
);

속성 객체에 alttitle이 존재하게 되면, 위의 정규식 기반 훅으로 다른 속성처럼 대상으로 지정할 수 있습니다.

예시 참조처

플러그인 자체의 통합 코드가 좋은 실제 참고 예시입니다. 설치한 플러그인 내의 다음 파일들을 살펴보세요:

  • 블록 속성 정규식: wp-content/plugins/gato-ai-translations-for-polylang/src/Constants/BlockTypeAttributeValues.php
  • 블록 속성 전처리: wp-content/plugins/gato-ai-translations-for-polylang/src/ConditionalOnContext/LicenseIsActive/Hooks/CoreBlockFlattenedDataItemAttributesHookSet.php