WordPress / wordpress-playground

Run WordPress in the browser via WebAssembly PHP
https://w.org/playground/
GNU General Public License v2.0
1.64k stars 257 forks source link

Load requested language by URL #1703

Closed threadi closed 2 weeks ago

threadi commented 2 months ago

The path from international WordPress plugin sites to the Playground is currently still somewhat confusing. If you click on a live preview button on https://de.wordpress.org, for example, you always end up in an English environment - not the German one.

Currently, the plugin-directory plugin calls this URL from the Playground, regardless of which language is actually used:

https://playground.wordpress.net/?plugin=%s&login=1&url=%s

Source: https://meta.trac.wordpress.org/browser/sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-template.php?rev=12931#L734

I think it would be easy to read the language in the plugin-directory plugin. But what would the above URL have to look like for playground to automatically load a requested language?

Example: https://de.wordpress.org/plugins/external-files-in-media-library/ - always loads in an English environment.

brandonpayton commented 2 months ago

Thank you for for reporting this, @threadi. We probably should support a query param for language/locale.

bgrgicak commented 2 months ago

We could use the language query parameter to set the language.

threadi commented 2 months ago

Thanks for the tip. Unfortunately, the parameter does not work for the call that would be initiated.

Example: https://playground.wordpress.net/?plugin=external-files-in-media-library&language=de_DE&networking=yes&blueprint-url=https://wordpress.org/plugins/wp-json/plugins/v1/plugin/external-files-in-media-library/blueprint.json?rev=3141102

Even without networking=yes it does not work (although this is already set within the blueprint.json.

brandonpayton commented 2 months ago

We could use the language query parameter to set the language.

Thanks for pointing this out, @bgrgicak 🙇 .

@threadi, it turns out that mixing other Playground query params with a blueprint_url argument is not guaranteed to work because the Blueprint takes precedence. But there is a setSiteLanguage Blueprint step that can be used instead.

Here is an example of your external Blueprint adapted to use this step: Example in the Blueprint Builder

threadi commented 2 months ago

I know about the options in blueprint.json, they are not the problem. Please take another look at my initial question. The issue is that when you click on “Live-Preview” on the plugin pages via the code stored in https://meta.trac.wordpress.org/browser/sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-template.php?rev=12931#L734, you are currently not redirected to the playground in a language-specific manner. The transfer of the language parameter for language-specific plugin pages to the playground is missing here. As written, it will certainly be possible to read out the language. The question is how to use this language to load the playground in the language the user is using.

A plugin on the Spanish pages should load the Spanish backend in the Playground during “Live-Preview”. A plugin on the German pages should load the German backend in the Playground for “Live-Preview”.

If it were possible to access an HTTP request parameter in blueprint.json to read the language parameter from the URL, you could perhaps use setSiteLanguage. But since it is a JSON and not a PHP file, I don't see any chance of that.

What would have to be done to enable the Playground to do this?

carstingaxion commented 2 months ago

I was looking for a way to do the same; so I agree absolutely in the need for a language query param that is compatible with a blueprint-url param.

I would love to run a Playground in a matrix of locales, as a Github actions workflow to generate screenshots of a plugin for the w.org repository. The possibility to set the language from outside the blueprint.json is the last missing puzzle-piece in GatherPress' migration from wp-env to wp-playground/cli for generating its screenshots.

carstingaxion commented 2 months ago

For now, I solved this by merging a dynamic setSiteLanguage step into my blueprint. This works fine in a workflow like so:

  - name: Prepare localized blueprint
    # en_US should not get any additional steps added, as this will result in errors!
    #
    # All other locales need this step!
    run: |
      if [ ${{ matrix.locale }} == 'en_US' ]; then
        cp .github/scripts/wordpress-org-screenshots/blueprint.json localized_blueprint.json
      else
        language_step='[
          {
            "step": "setSiteLanguage",
            "language": "${{ matrix.locale }}"
          }
        ]'
        echo "Use jq to append the site language step to the existing blueprint JSON file."
        jq --argjson languageStep "$language_step" '.steps += $languageStep' .github/scripts/wordpress-org-screenshots/blueprint.json > localized_blueprint.json
      fi

  - name: Starting Playground
    # The "&" is important to allow the next step to start!
    run: |
      ./node_modules/@wp-playground/cli/wp-playground.js server --blueprint=./localized_blueprint.json &
brandonpayton commented 2 months ago

I know about the options in blueprint.json, they are not the problem. Please take another look at my initial question. The issue is that when you click on “Live-Preview” on the plugin pages via the code stored in...

The question is how to use this language to load the playground in the language the user is using.

Sorry, @threadi, I see now.

I don't have time left today but made added this to my list for tomorrow.

If it were possible to access an HTTP request parameter in blueprint.json to read the language parameter from the URL, you could perhaps use setSiteLanguage. But since it is a JSON and not a PHP file, I don't see any chance of that.

I was thinking about something similar: What if we added support for Blueprint arguments?

Blueprints could declare argument names, types, and default values. Then we could either support text replacement or (probably much better) a structured way to express variable interpolation throughout the Blueprint.

^ @adamziel, @bgrgicak, and @dmsnell, do you have any thoughts on this?

bgrgicak commented 1 month ago

Blueprints could declare argument names, types, and default values. Then we could either support text replacement or (probably much better) a structured way to express variable interpolation throughout the Blueprint.

This sounds interesting but could add a lot of complexity. There is something nice about having a static JSON file that we can just read and the user can always expect the same result.

Would it work if query strings would override blueprints? In this example, we could swap the setSiteLanguage step value while building the blueprint if we detect a language query string. This would make the blueprint dynamic without the extra complexity that variables would add.

threadi commented 1 month ago

In the meantime I also had another idea (or 2) which doesn't concern the Playground but wordpress.org. The link containing the path to blueprint.json is generated at https://meta.trac.wordpress.org/browser/sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-template.php?rev=12931#L734.

Idea 1: language-specific blueprints.json at wordpress.org. Each plugin developer could provide these separately and thus ensure a switch themselves. There are certainly plugins that are fixed to one region of the world with a specific language, which would then have everything in their hands. They could then also provide individual language-specific content that they define in the blueprint.json (which would not be possible with the idea developed here so far).

Idea 2: wordpress.org could generate a language-specific file from the basic blueprint.json and pass it on to the Playgroud. The challenge here is that such files must also be saved somewhere and somehow.

Both would relieve you of the burden, but I still see major issues with both ideas that need to be clarified “over there”. I'll create a ticket there in the next few days. From my point of view as a plugin developer, my idea 1 would currently be the preferred way and would also take the work off your hands ;)

adamziel commented 1 month ago

The easiest solution here would be what @bgrgicak proposed – to still apply the language query arg even when the Blueprint is provided, as long as the Blueprint contains no setSiteLanguage step. I'd just hold off with that until https://github.com/WordPress/wordpress-playground/pull/1731 lands as it profoundly changes the state management logic and I'd rather avoid building that feature twice.

adamziel commented 1 month ago

Solved by #1731

bgrgicak commented 1 month ago

This doesn't seem to work the blueprints still override query strings: https://playground.wordpress.net/?language=en_US#{%22steps%22:%20[{%22step%22:%20%22setSiteLanguage%22,%22language%22:%20%22es_ES%22}]}

adamziel commented 4 weeks ago

@bgrgicak oh that was intentional. The logic is as follows – it only sets a site language when the Blueprint doesn't explicitly provide one:

    // Language
    if (query.get('language')) {
        if (
            !blueprint?.steps?.find(
                (step) => step && (step as any).step === 'setSiteLanguage'
            )
        ) {
            blueprint.steps?.push({
                step: 'setSiteLanguage',
                language: query.get('language')!,
            });
        }
    }

Do you think it makes more sense to override the Blueprint step? If so, why? And how would that generalize to other query API parameters?

bgrgicak commented 4 weeks ago

Do you think it makes more sense to override the Blueprint step? If so, why? And how would that generalize to other query API parameters?

TL;DR; I would like for the query API to override blueprints.

I've seen a few cases where users asked (or reported bugs) because the query API didn't work. The underlying issue was that they had a blueprint and wanted to adjust Playground using the query API.

I would prefer to set a policy for the entire query API instead of making exceptions.

Looking at these reports it makes sense to me that the query API can override blueprints.

A blueprint is harder to modify and sometimes you don't even want to change it, for example in Plugin previews, but you still might want to adjust something on the fly. Today the only option is to modify the blueprint, but if the query API overrides blueprints we get a lot more flexibility in how Playground is used.

adamziel commented 4 weeks ago

@bgrgicak you have a point. If the Query API was to have precedence in the browser, the CLI args should also have precedence in @wp-playground/cli. I wonder how much is this a special case of overrides, and how much are we dealing with the problem of either merging Blueprints or having "variables", e.g. there isn't much difference between saying ?language=pl#{"language":"en"} and saying $lang=pl#{"language": $lang}. I'm firmly against introducing variables as long as possible and perhaps these overrides would make a neat replacement.

adamziel commented 4 weeks ago

On the flip side, one could argue that #1797 is caused by a faulty assumption in the site settings form, namely that it uses the query parameters instead of updating the Blueprint. In my mind, that form is the first live version of the visual Blueprints builder and, eventually, it may have UI for editing every single step.

Furthermore, you could override the site language via query params, but the semantic isn't so clear when the Blueprint says {"plugins": ["gutenberg"]} and the query API says ?plugin=hello-dolly. Should the query API plugins replace the Blueprint plugins? Or should they be prepended? Or appended? And is there a way to make that choice crystal clear, so that one doesn't need to check with the documentation?

cc @brandonpayton for thoughts

bgrgicak commented 3 weeks ago

Furthermore, you could override the site language via query params, but the semantic isn't so clear when the Blueprint says {"plugins": ["gutenberg"]} and the query API says ?plugin=hello-dolly. Should the query API plugins replace the Blueprint plugins? Or should they be prepended? Or appended? And is there a way to make that choice crystal clear, so that one doesn't need to check with the documentation?

That reminds me of the puzzle app, I had to make the same decisions there while merging blueprints. We could easily decide what to do in each merge scenario, but as you mentioned, it wouldn't be obvious to users.

adamziel commented 2 weeks ago

I'm closing this for now. The solution today would be: do not include the site language in the Blueprint if you plan to override the language via the query API. If that doesn't help with your use-case, please comment on this issue. We'll revisit this given enough interest.