Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web Manifest Overrides #1045

Open
marcoscaceres opened this issue Jul 15, 2022 · 34 comments
Open

Web Manifest Overrides #1045

marcoscaceres opened this issue Jul 15, 2022 · 34 comments
Labels
i18n-needs-resolution Issue the Internationalization Group has raised and looks for a response on. TPAC2023

Comments

@marcoscaceres
Copy link
Member

marcoscaceres commented Jul 15, 2022

We’ve known for a while that we need some way to override the value of manifest members based on some “environmental condition”, be it user’s preferred language, OS color scheme (i.e., light or dark mode), or something we haven’t thought of yet.

The working assumption is that the overrides may apply at install time and may persist after installation. For example, if an installed application is running, and the OS switches color scheme to “dark mode”, the user agent should apply a matching theme_color for the dark color scheme.

Thus, the solution needs to cater for both OS level changes independently of the browser engine running, and the browser engine should be able to re-apply a manifest to reflect the runtime environmental conditions at any moment in time.

Requirements

The solution needs to be:

  • Built for purpose: excluding hypothetical use cases.
  • Backwards compatible: must work on existing user agents.
  • Easy to use and process: it should avoid, for instance, excessive nesting, and not dependent on array order from other members in the manifest.
  • Designed to handle user preferences and language selection (preferably all at once).

Related issues

The following issues and pull request have driven this discussion:

Points of contention

Throughout the discussion in the related issues, a few points of contention have arisen. There are valid arguments made for an against each of the following.

CSS media queries VS using manifest members

A primary point of contention is the use of CSS Media Queries VS using manifest members that represent the same thing. On the one hand, media queries define a lot of what we want (i.e., all the “prefers-“ media features and values). On the other hand, evaluation of those media features requires a CSS runtime.

As stated in #975:

“the challenge we face is then who actually evaluates the <media-query-list> to do the member selection? If it's the OS, then "light" and "dark" is definitely better: we can't expect an OS to do anything worthwhile with <media-query-list>, and converting <media-query-list> to something that the OS understands would be quite challenging and error prone.

Although the above holds true as a general statement, in the case of icons, the above currently has no bearing because operating systems don’t support switching application icons when the theme changes.

Further, some OSs restrain what iconography can be shown in shortcuts, again limiting the possibility of developers having to provide icons to the OS to deal with OS-level user preferences. Hence, if overrides only apply to members that are in control of the user agent, and which are applied at runtime: where interpreting a CSS media query is possible.

The point being: some members (e.g., theme_color) are interpreted at runtime by the browser engine, while others might need to be handled specifically by the OS. We should handle those individually and on a case-by-case basis.

Parsable property keys

Another point of contention has been using “parsable keys”, where by a key contains either a CSS media query or a language-tag. For example:

{
   "(prefers-color-scheme: dark)": {},
   "(prefers-color-scheme: light)": {},  
}

As opposed to using named keys with objects inside an array:

{
  "overrides": [
     {"media": "(prefers-color-scheme: dark)"},
     {"media": "(prefers-color-scheme: light)"},   
  ]
}

Using parsable keys is fairly common in JSON. However, where the order of keys is important, using parsable keys relies on JavaScript-based manifest parser in order to work: this is because JS treats JSON’s keys as an ordered map. As seen above, it also results in a flatter structure when compared to using arrays and objects.

However, a significant drawback is that a parsable-key structure is not extensible: The key needs to have all the information in it to support every type of matching. This works ok for matching user-preferences via media queries, but might not work for languages (because languages are not currently a media feature that can be matched).

On the other hand, using and array and a set of objects overcomes these issues at the cost of adding some verbosity. Nevertheless, using arrays + objects has several advantages:

  • doesn't depend on member order, but instead relies on array order, which overcomes the JS-JSON quirk where keys are an ordered map.
  • is extensible. So, for instance a “language” and “dir” members could be added to members that need it. Or, specific “media” queries or other user-preference determining members can be added as needed for a particular purpose.

Issue with translations proposal

Note that the “translations” proposal suffers from the same issues listed above, because it relies on a (parsable) language-tag as a key.

{
   "translations":
      "en": {
        "short_name": "whatever"
      }
}

Language selection is generally done using Unicode’s “lookup” algorithm, meaning that it’s not a simple match. The solution may also be inadequate in that it doesn’t allow specifying per member direction and language override. If individual direction and language is a requirement, then the following object structure is more appropriate:

{ "text": "some text", "dir": "ltr|rtl|auto", "lang": "language-tag" }

See "Purpose-built objects and members" below for how the above can be used to solve localization problems.

Media preference overrides

Another proposed solution was to have a grouping object with a special key (in this case prefers_color_scheme).

{
    "user_preferences": [
        {
            "prefers_color_scheme": "light",
            "theme_color": "white",
            "background_color": "black"
        },
        {
            "prefers_color_scheme": "dark",
            "theme_color": "black",
            "background_color": "white"
        }
    ]
}

The problem is that it’s overly broad in its applicability. For example, the following doesn’t make sense:

{
    "prefers_color_scheme": "light",
    "name": "light",
    "lang": "jp"
},
{
    "prefers_color_scheme": "dark",
    "name": "dark",
    "lang": "jp"
}

That is to say, changing the color scheme shouldn’t (and won’t) have any effect on the name of the application. The problem is that it’s not immediately obvious as to what prefers_color_scheme applies.

The redefinitions proposal

Another proposal is to use specific members, which include an array of objects that provide a “context” and an “override”.

 "user_preferences": [
    {
      "media": "(prefers-color-scheme: dark)",
      "override": {
        "theme_color": "#bdbdbd",
        "background_color": "#000000"
      }
    },
  ],
  "translations": [
    {
      "language": "de",
      "redefine": {
        "name": "Meine super coole App"
      }
    }
  ]

Although compact, this solution suffers from the same issues already mentioned above: in that a developer could end up adding members that are unaffected by the “context”. For example, adding “theme_color” under “translations“.

Thomas Steiner also showed that this separation between “translations” and “user_preferences” becomes unmanageable:
#975 (comment)

Purpose-built objects and members

Given that we need to override existing manifest members, another proposal is to just introduce new members and purpose-built objects. Then, each could contain an array of objects with a condition for the override it.

Thus, we could define a purpose-built “color object” and pluralize the name of “theme_color”. For example:

{
"theme_color": "red",
"theme_colors": [
    { "color": "red" },
    { "color": "darkred", "media": "(prefers-color-scheme: dark)" }
]
}

A potential problem with pluralization of member names is that we already have some members whose names are in plural form (icons, shortcuts), so this wouldn’t be backwards compatible. So, might need a new member for such cases (or we take the compat hit).

A possible solution might looks like:

{
    "shortcuts": [
        {
            "name": "Play Later",
            "localized_names": [{ "value": "Jugar Mas Tarde", "lang": "es" }],
            "description": "View the list of podcasts you saved for later",
            "localized_descriptions": [
                {
                    "value": "Ver la lista de podcasts que guardó para más tarde",
                    "lang": "es",
                    "dir": "ltr"
                }
            ],
            "url": "/play-later",
            "icons": [
                { "src": "/icons/play-later.svg", "type": "image/svg+xml" }
            ],
            "other_icons": [
                { "src": "/icons/play-later.svg", "scheme": "dark" },
                { "src": "/icons/en/play-later.svg", "scheme": "dark", "lang": "en" }
            ]
        }
    ]
}

It would be simple enough to apply the same principle to the “name“, ”short_name“ members, as well as the ”description“ member by defining a ”localizable object“ structure.

{
"short_name": "dog",
"localized_short_names": [
  {"value": "perro", "lang": "es", "dir": "ltr"},
  {"value": "כֶּלֶב", "lang": "he", "dir": "rtl"}
]
}

Despite having include new members, it does meet all the requirements:

  • ✅ Built for purpose: each member type can only accept a specific kind of object (e..g, localizable object, color object, etc.). This is already how the manifest format works.
  • ✅ Backwards compatible: if we add new members we don’t break backwards compatibility.
  • ✅ Easy to use: there is no excessive nesting and everything is kept together for each object type.
  • ✅ Designed to handle user preferences and language selection: because the objects and members are built for purpose, they cary all their own selection criteria (be it at media query, language, or whatever), which solves for matching selection being overly broad.

Conclusions

Although we have a number of different solutions, none are without their own set of problems. However, of all the approaches, the “purpose-built objects and members” seems to be the least problematic and one that best meets the requirements.

@tomayac
Copy link
Contributor

tomayac commented Jul 19, 2022

Thanks, @marcoscaceres, for doing the grunt work of summarizing all proposals so far. Boy, this space is complex. Regarding Purpose-built objects and members, it's not clear if your proposal would require CSS user preference media query parsing or not, since in your proposal you mention two ways:

{
  "color": "darkred",
  "media": "(prefers-color-scheme: dark)"
}
{
  "other_icons": [{
    "src": "/icons/play-later.svg",
    "scheme": "dark"
  }]
}

Can you clarify?

@alancutter
Copy link
Contributor

An extensible concept of manifest overriding sounds ideal to me if its syntax can accomodate all potential use cases.
Something with the data structure:

"conditional_overrides": [
  {
    "condition": <predicate>,
    "path.to.manifest.field": <override value>,
    ...
  },
  ...
]

I'm somewhat skeptical an acceptable syntax can be found though.

@loubrett
Copy link

Thanks for putting this all together Marcos!

The point being: some members (e.g., theme_color) are interpreted at runtime by the browser engine, while others might need to be handled specifically by the OS.

The main problem that I’m trying to solve with a dark theme_color is that currently when you open an app, you’ll see a flash of the manifest theme_color before the browser loads and the html theme_color takes over. If we have a media query for the theme_color we would still need to wait for the browser in order to evaluate the media query.

So your point that media queries don't work for icons also applies here. Therefore I think we should use the "scheme": "dark" syntax for the color objects instead of a media query so that it can be handled by the OS.

@mgiuca
Copy link
Collaborator

mgiuca commented Jul 21, 2022

Thanks Marcos!

Seconding what @loubrett said: one of the main objections to using the MQ syntax is that it can't be processed without a browser engine. Given that we're open to using the simplified syntax for icons, I hope we can extend that to the other members too (not just because we need to process them without a browser, but also for consistency).

@alancutter : my feeling is that we've spent a lot of energy trying to generalize this problem and have not come up with an acceptable syntax for quite some time. Sometimes, solving the specific problem you are trying to solve is better than finding a general solution to all conceivable problems (in particular, it means that we don't have to handle "ridiculous" cases that nobody will ever need, like making the name conditional on color scheme, or the theme_color conditional on language, and we can solve specific more complex problems, like icons that may need to be conditional on both, on a case-by-case basis).

So I'm overall in favour of Marcos' purpose-built members. And excited that we appear to be headed towards consensus.

If I may introduce a little bikeshedding: I think we can come up with a consistent naming scheme to avoid having localized_names, theme_colors and other_icons. This is rather similar to the display_override member introduced in manifest-incubations: the only real reason we introduced display_override instead of just extending the existing display member is to avoid introducing new values for that member that would break backwards compatibility. Similarly, I think that's the only reason Marcos is proposing localized_names, theme_colors and other_icons, instead of just allowing name, theme_color and icons to be lists of conditional alternatives. (Albeit, display_override is not a list of conditional alternatives, it's just an ordered list of preferences, but it's a very similar concept.)

So I would propose sticking with a consistent _override naming scheme, where X_override has the implied meaning "this is just an extended version of X but you can specify alternative values for that member that will be selected according to some member-specific rule". name_override, theme_color_override and icons_override.

This isn't a hill to die on; I'm happy with any naming that lets us move forward, so treat this as a suggestion.

@bathos
Copy link

bathos commented Jul 21, 2022

using parsable keys relies on JavaScript-based manifest parser in order to work

+1 on not relying on property order. The JSON spec explicitly defines its objects as having unordered members and though most JS objects implement [[OwnPropertyKeys]] as OrdinaryOwnPropertyKeys and that usually would match source text order, even OOPK has an exceptional case that makes it poorly suited for stuff like this:

image

@mgiuca
Copy link
Collaborator

mgiuca commented Jul 22, 2022

The JSON spec explicitly defines its objects as having unordered members

This is a debate we've had many times on this spec :) I've carefully read the two (!) JSON specs and I think both of them are sufficiently vague as to whether we can actually rely on the order that objects define their members. Suffice to say, some JSON parsers preserve the order, many do not. I would very strongly prefer that when we write JSON-based formats like manifest, we do not rely on the order of dictionary keys (Marcos' final proposal here does not).

Further, I would prefer that we treat objects in precisely one of two ways:

  • As a "struct" (with pre-defined keys for specific members), or
  • As an "unordered map" (with arbitrary string keys, where the order doesn't matter and the values all have the same type).

All of the objects in this proposal are "struct" type, so that's good with me.

@bathos
Copy link

bathos commented Jul 22, 2022

Oh, wild! I see what you mean about ECMA-402: it makes no semantic assertion about order and expressly permits other specs /implementations to overlay their own. I’m not sure what makes RFC 7159 vague since “An object is an unordered collection of...” is about as unambiguous as a semantic assertion can get — is that text not actually normative or something? In any case I hadn’t realized they conflicted on this and appreciate the info.

@marcoscaceres
Copy link
Member Author

@tomayac wrote:

Regarding Purpose-built objects and members, it's not clear if your proposal would require CSS user preference media query parsing or not, since in your proposal you mention two ways:
Can you clarify?

You are spot on and this is exactly what we need to discuss.

@alancutter wrote:

I'm somewhat skeptical an acceptable syntax can be found though.

Same, why I proposed just skipping all that and just using "whatever_members" express the same semantics by hard-coding the solution.

And 💯 to everything @mgiuca said on the matter.

@loubrett wrote:

The main problem that I’m trying to solve with a dark theme_color is that currently when you open an app, you’ll see a flash of the manifest theme_color before the browser loads and the html theme_color takes over.

Got it. But hat will happen no matter what if there is a mismatch between the manifest and the HTML. Consider:

  1. app is installed with manifest that declares dark + light theme_colors.
  2. App starts, start_url loads.
  3. HTML theme_color kicks in (mismatch!).

The solution is make sure the HTML theme is set via:

<meta name="theme-color" media="(prefers-color-scheme: dark)" content="yellow">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="blue">

(Or just leave it to the manifest to do its thing… only include the theme colors if not installed)

If we have a media query for the theme_color we would still need to wait for the browser in order to evaluate the media query.
So your point that media queries don't work for icons also applies here. Therefore I think we should use the "scheme": "dark" syntax for the color objects instead of a media query so that it can be handled by the OS.

Sorry, let me try to be more clear. I’m proposing that the MQs are evaluated and (statically) transformed at install time, not evaluated at start/runtime. So:

  1. Manifest -> theme_color_overrides [{MQ}, {MQ}].
  2. At install time, each {MQ} is converted to a native equivalent representation (e.g., on iOS, something in an XML .plist).
  3. User launches the app.
  4. OS reads the native (XML or whatever) description, launches the app and applies the theme color based on the OS scheme (i.e., all native, no MQ evaluation needed because there is no media query).

Implementations already take “static snapshots” of things in the manifest and convert them to OS equivalent data: in particular theme_color and background_color start as CSS colors and are then converted to Android/iOS equivalent static colors (e.g., the css keyword red becomes some hex representation equivalent on Android/iOS).

The .2 above is the non-trivial part, and @mgiuca is raising valid concerns about.

@mgiuca wrote:

one of the main objections to using the MQ syntax is that it can't be processed without a browser engine. Given that we're open to using the simplified syntax for icons, I hope we can extend that to the other members too (not just because we need to process them without a browser, but also for consistency).

Right. That's why I was proposing the browser convert the MQ to a static representation at install time, like we do with the color members. The valid question/concern is: how difficult is it going to be to do that?

Putting on my WebKit hat for a second, and having chatted with @dcrousso, we think it could be doable… but we would need to check how insane MQs could get and how much trouble it is to translate them to OS equivalents… it’s on us (WebKit folks) to show that it would work and it’s not insanely complicated.

On the other hand, if it does all get too crazy, falling back to a simple "scheme": "dark" (and other prefers_ equivalents) is definitely a workable solution, even if it does reinvent the wheel a bit.

The motivating factors on the Webkit side are:

  • don’t reinvent the [CSSMQ prefers_] wheel.
  • don’t burden developers with learning a new thing (when the CSS one will do).

@mgiuca wrote:

So I would propose sticking with a consistent _override naming scheme, where X_override has the implied meaning "this is just an extended version of X but you can specify alternative values for that member that will be selected according to some member-specific rule". name_override, theme_color_override and icons_override.

Something like that would work... the other reason I chose localized_X is because those members would only accept "localized objects". Bikeshedding on the above would be good, specially if we have agreement about the specific types. At the same time, "_overrides" could be fine even if members accept different object types.

@marcoscaceres
Copy link
Member Author

About "other_", just want to be clear that was not a serious proposal... I was just coming up empty with what to call those 🫠

@xfq xfq added the i18n-tracker Group bringing to attention of Internationalization, or tracked by i18n but not needing response. label Jul 25, 2022
@mgiuca
Copy link
Collaborator

mgiuca commented Jul 27, 2022

@bathos :

Oh, wild! I see what you mean about ECMA-402: it makes no semantic assertion about order and expressly permits other specs /implementations to overlay their own. I’m not sure what makes RFC 7159 vague since “An object is an unordered collection of...” is about as unambiguous as a semantic assertion can get — is that text not actually normative or something? In any case I hadn’t realized they conflicted on this and appreciate the info.

Yeah you're right I think: RFC 7159 does seem fairly opinionated that the objects' order should not matter (later on it says "JSON parsing libraries have been observed to differ as to whether or not they make the ordering of object members visible to calling software. Implementations whose behavior does not depend on member ordering will be interoperable in the sense that they will not be affected by these differences.". I don't know where I got the impression that it allowed the order to matter.

@marcoscaceres :

Got it. But hat will happen no matter what if there is a mismatch between the manifest and the HTML.

Yes, but the idea is that there should not be a mismatch between the manifest and HTML. If there is a mismatch, there will be a flash. All we are trying to do is make it possible for developers to write an app that has no mismatch.

I think what you are suggesting here is that the manifest parser (at parse time, not at app load time) runs the MQ parser with both a dark and light context, and then stores the result in an OS-specific context. That is theoretically possible (though it still creates a non-trivial dependency between the manifest parser and CSS parser which did not exist before). But it still has a number of issues:

  • It requires us to run the MQ parser for a limited hard-coded set of configurations in advance. That doesn't work well with combinations (e.g. if we have the capability to do an AND condition of, say, theme colour and language, we would need to run it on all permutations). The alternative is to be very limited in what operations are supported. If your goal is to not invent a new language for developers to learn, I would say it's harmful to claim it's CSS MQ when in reality it's a (potentially undocumented) subset of CSS MQ.
  • It's not clear what values we would ascribe to other MQ features that aren't applicable at the OS level, which is almost all of them. For example, say that a MQ in the manifest uses the viewport size features like width and height. How would we reflect those at the OS level? What value would we ascribe to those "meaningless" features?
  • Even for features that do make sense at the OS level, it isn't feasible to preprocess them unless they have a very limited range (like light and dark). For example, what if the manifest includes "(prefers-color-scheme: dark) and (resolution > 150dpi)" for one option, and "(prefers-color-scheme: light) and (resolution < 150dpi)" for another option? How do we pre-process this meaningfully? Even though resolution does make sense at the OS level, it still is probably not something we can "preprocess" because we would literally need to run the query over every possible resolution.
  • Since we're planning to use this for translations, it's worth pointing out that there is no language MQ feature. Not insurmountable, as we could get it added to CSS, but that's yet another yak to shave.

I can see the appeal of using MQs for this instead of "inventing a new wheel", but this really feels like using a sledgehammer when we need tweezers. We have a fairly simple feature request (be able to make manifest options conditional on theme colour and language), and while the CSS MQ can do the former, it can't (yet) do the latter, and it can do so many other things we don't want.

@mgiuca
Copy link
Collaborator

mgiuca commented Aug 3, 2022

Hi Marcos,

As discussed today, we're looking forward to seeing a concrete proposal using media queries, and @loubrett will provide a concrete proposal using the lightweight per-purpose syntax.

There are a few questions I'd like to see answered in the detailed MQ proposal:

  • What is the implementation expected to do. (While this isn't something you would put in the spec, I still want to see a discussion of the implementation in the proposal because we can't accept it if it isn't practical to implement.) As I see it, there are three possible implementation paths here:
    • Put a full MQ parser in the OS, so that the OS can respond to changes to the MQ inputs without having to load up a browser.
    • Pre-process all permutations of the MQ inputs at parse time, and store all possibilities in a file that the OS can respond to, so that when there are changes to the inputs, it can respond by selecting the appropriate one. (This works for just {light, dark}, but quickly becomes infeasible if there are many different inputs, especially integer values.)
    • Pre-process the current state at parse time. Re-process it when the app loads. (This would mean that the app's representation in the OS does not respond to changes to the input until the app reloads.)
  • Describe which MQ features you are intending to support, or possibly support in the future. (i.e. go through the list of MQ features -- which ones are feasible to include in this proposal?). Describe how the non-supported ones (like viewport size, for instance) would be handled.
  • Do you intend for the specification to state which MQ features are supported, and how they apply in a non-browser context, or is that left up to the implementation?
  • Do you intend to support all the syntactic constructs of MQ, such as numeric comparison operators? Or define a subset?
  • Are there concrete use cases for supporting all of these features or is this just a case of "we might need them in the future"?

Note that I'm focusing a lot on the implementation because my main concern here is that the MQ proposal adds significant complexity to the browser vendor. While I agree that when there is a trade-off between ease of use for the web developer vs ease of implementation for the browser vendor, the developer should win, there is a limit to this. IMO the benefit to the developer of MQ vs the per-purpose syntax would have to be shown to be extremely valuable to outweigh the large implementation overhead, or I would need to better understand how the implementation is not as complex as I think it is. (So before we go down the path of quantifying the benefits and costs, I'd like to have a clear picture of how you think a browser should implement this feature.)

Thanks and looking forward to chatting further.

@bathos
Copy link

bathos commented Aug 3, 2022

In the non-CSS-parsing model, I’m curious whether there could be alignment with User Preference Media Features Client Hints Headers? They’re an existing spot where media query data is decoupled from media query syntax, anyway, and since I didn’t see em mentioned in the thread, figured it might be worth a link just in case there’s something useful there.

@tomayac
Copy link
Contributor

tomayac commented Aug 4, 2022

In the non-CSS-parsing model, I’m curious whether there could be alignment with User Preference Media Features Client Hints Headers? They’re an existing spot where media query data is decoupled from media query syntax, anyway, and since I didn’t see em mentioned in the thread, figured it might be worth a link just in case there’s something useful there.

CC: @beaufortfrancois who has implemented Sec-CH-Prefers-Color-Scheme in Chromium and may be able to share his experience.

@mgiuca
Copy link
Collaborator

mgiuca commented Aug 5, 2022

@bathos that's a cool idea to align on this.

(To be clear: I don't think that we can use the UPMF Client Hints header for this use case, because we want it encoded in the manifest so it doesn't require a round-trip to the server at all to update the theme colour based on the user's mode preference. But I think what you're saying is that there's precedent for having a subset of MQ selectors without using the CSS MQ syntax.)

I think what this precedent shows is that:

  1. We can make use of the CSS MQ features' semantics without having to reuse its syntax or parser. (e.g. UMPF Client Hints spec defines the meaning of the Sec-CH-Prefers-Color-Scheme client hint as "modeled after the prefers-color-scheme user preference media feature as defined in Media Queries".) That's a good idea, to define a condition that's exactly the same logic as Media Queries, but without actually using the full parser.
  2. We can carefully define a subset of MQ features that make sense in this non-CSS context (in their case, in the context of HTTP requests; in our case, in the context of the operating system UI). UMPF Client Hints do not allow all possible MQs, but rather a hand-picked subset which could be expanded in the future as more use cases are requested.

Both of those points apply to the manifest as well. What that suggests to me is that a proposal here that avoids using MQ syntax should still use the exact name "prefers-color-scheme", to align with CSS and suggest that we're using the same name and same semantics as what's defined in CSS.

@bathos
Copy link

bathos commented Aug 7, 2022

But I think what you're saying is that there's precedent for having a subset of MQ selectors without using the CSS MQ syntax.

Yep! Though I suspect it could also lead to a nice kinda symmetry story if implementing fallback/robustness behaviors alongside the overrides. One might choose to leverage the sec-ch-* & vary headers to select the default non-override values in a manifest response that also includes the new override fields. If the agent doesn’t yet understand the manifest overrides but does implement sec-ch-* (like current Chromium), the user would likely end up with sensible initial behavior even though the agent wouldn’t dynamically respond to subsequent changes to the media conditions (e.g. the user changing the system color scheme) like it would have if the overrides were supported too.

I wouldn’t expect most folks to bother going that far I guess, but a common pattern shared between the two APIs might make that progressive enhancement strategy a little more discoverable / dev-friendly for those who do.

@aarongustafson
Copy link
Collaborator

Thanks for all this back and forth! It was a lot to catch up on post-vacation. One thing I’d like to see addressed with the proposal is this: The ability to handle intersections cleanly. If we go the purpose-built route, would a developer be able to provide alternate color mode icons (or screenshots) for each language if necessary? It doesn’t seem like they would.

@aarongustafson
Copy link
Collaborator

Marcos and I were talking a bit about the proposed approaches and some of the concerns around using Media Query syntax in the manifest. My sentiment on the topic is this:

  1. There are distinct advantages to using a syntax that is familiar and consistent for developers: consistency, easier to learn.
  2. MQs in CSS are only inferences about the context in which a page is rendered. PWAs do not render a page, they translate values to a host OS, but the inferences from the host OS about context remain useful. There may be benefits to using the CSS parser to handle MQ parsing from the Manifest, but it is equally true that just because we map the MQ syntax to the Manifest, we don’t need to load the CSS parser - that translation could be done directly and would need to map to the host OS’s means of managing different assets based on those contexts (e.g., when packaging for Windows, alternate color scheme icons are supported via asset naming in the bundle). As it stands, we are only likely to map to one MQ right now, which makes embedding the CSS parser overkill; a basic implementation of prefers-color-scheme should be achievable in far less code. If we want to make it clear we aren’t using the CSS parser, we can specifically say we are using an "MQ-like syntax."
  3. If we want to use the same configuration for the translations piece (instead of using raw language keys as originally proposed), that could also be accomplished following the MQ-like proposal @marcoscaceres shared previously: (language=en) which, for consistency sake, probably makes more sense than the CSS selector [lang=en*] as there is no DOM parsing taking place… the system language is what’s being used.
  4. Just to draw a line under it again, as I hadn’t seen any other responses to my earlier post, whatever solution we use should accommodate intersections of language and user preference (and whatever else we introduce in the future) cleanly, which is why I strongly favor proposals that allow individual members or portions of members to be rewritten. If it means we need to assign id values to complex constructs like shortcuts and icons to facilitate this, I’m ok with that (though I do believe that arrays would naturally be ordered, unlike names properties, so I don’t believe ordering in those contexts to be an issue).

@dotproto
Copy link
Member

dotproto commented Sep 12, 2022

I wanted to quickly chime in from the point of view of the WebExtensions Community Group (WECG). This discussion seems directly related to some conversations we're having with respect to WebExtensions. In particular, we're discussing how to handle light/dark icon declaration in the extension manifest, selecting an appropriate icon based on the browser's current theme, and how OS light/dark mode impact the default background color of a popup.

I'm commenting as this issue is being discussed at TPAC, so I haven't had an opportunity to give the conversation a close read, but at the moment I suspect that we may want to align here.

Relevant WECG discussions:

aarongable pushed a commit to chromium/chromium that referenced this issue Oct 27, 2022
Parses the 'theme_colors' and 'background_colors' fields as described
in w3c/manifest#1045.

The media query is parsed using the CSS parser.

Bug: 1318305
Change-Id: I792275045a1adc2ace37e57458d60971fd638021
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3935769
Reviewed-by: Dominick Ng <[email protected]>
Commit-Queue: Louise Brett <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1064150}
@tomayac
Copy link
Contributor

tomayac commented Nov 23, 2022

@loubrett Since the present Issue serves as the Explainer of the V2 origin trial and features several syntax ideas, could you add a comment with an example of the syntax developers need to use for the origin trial? Thank you!

@loubrett
Copy link

loubrett commented Nov 23, 2022

The syntax that I've implemented for the origin trial is:

{
    "theme_color": "#fff",
    "background_color": "#fff",
    "theme_colors": [
      { "color": "#000", "media": "(prefers-color-scheme: dark)" }
    ],
    "background_colors": [
      { "color": "#000", "media": "(prefers-color-scheme: dark)" }
    ]
}

Currently the only supported fields are "theme_colors" and "background_colors" and the only supported media query is "(prefers-color-scheme: dark)".

@mbrevda
Copy link

mbrevda commented Aug 23, 2023

how'd the origin trial go?

@mgiuca
Copy link
Collaborator

mgiuca commented Aug 24, 2023

Thread: https://groups.google.com/a/chromium.org/g/blink-dev/c/1uKxZUFUQsU/m/jeo18C5tAgAJ

"The feedback from the trial showed there was very little interest so we are just going to let it expire."

There is a discussion about this scheduled for TPAC in September IIRC. I think we should eventually pick this up again but the priorities didn't align for us this time.

@mbrevda
Copy link

mbrevda commented Aug 24, 2023

Shame. Thanks!

@aphillips
Copy link
Contributor

@marcoscaceres sent I18N a pointer to this issue today and I'm going to spend a moment to comment on it in part because it is similar to comments we're engaged with with the verified credentials folks.

There are two potential problems to organizing localization as proposed here.

First, if a given manifest omits localizations, the core document has natural language strings that do not have language or direction metadata. In a number of examples, these consist of words that are both program internal values (which should be immutable and non-localized) and also the display name, e.g.:

preferred_color_scheme: dark  <- both a keyword and the display name for the color scheme

Ideally the core manifest would have display names separate from enumerated program internal values. It may be useful to allow a manifest to declare a default language and direction that applies to any natural language string not overridden locally, e.g.:

"language": "en",
"dir": "ltr",
"short_name": "My App", <- English, LTR
... etc...

The second problem I want to call out is the inconvenience of the localization structures found in JSON currently. Language maps don't allow direction metadata, but a list of objects makes it harder to implement selection because every one of the localization entries has to be parsed when matching. Using a "lookup" matcher generally works best when localized values are keyed by language:

"short_name.localizations": [
   "en":  [ value: "My App, hey!", dir: "ltr"],
   "en-GB": [ value: "My App, eh wut?", dir: "ltr"],
   "fr": [ ... ],
   "ar": [ value: "...", dir: "rtl" ]
}

Lacking a common structure for this in e.g. JSON-LD and other similar schemes means everyone will invent it over or try to adapt inconvenient solutions that omit direction or require additional processing.

Look forward to chatting in Seville.

@marcoscaceres
Copy link
Member Author

marcoscaceres commented Sep 11, 2023

Potentially:

"dir": "ltr",
"lang": "en-x-marcos",
"short_name": "I'm a short name",
"short_names": {
   "en":  { "value": "My App, hey!", "dir": "ltr", "lang": "fr"},
   "en-GB": { "value": "My App, eh wut?", "dir": "ltr"},
   "fr": "string",
   "ar": { "value": "...", "dir": "rtl" }
}

@aarongustafson
Copy link
Collaborator

Not sure I fully follow what was happening in that last comment, but I am in favor of a simpler syntax where values that still hold from the root manifest are inherited unless explicitly reset (e.g., direction). Unless that's some major problem for parsers, I think it aligns more closely with other concepts developers are familiar with (e.g., language in HTML, inheritance, the CSS cascade).

@christianliebel
Copy link
Member

I am in favor of a simpler syntax where values that still hold from the root manifest are inherited unless explicitly reset (e.g., direction)

@aarongustafson Yes, that would be the plan. dir and lang in the translation map would be entirely optional and inherited from the root dir property or the lang they are in.

@carlosjeurissen
Copy link

Quick update on the progress of the discussion in the WebExtensions Community Group (WECG). See w3c/webextensions#585 and w3c/webextensions#229. We concluded a new top level member needs to be introduced and I believe this is the moment we can align on a common syntax for both web app manifests and webExtensions.

It seems in above discussion the purpose-built objects and members seems to be the way forward. A potential structure could be the following:

[{
  "any": "16.svg",
  "type": "image/svg+xml"
}, {
  "16": "mono16.png",
  "32": "mono32.png",
  "type": "image/png",
  "purpose": "monochrome"
}, {
  "16": "mono16fr.png",
  "32": "mono32fr.png",
  "type": "image/png",
  "purpose": "monochrome",
  "lang": "fr"
}, {
  "16": "[email protected]",
  "32": "[email protected]",
  "type": "image/png",
  "color_scheme": "dark",
  "density": 2
}, {
  "16": "light16.png",
  "32": "light32.png",
  "type": "image/png",
  "color_scheme": "light"
}, {
  "16": "default16.png",
  "32": "default32.png",
  "type": "image/png"
}]

Some benefits are skipping repeated props (like type). Making the syntax less verbose.

A similar tactic could be used for other properties like name and short_name. Joining them together to drop ambiguity for which should be applied. Say a translated member for name in French exists. But a short_name in French is lacking. Ideally the browser would use the name in French and truncate it if needed. This could be implied by using a syntax like:

{
  "names": [{
    "full": "Some amazing app",
    "short": "Amazing",
    "lang": "en en-US"
  }, {
    "full": "Une application étonnante",
    "lang": "fr"
  }]
}

We can then restrict the filters (lang, color_scheme) to the members for which it would make sense.

@dmurph
Copy link
Collaborator

dmurph commented May 2, 2024

Current plans are triplets like so:

"dir": "ltr",
"lang": "en-x-marcos",
"short_name": "I'm a short name",
"short_name_localized": {
   "en":  { "value": "My App, hey!", "dir": "ltr", "lang": "fr"},
   "en-GB": { "value": "My App, eh wut?", "dir": "ltr"},
   "fr": "string",
   "ar": { "value": "...", "dir": "rtl" }
}

See discussion on pull request #1101 and tpac notes here

@aarongustafson
Copy link
Collaborator

aarongustafson commented May 3, 2024

Current plans are triplets like so

Just to clarify, dir is available in each translation object, but remains optional, unlike the value member. Without an explicit value, a value of “auto” is applied.

Question: Could dir_localized be used to establish global directional rules for each language used instead?

@xfq xfq added i18n-needs-resolution Issue the Internationalization Group has raised and looks for a response on. and removed i18n-tracker Group bringing to attention of Internationalization, or tracked by i18n but not needing response. labels May 23, 2024
@kenchris
Copy link
Collaborator

kenchris commented Jun 6, 2024

Related issue: #617

@kenchris
Copy link
Collaborator

kenchris commented Jun 6, 2024

Related issue: #975

@tomayac
Copy link
Contributor

tomayac commented Sep 30, 2024

Browser extensions now solve dark mode icons via icon_variants:

"icon_variants": [
  {
    "any": "any.svg"
  },
  {
    "16": "16.png",
    "32": "32.png"
  },
  {
    "16": "dark16.png",
    "32": "dark32.png",
    "color_schemes": ["dark"],
  },
  {
    "16": "light16.png",
    "32": "light32.png",
    "color_schemes": ["dark", "light"]
  }
]

@carlosjeurissen
Copy link

Browser extensions now solve dark mode icons via icon_variants:

Correct. Listed some of the benefits of using this syntax in this thread:
#1045 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
i18n-needs-resolution Issue the Internationalization Group has raised and looks for a response on. TPAC2023
Projects
None yet
Development

No branches or pull requests