mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 16:04:25 +02:00
MDL-72783 usertours: Make tour name and description translatable
We can use the Moodle language format for tour's name and description now. Also, several existing bugs were fixed in this commit when we use the Moodle language format for step's title and content. Now, it will display the translated text in the breadcrumb, editing page instead of displaying the [identifier][component]
This commit is contained in:
parent
87f233e698
commit
c59d3d7496
@ -24,6 +24,7 @@
|
||||
|
||||
namespace tool_usertours;
|
||||
|
||||
use core\output\inplace_editable;
|
||||
use tool_usertours\local\clientside_filter\clientside_filter;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -51,6 +52,11 @@ class helper {
|
||||
*/
|
||||
private static $bootstrapped = false;
|
||||
|
||||
/**
|
||||
* @var string Regex to check any matching lang string.
|
||||
*/
|
||||
protected const LANG_STRING_REGEX = '|^([a-zA-Z][a-zA-Z0-9\.:/_-]*),([a-zA-Z][a-zA-Z0-9\.:/_-]*)$|';
|
||||
|
||||
/**
|
||||
* Get the link to edit the step.
|
||||
*
|
||||
@ -302,18 +308,19 @@ class helper {
|
||||
/**
|
||||
* Render the inplace editable used to edit the tour name.
|
||||
*
|
||||
* @param tour $tour The tour to edit.
|
||||
* @return string
|
||||
* @param tour $tour The tour to edit.
|
||||
* @return inplace_editable
|
||||
*/
|
||||
public static function render_tourname_inplace_editable(tour $tour) {
|
||||
return new \core\output\inplace_editable(
|
||||
public static function render_tourname_inplace_editable(tour $tour): inplace_editable {
|
||||
$name = format_text(static::get_string_from_input($tour->get_name()), FORMAT_HTML);
|
||||
return new inplace_editable(
|
||||
'tool_usertours',
|
||||
'tourname',
|
||||
$tour->get_id(),
|
||||
true,
|
||||
\html_writer::link(
|
||||
$tour->get_view_link(),
|
||||
$tour->get_name()
|
||||
$name
|
||||
),
|
||||
$tour->get_name()
|
||||
);
|
||||
@ -322,16 +329,17 @@ class helper {
|
||||
/**
|
||||
* Render the inplace editable used to edit the tour description.
|
||||
*
|
||||
* @param tour $tour The tour to edit.
|
||||
* @return string
|
||||
* @param tour $tour The tour to edit.
|
||||
* @return inplace_editable
|
||||
*/
|
||||
public static function render_tourdescription_inplace_editable(tour $tour) {
|
||||
return new \core\output\inplace_editable(
|
||||
public static function render_tourdescription_inplace_editable(tour $tour): inplace_editable {
|
||||
$description = format_text(static::get_string_from_input($tour->get_description()), FORMAT_HTML);
|
||||
return new inplace_editable(
|
||||
'tool_usertours',
|
||||
'tourdescription',
|
||||
$tour->get_id(),
|
||||
true,
|
||||
$tour->get_description(),
|
||||
$description,
|
||||
$tour->get_description()
|
||||
);
|
||||
}
|
||||
@ -339,10 +347,10 @@ class helper {
|
||||
/**
|
||||
* Render the inplace editable used to edit the tour enable state.
|
||||
*
|
||||
* @param tour $tour The tour to edit.
|
||||
* @return string
|
||||
* @param tour $tour The tour to edit.
|
||||
* @return inplace_editable
|
||||
*/
|
||||
public static function render_tourenabled_inplace_editable(tour $tour) {
|
||||
public static function render_tourenabled_inplace_editable(tour $tour): inplace_editable {
|
||||
global $OUTPUT;
|
||||
|
||||
if ($tour->is_enabled()) {
|
||||
@ -355,7 +363,7 @@ class helper {
|
||||
$value = 0;
|
||||
}
|
||||
|
||||
$editable = new \core\output\inplace_editable(
|
||||
$editable = new inplace_editable(
|
||||
'tool_usertours',
|
||||
'tourenabled',
|
||||
$tour->get_id(),
|
||||
@ -373,13 +381,13 @@ class helper {
|
||||
/**
|
||||
* Render the inplace editable used to edit the step name.
|
||||
*
|
||||
* @param step $step The step to edit.
|
||||
* @return string
|
||||
* @param step $step The step to edit.
|
||||
* @return inplace_editable
|
||||
*/
|
||||
public static function render_stepname_inplace_editable(step $step) {
|
||||
$title = format_text(step::get_string_from_input($step->get_title()), FORMAT_HTML);
|
||||
public static function render_stepname_inplace_editable(step $step): inplace_editable {
|
||||
$title = format_text(static::get_string_from_input($step->get_title()), FORMAT_HTML);
|
||||
|
||||
return new \core\output\inplace_editable(
|
||||
return new inplace_editable(
|
||||
'tool_usertours',
|
||||
'stepname',
|
||||
$step->get_id(),
|
||||
@ -585,4 +593,37 @@ class helper {
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to fetch any matching langstring if the content is in the
|
||||
* format identifier,component.
|
||||
*
|
||||
* @param string $content Step's content or Tour's name or Tour's description
|
||||
* @return string Processed content, any langstring will be converted to translated text
|
||||
*/
|
||||
public static function get_string_from_input(string $content): string {
|
||||
$content = trim($content);
|
||||
|
||||
if (preg_match(static::LANG_STRING_REGEX, $content, $matches)) {
|
||||
if ($matches[2] === 'moodle') {
|
||||
$matches[2] = 'core';
|
||||
}
|
||||
|
||||
if (get_string_manager()->string_exists($matches[1], $matches[2])) {
|
||||
$content = get_string($matches[1], $matches[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given string contains any matching langstring.
|
||||
*
|
||||
* @param string $string
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_language_string_from_input(string $string): bool {
|
||||
return preg_match(static::LANG_STRING_REGEX, $string) == true;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
namespace tool_usertours\local\forms;
|
||||
|
||||
use stdClass;
|
||||
use tool_usertours\helper;
|
||||
use tool_usertours\step;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
@ -188,7 +189,7 @@ class editstep extends \moodleform {
|
||||
public function set_data($data): void {
|
||||
$data = (object) $data;
|
||||
if (!isset($data->contenttype)) {
|
||||
if (!empty($data->content['text']) && step::is_language_string_from_input($data->content['text'])) {
|
||||
if (!empty($data->content['text']) && helper::is_language_string_from_input($data->content['text'])) {
|
||||
$data->contenttype = static::CONTENTTYPE_LANGSTRING;
|
||||
$data->contentlangstring = $data->content['text'];
|
||||
|
||||
|
@ -67,10 +67,12 @@ class edittour extends \moodleform {
|
||||
$mform->addElement('text', 'name', get_string('name', 'tool_usertours'));
|
||||
$mform->addRule('name', get_string('required'), 'required', null, 'client');
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
$mform->addHelpButton('name', 'name', 'tool_usertours');
|
||||
|
||||
// Admin-only descriptions.
|
||||
$mform->addElement('textarea', 'description', get_string('description', 'tool_usertours'));
|
||||
$mform->setType('description', PARAM_RAW);
|
||||
$mform->addHelpButton('description', 'description', 'tool_usertours');
|
||||
|
||||
// Application.
|
||||
$mform->addElement('text', 'pathmatch', get_string('pathmatch', 'tool_usertours'));
|
||||
|
@ -101,7 +101,7 @@ class step_list extends \flexible_table {
|
||||
$content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $systemcontext->id,
|
||||
'tool_usertours', 'stepcontent', $step->get_id());
|
||||
|
||||
return format_text(step::get_string_from_input($content), $step->get_contentformat());
|
||||
return format_text(helper::get_string_from_input($content), $step->get_contentformat());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,7 +353,7 @@ class manager {
|
||||
global $PAGE;
|
||||
if ($id) {
|
||||
$tour = tour::instance($id);
|
||||
$PAGE->navbar->add($tour->get_name(), $tour->get_edit_link());
|
||||
$PAGE->navbar->add(helper::get_string_from_input($tour->get_name()), $tour->get_edit_link());
|
||||
|
||||
} else {
|
||||
$tour = new tour();
|
||||
@ -393,7 +393,8 @@ class manager {
|
||||
notification::add(get_string('modifyshippedtourwarning', 'tool_usertours'), notification::WARNING);
|
||||
}
|
||||
|
||||
$this->header($tour->get_name());
|
||||
$tourname = !empty($tour->get_name()) ? helper::get_string_from_input($tour->get_name()) : '';
|
||||
$this->header($tourname);
|
||||
$data = $tour->prepare_data_for_form();
|
||||
|
||||
// Prepare filter values for the form.
|
||||
@ -475,12 +476,13 @@ class manager {
|
||||
protected function view_tour($tourid) {
|
||||
global $PAGE;
|
||||
$tour = helper::get_tour($tourid);
|
||||
$tourname = helper::get_string_from_input($tour->get_name());
|
||||
|
||||
$PAGE->navbar->add($tour->get_name(), $tour->get_view_link());
|
||||
$PAGE->navbar->add($tourname, $tour->get_view_link());
|
||||
|
||||
$this->header($tour->get_name());
|
||||
$this->header($tourname);
|
||||
echo \html_writer::span(get_string('viewtour_info', 'tool_usertours', [
|
||||
'tourname' => $tour->get_name(),
|
||||
'tourname' => $tourname,
|
||||
'path' => $tour->get_pathmatch(),
|
||||
]));
|
||||
echo \html_writer::div(get_string('viewtour_edit', 'tool_usertours', [
|
||||
@ -728,9 +730,9 @@ class manager {
|
||||
notification::add(get_string('modifyshippedtourwarning', 'tool_usertours'), notification::WARNING);
|
||||
}
|
||||
|
||||
$PAGE->navbar->add($tour->get_name(), $tour->get_view_link());
|
||||
$PAGE->navbar->add(helper::get_string_from_input($tour->get_name()), $tour->get_view_link());
|
||||
if (isset($id)) {
|
||||
$PAGE->navbar->add($step->get_title(), $step->get_edit_link());
|
||||
$PAGE->navbar->add(helper::get_string_from_input($step->get_title()), $step->get_edit_link());
|
||||
} else {
|
||||
$PAGE->navbar->add(get_string('newstep', 'tool_usertours'), $step->get_edit_link());
|
||||
}
|
||||
@ -746,7 +748,7 @@ class manager {
|
||||
if (empty($id)) {
|
||||
$this->header(get_string('newstep', 'tool_usertours'));
|
||||
} else {
|
||||
$this->header(get_string('editstep', 'tool_usertours', $step->get_title()));
|
||||
$this->header(get_string('editstep', 'tool_usertours', helper::get_string_from_input($step->get_title())));
|
||||
}
|
||||
$form->set_data($step->prepare_data_for_form());
|
||||
|
||||
|
@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . "/filelib.php");
|
||||
|
||||
use tool_usertours\helper;
|
||||
use tool_usertours\step as stepsource;
|
||||
|
||||
/**
|
||||
@ -70,13 +71,13 @@ class step implements \renderable {
|
||||
$result = (object) [
|
||||
'stepid' => $step->get_id(),
|
||||
'title' => external_format_text(
|
||||
stepsource::get_string_from_input($step->get_title()),
|
||||
helper::get_string_from_input($step->get_title()),
|
||||
FORMAT_HTML,
|
||||
$PAGE->context->id,
|
||||
'tool_usertours'
|
||||
)[0],
|
||||
'content' => external_format_text(
|
||||
stepsource::get_string_from_input($content),
|
||||
helper::get_string_from_input($content),
|
||||
$step->get_contentformat(),
|
||||
$PAGE->context->id,
|
||||
'tool_usertours'
|
||||
|
@ -92,11 +92,6 @@ class step {
|
||||
*/
|
||||
protected $dirty = false;
|
||||
|
||||
/**
|
||||
* @var string Regex to check any matching lang string.
|
||||
*/
|
||||
protected const LANG_STRING_REGEX = '|^([a-zA-Z][a-zA-Z0-9\.:/_-]*),([a-zA-Z][a-zA-Z0-9\.:/_-]*)$|';
|
||||
|
||||
/**
|
||||
* @var bool $isimporting Whether the step is being imported or not.
|
||||
*/
|
||||
@ -801,13 +796,16 @@ class step {
|
||||
* Attempt to fetch any matching langstring if the string is in the
|
||||
* format identifier,component.
|
||||
*
|
||||
* @deprecated since Moodle 4.0 MDL-72783. Please use helper::get_string_from_input() instead.
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public static function get_string_from_input($string) {
|
||||
debugging('Use of ' . __FUNCTION__ .
|
||||
'() have been deprecated, please update your code to use helper::get_string_from_input()', DEBUG_DEVELOPER);
|
||||
$string = trim($string);
|
||||
|
||||
if (preg_match(static::LANG_STRING_REGEX, $string, $matches)) {
|
||||
if (preg_match('|^([a-zA-Z][a-zA-Z0-9\.:/_-]*),([a-zA-Z][a-zA-Z0-9\.:/_-]*)$|', $string, $matches)) {
|
||||
if ($matches[2] === 'moodle') {
|
||||
$matches[2] = 'core';
|
||||
}
|
||||
@ -819,14 +817,4 @@ class step {
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given string contains any matching langstring.
|
||||
*
|
||||
* @param string $string Tour step content
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_language_string_from_input(string $string): bool {
|
||||
return preg_match(static::LANG_STRING_REGEX, $string) == true;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ $string['block_named'] = 'Block named \'{$a}\'';
|
||||
$string['cachedef_stepdata'] = 'List of user tour steps';
|
||||
$string['cachedef_tourdata'] = 'List of enabled user tours information which is fetched on every page';
|
||||
$string['description'] = 'Description';
|
||||
$string['description_help'] = 'The description of a tour may be added as plain text, enclosed in multilang tags (for use with the multi-language content filter) if required.
|
||||
|
||||
Alternatively, a language string ID may be entered in the format identifier,component (with no brackets or space after the comma).';
|
||||
$string['displaystepnumbers'] = 'Display step numbers';
|
||||
$string['displaystepnumbers_help'] = 'Whether to display a step number count e.g. 1/4, 2/4 etc. to indicate the length of the user tour.';
|
||||
$string['confirmstepremovalquestion'] = 'Are you sure that you wish to remove this step?';
|
||||
@ -93,6 +96,9 @@ $string['movestepup'] = 'Move step up';
|
||||
$string['movetourdown'] = 'Move tour down';
|
||||
$string['movetourup'] = 'Move tour up';
|
||||
$string['name'] = 'Name';
|
||||
$string['name_help'] = 'The name of a tour may be added as plain text, enclosed in multilang tags (for use with the multi-language content filter) if required.
|
||||
|
||||
Alternatively, a language string ID may be entered in the format identifier,component (with no brackets or space after the comma).';
|
||||
$string['newstep'] = 'Create step';
|
||||
$string['newstep'] = 'New step';
|
||||
$string['newtour'] = 'Create a new tour';
|
||||
|
@ -24,15 +24,16 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\output\inplace_editable;
|
||||
use tool_usertours\helper;
|
||||
|
||||
/**
|
||||
* Manage inplace editable saves.
|
||||
*
|
||||
* @param string $itemtype The type of item.
|
||||
* @param int $itemid The ID of the item.
|
||||
* @param mixed $newvalue The new value
|
||||
* @return string
|
||||
* @param string $itemtype The type of item.
|
||||
* @param int $itemid The ID of the item.
|
||||
* @param mixed $newvalue The new value
|
||||
* @return inplace_editable
|
||||
*/
|
||||
function tool_usertours_inplace_editable($itemtype, $itemid, $newvalue) {
|
||||
$context = \context_system::instance();
|
||||
|
@ -11,6 +11,11 @@ Feature: Apply content type to a tour
|
||||
| Description | My first tour |
|
||||
| Apply to URL match | /my/% |
|
||||
| Tour is enabled | 1 |
|
||||
And I add a new user tour with:
|
||||
| Name | tour_activityinfo_activity_student_title,tool_usertours |
|
||||
| Description | tour_activityinfo_activity_student_content,tool_usertours |
|
||||
| Apply to URL match | /my/% |
|
||||
| Tour is enabled | 0 |
|
||||
|
||||
@javascript
|
||||
Scenario: User can choose the the content type of the tour step
|
||||
@ -42,6 +47,7 @@ Feature: Apply content type to a tour
|
||||
And I should see "New: Activity information"
|
||||
And I should see "New course settings 'Show completion conditions' and 'Show activity dates' enable you to choose whether activity completion conditions (if set) and/or dates are displayed for students on the course page."
|
||||
And I click on "Edit" "link" in the "New: Activity information" "table_row"
|
||||
And I should see "Editing \"New: Activity information\""
|
||||
And the field "Title" matches value "tour_activityinfo_course_teacher_title,tool_usertours"
|
||||
And the field "Moodle language identifier" matches value "tour_activityinfo_course_teacher_content,tool_usertours"
|
||||
|
||||
@ -57,6 +63,20 @@ Feature: Apply content type to a tour
|
||||
And I should see "New: Activity information"
|
||||
And I should see "Test content"
|
||||
And I click on "Edit" "link" in the "New: Activity information" "table_row"
|
||||
And I should see "Editing \"New: Activity information\""
|
||||
And I should not see "Moodle language identifier"
|
||||
And the field "Title" matches value "tour_activityinfo_course_teacher_title,tool_usertours"
|
||||
And the field "id_content" matches value "<b>Test content</b>"
|
||||
|
||||
@javascript
|
||||
Scenario: Tour name and description can be translatable
|
||||
Given I open the User tour settings page
|
||||
And I should see "New: Activity information"
|
||||
And I should see "Activity dates plus what to do to complete the activity are shown on the activity page."
|
||||
When I click on "View" "link" in the "New: Activity information" "table_row"
|
||||
Then I should see "New: Activity information"
|
||||
And I should see "This is the 'New: Activity information' tour. It applies to the path '/my/%'."
|
||||
And I click on "edit the tour defaults" "link"
|
||||
And I should see "New: Activity information"
|
||||
And the field "Name" matches value "tour_activityinfo_activity_student_title,tool_usertours"
|
||||
And the field "Description" matches value "tour_activityinfo_activity_student_content,tool_usertours"
|
||||
|
84
admin/tool/usertours/tests/helper_test.php
Normal file
84
admin/tool/usertours/tests/helper_test.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for helper.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2022 Huong Nguyen <huongnv13@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_usertours;
|
||||
|
||||
use advanced_testcase;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Tests for helper.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2022 Huong Nguyen <huongnv13@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class helper_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Data Provider for get_string_from_input.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_string_from_input_provider(): array {
|
||||
return [
|
||||
'Text' => [
|
||||
'example',
|
||||
'example',
|
||||
],
|
||||
'Text which looks like a langstring' => [
|
||||
'example,fakecomponent',
|
||||
'example,fakecomponent',
|
||||
],
|
||||
'Text which is a langstring' => [
|
||||
'administration,core',
|
||||
'Administration',
|
||||
],
|
||||
'Text which is a langstring but uses "moodle" instead of "core"' => [
|
||||
'administration,moodle',
|
||||
'Administration',
|
||||
],
|
||||
'Text which is a langstring, but with extra whitespace' => [
|
||||
' administration,moodle ',
|
||||
'Administration',
|
||||
],
|
||||
'Looks like a langstring, but has incorrect space around comma' => [
|
||||
'administration , moodle',
|
||||
'administration , moodle',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the get_string_from_input function returns langstring strings correctly.
|
||||
*
|
||||
* @dataProvider get_string_from_input_provider
|
||||
* @param string $string The string to test
|
||||
* @param string $expected The expected result
|
||||
*/
|
||||
public function test_get_string_from_input($string, $expected) {
|
||||
$this->assertEquals($expected, helper::get_string_from_input($string));
|
||||
}
|
||||
}
|
@ -823,49 +823,4 @@ class step_testcase extends advanced_testcase {
|
||||
|
||||
$this->assertEquals($value, $step->$getter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Provider for get_string_from_input.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_string_from_input_provider() {
|
||||
return [
|
||||
'Text' => [
|
||||
'example',
|
||||
'example',
|
||||
],
|
||||
'Text which looks like a langstring' => [
|
||||
'example,fakecomponent',
|
||||
'example,fakecomponent',
|
||||
],
|
||||
'Text which is a langstring' => [
|
||||
'administration,core',
|
||||
'Administration',
|
||||
],
|
||||
'Text which is a langstring but uses "moodle" instead of "core"' => [
|
||||
'administration,moodle',
|
||||
'Administration',
|
||||
],
|
||||
'Text which is a langstring, but with extra whitespace' => [
|
||||
' administration,moodle ',
|
||||
'Administration',
|
||||
],
|
||||
'Looks like a langstring, but has incorrect space around comma' => [
|
||||
'administration , moodle',
|
||||
'administration , moodle',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the get_string_from_input function returns langstring strings correctly.
|
||||
*
|
||||
* @dataProvider get_string_from_input_provider
|
||||
* @param string $string The string to test
|
||||
* @param string $expected The expected result
|
||||
*/
|
||||
public function test_get_string_from_input($string, $expected) {
|
||||
$this->assertEquals($expected, \tool_usertours\step::get_string_from_input($string));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user