mirror of
https://github.com/yeongpin/cursor-free-vip.git
synced 2025-08-02 20:47:35 +08:00
Merge pull request #489 from Hexoso/main
Fix: bug in disable cursor auto update
This commit is contained in:
commit
1244d86994
@ -66,7 +66,8 @@ def setup_config(translator=None):
|
|||||||
'machine_id_path': os.path.join(appdata, "Cursor", "machineId"),
|
'machine_id_path': os.path.join(appdata, "Cursor", "machineId"),
|
||||||
'cursor_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app"),
|
'cursor_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app"),
|
||||||
'updater_path': os.path.join(localappdata, "cursor-updater"),
|
'updater_path': os.path.join(localappdata, "cursor-updater"),
|
||||||
'update_yml_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app-update.yml")
|
'update_yml_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app-update.yml"),
|
||||||
|
'product_json_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app", "product.json")
|
||||||
}
|
}
|
||||||
# Create storage directory
|
# Create storage directory
|
||||||
os.makedirs(os.path.dirname(default_config['WindowsPaths']['storage_path']), exist_ok=True)
|
os.makedirs(os.path.dirname(default_config['WindowsPaths']['storage_path']), exist_ok=True)
|
||||||
@ -78,7 +79,8 @@ def setup_config(translator=None):
|
|||||||
'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId"),
|
'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId"),
|
||||||
'cursor_path': "/Applications/Cursor.app/Contents/Resources/app",
|
'cursor_path': "/Applications/Cursor.app/Contents/Resources/app",
|
||||||
'updater_path': os.path.expanduser("~/Library/Application Support/cursor-updater"),
|
'updater_path': os.path.expanduser("~/Library/Application Support/cursor-updater"),
|
||||||
'update_yml_path': "/Applications/Cursor.app/Contents/Resources/app-update.yml"
|
'update_yml_path': "/Applications/Cursor.app/Contents/Resources/app-update.yml",
|
||||||
|
'product_json_path': "/Applications/Cursor.app/Contents/Resources/app/product.json"
|
||||||
}
|
}
|
||||||
# Create storage directory
|
# Create storage directory
|
||||||
os.makedirs(os.path.dirname(default_config['MacPaths']['storage_path']), exist_ok=True)
|
os.makedirs(os.path.dirname(default_config['MacPaths']['storage_path']), exist_ok=True)
|
||||||
@ -185,7 +187,8 @@ def setup_config(translator=None):
|
|||||||
'machine_id_path': os.path.join(cursor_dir, "machineid") if cursor_dir else "",
|
'machine_id_path': os.path.join(cursor_dir, "machineid") if cursor_dir else "",
|
||||||
'cursor_path': get_linux_cursor_path(),
|
'cursor_path': get_linux_cursor_path(),
|
||||||
'updater_path': os.path.join(config_base, "cursor-updater"),
|
'updater_path': os.path.join(config_base, "cursor-updater"),
|
||||||
'update_yml_path': os.path.join(cursor_dir, "resources/app-update.yml") if cursor_dir else ""
|
'update_yml_path': os.path.join(cursor_dir, "resources/app-update.yml") if cursor_dir else "",
|
||||||
|
'product_json_path': os.path.join(cursor_dir, "resources/app/product.json") if cursor_dir else ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read existing configuration and merge
|
# Read existing configuration and merge
|
||||||
|
@ -34,12 +34,15 @@ class AutoUpdateDisabler:
|
|||||||
if self.system == "Windows":
|
if self.system == "Windows":
|
||||||
self.updater_path = config.get('WindowsPaths', 'updater_path', fallback=os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"))
|
self.updater_path = config.get('WindowsPaths', 'updater_path', fallback=os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"))
|
||||||
self.update_yml_path = config.get('WindowsPaths', 'update_yml_path', fallback=os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "update.yml"))
|
self.update_yml_path = config.get('WindowsPaths', 'update_yml_path', fallback=os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "update.yml"))
|
||||||
|
self.product_json_path = config.get('WindowsPaths', 'product_json_path', fallback=os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "product.json"))
|
||||||
elif self.system == "Darwin":
|
elif self.system == "Darwin":
|
||||||
self.updater_path = config.get('MacPaths', 'updater_path', fallback=os.path.expanduser("~/Library/Application Support/cursor-updater"))
|
self.updater_path = config.get('MacPaths', 'updater_path', fallback=os.path.expanduser("~/Library/Application Support/cursor-updater"))
|
||||||
self.update_yml_path = config.get('MacPaths', 'update_yml_path', fallback="/Applications/Cursor.app/Contents/Resources/app-update.yml")
|
self.update_yml_path = config.get('MacPaths', 'update_yml_path', fallback="/Applications/Cursor.app/Contents/Resources/app-update.yml")
|
||||||
|
self.product_json_path = config.get('MacPaths', 'product_json_path', fallback="/Applications/Cursor.app/Contents/Resources/app/product.json")
|
||||||
elif self.system == "Linux":
|
elif self.system == "Linux":
|
||||||
self.updater_path = config.get('LinuxPaths', 'updater_path', fallback=os.path.expanduser("~/.config/cursor-updater"))
|
self.updater_path = config.get('LinuxPaths', 'updater_path', fallback=os.path.expanduser("~/.config/cursor-updater"))
|
||||||
self.update_yml_path = config.get('LinuxPaths', 'update_yml_path', fallback=os.path.expanduser("~/.config/cursor/resources/app-update.yml"))
|
self.update_yml_path = config.get('LinuxPaths', 'update_yml_path', fallback=os.path.expanduser("~/.config/cursor/resources/app-update.yml"))
|
||||||
|
self.product_json_path = config.get('LinuxPaths', 'product_json_path', fallback=os.path.expanduser("~/.config/cursor/resources/app/product.json"))
|
||||||
else:
|
else:
|
||||||
# If configuration loading fails, use default paths
|
# If configuration loading fails, use default paths
|
||||||
self.updater_paths = {
|
self.updater_paths = {
|
||||||
@ -56,21 +59,29 @@ class AutoUpdateDisabler:
|
|||||||
}
|
}
|
||||||
self.update_yml_path = self.update_yml_paths.get(self.system)
|
self.update_yml_path = self.update_yml_paths.get(self.system)
|
||||||
|
|
||||||
def _change_main_js(self):
|
self.product_json_paths = {
|
||||||
"""Change main.js"""
|
"Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "product.json"),
|
||||||
|
"Darwin": "/Applications/Cursor.app/Contents/Resources/app/product.json",
|
||||||
|
"Linux": os.path.expanduser("~/.config/cursor/resources/app/product.json")
|
||||||
|
}
|
||||||
|
self.product_json_path = self.product_json_paths.get(self.system)
|
||||||
|
|
||||||
|
def _remove_update_url(self):
|
||||||
|
"""Remove update URL"""
|
||||||
try:
|
try:
|
||||||
main_path = get_config(self.translator).get('main_js_path', fallback=os.path.expanduser("~/.config/cursor/resources/app/main.js"))
|
original_stat = os.stat(self.product_json_path)
|
||||||
original_stat = os.stat(main_path)
|
|
||||||
original_mode = original_stat.st_mode
|
original_mode = original_stat.st_mode
|
||||||
original_uid = original_stat.st_uid
|
original_uid = original_stat.st_uid
|
||||||
original_gid = original_stat.st_gid
|
original_gid = original_stat.st_gid
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file:
|
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file:
|
||||||
with open(main_path, "r", encoding="utf-8") as main_file:
|
with open(self.product_json_path, "r", encoding="utf-8") as product_json_file:
|
||||||
content = main_file.read()
|
content = product_json_file.read()
|
||||||
|
|
||||||
patterns = {
|
patterns = {
|
||||||
r"https://api2.cursor.sh/aiserver.v1.AuthService/DownloadUpdate": r"",
|
r"https://api2.cursor.sh/aiserver.v1.AuthService/DownloadUpdate": r"",
|
||||||
|
r"https://api2.cursor.sh/updates": r"",
|
||||||
|
r"http://cursorapi.com/updates": r"",
|
||||||
}
|
}
|
||||||
|
|
||||||
for pattern, replacement in patterns.items():
|
for pattern, replacement in patterns.items():
|
||||||
@ -79,12 +90,12 @@ class AutoUpdateDisabler:
|
|||||||
tmp_file.write(content)
|
tmp_file.write(content)
|
||||||
tmp_path = tmp_file.name
|
tmp_path = tmp_file.name
|
||||||
|
|
||||||
shutil.copy2(main_path, main_path + ".old")
|
shutil.copy2(self.product_json_path, self.product_json_path + ".old")
|
||||||
shutil.move(tmp_path, main_path)
|
shutil.move(tmp_path, self.product_json_path)
|
||||||
|
|
||||||
os.chmod(main_path, original_mode)
|
os.chmod(self.product_json_path, original_mode)
|
||||||
if os.name != "nt":
|
if os.name != "nt":
|
||||||
os.chown(main_path, original_uid, original_gid)
|
os.chown(self.product_json_path, original_uid, original_gid)
|
||||||
|
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.file_modified')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.file_modified')}{Style.RESET_ALL}")
|
||||||
return True
|
return True
|
||||||
@ -122,17 +133,18 @@ class AutoUpdateDisabler:
|
|||||||
print(f"{Fore.CYAN}{EMOJI['FOLDER']} {self.translator.get('update.removing_directory') if self.translator else '正在删除更新程序目录...'}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['FOLDER']} {self.translator.get('update.removing_directory') if self.translator else '正在删除更新程序目录...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
if os.path.exists(updater_path):
|
if os.path.exists(updater_path):
|
||||||
if os.path.isdir(updater_path):
|
try:
|
||||||
shutil.rmtree(updater_path)
|
if os.path.isdir(updater_path):
|
||||||
else:
|
shutil.rmtree(updater_path)
|
||||||
os.remove(updater_path)
|
else:
|
||||||
|
os.remove(updater_path)
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.directory_removed') if self.translator else '更新程序目录已删除'}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.directory_removed') if self.translator else '更新程序目录已删除'}{Style.RESET_ALL}")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('update.directory_locked', path=updater_path) if self.translator else f'更新程序目录已被锁定,跳过删除: {updater_path}'}{Style.RESET_ALL}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.remove_directory_failed', error=str(e)) if self.translator else f'删除目录失败: {e}'}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.remove_directory_failed', error=str(e)) if self.translator else f'删除目录失败: {e}'}{Style.RESET_ALL}")
|
||||||
# 即使删除失败,也返回 True,继续执行下一步
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _clear_update_yml_file(self):
|
def _clear_update_yml_file(self):
|
||||||
@ -145,15 +157,15 @@ class AutoUpdateDisabler:
|
|||||||
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.clearing_update_yml') if self.translator else '正在清空更新配置文件...'}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.clearing_update_yml') if self.translator else '正在清空更新配置文件...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
if os.path.exists(update_yml_path):
|
if os.path.exists(update_yml_path):
|
||||||
# 清空文件内容
|
try:
|
||||||
with open(update_yml_path, 'w') as f:
|
with open(update_yml_path, 'w') as f:
|
||||||
f.write('')
|
f.write('')
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.update_yml_cleared') if self.translator else '更新配置文件已清空'}{Style.RESET_ALL}")
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.update_yml_cleared') if self.translator else '更新配置文件已清空'}{Style.RESET_ALL}")
|
except PermissionError:
|
||||||
return True
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('update.yml_locked') if self.translator else '更新配置文件已被锁定,跳过清空'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('update.update_yml_not_found') if self.translator else '更新配置文件不存在'}{Style.RESET_ALL}")
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('update.update_yml_not_found') if self.translator else '更新配置文件不存在'}{Style.RESET_ALL}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.clear_update_yml_failed', error=str(e)) if self.translator else f'清空更新配置文件失败: {e}'}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.clear_update_yml_failed', error=str(e)) if self.translator else f'清空更新配置文件失败: {e}'}{Style.RESET_ALL}")
|
||||||
@ -170,37 +182,43 @@ class AutoUpdateDisabler:
|
|||||||
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.creating_block_file') if self.translator else '正在创建阻止文件...'}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.creating_block_file') if self.translator else '正在创建阻止文件...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 创建 updater_path 阻止文件
|
# 创建 updater_path 阻止文件
|
||||||
os.makedirs(os.path.dirname(updater_path), exist_ok=True)
|
try:
|
||||||
open(updater_path, 'w').close()
|
os.makedirs(os.path.dirname(updater_path), exist_ok=True)
|
||||||
|
open(updater_path, 'w').close()
|
||||||
# 设置 updater_path 为只读
|
|
||||||
if self.system == "Windows":
|
# 设置 updater_path 为只读
|
||||||
os.system(f'attrib +r "{updater_path}"')
|
if self.system == "Windows":
|
||||||
else:
|
os.system(f'attrib +r "{updater_path}"')
|
||||||
os.chmod(updater_path, 0o444) # 设置为只读
|
else:
|
||||||
|
os.chmod(updater_path, 0o444) # 设置为只读
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.block_file_created') if self.translator else '阻止文件已创建'}: {updater_path}{Style.RESET_ALL}")
|
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.block_file_created') if self.translator else '阻止文件已创建'}: {updater_path}{Style.RESET_ALL}")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('update.block_file_locked') if self.translator else '阻止文件已被锁定,跳过创建'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 检查 update_yml_path
|
# 检查 update_yml_path
|
||||||
update_yml_path = self.update_yml_path
|
update_yml_path = self.update_yml_path
|
||||||
if update_yml_path and os.path.exists(os.path.dirname(update_yml_path)):
|
if update_yml_path and os.path.exists(os.path.dirname(update_yml_path)):
|
||||||
# 创建 update_yml_path 阻止文件
|
try:
|
||||||
with open(update_yml_path, 'w') as f:
|
# 创建 update_yml_path 阻止文件
|
||||||
f.write('# This file is locked to prevent auto-updates\nversion: 0.0.0\n')
|
with open(update_yml_path, 'w') as f:
|
||||||
|
f.write('# This file is locked to prevent auto-updates\nversion: 0.0.0\n')
|
||||||
# 设置 update_yml_path 为只读
|
|
||||||
if self.system == "Windows":
|
# 设置 update_yml_path 为只读
|
||||||
os.system(f'attrib +r "{update_yml_path}"')
|
if self.system == "Windows":
|
||||||
else:
|
os.system(f'attrib +r "{update_yml_path}"')
|
||||||
os.chmod(update_yml_path, 0o444) # 设置为只读
|
else:
|
||||||
|
os.chmod(update_yml_path, 0o444) # 设置为只读
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.yml_locked') if self.translator else '更新配置文件已锁定'}: {update_yml_path}{Style.RESET_ALL}")
|
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.yml_locked') if self.translator else '更新配置文件已锁定'}: {update_yml_path}{Style.RESET_ALL}")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('update.yml_already_locked') if self.translator else '更新配置文件已被锁定,跳过修改'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.create_block_file_failed', error=str(e)) if self.translator else f'创建阻止文件失败: {e}'}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.create_block_file_failed', error=str(e)) if self.translator else f'创建阻止文件失败: {e}'}{Style.RESET_ALL}")
|
||||||
return False
|
return True # 返回 True 以继续执行后续步骤
|
||||||
|
|
||||||
def disable_auto_update(self):
|
def disable_auto_update(self):
|
||||||
"""Disable auto update"""
|
"""Disable auto update"""
|
||||||
@ -222,8 +240,8 @@ class AutoUpdateDisabler:
|
|||||||
if not self._create_blocking_file():
|
if not self._create_blocking_file():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 5. Change main.js
|
# 5. Remove update URL from product.json
|
||||||
if not self._change_main_js():
|
if not self._remove_update_url():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print(f"{Fore.GREEN}{EMOJI['CHECK']} {self.translator.get('update.disable_success') if self.translator else '自动更新已禁用'}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['CHECK']} {self.translator.get('update.disable_success') if self.translator else '自动更新已禁用'}{Style.RESET_ALL}")
|
||||||
|
@ -307,7 +307,16 @@
|
|||||||
"clear_update_yml_failed": "Failed to clear update.yml file: {error}",
|
"clear_update_yml_failed": "Failed to clear update.yml file: {error}",
|
||||||
"unsupported_os": "Unsupported OS: {system}",
|
"unsupported_os": "Unsupported OS: {system}",
|
||||||
"remove_directory_failed": "Failed to remove directory: {error}",
|
"remove_directory_failed": "Failed to remove directory: {error}",
|
||||||
"create_block_file_failed": "Failed to create block file: {error}"
|
"create_block_file_failed": "Failed to create block file: {error}",
|
||||||
|
"directory_locked": "Directory is locked: {path}",
|
||||||
|
"yml_locked": "update.yml file is locked",
|
||||||
|
"block_file_locked": "block file is locked",
|
||||||
|
"yml_already_locked": "update.yml file is already locked",
|
||||||
|
"block_file_already_locked": "block file is already locked",
|
||||||
|
"block_file_locked_error": "Block file locked error: {error}",
|
||||||
|
"yml_locked_error": "update.yml file locked error: {error}",
|
||||||
|
"block_file_already_locked_error": "Block file already locked error: {error}",
|
||||||
|
"yml_already_locked_error": "update.yml file already locked error: {error}"
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"checking": "Checking for updates...",
|
"checking": "Checking for updates...",
|
||||||
|
@ -302,7 +302,16 @@
|
|||||||
"clear_update_yml_failed": "清空 update.yml 文件失败: {error}",
|
"clear_update_yml_failed": "清空 update.yml 文件失败: {error}",
|
||||||
"unsupported_os": "不支持的操作系统: {system}",
|
"unsupported_os": "不支持的操作系统: {system}",
|
||||||
"remove_directory_failed": "删除目录失败: {error}",
|
"remove_directory_failed": "删除目录失败: {error}",
|
||||||
"create_block_file_failed": "创建阻止文件失败: {error}"
|
"create_block_file_failed": "创建阻止文件失败: {error}",
|
||||||
|
"directory_locked": "目录被锁定: {path}",
|
||||||
|
"yml_locked": "update.yml 文件被锁定",
|
||||||
|
"block_file_locked": "阻止文件被锁定",
|
||||||
|
"yml_already_locked": "update.yml 文件已锁定",
|
||||||
|
"block_file_already_locked": "阻止文件已锁定",
|
||||||
|
"block_file_locked_error": "阻止文件锁定错误: {error}",
|
||||||
|
"yml_locked_error": "update.yml 文件锁定错误: {error}",
|
||||||
|
"block_file_already_locked_error": "阻止文件已锁定错误: {error}",
|
||||||
|
"yml_already_locked_error": "update.yml 文件已锁定错误: {error}"
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"checking": "检查更新...",
|
"checking": "检查更新...",
|
||||||
|
@ -284,7 +284,16 @@
|
|||||||
"clear_update_yml_failed": "清空 update.yml 文件失败: {error}",
|
"clear_update_yml_failed": "清空 update.yml 文件失败: {error}",
|
||||||
"unsupported_os": "不支持的操作系统: {system}",
|
"unsupported_os": "不支持的操作系统: {system}",
|
||||||
"remove_directory_failed": "刪除目錄失败: {error}",
|
"remove_directory_failed": "刪除目錄失败: {error}",
|
||||||
"create_block_file_failed": "創建阻止文件失败: {error}"
|
"create_block_file_failed": "創建阻止文件失败: {error}",
|
||||||
|
"directory_locked": "目錄被鎖定: {path}",
|
||||||
|
"yml_locked": "update.yml 文件被鎖定",
|
||||||
|
"block_file_locked": "阻止文件被鎖定",
|
||||||
|
"yml_already_locked": "update.yml 文件已鎖定",
|
||||||
|
"block_file_already_locked": "阻止文件已鎖定",
|
||||||
|
"block_file_locked_error": "阻止文件锁定错误: {error}",
|
||||||
|
"yml_locked_error": "update.yml 文件锁定错误: {error}",
|
||||||
|
"block_file_already_locked_error": "阻止文件已锁定错误: {error}",
|
||||||
|
"yml_already_locked_error": "update.yml 文件已锁定错误: {error}"
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"checking": "檢查更新...",
|
"checking": "檢查更新...",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user