cocoapods-aqara-localzedLoader 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b7fdeaa4c9af99d6d9d4530f324362ab1c5e467f49390465282cd9df5147e74f
|
|
4
|
+
data.tar.gz: 50c4a8eb1f2c97d91ecff0973a607c2d787eaa3f355fbd80408d0b96b4b97ca9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9e39d70e6c65937d9c2a7537cb33764481b3c0ed29dbf83c7092720d233100865ac20b1053dcb374f5ae12629db29b191b6ca4aa0367a952d06a410b516b5e65
|
|
7
|
+
data.tar.gz: d8717544101f5bdf4955ae4512a7019dc4e6f6233eb7c5b295b93ed8fde7bee36c4fa0e64653d284874282c31177cd6d4f39fda068a48583a80211c33dc2e96f
|
|
@@ -2,6 +2,7 @@ import shutil
|
|
|
2
2
|
import os, sys, stat
|
|
3
3
|
import time
|
|
4
4
|
import requests
|
|
5
|
+
import zipfile
|
|
5
6
|
from typing import Optional
|
|
6
7
|
|
|
7
8
|
|
|
@@ -170,136 +171,85 @@ class CrowdinPlatform():
|
|
|
170
171
|
"Content-Type": "application/json"
|
|
171
172
|
}
|
|
172
173
|
|
|
173
|
-
def
|
|
174
|
-
""
|
|
174
|
+
def _get_directories(self) -> dict:
|
|
175
|
+
url = f"{self.base_url}/projects/{self.project_id}/directories"
|
|
176
|
+
resp = requests.get(url, headers=self._get_headers(), params={"limit": 500})
|
|
177
|
+
resp.raise_for_status()
|
|
178
|
+
return resp.json()
|
|
175
179
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
""
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
response = requests.get(url, headers=headers, params=params)
|
|
184
|
-
#print(f"Response: {response.status_code}")
|
|
185
|
-
# print(f"Response Body: {response.text}")
|
|
186
|
-
if response.status_code != 200:
|
|
187
|
-
raise Exception(f"获取项目文件列表失败: {response.status_code}, {response.text}")
|
|
188
|
-
return response.json()
|
|
189
|
-
|
|
190
|
-
def _find_file_id_by_name(self, files_data: dict, file_name: str) -> Optional[int]:
|
|
191
|
-
"""从文件列表中查找指定文件名的 fileId
|
|
180
|
+
def _find_directory_id_by_path(self, directory_path: str) -> int:
|
|
181
|
+
dirs = self._get_directories()
|
|
182
|
+
for item in dirs["data"]:
|
|
183
|
+
data = item["data"]
|
|
184
|
+
if data.get("path") == directory_path:
|
|
185
|
+
return data["id"]
|
|
186
|
+
raise Exception(f"未找到目录: {directory_path}")
|
|
192
187
|
|
|
193
|
-
|
|
194
|
-
files_data: get_project_files 返回的数据
|
|
195
|
-
file_name: 要查找的文件名
|
|
188
|
+
def build_directory_all_languages(self, directory_path: str) -> int:
|
|
196
189
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
""
|
|
200
|
-
|
|
201
|
-
raise Exception("文件列表数据格式错误: 缺少 'data' 字段")
|
|
202
|
-
for file_item in files_data["data"]:
|
|
203
|
-
if "data" in file_item and file_item["data"]["name"] == file_name:
|
|
204
|
-
return file_item["data"]["id"]
|
|
205
|
-
return None
|
|
190
|
+
print("开始获取 /APP 目录的directory_id...")
|
|
191
|
+
directory_id = self._find_directory_id_by_path(directory_path)
|
|
192
|
+
print(f"开始构建directory_id:{directory_id}的翻译文件")
|
|
193
|
+
url = f"{self.base_url}/projects/{self.project_id}/translations/builds/directories/{directory_id}"
|
|
206
194
|
|
|
207
|
-
def _get_file_download_url(self, file_id: int) -> str:
|
|
208
|
-
"""获取文件下载 URL
|
|
209
195
|
|
|
210
|
-
|
|
211
|
-
|
|
196
|
+
resp = requests.post(url, headers=self._get_headers())
|
|
197
|
+
resp.raise_for_status()
|
|
212
198
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
"""
|
|
216
|
-
url = f"{self.base_url}/projects/{self.project_id}/files/{file_id}/download"
|
|
217
|
-
headers = self._get_headers()
|
|
218
|
-
print(f"Request: GET {url}")
|
|
219
|
-
response = requests.get(url, headers=headers)
|
|
220
|
-
#print(f"Response: {response.status_code}")
|
|
221
|
-
# print(f"Response Body: {response.text}")
|
|
222
|
-
if response.status_code != 200:
|
|
223
|
-
raise Exception(f"获取文件下载 URL 失败: {response.status_code}, {response.text}")
|
|
224
|
-
data = response.json()
|
|
225
|
-
if "data" not in data or "url" not in data["data"]:
|
|
226
|
-
raise Exception(f"下载 URL 数据格式错误: {data}")
|
|
227
|
-
return data["data"]["url"]
|
|
228
|
-
|
|
229
|
-
def _download_file_from_url(self, download_url: str, save_path: str, max_retries: int = 3) -> None:
|
|
230
|
-
"""从 URL 下载文件
|
|
199
|
+
build_id = resp.json()["data"]["id"]
|
|
200
|
+
return build_id
|
|
231
201
|
|
|
232
|
-
Args:
|
|
233
|
-
download_url: 文件下载 URL
|
|
234
|
-
save_path: 保存路径
|
|
235
|
-
max_retries: 最大重试次数
|
|
236
|
-
"""
|
|
237
|
-
for attempt in range(max_retries):
|
|
238
|
-
try:
|
|
239
|
-
# print(f"Request: GET {download_url} (Attempt {attempt + 1}/{max_retries})")
|
|
240
|
-
response = requests.get(download_url, stream=True, timeout=60)
|
|
241
|
-
#print(f"Response: {response.status_code}")
|
|
242
|
-
if response.status_code != 200:
|
|
243
|
-
raise Exception(f"下载文件失败: {response.status_code}, {response.text}")
|
|
244
|
-
|
|
245
|
-
os.makedirs(os.path.dirname(save_path) if os.path.dirname(save_path) else ".", exist_ok=True)
|
|
246
|
-
with open(save_path, "wb") as f:
|
|
247
|
-
for chunk in response.iter_content(chunk_size=8192):
|
|
248
|
-
if chunk:
|
|
249
|
-
f.write(chunk)
|
|
250
|
-
#print(f"文件下载成功: {save_path}")
|
|
251
|
-
return
|
|
252
|
-
except (requests.exceptions.ChunkedEncodingError, requests.exceptions.RequestException, Exception) as e:
|
|
253
|
-
print(f"下载失败 (Attempt {attempt + 1}/{max_retries}): {e}")
|
|
254
|
-
if attempt < max_retries - 1:
|
|
255
|
-
wait_time = (attempt + 1) * 2
|
|
256
|
-
print(f"等待 {wait_time} 秒后重试...")
|
|
257
|
-
time.sleep(wait_time)
|
|
258
|
-
else:
|
|
259
|
-
raise Exception(f"文件下载最终失败,已重试 {max_retries} 次: {e}")
|
|
260
|
-
|
|
261
|
-
def download_file(self, target_file_name: str, output_path: str, **kwargs) -> None:
|
|
262
|
-
"""从 Crowdin 下载指定文件
|
|
263
|
-
|
|
264
|
-
Args:
|
|
265
|
-
target_file_name: 目标文件名
|
|
266
|
-
output_path: 输出文件路径
|
|
267
|
-
**kwargs: 其他参数(未使用)
|
|
268
|
-
"""
|
|
269
|
-
print(f"开始从 Crowdin 下载文件: {target_file_name}")
|
|
270
|
-
# 1. 获取项目文件列表
|
|
271
|
-
print("正在获取项目文件列表...")
|
|
272
|
-
files_data = self._get_project_files()
|
|
273
|
-
# 2. 查找目标文件的 fileId
|
|
274
|
-
print(f"正在查找文件: {target_file_name}")
|
|
275
|
-
file_id = self._find_file_id_by_name(files_data, target_file_name)
|
|
276
|
-
if file_id is None:
|
|
277
|
-
raise Exception(f"未找到文件: {target_file_name}")
|
|
278
|
-
print(f"找到文件 ID: {file_id}")
|
|
279
|
-
# 3. 获取下载 URL
|
|
280
|
-
print("正在获取下载 URL...")
|
|
281
|
-
download_url = self._get_file_download_url(file_id)
|
|
282
|
-
print("下载 URL 获取成功")
|
|
283
|
-
# 4. 下载文件
|
|
284
|
-
print("正在下载文件...")
|
|
285
|
-
self._download_file_from_url(download_url, output_path)
|
|
286
|
-
print("文件下载完成")
|
|
287
|
-
|
|
288
|
-
def update_source_language(self, target_file_name: str, output_path: str, **kwargs) -> None:
|
|
289
|
-
"""从 Crowdin 更新源语言文件
|
|
290
|
-
|
|
291
|
-
Args:
|
|
292
|
-
target_file_name: 目标文件名
|
|
293
|
-
output_path: 输出文件路径(最终保存位置)
|
|
294
|
-
**kwargs: 其他参数(未使用)
|
|
295
|
-
"""
|
|
296
|
-
temp_file = "./APP.xlsx"
|
|
297
|
-
self.download_file(target_file_name, temp_file, **kwargs)
|
|
298
|
-
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
299
|
-
shutil.copy(temp_file, output_path)
|
|
300
|
-
os.remove(temp_file)
|
|
301
|
-
print(f"源语言文件已更新: {output_path}")
|
|
302
202
|
|
|
203
|
+
def wait_for_build(self, build_id: int, timeout: int = 120) -> None:
|
|
204
|
+
"""等待构建完成"""
|
|
205
|
+
url = f"{self.base_url}/projects/{self.project_id}/translations/builds/{build_id}"
|
|
206
|
+
headers = self._get_headers()
|
|
207
|
+
start_time = time.time()
|
|
208
|
+
print("等待构建完成...")
|
|
209
|
+
while True:
|
|
210
|
+
resp = requests.get(url, headers=headers)
|
|
211
|
+
resp.raise_for_status()
|
|
212
|
+
status = resp.json()["data"]["status"]
|
|
213
|
+
print(f"当前构建状态: {status}")
|
|
214
|
+
if status == "finished":
|
|
215
|
+
print("构建完成")
|
|
216
|
+
return
|
|
217
|
+
elif status == "failed":
|
|
218
|
+
raise Exception("Crowdin 构建失败")
|
|
219
|
+
elif time.time() - start_time > timeout:
|
|
220
|
+
raise TimeoutError("等待 Crowdin 构建超时")
|
|
221
|
+
time.sleep(3)
|
|
222
|
+
|
|
223
|
+
def download_translations_zip(self, output_zip_path: str) -> None:
|
|
224
|
+
"""下载整个项目的多语言文件 ZIP"""
|
|
225
|
+
build_id = self.build_directory_all_languages("/APP")
|
|
226
|
+
self.wait_for_build(build_id)
|
|
227
|
+
url = f"{self.base_url}/projects/{self.project_id}/translations/builds/{build_id}/download"
|
|
228
|
+
headers = self._get_headers()
|
|
229
|
+
resp = requests.get(url, headers=headers)
|
|
230
|
+
resp.raise_for_status()
|
|
231
|
+
download_url = resp.json()["data"]["url"]
|
|
232
|
+
|
|
233
|
+
# 下载 ZIP 文件
|
|
234
|
+
print(f"正在下载 ZIP 文件到 {output_zip_path} ...")
|
|
235
|
+
r = requests.get(download_url, stream=True)
|
|
236
|
+
r.raise_for_status()
|
|
237
|
+
os.makedirs(os.path.dirname(output_zip_path) or ".", exist_ok=True)
|
|
238
|
+
with open(output_zip_path, "wb") as f:
|
|
239
|
+
for chunk in r.iter_content(chunk_size=8192):
|
|
240
|
+
if chunk:
|
|
241
|
+
f.write(chunk)
|
|
242
|
+
print(f"多语言 ZIP 下载完成: {output_zip_path}")
|
|
243
|
+
|
|
244
|
+
def download_and_extract_translations(self, output_dir: str) -> None:
|
|
245
|
+
"""下载并解压整个多语言文件"""
|
|
246
|
+
zip_path = "./crowdin_translations.zip"
|
|
247
|
+
self.download_translations_zip(zip_path)
|
|
248
|
+
print(f"正在解压 {zip_path} 到 {output_dir}")
|
|
249
|
+
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
|
250
|
+
zip_ref.extractall(output_dir)
|
|
251
|
+
os.remove(zip_path)
|
|
252
|
+
print(f"多语言文件已解压到: {output_dir}APP.xlsx")
|
|
303
253
|
|
|
304
254
|
# 默认配置(需要设置)
|
|
305
255
|
DEFAULT_ACCESS_TOKEN = "db0506fb755d528c7b9b750e15174d3cfa483859488da978748ad6b9e34d13dc94d8716810a2f978" # 需要设置
|
|
@@ -320,7 +270,7 @@ if __name__ == '__main__':
|
|
|
320
270
|
|
|
321
271
|
if crowdin:
|
|
322
272
|
platform = CrowdinPlatform(DEFAULT_ACCESS_TOKEN, DEFAULT_PROJECT_ID)
|
|
323
|
-
target_path = f"{localizable_path}/APP/
|
|
324
|
-
platform.
|
|
273
|
+
target_path = f"{localizable_path}/APP/"
|
|
274
|
+
platform.download_and_extract_translations(target_path)
|
|
325
275
|
else:
|
|
326
276
|
DownLatestLocalizableSource(localizable_path)
|
metadata
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cocoapods-aqara-localzedLoader
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- zhaoxifan
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2025-12-31 00:00:00.000000000 Z
|
|
@@ -202,7 +202,7 @@ homepage: https://github.com/LuckZXF/cocoapods-aqara-localzedLoader
|
|
|
202
202
|
licenses:
|
|
203
203
|
- MIT
|
|
204
204
|
metadata: {}
|
|
205
|
-
post_install_message:
|
|
205
|
+
post_install_message:
|
|
206
206
|
rdoc_options: []
|
|
207
207
|
require_paths:
|
|
208
208
|
- lib
|
|
@@ -217,8 +217,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
217
217
|
- !ruby/object:Gem::Version
|
|
218
218
|
version: '0'
|
|
219
219
|
requirements: []
|
|
220
|
-
rubygems_version: 3.
|
|
221
|
-
signing_key:
|
|
220
|
+
rubygems_version: 3.2.22
|
|
221
|
+
signing_key:
|
|
222
222
|
specification_version: 4
|
|
223
223
|
summary: Aqara 多语言从云端多语言平台下载并处理解析成Xcode需要的多语言文件
|
|
224
224
|
test_files:
|