Skip to content

Commit 5342eff

Browse files
authored
fix(google-meet): force English Meet UI via hl=en so automation works on any locale (#89671)
Summary: - The branch adds `forceMeetEnglishUi()` for Google Meet URLs, applies it to join/create browser opens, canonicalizes browser-created meeting links, and updates focused Google Meet tests. - PR surface: Source +18, Tests +19. Total +37 across 6 files. - Reproducibility: yes. Current main opens raw Meet URLs while the browser automation matches English-only lab ... R body provides after-fix CDP output showing non-English pages render expected English labels with `hl=en`. Automerge notes: - PR branch already contained follow-up commit before automerge: chore(tooling): add unused agent-cache-store files to knip optional a… - PR branch already contained follow-up commit before automerge: fix(google-meet): repair non-Latin mic regex matching boundary - PR branch already contained follow-up commit before automerge: revert(tooling): preserve current main deadcode allowlist guard - PR branch already contained follow-up commit before automerge: revert(tooling): perfectly match origin/main deadcode list - PR branch already contained follow-up commit before automerge: revert: match origin/main deadcode list exactly Validation: - ClawSweeper review passed for head 880a41b. - Required merge gates passed before the squash merge. Prepared head SHA: 880a41b Review: #89671 (comment) Co-authored-by: Chen Chia Yang <[email protected]> Approved-by: hxy91819
1 parent e272da5 commit 5342eff

6 files changed

Lines changed: 46 additions & 10 deletions

File tree

extensions/google-meet/index.create.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ describe("google-meet create flow", () => {
304304
return false;
305305
}
306306
const body = proxy.body as Record<string, unknown>;
307-
return proxy.path === "/tabs/open" && body.url === "https://meet.google.com/new";
307+
return proxy.path === "/tabs/open" && body.url === "https://meet.google.com/new?hl=en";
308308
});
309309
});
310310

@@ -426,7 +426,9 @@ describe("google-meet create flow", () => {
426426
payload: {
427427
result: {
428428
targetId:
429-
proxy.body?.url === "https://meet.google.com/new" ? "create-tab" : "join-tab",
429+
proxy.body?.url === "https://meet.google.com/new?hl=en"
430+
? "create-tab"
431+
: "join-tab",
430432
title: "Meet",
431433
url: proxy.body?.url,
432434
},

extensions/google-meet/index.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,7 +2294,7 @@ describe("google-meet plugin", () => {
22942294
method: "POST",
22952295
path: "/tabs/open",
22962296
timeoutMs: 30000,
2297-
body: { url: "https://meet.google.com/abc-defg-hij" },
2297+
body: { url: "https://meet.google.com/abc-defg-hij?hl=en" },
22982298
});
22992299
expect(openCall[3]).toEqual({ progress: false });
23002300
expect(
@@ -3105,7 +3105,7 @@ describe("google-meet plugin", () => {
31053105
method: "POST",
31063106
path: "/tabs/open",
31073107
timeoutMs: 30000,
3108-
body: { url: "https://meet.google.com/abc-defg-hij" },
3108+
body: { url: "https://meet.google.com/abc-defg-hij?hl=en" },
31093109
});
31103110
const startCall = nodesInvoke.mock.calls.find(([rawCall]) => {
31113111
const call = requireRecord(rawCall, "node invoke");
@@ -4105,7 +4105,7 @@ describe("google-meet plugin", () => {
41054105
const request = requireRecord(params, "local browser open request");
41064106
expect(request.method).toBe("POST");
41074107
expect(request.path).toBe("/tabs/open");
4108-
expect(request.body).toStrictEqual({ url: "https://meet.google.com/abc-defg-hij" });
4108+
expect(request.body).toStrictEqual({ url: "https://meet.google.com/abc-defg-hij?hl=en" });
41094109
expect(extra).toStrictEqual({ progress: false });
41104110
} finally {
41114111
Object.defineProperty(process, "platform", { value: originalPlatform });

extensions/google-meet/src/transports/chrome-browser-proxy.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,24 @@
22
import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime";
33
import type { PluginRuntime } from "openclaw/plugin-sdk/plugin-runtime";
44
import { describe, expect, it, vi } from "vitest";
5-
import { callBrowserProxyOnNode } from "./chrome-browser-proxy.js";
5+
import { callBrowserProxyOnNode, forceMeetEnglishUi } from "./chrome-browser-proxy.js";
6+
7+
describe("forceMeetEnglishUi", () => {
8+
it("pins hl=en on Meet URLs", () => {
9+
expect(forceMeetEnglishUi("https://meet.google.com/abc-defg-hij")).toBe(
10+
"https://meet.google.com/abc-defg-hij?hl=en",
11+
);
12+
expect(forceMeetEnglishUi("https://meet.google.com/new")).toBe(
13+
"https://meet.google.com/new?hl=en",
14+
);
15+
});
16+
17+
it("overrides an existing hl and keeps other params", () => {
18+
expect(forceMeetEnglishUi("https://meet.google.com/abc-defg-hij?hl=zh-TW&authuser=1")).toBe(
19+
"https://meet.google.com/abc-defg-hij?hl=en&authuser=1",
20+
);
21+
});
22+
});
623

724
describe("Google Meet Chrome browser proxy", () => {
825
it("reports malformed node proxy payloadJSON with an owned error", async () => {

extensions/google-meet/src/transports/chrome-browser-proxy.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@ export type BrowserTab = {
1212
url?: string;
1313
};
1414

15+
// Meet automation scripts match English UI labels ("Join now", "Turn off microphone").
16+
// hl=en pins the Meet page language regardless of account/browser locale; without it,
17+
// non-English profiles render localized labels and every DOM matcher goes blind.
18+
export function forceMeetEnglishUi(url: string): string {
19+
try {
20+
const parsed = new URL(url);
21+
parsed.searchParams.set("hl", "en");
22+
return parsed.toString();
23+
} catch {
24+
return url;
25+
}
26+
}
27+
1528
export function normalizeMeetUrlForReuse(url: string | undefined): string | undefined {
1629
if (!url) {
1730
return undefined;

extensions/google-meet/src/transports/chrome-create.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { GoogleMeetConfig } from "../config.js";
55
import {
66
asBrowserTabs,
77
callBrowserProxyOnNode,
8+
forceMeetEnglishUi,
89
readBrowserTab,
910
resolveChromeNode,
1011
type BrowserTab,
@@ -199,7 +200,9 @@ export const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
199200
}
200201
const href = current();
201202
if (meetUrlPattern.test(href)) {
202-
return { meetingUri: href, browserUrl: href, browserTitle: document.title, notes };
203+
// The /new redirect keeps the hl=en param we open with; strip query/hash so the
204+
// meeting link handed to users stays canonical instead of forcing English on them.
205+
return { meetingUri: href.split(/[?#]/)[0], browserUrl: href, browserTitle: document.title, notes };
203206
}
204207
const pageText = text(document.body);
205208
if (clickButton(/\\buse microphone\\b/i, "Accepted Meet microphone prompt with browser automation.")) {
@@ -288,7 +291,7 @@ export async function createMeetWithBrowserProxyOnNode(params: {
288291
nodeId,
289292
method: "POST",
290293
path: "/tabs/open",
291-
body: { url: GOOGLE_MEET_NEW_URL },
294+
body: { url: forceMeetEnglishUi(GOOGLE_MEET_NEW_URL) },
292295
timeoutMs: stepTimeoutMs,
293296
}),
294297
);

extensions/google-meet/src/transports/chrome.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
import {
2424
asBrowserTabs,
2525
callBrowserProxyOnNode,
26+
forceMeetEnglishUi,
2627
isSameMeetUrlForReuse,
2728
normalizeMeetUrlForReuse,
2829
readBrowserTab,
@@ -433,7 +434,7 @@ function meetStatusScript(params: {
433434
notes.push("Muted Meet microphone for observe-only mode.");
434435
}
435436
const join = !readOnly && ${JSON.stringify(params.autoJoin)}
436-
? findButton(/join now|ask to join/i)
437+
? findButton(/join now|ask to join|join here too/i)
437438
: null;
438439
if (join) join.click();
439440
const microphoneChoice = findButton(/\\buse microphone\\b/i);
@@ -690,7 +691,7 @@ async function openMeetWithBrowserRequest(params: {
690691
await params.callBrowser({
691692
method: "POST",
692693
path: "/tabs/open",
693-
body: { url: params.url },
694+
body: { url: forceMeetEnglishUi(params.url) },
694695
timeoutMs,
695696
}),
696697
);

0 commit comments

Comments
 (0)