When we closed the design phase of the FTL syntax for L20n, we decided to force
ourselves to work with the new syntax for half a year, collect feedback from
adopters and other stakeholders like tool authors, and only then come back to
review the syntax.
It's been over 6 months since and we (mostly :stas, :matjaz and :gandalf)
accumulated a number of items to review that are worth considering.
Most of the feedback comes from user testing, implementation woes, feedback
from potential users and conversations with experts.
My personal opinion is that for the 6 months of working with the syntax, the
number and severity of items is low, but I believe it's a good time to consider
making any changes resulting form them rather now than later.
====================================
1) Suboptimal selector and trait reference resolution when no default index is
available
Currently, our grammar allows but doesn't enforce default value for traits and
variants.
In the process of developing runtime resolution, we identified that lack of
that annotation significantly reduces how resilient our resolver can be.
Without it, the entity is not "resolvable" within itself - if external
arguments or other entities are not resolved, there is no way to indicate which
variant should be selected and the fallback stringification of the selector is
limited.
For traits, lack of default trait means that if the entity has no value, and
there is no default trait, and caller selects trait that is not available, then
the reference expression cannot be resolved.
Beyond error recovery, this impacts environments that would benefit from
ability to display whole or parts of the entity without surrounding context
available.
Example of such environment are localization tools. Having a default variant
would allow for an easy display of a "folded" selector, and availability of the
default trait would allow for an easy display of a string representation of the
entity value when value itself is not present.
2) Forward-compatible functions
During concaptualization of how to make builtin functions forward compatible,
we identified that we cannot ensure that the contract between the provider of
the function and the localizer using it will be preserved.
One can imagine a builtin function like `PLATFORM()`, `OS()` or
`SCREEN_WIDTH()`, that will change its signature over time.
Same can be said for the environment in which the entity is being used. At the
time of creation of the entity, maybe just 2 platforms are considered, but
later the project target platforms may change.
In such cases, additional bit of information allowing for better fallbacking in
case of such incompatibilities would be of high value to the quality of the
output.
3) Confusing similarity of traits and variants
While variants are not a completely new feature in l20n - they exist in a
similar form in MessageFormat, traits are, as far as we know, unprecedented
localization entity features.
That means that most users are unfamiliar with the concept and how to use it
when they encounter it, and the feedback we collected indicates that the
syntactic similarity of the representation adds to that confusion and hides
semantic differences.
An example of such an entity would be:
brandName =
[nominative] Firefox
[possesive] Firefoksa
welcome = { $num ->
[one] Witaj
[other] Witajcie
}
There can be more extreme (and less realistic) examples created where both
trait and variants are next to each other visually overlapping and
differentiated only by indentation and syntax in surrounding lines of code.
We believe it would be worth revisiting the syntax around them and consider
changing one or the other to indicate the difference.
4) Traits are a syntactic cluster of semantically different concepts
Explaining traits and reasoning about them has been found to be particularly
challenging. The feature feels very open-ended, ambiguous and seems to be of a
"catch-all" nature.
Over last 6 months (and previous work with FxOS and Vaani), we really
encountered three classes of linguistic concepts that are served by traits:
a) Multi-value translations
For example a widget with a label, ok and cancel button may be localized with a
single entity with a value and two traits:
install-widget = Do you want to install { brandName }?
[ui/ok] OK
[ui/cancel] Cancel
b) Multi-variant values
When the entity value has multiple potential variants:
brandName =
[nominative] Firefox
[possesive] Firefoksa
or:
welcome =
[written] Welcome!
[spoken] Welcome to { brandName }
c) Meta-information
When we want to encode additional information on the entity that will be useful
for further translation:
brandName = Firefox
[gender] masculine
froze = { brandName[gender] ->
[masculine] { brandName } zawiesil sie
[feminine] { brandName } zawiesila sie
}
Those three use cases are of vastly different nature and clustering them into a
single syntactic structure seems to be a workaround rather than a solution,
making each three work "well-enough", but none of them working really
intuitively for the reader.
On top of that, it creates a possibility to end up with a really confusing
entity:
key =
[gender] masculine
*[nominative] Firefox
[dom/tooltip] Nazwa programu
This becomes especially visible while working on GUI localization tool that is
supposed to handle such cases and aid localizer in making right decisions.
The multi-variant value case would benefit from the default index, but of
course gender trait nor dom/tooltip traits should have it. The visual
representation of this is at best confusing.
5) We don't seem to have a way to represent a combination of L20n and Intl API
using `formatToParts` feature.
Although this did not come up in our prototyping yet, I believe that it is the
last moment to try to make space for such use case in our syntax.
The common case would be an attempt to create a localization phrase with a unit
or date formatted and styled.
Below are three examples with ftl/js solutions *without* the formatToParts part.
a) "You have to pick up your package by December <b>2nd</b> 2016"
ftl:
key = "You have to pick up your package by { $date }"
js:
let date = new Date();
ctx.formatValue('key', {
date: FTL.DateTime(date, {month: 'long', day: 'short', year: 'numeric'})
});
b) "The fastest route will get you to your destination in <b>30</b> minutes"
ftl:
key = "The fastest route will get you to your destination in { $time }"
js:
ctx.formatValue('key', {
time: FTL.Unit(30, {unit: 'minute', style: 'long'})
});
c) "This email has been sent to you 2 <b>hours</b> ago"
ftl:
key = "This email has been sent to you { $relative_time }"
js:
ctx.formatValue('key', {
time: FTL.RelativeTime(-2, {unit: 'hour', style: 'long'})
});
The question is how can we incorporate formatToParts approach to solve them
*with* formatting.
===================================
My experience with UX is that the first study is the most significant one,
since it changes the sample tested from 0 to non-zero and that's a 100% change.
>From there, each further sample is giving diminishing returns, so I expect
>that the number of items we'll collect over the next 6 months will be lower.
This thread is for discussing the validity of the problem statements and their
severity, rather than proposing solutions. I'd like to ask everyone to kick of
new threads for each solution proposal, so that we can discuss each separately.
zb.
_______________________________________________
tools-l10n mailing list
[email protected]
https://lists.mozilla.org/listinfo/tools-l10n