Skip to content

feat(menu): support entry localization#1403

Open
caugner wants to merge 6 commits intomainfrom
1402-menu-l10n
Open

feat(menu): support entry localization#1403
caugner wants to merge 6 commits intomainfrom
1402-menu-l10n

Conversation

@caugner
Copy link
Copy Markdown
Contributor

@caugner caugner commented Mar 20, 2026

Description

Makes the menu entries localizable.

Motivation

Ensure other locales don't have to live with the English menu.

Additional details

Related issues and pull requests

Fixes #1402.

@caugner caugner requested a review from a team as a code owner March 20, 2026 13:02
@caugner caugner requested a review from LeoMcA March 20, 2026 13:02
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 20, 2026

c2d788d was deployed to: https://fred-pr1403.review.mdn.allizom.net/

Copy link
Copy Markdown
Member

@LeoMcA LeoMcA left a comment

Choose a reason for hiding this comment

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

Only done an initial skim so far, but nice idea. I imagine you've already thought of this, but this approach of exposing strings at "l10n extract" runtime would allow us to localise strings coming from an upstream source as well - nice!

Let's add some simple tests, with some simple fixtures, in the same vein as the current ones.

entries.push([tab.buttonL10nId.long, tab.buttonText.long], [tab.buttonL10nId.short, tab.buttonText.short]);
}

if (!("panelTitle" in tab)) return entries;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: I'd prefer an if("panelTitle" in tab) { block wrapping the below lines, than a negated condition - makes the code read easier IMO

entries.push([group.titleL10nId, /** @type {string} */ (group.title)]);
}
for (const item of group.items) {
if (!("l10nId" in item)) continue;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: similarly, a non-negated if would read better imo

const { strings } = await import(
pathToFileURL(path.join(componentsDir, file)).href
);
if (!(strings instanceof Map)) continue;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: avoid the negated if, wrap the section below

for (const [id, value] of strings) {
if (map.has(id) && map.get(id) !== value) {
throw new Error(
`L10n extractor: \`${id}\` is a duplicate id with different text`,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this needs a test

for (const [id, value] of await scrapeL10nModules(componentsDir)) {
if (tags.has(id) && tags.get(id) !== value) {
throw new Error(
`L10n extractor: \`${id}\` is a duplicate id with different text`,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this needs a test

href=${tab.href}
data-glean-id=${`menu_click_link: top-level -> ${tab.href}`}
>${tab.buttonText}</a
>${context.l10n(tab.buttonL10nId)}</a
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The plain context.l10n function doesn't work like this any more, perhaps that's an oversight from me.

You have to use context.l10n.raw({ id: ... if you're not providing the en-US text inline.

const slugify = (str) =>
str
.toLowerCase()
.replaceAll(/[^\p{L}\p{N}]+/gu, "-")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure if fluent ids support non-ascii characters, perhaps simplify to [^a-z0-9]?

Comment on lines +427 to +434
menu-tools-0-playground = Playground
menu-tools-0-http-observatory = HTTP Observatory
menu-tools-1-border-image-generator = Border-image generator
menu-tools-1-border-radius-generator = Border-radius generator
menu-tools-1-box-shadow-generator = Box-shadow generator
menu-tools-1-color-format-converter = Color format converter
menu-tools-1-color-mixer = Color mixer
menu-tools-1-shape-generator = Shape generator
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think the number is necessary here, and just means we'll have unstable ids if we rearrange things

* Imports all `l10n.js` modules under the components directory and merges
* their exported `strings` Maps into a single Map.
*
* @param {string} componentsDir
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't think it's necessary to pass componentsDir as a param

user-menu-user = User
writer-open-editor-open-in-editor = Open in editor
writer-toolbar-view-on-mdn = View on MDN
menu-html = HTML
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As these strings don't exist in en-US.ftl, we don't actually have anything to render:

Image

I'd suggest that the extraction logic you've added should add them to en-US.ftl, then allow the usual en-US.ftl -> template.ftl logic to copy them here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make menu localizable

3 participants