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

Reply via email to