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

Language picker #12006

Merged
merged 55 commits into from
Feb 7, 2024
Merged

Language picker #12006

merged 55 commits into from
Feb 7, 2024

Conversation

wackerow
Copy link
Member

@wackerow wackerow commented Jan 23, 2024

Description

Adds a new language selection menu to replace the "Languages" link in the navigation bar (or mobile menu), using Chakra-UI Menu component.

  • Language menu displays without changing the users route, rendering a list of all available locales
  • Language items show name in both current site language and the local language
  • Language items now display percentage of site available in that language, along with total word count, and a progress bar (Chakra-UI Progress component).
  • Auto-focuses to input to filter by target language in: english, that language, the current page language, or the language code itself
  • Languages are sorted in descending order by words translated
  • Browser preference featured at the top for quick-access
  • Keyboard navigation enabled

Translation callouts

  • Bottom has a callout to help us translate the site with "learn more" link to /contributing/translation-program
  • If filter query has no results, the message from the bottom of the /languages page is displayed as a call-to-action, again with a link the Translation Program

Data fetching

  • New script added to fetch progress data using @crowdin/crowdin-api-client, saving results to a data file
  • Adds a GitHub action cron job to run this script once a week, commit the results, and post as a PR
  • Crowdin API env var handled through GitHub secrets

Screenshot

image

Preview link

Related issue

Related PRs

fix logic to fetch a display name for each locale in the LanguagePicker, both in the language of the current locale (source) and the language of that locale choice (target). Uses internal i18n translations if available, falling back to native Intl package if not available, and falling back to English name for locales that are not found elsewhere.

Updates translations.ts to add "page-translations" next to "common" for all pages, and updates `existsNamespace` "primary namespace" argument to look at the index one higher (except for /languages page and pages that use "common" as primary ns)
Copy link

netlify bot commented Jan 23, 2024

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit 4172a13
🔍 Latest deploy log https://app.netlify.com/sites/ethereumorg/deploys/65c2c49d01de1200081bb37c
😎 Deploy Preview https://deploy-preview-12006--ethereumorg.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@github-actions github-actions bot added content 🖋️ This involves copy additions or edits review needed 👀 tooling 🔧 Changes related to tooling of the project translation 🌍 This is related to our Translation Program labels Jan 23, 2024
@wackerow wackerow marked this pull request as ready for review January 31, 2024 04:01
Copy link
Member

@pettinarip pettinarip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second part of the review.

@wackerow
Copy link
Member Author

One thing I noticed that I'll note as a potential bug:

This is currently set up to auto-focus on the filter input when the menu is opened. It is also set up where pressing "Enter" from the filter input will automatically navigate to the first filter option available.

If a user clicks this menu from ANY non-English page, and then they press "Enter", they will automatically be taken to the English version of the site, since that always be the first result with an empty filter query... This may be easier to switch than we'd like, since it may be triggered by accident.

I'm not sure I see this as a blocker myself, but open to thoughts or suggestions on how we can keep this convenience without potentially inhibiting the UX. We could ditch the auto-focus, and/or the "Enter" shortcut to trigger first result.... Personally think I'd be more in favor of removing the "Enter" trigger (since user can still press "Down -> Enter"); or only allowing this shortcut ONLY IF the filter query is not empty.

@pettinarip
Copy link
Member

@wackerow agreed. Given that we have changed the default Menu behavior, I think we should disabled the default "Enter" trigger and keep our implementation since now it is not just a list, it is more of a form where the "Enter" key plays a different role.

Copy link
Member

@pettinarip pettinarip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job @wackerow! a lot of work done here. Overall it works really well.

Small issue (or feature 🤔?? xD): the user can get a weird experience when scrolling and hovering the items. If you point to the top of the list, you might get some undesired scrolling to the top of the list. Don't expect this to be an easy fix so no bother on investigating this now. Just saying in case we want to try to fix it later.
https://github.com/ethereum/ethereum-org-website/assets/468158/6d599ce8-707e-4145-892c-cc4a18987fc0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment for next iterations: is it possible to add a new step to minimize this as much as we can? seems that there is room for improvements here.
This file will get bundled in the main app.js file that all the pages need to load impacting the overall client load performance.

useEventListener("keydown", (e) => {
if (e.key !== "\\") return
e.preventDefault()
inputRef.current?.focus()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we simplify this autofocus when the menu is opened, not just when the keydown is pressed? I say this because we should also autofocus the input when the user clicks the button.

There is a pretty standard user behavior where you click the button and then just start typing. You can't do that right now.

I think this was the original idea and I saw it working before. Just calling it out.

onKeyDown={(e) => {
if (e.key === "Tab" || e.key === "\\") {
e.preventDefault()
;(e.shiftKey ? inputRef : footerRef).current?.focus()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool, but I have a feeling that most users will never notice that it exists. For future iterations, we could add a help icon/tooltip or a shortcuts summary that explains this.

onChange={(e) => setFilterValue(e.target.value)}
onBlur={(e) => {
if (e.relatedTarget?.tagName.toLowerCase() === "div") {
e.currentTarget.focus()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't understand what this is for, could you explain? (we could add a comment)

Comment on lines +91 to +92
<Box
position="relative"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker: wondering if we could treat this as an actual form

Suggested change
<Box
position="relative"
<Box
as="form"
position="relative"

We could have some a11y wins when we submit the form (also, would remove the need of the custom onKeyDown handler).

Comment on lines +41 to +60
const navLangs = typeof navigator !== "undefined" ? navigator.languages : []

// For each browser preference, reduce to the most specific match found in `locales` array
const allBrowserLocales: Lang[] = navLangs
.map(
(navLang) =>
locales?.reduce((acc, cur) => {
if (cur.toLowerCase() === navLang.toLowerCase()) return cur
if (
navLang.toLowerCase().startsWith(cur.toLowerCase()) &&
acc !== navLang
)
return cur
return acc
}, "") as Lang
)
.filter((i) => !!i) // Remove those without matches

// Remove duplicate matches
const browserLocales = Array.from(new Set(allBrowserLocales))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor idea: move all this logic to a util function.

Suggested change
const navLangs = typeof navigator !== "undefined" ? navigator.languages : []
// For each browser preference, reduce to the most specific match found in `locales` array
const allBrowserLocales: Lang[] = navLangs
.map(
(navLang) =>
locales?.reduce((acc, cur) => {
if (cur.toLowerCase() === navLang.toLowerCase()) return cur
if (
navLang.toLowerCase().startsWith(cur.toLowerCase()) &&
acc !== navLang
)
return cur
return acc
}, "") as Lang
)
.filter((i) => !!i) // Remove those without matches
// Remove duplicate matches
const browserLocales = Array.from(new Set(allBrowserLocales))
const browserLocales = getBrowserLocales(locales)


import { DEFAULT_LOCALE } from "@/lib/constants"

const data = progressData as ProjectProgressData[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep using progressData for its name, much clearer than the generic data.

We do have resolveJsonModule in our tsconfig so, this data should be typed already. If we need to force the ProjectProgressData type, we could do that in our global.d.ts using declare module.

Copy link
Member

@pettinarip pettinarip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LFG!! 🚀 🚀

@wackerow
Copy link
Member Author

wackerow commented Feb 7, 2024

Thank you for noting these remaining issues! Will take note of these, but gonna bring it in in the meantime. Will merge these into the Radix-UI nav-menu PR (#12125) to clear conflicts

@wackerow wackerow merged commit d3af5ac into dev Feb 7, 2024
10 checks passed
@wackerow wackerow deleted the language-menu branch February 7, 2024 17:44
This was referenced Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
content 🖋️ This involves copy additions or edits tooling 🔧 Changes related to tooling of the project translation 🌍 This is related to our Translation Program
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants