New feature: Translation message placeholder support - #121
Conversation
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
e020ffa to
1306a09
Compare
|
@TotalWipeOut Some comments:
A placeholder is in the message: "Hello {name}!" and the process of converting the message with a placeholder can be called formatting or replacement. To format or replace the placeholders, values/parameters are required.
Hijacking is not an option because:
My first thought was, why allow multiple variants when one official is enough, but if we see this component in use with different frameworks or CMS, this would be a benefit.
Why not? We can update the view helper configuration to use the new view helpers with parameter support: laminas-i18n/src/ConfigProvider.php Lines 151 to 158 in b3259ac And the new view helper(s) can be used like this: <?= $this->translate($message, params: ['name' => 'World']) ?>The old view helpers must be retained for reasons of backward compatibility. |
|
@froschdesign The reason for multiple placeholder formats is that while I agree ICU message format is the place to be, i wanted the ability to allow this feature to integrate with existing apps with existing translation files that might do it in the various other ways via custom solutions. The app I work on uses printf format for this task currently Should I add a new method in Regarding view helpers, from your example, can you show me how this will work with a new view helper, but called the same in the view and it not being a BC break? I don't fully understand Thanks again for your detailed response ❤️ |
This is a simple mapping: $renderer = new Laminas\View\Renderer\PhpRenderer();
$renderer->getHelperPluginManager()->configure(
(new Laminas\I18n\ConfigProvider())->getViewHelperConfig()
);
$renderer->getHelperPluginManager()->setFactory(
NewTranslate::class,
Laminas\ServiceManager\Factory\InvokableFactory::class
);
$renderer->getHelperPluginManager()->setAlias(
'translate',
NewTranslate::class
);
echo $renderer->translate('example', params: ['foo' => 'bar']);This overwrites the existing view helper, as is done if you want to use your own. |
|
@froschdesign So i understand correctly with this approach, this functionality requires additional config in the app, add wont work out of the box? |
This component already provides a configuration: laminas-i18n/src/ConfigProvider.php Lines 151 to 198 in b3259ac This must be extended so that the new view helper(s) can be used.
No, because a new view helper must be created and the old one remains as it is. (The view helpers are not marked as final, so we cannot change them.)
No, nothing must and will be changed in this case. Via the configuration we will map This works out of the box. Please look at the renderer of laminas-view: |
…lpers Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
5a8b9f5 to
de5e914
Compare
|
@froschdesign Thanks - I have tried to address your feedback :) |
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
|
@froschdesign Let me know if this is something your happy to be included in this library, and i will get the tests written. Thanks |
|
@TotalWipeOut
Short: The feature is definitely necessary, but with a modified implementation. Minor ReleaseIf we add this feature in a minor release then without any changes on the Examplenamespace Laminas\I18n\Translator\Formatter;
use Laminas\I18n\Translator\Translator;
use Laminas\I18n\Translator\TranslatorInterface;
final class TranslatorFormatterDecorator implements TranslatorInterface
{
public function __construct(
private readonly Translator $translator,
private readonly FormatterInterface $formatter
) {
}
public function translate(
$message,
$textDomain = 'default',
$locale = null,
iterable $parameters = []
): string {
// …
}
public function translatePlural(
$singular,
$plural,
$number,
$textDomain = 'default',
$locale = null,
iterable $parameters = []
): string {
// …
}
}Benefits
More Informations
Major ReleaseHere we can change the interface for the translator and rework the entire So if you can wait, the next major version is an option. |
Not entirely true: "Originally posted by @thexpand at zendframework/zend-i18n#104" (See: #7) |
|
|
||
| use function str_replace; | ||
|
|
||
| class HandlebarPlaceholder implements PlaceholderInterface |
There was a problem hiding this comment.
The naming is still wrong because it is an formatter which formats a message. A placeholder is in the message: "Hello {name}!" – here {name}.
There was a problem hiding this comment.
@froschdesign so then from this, shall i rename things like this:
- namespace to be
Laminas\I18n\Translator\Formatter PlaceholderPluginManagertoFormatterPluginManager, same with factoryPlaceholderInterfacetoFormatterInterface- and all class suffixes to
*Formatter
or, if you have something else in mind, please advise
Oh yes, thanks for spotting that. |
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
d4db28e to
da1f695
Compare
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
| View\Helper\TranslateWithParams::class => InvokableFactory::class, | ||
| View\Helper\TranslatePluralWithParams::class => InvokableFactory::class, |
There was a problem hiding this comment.
I will provide the delegator to add the decorator for the new view helpers.
There was a problem hiding this comment.
Thank you, I was going to ask regarding that. That would be great.
Thanks for all your time on this!
Co-authored-by: Frank Brückner <info@froschdesignstudio.de> Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
Signed-off-by: Kevin Hamilton <kevin@eagleeye.com>
|
@TotalWipeOut Any progress on this |
|
@graemedewe |
@froschdesign Thanks for the update, i am still keen to add this functionality - and can continue with this PR if you are still happy to provide the delegator as mentioned further up? |
|
This patch is great. Having this feature in the translator is very necessary IMO. However, I think that the parameters should be part of the main translator interface rather than a decorator. If a translator is decorated multiple times, you'd never end up with the right instance with the right parameters: $translator = new Laminas\I18n\Translator();
$translator = new Laminas\I18n\FormattingTranslator($translator);
// and in another delegator somewhere else…
$translator = new Laminas\I18n\CachingTranslator($translator);So, I think that we should consider this for a v2.0 of public function translate(
string $message,
array $parameters = [],
string|null $textDomain = null,
string|null $locale = null,
);I don't have huge experience in this domain, so this is my 2 cents, and I'm happy for others to correct me. |
With a |
Description
WORK IN PROGRESS
Upon needing message placeholders and seeing the 4 year old issue #7 about needing it, I decided to take a stab at adding message placeholder support into laminas-i18n, as I see it as key missing feature.
(I decided to use the term 'placeholders' instead of 'parameters' so that it is less ambiguous)
As I really didn't want a BC break, I have hijacked the$textDomainparameter of thetranslate/translatePluralmethod to allow passing in placeholders where it seemed most logical going forward. There is a way to be able to provide bothtextDomainandplaceholdersif that's needed.Goals
What I've done so far
Translator\TranslatorServiceFactoryto inject a placeholder from configTranslator\Translatorclass to add new methods that pass messages through a placeholder compiler before returningTODO
Before i go any further, I am seeking advice as to if this is the correct approach for adding this without a bc break
The code is not perfect, so any guidance on naming/architecture/design would be amazing. Once i have some feedback, i will make any required changes and get on with the tests
And, a thank you to everyone in the Laminas community for being so kind and generous with your time ❤️