Skip to content

Commit

Permalink
Generate translatable strings for non-static front end UI (#205)
Browse files Browse the repository at this point in the history
This adds a script that retrieves taxonomy term names and descriptions from Learn WP via the REST API and writes them to a file that can get picked up by the pot file generator. This way the terms will get imported into the learn-wordpress translation project and can get translated by community volunteers.

This new script will get run by a scheduled GitHub action and committed directly back to this repo. The generated file is outside of the wp-content directory, so it should never end up being committed to SVN or otherwise make an appearance on the production server.

This also adds the filter to dynamically translate term names and descriptions when they are output on the front end, and adds a notice on term edit screens so users know that the strings will get translated.

Refs #187
  • Loading branch information
coreymckrill committed Apr 7, 2021
1 parent 9005221 commit 3493e89
Show file tree
Hide file tree
Showing 8 changed files with 505 additions and 8 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/i18n.yml
@@ -0,0 +1,34 @@
name: I18n

on:
schedule:
- cron: '0 6,18 * * *'

jobs:
translation-strings:
name: Translation strings

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set PHP version
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
tools: composer:v2

- name: Install dependencies
run: composer install

- name: Run translation script
run: php ./bin/i18n.php

- name: Commit and push
# Using a specific hash here instead of a tagged version, for risk mitigation, since this action modifies our repo.
uses: actions-js/push@4decc2887d2770f29177082be3c8b04d342f5b64
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: trunk
message: Update translation strings
160 changes: 160 additions & 0 deletions bin/i18n.php
@@ -0,0 +1,160 @@
#!/usr/bin/php
<?php

namespace WPOrg_Learn\Bin\I18n;

use Requests;

require_once dirname( __DIR__ ) . '/vendor/autoload.php';

const ENDPOINT_BASE = 'https://learn.wordpress.org/wp-json/wp/v2/';

/**
* Get data about taxonomies from a REST API endpoint.
*
* @param array $valid_post_types Slugs of post types that support the taxonomies we want.
*
* @return array
*/
function get_taxonomies( array $valid_post_types = array() ) {
$endpoint = ENDPOINT_BASE . 'taxonomies';

$response = Requests::get( $endpoint );

if ( 200 !== $response->status_code ) {
die( 'Could not retrieve taxonomy data.' );
}

$taxonomies = json_decode( $response->body, true );

if ( ! is_array( $taxonomies ) ) {
die( 'Taxonomies request returned unexpected data.' );
}

if ( count( $valid_post_types ) > 0 ) {
$taxonomies = array_filter(
$taxonomies,
function( $tax ) use ( $valid_post_types ) {
$supported_types = $tax['types'];
$matches = array_intersect( $supported_types, $valid_post_types );

return count( $matches ) > 0;
}
);
}

return $taxonomies;
}

/**
* Get data about a taxonomy's terms from a REST API endpoint.
*
* @param string $taxonomy
*
* @return array
*/
function get_taxonomy_terms( $taxonomy ) {
$endpoint = ENDPOINT_BASE . $taxonomy . '?per_page=100';

$response = Requests::get( $endpoint );

if ( 200 !== $response->status_code ) {
die( sprintf(
'Could not retrieve terms for %s.',
$taxonomy // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
) );
}

$terms = json_decode( $response->body, true );

if ( ! is_array( $terms ) ) {
die( sprintf(
'Terms request for %s returned unexpected data.',
$taxonomy // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
) );
}

return $terms;
}

/**
* Run the script.
*/
function main() {
if ( 'cli' === php_sapi_name() ) {
echo "\n";
echo "Retrieving taxonomies...\n";
}

$valid_post_types = array(
'lesson-plan',
'wporg_workshop',
'course',
'lesson',
);
$taxonomies = get_taxonomies( $valid_post_types );

if ( 'cli' === php_sapi_name() ) {
echo "Retrieving terms...\n";
echo "\n";
}

$terms_by_tax = array();
foreach ( $taxonomies as $taxonomy ) {
$terms = get_taxonomy_terms( $taxonomy['slug'] );

if ( count( $terms ) > 0 ) {
$terms_by_tax[ $taxonomy['name'] ] = $terms;
}

unset( $terms );
}

$file_content = '';
foreach ( $terms_by_tax as $tax_label => $terms ) {
$label = addcslashes( $tax_label, "'" );

foreach ( $terms as $term ) {
$name = addcslashes( $term['name'], "'" );
$file_content .= "_x( '{$name}', '$label term name', 'wporg-learn' );\n";

if ( 'cli' === php_sapi_name() ) {
echo "$name\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}

if ( $term['description'] ) {
$description = addcslashes( $term['description'], "'" );
$file_content .= "_x( '{$description}', '$label term description', 'wporg-learn' );\n";
}
}
}

$path = dirname( __DIR__ ) . '/extra';
if ( ! is_readable( $path ) ) {
mkdir( $path );
}

$file_name = 'translation-strings.php';
$file_header = <<<HEADER
<?php
/**
* Generated file for translation strings.
*
* Used to import additional strings into the learn-wordpress translation project.
*
* ⚠️ This is a generated file. Do not edit manually. See bin/i18n.php.
* ⚠️ Do not require or include this file anywhere.
*/
HEADER;

file_put_contents( $path . '/' . $file_name, $file_header . $file_content );

if ( 'cli' === php_sapi_name() ) {
echo "\n";
echo "Done.\n";
}
}

main();
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -61,7 +61,8 @@
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"wp-coding-standards/wpcs": "2.*",
"phpcompatibility/phpcompatibility-wp": "*"
"phpcompatibility/phpcompatibility-wp": "*",
"rmccue/requests": "^1.7"
},
"scripts": {
"format": "phpcbf -p",
Expand Down
67 changes: 60 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 86 additions & 0 deletions extra/translation-strings.php
@@ -0,0 +1,86 @@
<?php
/**
* Generated file for translation strings.
*
* Used to import additional strings into the learn-wordpress translation project.
*
* ⚠️ This is a generated file. Do not edit manually. See bin/i18n.php.
* ⚠️ Do not require or include this file anywhere.
*/

_x( 'All', 'Audiences term name', 'wporg-learn' );
_x( 'Contributor', 'Audiences term name', 'wporg-learn' );
_x( 'Designers', 'Audiences term name', 'wporg-learn' );
_x( 'Developers', 'Audiences term name', 'wporg-learn' );
_x( 'Speakers', 'Audiences term name', 'wporg-learn' );
_x( 'Users', 'Audiences term name', 'wporg-learn' );
_x( 'Builder', 'Lesson Categories term name', 'wporg-learn' );
_x( 'Developing or Customizing with code.', 'Lesson Categories term description', 'wporg-learn' );
_x( 'Español', 'Lesson Categories term name', 'wporg-learn' );
_x( 'General', 'Lesson Categories term name', 'wporg-learn' );
_x( 'History of WordPress, About the Community, Open Source, or other broad overview lessons', 'Lesson Categories term description', 'wporg-learn' );
_x( 'General Admin', 'Lesson Categories term name', 'wporg-learn' );
_x( 'Using admin settings, the dashboard, posts, pages,', 'Lesson Categories term description', 'wporg-learn' );
_x( 'Plugin', 'Lesson Categories term name', 'wporg-learn' );
_x( 'Plugin Dev', 'Lesson Categories term name', 'wporg-learn' );
_x( 'Speaker', 'Lesson Categories term name', 'wporg-learn' );
_x( 'Templates', 'Lesson Categories term name', 'wporg-learn' );
_x( 'How to get started writing lesson plans, templates for lessons, guidelines for Learn', 'Lesson Categories term description', 'wporg-learn' );
_x( 'Theme', 'Lesson Categories term name', 'wporg-learn' );
_x( 'Theme Dev', 'Lesson Categories term name', 'wporg-learn' );
_x( 'User', 'Lesson Categories term name', 'wporg-learn' );
_x( '15', 'Duration term name', 'wporg-learn' );
_x( '30', 'Duration term name', 'wporg-learn' );
_x( '45', 'Duration term name', 'wporg-learn' );
_x( '60', 'Duration term name', 'wporg-learn' );
_x( 'Get Started', 'Lesson Groups term name', 'wporg-learn' );
_x( 'Speaker Training', 'Lesson Groups term name', 'wporg-learn' );
_x( 'Demonstration', 'Instruction Types term name', 'wporg-learn' );
_x( 'Discussion', 'Instruction Types term name', 'wporg-learn' );
_x( 'Exercises', 'Instruction Types term name', 'wporg-learn' );
_x( 'Feedback', 'Instruction Types term name', 'wporg-learn' );
_x( 'Lecture', 'Instruction Types term name', 'wporg-learn' );
_x( 'Show &amp; Tell', 'Instruction Types term name', 'wporg-learn' );
_x( 'Tutorial', 'Instruction Types term name', 'wporg-learn' );
_x( 'Advanced', 'Experience Levels term name', 'wporg-learn' );
_x( 'Any', 'Experience Levels term name', 'wporg-learn' );
_x( 'Beginner', 'Experience Levels term name', 'wporg-learn' );
_x( 'Intermediate', 'Experience Levels term name', 'wporg-learn' );
_x( 'Advanced site management', 'Workshop Series term name', 'wporg-learn' );
_x( 'Contributing to WordPress', 'Workshop Series term name', 'wporg-learn' );
_x( 'Get involved in contributing to WordPress - no matter you do with WordPress there\'s a way that you can be a part of building the project and community. You will need to <a href="https://learn.wordpress.org/workshop/set-up-a-wordpress-org-account">set up a WordPress.org profile</a> in order to contribute.', 'Workshop Series term description', 'wporg-learn' );
_x( 'Developing for the Block Editor', 'Workshop Series term name', 'wporg-learn' );
_x( 'This series is aimed at WordPress developers interested in developing for the block editor.', 'Workshop Series term description', 'wporg-learn' );
_x( 'Diverse Speaker Training', 'Workshop Series term name', 'wporg-learn' );
_x( 'This series is for people from marginalized or underrepresented groups who are thinking about speaking at WordPress events. You do not need to have any experience in public speaking, and this series is for all levels of experience. Topics include finding a talk topic, writing a pitch, creating the talk, becoming a better speaker, creating great slides, handling tough questions, and more!', 'Workshop Series term description', 'wporg-learn' );
_x( 'Editor de Bloques - Tutorial básico', 'Workshop Series term name', 'wporg-learn' );
_x( 'En esta serio de tutoriales, o WorkShops, se abordan los conceptos básico, y no tanto, para poder adentrarnos en el fascinante mundo del desarrollo en el editor de bloques de WordPress, también conocido como Gutenberg.
Partiendo de lo indispensable, iremos viendo sección tras sección, video tras video, cómo poder implementar nuestras propias ideas, necesidades, requerimientos, etc. de una manera simple y al alcance de todo el mundo.', 'Workshop Series term description', 'wporg-learn' );
_x( 'Organizing WordPress Meetups', 'Workshop Series term name', 'wporg-learn' );
_x( 'This series aimed at all WordPress Community members across the world that are interested in organizing WordPress meetups. You will learn how to organize a local WordPress Meetup, the important things to keep in mind while organizing a meetup, and how to keep your local meetup group active.', 'Workshop Series term description', 'wporg-learn' );
_x( 'Seguridad en WordPress', 'Workshop Series term name', 'wporg-learn' );
_x( 'Using the Block Editor', 'Workshop Series term name', 'wporg-learn' );
_x( 'Learn how to get the most out of the WordPress block editor when publishing your content.', 'Workshop Series term description', 'wporg-learn' );
_x( 'WordPress の基本', 'Workshop Series term name', 'wporg-learn' );
_x( 'WordPress for Kids', 'Workshop Series term name', 'wporg-learn' );
_x( 'WordPress Troubleshooting', 'Workshop Series term name', 'wporg-learn' );
_x( 'Learn how to troubleshoot WordPress issues.', 'Workshop Series term description', 'wporg-learn' );
_x( 'Block Development', 'Topics term name', 'wporg-learn' );
_x( 'Block Editor', 'Topics term name', 'wporg-learn' );
_x( 'Community Team', 'Topics term name', 'wporg-learn' );
_x( 'Contributing', 'Topics term name', 'wporg-learn' );
_x( 'Core', 'Topics term name', 'wporg-learn' );
_x( 'CSS', 'Topics term name', 'wporg-learn' );
_x( 'Diversity', 'Topics term name', 'wporg-learn' );
_x( 'eCommerce', 'Topics term name', 'wporg-learn' );
_x( 'Gutenberg', 'Topics term name', 'wporg-learn' );
_x( 'Hosting', 'Topics term name', 'wporg-learn' );
_x( 'Meetups', 'Topics term name', 'wporg-learn' );
_x( 'Open-Source', 'Topics term name', 'wporg-learn' );
_x( 'Publishing', 'Topics term name', 'wporg-learn' );
_x( 'Security', 'Topics term name', 'wporg-learn' );
_x( 'Translation', 'Topics term name', 'wporg-learn' );
_x( 'Troubleshooting', 'Topics term name', 'wporg-learn' );
_x( 'Sessions on WordPress Troubleshooting.', 'Topics term description', 'wporg-learn' );
_x( 'UI', 'Topics term name', 'wporg-learn' );
_x( 'WordPress', 'Topics term name', 'wporg-learn' );

0 comments on commit 3493e89

Please sign in to comment.