ts() - Allow symbolic placeholders
Overview
When writing translatable strings, placeholders must be numeric.
This leads to some quirky strings - eg if you're outputting a title and subtitle ("Some Chapter: Some Section"), the only way to encode that is ts('%1: %2')
. This string should be translatable because the layout is language dependent (eg LTR/RTL; eg punctuation-preferences), but the exported string will become meaningless when presented in Transifex (or similar). And it may be confused with other/similar strings.
Current behavior
The function ts(string $str, array $params)
accepts the following $params
:
- Functional params (
count
,plural
,context
,domain
,escape
,skip_translation
) - Substitution params (numeric keys;
0
,1
,2
, ...)
As in:
echo ts('Hello, %1!', [
1 => $name,
]);
echo '<li>' . ts('%1: %2', [
1 => $title,
2 => $subtitle,
]) . '</li>';
echo ts('The directory %1 is not writable. Please check your file permissions.', [
'plural' => 'The following directories are not writable: %1. Please check your file permissions.',
'count' => count($notWritableDirs),
1 => implode(', ', $notWritableDirs),
]),
{ts 1=Bob}Hello %1!{/ts}
<li>{ts 1="Title" 2="Subtitle"}%1: %2{/ts}</li>
Proposed behavior (draft 1; symbol-prefix)
Any $params
which begin with a symbol (%
, _
, {
, @
, etc) will be used for variable substitution.
The earlier examples remain valid. Additionally, these examples are also valid:
echo ts('Hello, %name!', [
'%name' => $name,
]);
echo '<li>' . ts('%title: %subtitle', [
'%title' => $title,
'%subtitle' => $subtitle],
) . '</li>';
echo ts('The directory %dir is not writable. Please check your file permissions.', [
'plural' => 'The following directories are not writable: %dir. Please check your file permissions.',
'count' => count($notWritableDirs),
'%dir' => implode(', ', $notWritableDirs),
]),
{ts _NAME_=Bob}Hello _NAME_!{/ts}
<li>{ts _title_="Foo" _subtitle_="Bar"}_title_: _subtitle_{/ts}</li>
Proposed behavior (draft 2; capitalization-based)
Any $params
which begin with a capital letter ([A-Z]
) will be used for variable substitution.
echo ts('Hello, %NAME!', [
'NAME' => $name,
]);
echo '<li>' . ts('%TITLE: %SUBTITLE', [
'TITLE' => $title,
'SUBTITLE' => $subtitle],
) . '</li>';
echo ts('The directory %DIR is not writable. Please check your file permissions.', [
'plural' => 'The following directories are not writable: %DIR. Please check your file permissions.',
'count' => count($notWritableDirs),
'DIR' => implode(', ', $notWritableDirs),
]),
{ts NAME=Bob}Hello %NAME!{/ts}
<li>{ts TITLE="Foo" SUBTITLE="Bar"}%TITLE: %SUBTITLE{/ts}</li>
Comments
Either draft (using symbol-prefix or using uppercase) should avoid conflicts with existing strings+params. (Existing params do not begin with symbols and they are not uppercase.)
A couple factors in choosing a symbol:
- Using
%
is most consistent with currentts()
style. -
ts()
is used in multiple programming languages. Each has different compatibility/constraints.- Pure PHP and pure JS are fairly flexible (
%FOO
,{{FOO}}
,_FOO_
, etc) - Smarty-HTML (
{ts KEY=VALUE}...{/ts}
) is pretty limited. The bottleneck is how it parses theKEY
. - Angular-HTML (
{{ts('...')}}
) is in the middle. It's OK for{{ts('%FOO')}}
,{{ts('_FOO_')}}
, but I wouldn't count on{{ts('{{FOO}}')}}
.
- Pure PHP and pure JS are fairly flexible (
- If you want one symbol that works everywhere,
_
is probably it. - Being flexible about symbol may be good for compatibility in the most contexts.
I suppose that the uppercase approach constrains style a bit, but maybe that's a good thing - ie you get more consistency in how ts()
looks across environments.
Questions
Are there any constraints in other layers -- eg Transifex, civistrings -- which would prevent this?
As far as I know, the only constraints which require using numeric-keys are baked into ts()
itself.