Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: L10nID Object type

13 views
Skip to first unread message

Staś Małolepszy

unread,
Aug 12, 2015, 10:55:27 AM8/12/15
to Zibi Braniecki, mozilla-t...@lists.mozilla.org
I see the value of the helper, especially right now, but I generally have
doubts about this polymorphism. I base that on a set of the following 4
principles:

- avoid direct manipulation of textContent (because it requires manual
retranslations),
- avoid direct manipulation of innerHTML (because it's not safe),
- give more control to the localizer (don't bypass the localization layer
and insert the text yourself), and
- redundancy is good for localization because it gives localizers even
more control.

With these in mind, I think that many of the use-cases of the l10n-id
object could be serviced simpler by having two entities:

<songtitle "{{ $songtitle }}">
<songtitleUnknown "Unknown sing">

or, if more text is needed:

<deviceConnected "You've connected to {{ $deviceName }}">
<deviceConnectedUnknown "You've connected to an unknown device.">

Would that help us achieve the same goal?

-stas

On Sun, Aug 2, 2015 at 4:47 AM, Zibi Braniecki <zbigniew....@gmail.com
> wrote:

> As I work with Gaia apps to migrate more of them to L20n API I noticed
> that a lot of apps need to behave in a polymorphic way when it comes to
> translation.
>
> Instead of clear element is localized by an entity with ID X, we have a
> scenario where something may receive an ID or a raw string or maybe an
> ID/Args combo.
>
> The two common scenario is HTML element translation:
>
> var songName = data.name;
>
> if (songName) {
> nameElement.textContent = songName;
> } else {
> nameElement.setAttribute('data-l10n-id', 'unnamedSong');
> }
>
> ------------
>
> This of course may happen to Notification, or Bluetooth connection where
> we may have a name of the device, or want to pass a localized version of
> the string "unknown device".
>
> Over time, I developed a convention in which I pass an argument of type
> L10nID which can be one of:
>
> 1) 'id'
> 2) {id: 'id', args: {}}
> 3) {raw: 'string'}
> 4) {html: 'html fragment'}
>
> The first is just a shortcut to the most commonly used scenario where you
> just pass a string with an ID of the entity.
>
> Second is the second most common scenario where you need to pass an
> id/args pair that will be resolved by L20n.
>
> Third is the scenario in which a raw string is to be used, and fourth is
> for HTML scenario.
>
> This allows to write easy code like:
>
> function updateTitleField(l10nId) {
> var titleElement = document.getElementByid('songTitle');
>
> localizeElement(titleElement, l10nId);
> }
>
> function localizeElement(element, l10nId) {
> if (typeof l10nId === 'string') {
> element.setAttribute('data-l10n-id', l10nId);
> } else if (l10nId.raw) {
> element.textContent = l10nId.raw;
> } else if (l10nId.html) {
> element.innerHTML = l10nId.html;
> } else {
> document.l10n.setAttributes(element, l10nId.id, l10nId.args);
> }
> }
>
> ---------------
>
> This pattern is super helpful as it standardizes code localization and
> once a developer is familiar with how L10nId object may look like its easy
> to work with across different code pieces. The localizeElement I usually
> implement is not full (the 'html' scenario is rarely used) but it works
> well because it is easily extensible (for templating we could add template
> arguments to 'html' scenario, or add another one).
> On top of that the fact that the string scenario is resolving to entity ID
> means that the API promotes writing localizable code which is one feature I
> find very important when designing API's - it should suggest the right
> solution by making it the easiest.
>
> I started using it across many apps and started thinking about adding it
> as a helper to l20n.js. While I don't think that there's a value to add a
> class type because it would just increase memory cost, I think that having
> such localizeElement in our DOM API would help developers use L10nID
> approach.
>
> It also means that it will be easier to transition to l10n-id once we
> standardize, or make any other alternations since the API is more
> centralized.
>
> What do you think?
> zb.
> _______________________________________________
> tools-l10n mailing list
> tools...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/tools-l10n
>

Staś Małolepszy

unread,
Sep 25, 2015, 11:07:22 AM9/25/15
to Zibi Braniecki, mozilla-t...@lists.mozilla.org
While working on mock_l20n in https://bugzil.la/1208369 I remembered this
thread. Zibi, any thoughts on the future of l10nId?

zbran...@mozilla.com

unread,
Sep 28, 2015, 3:49:28 PM9/28/15
to mozilla-t...@lists.mozilla.org
Thanks for reminding me about it.

So, I didn't think too much about it. I still see people using it and I think that there are good reasons for them to prefer that "polymorphism" over what you are suggesting. Here's my devils advocate hat:

> - avoid direct manipulation of textContent (because it requires manual
retranslations),

When they want to use l10nObject.raw, that's because the content is *not* supposed to be retranslated. Think, song names.

> - avoid direct manipulation of innerHTML (because it's not safe),

Same here. Yeah, it is less safe, and they have to secure it themselves, but they want it in the scenario where they don't want the content to be localized.

> - give more control to the localizer (don't bypass the localization layer
and insert the text yourself), and

The thing is, I don't believe it should always go through the localizer.

Let's revisit the song list example in Music app. The developer wants to display an UI with a list of songs. He has a data base with those songs.
He wants to just loop over those songs and add them to UI, but he knows that some songs have no title. In that case, he wants to localize the title HTML element with l10nId "unknownTitle".

Or another example, where 99% of elements will have raw strings, and just 1% will be localized - displaying a contact name in a contacts list UI. Every once in a while that number is a voice mail. And we want to localize the node in that case using "voicemail" l10nId.

The problem I see with your proposal is that you are requiring developers to produce a significant number of strings that localizers will most likely never want to touch. And if they touch them, they'll most likely will break them.

I don't know of any localizability problem that would be resolved by letting localizers operate on such `songTitle` string, but I do believe that adding more strings to resources, that are not going to be localized by anyone, is a design mistake.

So, while I always thought that the if(translatable){}else{} pattern could be replaced by what you suggested, and I even documented it in our docs stating that devs can choose either way to go about it, I can see why they prefer the if/else approach.

On top of that, there's one more issue which is performance. In principle, the difference between if/else and "everything goes through l10n" can be described as a difference between 0 CPU/mem cost, and pushing this string through hundreds of lines of code, including string search, variable resolving, concatenation, surrounding with FSI/PDI marks and in the end, we just put it into textContent anyway.

If there's any reason to believe that this UI would work better in some locales if we went for entity-with-variable approach, I'm all for it. But so far, I haven't encounter a single case, and I've been refactoring a lot of our apps.

So, while the principle of "everything goes through l10n" appeals to me, the pragmatic perspective suggests that this case is in fact a duality between a localizable couple elements with "unknownTitle" and hundreds of elements with raw strings should not result in hundreds of resolved entities that get retranslated on language changes.

This brings my to my point. We can leave it "open", or we can help people write what they want in a more regulated manner that also, as a benefit, will make it easier for us to switch them if we eventually decide that yours, or yet another, approach is better (I can imagine equivalent of plural form for undefined variable).

zb.
0 new messages