Skip to content

Do not force string return type from ITranslator interface #231

Closed
@smuuf

Description

@smuuf

Is your feature request related to a problem? Please describe.

Due to the change in \Nette\Localization\ITranslator, where string return type was added in version 3, we're no longer able to have easily translatable pieces of HTML in our Latte templates/Nette forms.

Explain your intentions.

Previously, in Nette 2.4, we were able to return instances of \Nette\Utils\Html (class which implements the \Nette\Utils\IHtmlString interface) from our own implementation of \Nette\Localization\ITranslator. This is no longer possible as of version 3, due to the added string return type, which disallows the previously working logic.

This, unfortunately, makes the transition to Nette 3 very painful.

A "translatable piece of HTML" can, for example, be some piece of Markdown rendered into HTML. Markdown-markuped text is identified by our translator, processed, and then returned as a \Nette\Utils\Html object (instead of just string) - which is then not escaped when placed inside a Latte template.

Minimal example from our current 2.4 translator:

class OurTranslator implements \Nette\Localization\ITranslator {

	private $parsedown;

	// ...

	public function translate($message, $count = null) {
		$translated = gettext($message);
		return $this->processMarkdown(sprintf($translated, ...func_get_args()));
	}

	/**
	 * If the string begins with a magic "md:" prefix, process that string as
	 * if it uses markdown markup. This is opt-in to avoid any potential
	 * vulnerabilities from strings provided by untrusted third-parties.
	 *
	 * @return string|\Nette\Utils\Html
	 */
	protected function processMarkdown(string $message) {

		if (strpos($message, "md:") === 0) {
			$html = new \Nette\Utils\Html;
			return $html->setHtml($this->parsedown->line(substr($message, 3)));
		}

		return $message;

	}

}

The translator can simply return a Html object and then we don't have to deal with manually escaping/unescaping everything in Latte templates. This is because the \Latte\Runtime\Filters\escapeHtmlText itself supports this:

https://github.com/nette/latte/blob/bda925b140fe1fbc42b14c3f4f6343b808caf795/src/Latte/Runtime/Filters.php#L45-L50

	public static function escapeHtmlText($s): string
	{
		return $s instanceof HtmlStringable || $s instanceof \Nette\Utils\IHtmlString
			? $s->__toString(true)
			: htmlspecialchars((string) $s, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
	}

Now, because of the change of the ITranslator interface forcing the string return type, this mechanism can no longer be used.

Yes, in PHP 8 with union types it might be ok to use union string|IHtmlString|HtmlStringable return type for the translate method, but since that's not what can be done now, I'm proposing for the removal of the currently needlessly limiting string return type.

Activity

her-ur

her-ur commented on Nov 16, 2021

@her-ur

We are in the same situation as @smuuf

dg

dg commented on Nov 16, 2021

@dg
Member

How about this?

interface Translator
{
	/** @param  mixed  ...$parameters */
	function translate(string|Stringable $message, ...$parameters): string|Stringable;
}
her-ur

her-ur commented on Nov 16, 2021

@her-ur

Looks good 👍

added a commit that references this issue on Nov 16, 2021
f619332
dg

dg commented on Nov 16, 2021

@dg
Member

I think it's not even a BC break.

added 3 commits that reference this issue on Nov 16, 2021
2337130
32809e8
f483116
added 6 commits that reference this issue on Dec 8, 2021
d312d4b
af23c00
4e31dfb
5783c80
5b37cf8
86bff7a

61 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @ondrejmirtes@dg@petrparolek@smuuf@martenb

        Issue actions

          Do not force string return type from ITranslator interface · Issue #231 · nette/utils