Skip to content

Commit c50fcf7

Browse files
CodFrmCopilot
andauthored
🐛 优化 systemconfig 和修复 SW 中的i18n问题 (#976)
* ♻️ 重构 system config 监听 * 🐛 处理 localePath 变化的问题 #972 * 处理lint问题 * Update src/locales/locales.ts Co-authored-by: Copilot <[email protected]> * systemconfig watch增加上一次值返回 --------- Co-authored-by: Copilot <[email protected]>
1 parent 45b22c9 commit c50fcf7

12 files changed

Lines changed: 193 additions & 190 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "scriptcat",
3-
"version": "1.2.0-beta.5",
3+
"version": "1.3.0-beta",
44
"description": "脚本猫,一个可以执行用户脚本的浏览器扩展,万物皆可脚本化,让你的浏览器可以做更多的事情!",
55
"author": "CodFrm",
66
"license": "GPLv3",

packages/message/message_queue.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import EventEmitter from "eventemitter3";
22
import LoggerCore from "@App/app/logger/core";
33
import { type TMessage } from "./types";
4+
import type { SystemConfigKey, SystemConfigValueType } from "@App/pkg/config/config";
45

5-
export type TKeyValue = { key: string; value: string };
6+
export type TKeyValue<T extends SystemConfigKey> = {
7+
key: T;
8+
value: SystemConfigValueType<T> | undefined;
9+
prev: SystemConfigValueType<T> | undefined;
10+
};
611

712
// 中间件函数类型
813
type MiddlewareFunction<T = any> = (topic: string, message: T, next: () => void) => void | Promise<void>;

src/app/service/service_worker/index.ts

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { SubscribeService } from "./subscribe";
1313
import { ScriptDAO } from "@App/app/repo/scripts";
1414
import { SystemService } from "./system";
1515
import { type Logger, LoggerDAO } from "@App/app/repo/logger";
16-
import { initLocales, localePath, t } from "@App/locales/locales";
16+
import { initLocales, initLocalesPromise, localePath, t, watchLanguageChange } from "@App/locales/locales";
1717
import { getCurrentTab, InfoNotification } from "@App/pkg/utils/utils";
1818
import { onTabRemoved, onUrlNavigated, setOnUserActionDomainChanged } from "./url_monitor";
1919
import { LocalStorageDAO } from "@App/app/repo/localStorage";
@@ -178,14 +178,10 @@ export default class ServiceWorkerManager {
178178
}
179179
});
180180

181-
// 监听配置变化
182-
systemConfig.addListener("cloud_sync", (value) => {
181+
// 云同步
182+
systemConfig.watch("cloud_sync", (value) => {
183183
synchronize.cloudSyncConfigChange(value);
184184
});
185-
// 启动一次云同步
186-
systemConfig.getCloudSync().then((config) => {
187-
synchronize.cloudSyncConfigChange(config);
188-
});
189185

190186
if (process.env.NODE_ENV === "production") {
191187
chrome.runtime.onInstalled.addListener((details) => {
@@ -194,41 +190,45 @@ export default class ServiceWorkerManager {
194190
console.error("chrome.runtime.lastError in chrome.runtime.onInstalled:", lastError);
195191
// chrome.runtime.onInstalled API出错不进行后续处理
196192
}
197-
if (details.reason === "install") {
198-
chrome.tabs.create({ url: `${DocumentationSite}${localePath}/docs/use/install_comple` });
199-
} else if (details.reason === "update") {
200-
const url = `${DocumentationSite}/docs/change/${ExtVersion.includes("-") ? "beta-changelog/" : ""}#${ExtVersion}`;
201-
getCurrentTab()
202-
.then((tab) => {
203-
// 检查是否正在播放视频,或者窗口未激活
204-
const openInBackground = !tab || tab.audible === true || !tab.active;
205-
// chrome.tabs.create 传回 Promise<chrome.tabs.Tab>
206-
return chrome.tabs.create({
207-
url,
208-
active: !openInBackground,
209-
index: !tab ? undefined : tab.index + 1,
210-
windowId: !tab ? undefined : tab.windowId,
193+
initLocalesPromise.then(() => {
194+
if (details.reason === "install") {
195+
chrome.tabs.create({ url: `${DocumentationSite}${localePath}/docs/use/install_comple` });
196+
} else if (details.reason === "update") {
197+
const url = `${DocumentationSite}${localePath}/docs/change/${ExtVersion.includes("-") ? "beta-changelog/" : ""}#${ExtVersion}`;
198+
getCurrentTab()
199+
.then((tab) => {
200+
// 检查是否正在播放视频,或者窗口未激活
201+
const openInBackground = !tab || tab.audible === true || !tab.active;
202+
// chrome.tabs.create 传回 Promise<chrome.tabs.Tab>
203+
return chrome.tabs.create({
204+
url,
205+
active: !openInBackground,
206+
index: !tab ? undefined : tab.index + 1,
207+
windowId: !tab ? undefined : tab.windowId,
208+
});
209+
})
210+
.then((_createdTab) => {
211+
// 当新 Tab 成功建立时才执行
212+
InfoNotification(
213+
t("ext_update_notification"),
214+
t("ext_update_notification_desc", { version: ExtVersion })
215+
);
216+
})
217+
.catch((e) => {
218+
console.error(e);
211219
});
212-
})
213-
.then((_createdTab) => {
214-
// 当新 Tab 成功建立时才执行
215-
InfoNotification(
216-
t("ext_update_notification"),
217-
t("ext_update_notification_desc", { version: ExtVersion })
218-
);
219-
})
220-
.catch((e) => {
221-
console.error(e);
222-
});
223-
}
220+
}
221+
});
224222
});
225223

226224
// 监听扩展卸载事件
227-
chrome.runtime.setUninstallURL(`${DocumentationSite}${localePath}/uninstall`, () => {
228-
const lastError = chrome.runtime.lastError;
229-
if (lastError) {
230-
console.error("chrome.runtime.lastError in chrome.runtime.setUninstallURL:", lastError);
231-
}
225+
watchLanguageChange(() => {
226+
chrome.runtime.setUninstallURL(`${DocumentationSite}${localePath}/uninstall`, () => {
227+
const lastError = chrome.runtime.lastError;
228+
if (lastError) {
229+
console.error("chrome.runtime.lastError in chrome.runtime.setUninstallURL:", lastError);
230+
}
231+
});
232232
});
233233
}
234234

src/app/service/service_worker/runtime.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import { type ResourceService } from "./resource";
4242
import { type LocalStorageDAO } from "@App/app/repo/localStorage";
4343
import Logger from "@App/app/logger/logger";
4444
import type { GMInfoEnv } from "../content/types";
45-
import { localePath } from "@App/locales/locales";
45+
import { initLocalesPromise, localePath } from "@App/locales/locales";
4646
import { DocumentationSite } from "@App/app/const";
4747
import { extractUrlPatterns, RuleType, type URLRuleEntry } from "@App/pkg/utils/url_matcher";
4848
import { parseUserConfig } from "@App/pkg/utils/yaml";
@@ -183,8 +183,10 @@ export class RuntimeService {
183183
value: true,
184184
});
185185
// 打开页面
186-
chrome.tabs.create({
187-
url: `${DocumentationSite}${localePath}/docs/use/open-dev/`,
186+
initLocalesPromise.then(() => {
187+
chrome.tabs.create({
188+
url: `${DocumentationSite}${localePath}/docs/use/open-dev/`,
189+
});
188190
});
189191
}
190192
});

src/app/service/service_worker/script.ts

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { type ResourceService } from "./resource";
2828
import { type ValueService } from "./value";
2929
import { compileScriptCode } from "../content/utils";
3030
import { type SystemConfig } from "@App/pkg/config/config";
31-
import { localePath } from "@App/locales/locales";
31+
import { localePath, watchLanguageChange } from "@App/locales/locales";
3232
import { arrayMove } from "@dnd-kit/sortable";
3333
import { DocumentationSite } from "@App/app/const";
3434
import type {
@@ -243,67 +243,69 @@ export class ScriptService {
243243
requestDomains: ["bitbucket.org"], // Chrome 101+
244244
},
245245
];
246-
const rules = conditions.map((condition, idx) => {
247-
Object.assign(condition, {
248-
excludedTabIds: [chrome.tabs.TAB_ID_NONE],
249-
});
250-
if (addResponseHeaders) {
246+
watchLanguageChange(() => {
247+
const rules = conditions.map((condition, idx) => {
251248
Object.assign(condition, {
252-
responseHeaders: [
253-
{
254-
header: "Content-Type",
255-
values: [
256-
"text/javascript*",
257-
"application/javascript*",
258-
"text/html*",
259-
"text/plain*",
260-
"application/octet-stream*",
261-
"application/force-download*",
262-
],
263-
},
264-
],
249+
excludedTabIds: [chrome.tabs.TAB_ID_NONE],
265250
});
266-
}
267-
return {
268-
id: 1000 + idx,
269-
priority: 1,
270-
action: {
271-
type: "redirect" as chrome.declarativeNetRequest.RuleActionType,
272-
redirect: {
273-
regexSubstitution: `${DocumentationSite}${localePath}/docs/script_installation/#url=\\1`,
251+
if (addResponseHeaders) {
252+
Object.assign(condition, {
253+
responseHeaders: [
254+
{
255+
header: "Content-Type",
256+
values: [
257+
"text/javascript*",
258+
"application/javascript*",
259+
"text/html*",
260+
"text/plain*",
261+
"application/octet-stream*",
262+
"application/force-download*",
263+
],
264+
},
265+
],
266+
});
267+
}
268+
return {
269+
id: 1000 + idx,
270+
priority: 1,
271+
action: {
272+
type: "redirect" as chrome.declarativeNetRequest.RuleActionType,
273+
redirect: {
274+
regexSubstitution: `${DocumentationSite}${localePath}/docs/script_installation/#url=\\1`,
275+
},
274276
},
277+
condition: condition,
278+
} as chrome.declarativeNetRequest.Rule;
279+
});
280+
// 重定向到脚本安装页
281+
chrome.declarativeNetRequest.updateDynamicRules(
282+
{
283+
removeRuleIds: [1],
275284
},
276-
condition: condition,
277-
} as chrome.declarativeNetRequest.Rule;
278-
});
279-
// 重定向到脚本安装页
280-
chrome.declarativeNetRequest.updateDynamicRules(
281-
{
282-
removeRuleIds: [1],
283-
},
284-
() => {
285-
if (chrome.runtime.lastError) {
286-
console.error(
287-
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateDynamicRules:",
288-
chrome.runtime.lastError
289-
);
285+
() => {
286+
if (chrome.runtime.lastError) {
287+
console.error(
288+
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateDynamicRules:",
289+
chrome.runtime.lastError
290+
);
291+
}
290292
}
291-
}
292-
);
293-
chrome.declarativeNetRequest.updateSessionRules(
294-
{
295-
removeRuleIds: [...rules.map((rule) => rule.id)],
296-
addRules: rules,
297-
},
298-
() => {
299-
if (chrome.runtime.lastError) {
300-
console.error(
301-
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateSessionRules:",
302-
chrome.runtime.lastError
303-
);
293+
);
294+
chrome.declarativeNetRequest.updateSessionRules(
295+
{
296+
removeRuleIds: [...rules.map((rule) => rule.id)],
297+
addRules: rules,
298+
},
299+
() => {
300+
if (chrome.runtime.lastError) {
301+
console.error(
302+
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateSessionRules:",
303+
chrome.runtime.lastError
304+
);
305+
}
304306
}
305-
}
306-
);
307+
);
308+
});
307309
}
308310

309311
public async openInstallPageByUrl(

src/locales/locales.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ export function changeLanguage(lng: string, callback?: Callback): void {
3232
dayjs.locale(lng.toLocaleLowerCase());
3333
}
3434

35+
let initLocalesResolve: (value: string) => void;
36+
export const initLocalesPromise = new Promise<string>((resolve) => {
37+
initLocalesResolve = resolve;
38+
});
39+
3540
export function initLocales(systemConfig: SystemConfig) {
3641
const uiLanguage = chrome.i18n.getUILanguage();
3742
const defaultLanguage = globalThis.localStorage ? localStorage["language"] || uiLanguage : uiLanguage;
@@ -58,20 +63,39 @@ export function initLocales(systemConfig: SystemConfig) {
5863
localePath = "/en";
5964
}
6065

61-
systemConfig.getLanguage().then((lng) => {
62-
changeLanguage(lng);
63-
if (!lng.startsWith("zh-")) {
64-
localePath = "/en";
65-
}
66-
});
67-
systemConfig.addListener("language", (lng) => {
68-
changeLanguage(lng);
66+
const changeLanguageCallback = (lng: string) => {
6967
if (!lng.startsWith("zh-")) {
7068
localePath = "/en";
7169
} else {
7270
localePath = "";
7371
}
72+
changeLanguage(lng);
73+
};
74+
75+
systemConfig.getLanguage().then((lng) => {
76+
initLocalesResolve(lng);
77+
changeLanguageCallback(lng);
7478
});
79+
80+
systemConfig.addListener("language", changeLanguageCallback);
81+
}
82+
83+
export function watchLanguageChange(callback: (lng: string) => void) {
84+
// 马上执行一次
85+
let registered = false;
86+
initLocalesPromise.then(() => {
87+
callback(i18n.language);
88+
89+
// 监听变化
90+
i18n.on("languageChanged", callback);
91+
registered = true;
92+
});
93+
94+
return () => {
95+
if (registered) {
96+
i18n.off("languageChanged", callback);
97+
}
98+
};
7599
}
76100

77101
export function i18nName(script: { name: string; metadata: SCMetadata }) {

src/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 3,
33
"name": "__MSG_scriptcat__",
4-
"version": "1.2.0.1600",
4+
"version": "1.3.0.1100",
55
"author": "CodFrm",
66
"description": "__MSG_scriptcat_description__",
77
"options_ui": {

src/pages/components/layout/Sider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ const Sider: React.FC = () => {
139139
<RiGuideLine /> {t("guide")}
140140
</Menu.Item>
141141
<Menu.Item key="scriptcat/docs/use/">
142-
<a href={`${DocumentationSite}${localePath}/docs/use/`} target="_blank" rel="noreferrer">
142+
<a href={`${DocumentationSite}${localePath}/docs/use/use/`} target="_blank" rel="noreferrer">
143143
<RiFileCodeLine /> {t("user_guide")}
144144
</a>
145145
</Menu.Item>

0 commit comments

Comments
 (0)