diff --git a/Bark.xcodeproj/project.pbxproj b/Bark.xcodeproj/project.pbxproj index feb012c..fc9b2f8 100644 --- a/Bark.xcodeproj/project.pbxproj +++ b/Bark.xcodeproj/project.pbxproj @@ -140,7 +140,6 @@ 06C2CF232685B88D0034B127 /* TextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06C2CF222685B88D0034B127 /* TextCell.swift */; }; 06C2CF252685BDB80034B127 /* SpacerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06C2CF242685BDB80034B127 /* SpacerCell.swift */; }; 06C5952D2480E3F8006B98F3 /* LabelCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06C5952C2480E3F8006B98F3 /* LabelCell.swift */; }; - 06C5952F248107F5006B98F3 /* iCloudStatusCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06C5952E248107F5006B98F3 /* iCloudStatusCell.swift */; }; 06C5953124811392006B98F3 /* ArchiveSettingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06C5953024811392006B98F3 /* ArchiveSettingCell.swift */; }; 06C595362481160F006B98F3 /* BKLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06C595352481160F006B98F3 /* BKLabel.swift */; }; 06CF784721C7A50300A052D7 /* NotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 06CF784021C7A50300A052D7 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -380,7 +379,6 @@ 06C2CF222685B88D0034B127 /* TextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCell.swift; sourceTree = ""; }; 06C2CF242685BDB80034B127 /* SpacerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpacerCell.swift; sourceTree = ""; }; 06C5952C2480E3F8006B98F3 /* LabelCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelCell.swift; sourceTree = ""; }; - 06C5952E248107F5006B98F3 /* iCloudStatusCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iCloudStatusCell.swift; sourceTree = ""; }; 06C5953024811392006B98F3 /* ArchiveSettingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSettingCell.swift; sourceTree = ""; }; 06C5953224811505006B98F3 /* ArchiveSettingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSettingManager.swift; sourceTree = ""; }; 06C595352481160F006B98F3 /* BKLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BKLabel.swift; sourceTree = ""; }; @@ -505,7 +503,6 @@ 0603706820E1F89500F4CA05 /* PreviewCardCell.swift */, 064CAB9D256BE9090018155C /* PreviewCardCellViewModel.swift */, 06C5952C2480E3F8006B98F3 /* LabelCell.swift */, - 06C5952E248107F5006B98F3 /* iCloudStatusCell.swift */, 06C5953024811392006B98F3 /* ArchiveSettingCell.swift */, 06BBB8BB2567B3AD0076F63E /* ArchiveSettingCellViewModel.swift */, 060481EF250F51CA00BC9799 /* SoundCell.swift */, @@ -1279,7 +1276,6 @@ 064CABA6256BE9510018155C /* PreviewModel.swift in Sources */, 0637FA7E20E0969800E80174 /* Client.swift in Sources */, 0661A545204FDA4100965E4E /* HomeViewController.swift in Sources */, - 06C5952F248107F5006B98F3 /* iCloudStatusCell.swift in Sources */, 06BBB88725650C6C0076F63E /* ArchiveSettingManager.swift in Sources */, 065BE44B2563D8E1002A8CA4 /* Reusable.swift in Sources */, 0637FA8620E0AB6600E80174 /* UIColor+Extension.swift in Sources */, diff --git a/Bark/Localizable.xcstrings b/Bark/Localizable.xcstrings index 17fd607..50ee6cd 100644 --- a/Bark/Localizable.xcstrings +++ b/Bark/Localizable.xcstrings @@ -291,35 +291,6 @@ } } }, - "available" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enabled" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "有効" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Etkin" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已开启" - } - } - } - }, "badge" : { "extractionState" : "manual", "localizations" : { @@ -929,35 +900,6 @@ } } }, - "copyCrashLog" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Copy Crash Log" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "クラッシュログをコピー" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Copy Crash Log" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制闪退日志" - } - } - } - }, "copyExample" : { "extractionState" : "manual", "localizations" : { @@ -1016,64 +958,6 @@ } } }, - "crashContent" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "You need to restart the app! \n\nIf the problem persists, you can try to check the FAQ to see if there is a solution.\nhttps://bark.day.app/#/en-us/faq\n\nBark will not upload any logs! If you need help (or wish to help the developer fix the crash), you can also send the crash log to me, and I will contact you as soon as possible.\n\nEmail: to@day.app\nTelegram: https://t.me/joinchat/OsCbLzovUAE0YjY1\nGithub Issue: https://github.com/Finb/Bark/issues\n" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "問題が解決しない場合は、FAQを確認して解決策があるかどうかを確認できます。 \nhttps://bark.day.app/#/en-us/faq \n\nBarkはログをアップロードしません!助けが必要な場合(または開発者がクラッシュを修正するのを手伝いたい場合)、クラッシュログを私に送ってください。できるだけ早く連絡します。 \n\nメール: to@day.app \nTelegram: https://t.me/joinchat/OsCbLzovUAE0YjY1 \nGithub Issue: https://github.com/Finb/Bark/issues " - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Uygulamayı yeniden başlatmanız gerekiyor!\n\nSorun devam ederse bir çözüm olup olmadığını görmek için SSS'yi kontrol etmeyi deneyebilirsiniz.\nhttps://bark.day.app/#/en-us/faq\n\nBark herhangi bir günlük yüklemeyecek! Yardıma ihtiyacınız varsa (veya geliştiricinin çökmeyi düzeltmesine yardım etmek istiyorsanız), kilitlenme günlüğünü bana da gönderebilirsiniz; mümkün olan en kısa sürede sizinle iletişime geçeceğim.\n\nE-posta: to@day.app\nTelgraf: https://t.me/joinchat/OsCbLzovUAE0YjY1\nGithub Sorunları: https://github.com/Finb/Bark/issues" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "您需要重启APP!\n\n如还是提示闪退,可以尝试查看FAQ看是否有解决办法\nhttps://bark.day.app/#/faq\n\nBark 不会上传任何日志!如您需帮助(或帮助作者修复闪退),可以将闪退日志手动复制发送给我,我会尽快与您联系。\n\n邮箱: to@day.app\nTelegram: https://t.me/joinchat/OsCbLzov\nGithub Issue: https://github.com/Finb/Bark/issues\n" - } - } - } - }, - "crashed" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Crashed!" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "クラッシュしました!" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "düştü!" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "好像闪退了!" - } - } - } - }, "criticalAlert" : { "extractionState" : "manual", "localizations" : { @@ -2001,35 +1885,6 @@ } } }, - "iCloudSatatus" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "iCloud Sync" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "iCloud同期" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "iCloud Senkronizasyonu" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "iCloud 同步" - } - } - } - }, "imageParameter" : { "extractionState" : "manual", "localizations" : { @@ -3132,35 +2987,6 @@ } } }, - "restricted" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Disabled" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "無効" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Devre Dışı" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未开启" - } - } - } - }, "ringtone" : { "extractionState" : "manual", "localizations" : { diff --git a/Controller/MessageListViewController.swift b/Controller/MessageListViewController.swift index ee5c682..aa4277a 100644 --- a/Controller/MessageListViewController.swift +++ b/Controller/MessageListViewController.swift @@ -58,7 +58,7 @@ class MessageListViewController: BaseViewController { btn.setImage(UIImage(named: "group_collapse")?.withRenderingMode(.alwaysTemplate), for: .selected) btn.imageView?.tintColor = BKColor.black btn.frame = CGRect(x: 0, y: 0, width: 40, height: 40) - btn.accessibilityLabel = "toggle" + btn.accessibilityLabel = "toggle".localized return UIBarButtonItem(customView: btn) }() diff --git a/Controller/MessageSettingsViewController.swift b/Controller/MessageSettingsViewController.swift index 22d062f..5442684 100644 --- a/Controller/MessageSettingsViewController.swift +++ b/Controller/MessageSettingsViewController.swift @@ -21,7 +21,6 @@ class MessageSettingsViewController: BaseViewController { let copyButton: IconButton = { let button = IconButton(image: UIImage(named: "baseline_file_copy_white_24pt"), tintColor: BKColor.grey.base) - button.accessibilityLabel = "copy".localized + button.accessibilityLabel = "Copy".localized return button }() diff --git a/View/SoundCell.swift b/View/SoundCell.swift index 6282b8f..2aee0c4 100644 --- a/View/SoundCell.swift +++ b/View/SoundCell.swift @@ -13,7 +13,7 @@ import UIKit class SoundCell: BaseTableViewCell { let copyButton: IconButton = { let button = IconButton(image: UIImage(named: "baseline_file_copy_white_24pt"), tintColor: BKColor.grey.base) - button.accessibilityLabel = "copy".localized + button.accessibilityLabel = "Copy".localized return button }() diff --git a/View/iCloudStatusCell.swift b/View/iCloudStatusCell.swift deleted file mode 100644 index 36c31c6..0000000 --- a/View/iCloudStatusCell.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// iCloudStatusCell.swift -// Bark -// -// Created by huangfeng on 2020/5/29. -// Copyright © 2020 Fin. All rights reserved. -// - -import CloudKit -import UIKit - -class iCloudStatusCell: UITableViewCell { - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: reuseIdentifier) - self.selectionStyle = .none - self.backgroundColor = BKColor.background.secondary - self.textLabel?.text = "iCloudStatus".localized - self.detailTextLabel?.text = "" - self.detailTextLabel?.textColor = BKColor.grey.darken2 - CKContainer.default().accountStatus { status, _ in - dispatch_sync_safely_main_queue { - switch status { - case .available: - self.detailTextLabel?.text = "available".localized - case .noAccount, .restricted, .temporarilyUnavailable: - self.detailTextLabel?.text = "restricted".localized - case .couldNotDetermine: - self.detailTextLabel?.text = "unknown".localized - @unknown default: - break - } - } - } - } - - @available(*, unavailable) - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/check_unused_translations.py b/check_unused_translations.py index 5f8b179..a3d3d1f 100644 --- a/check_unused_translations.py +++ b/check_unused_translations.py @@ -3,7 +3,9 @@ Bark项目本地化字符串分析工具 这个脚本会扫描整个Bark项目,找出 Localizable.xcstrings 中未使用的翻译key。 -检测方式:任何在双引号内且在本地化文件中定义的字符串都会被认为是被使用的key。 +检测方式: +1. 任何在双引号内且在本地化文件中定义的字符串都会被认为是被使用的key +2. "key".localized 和 "key".localized(with:) 模式 使用方法: python3 check_unused_translations.py @@ -45,7 +47,7 @@ class BarkLocalizationAnalyzer: def extract_used_keys_from_file(self, file_path, all_defined_keys): """从Swift文件中提取使用的本地化key""" used_keys = set() - nslocalizedstring_keys = set() # 新增:专门收集NSLocalizedString中的key + localized_keys = set() # 收集.localized中的key try: with open(file_path, 'r', encoding='utf-8') as f: @@ -61,26 +63,27 @@ class BarkLocalizationAnalyzer: if quoted_string and quoted_string in all_defined_keys: used_keys.add(quoted_string) - # 方法2: 专门查找 NSLocalizedString("key") 模式 - nslocalizedstring_patterns = [ - r'NSLocalizedString\s*\(\s*"([^"]+)"\s*\)', # NSLocalizedString("key") - r'NSLocalizedString\s*\(\s*\'([^\']+)\'\s*\)', # NSLocalizedString('key') - r'NSLocalizedString\s*\(\s*@"([^"]+)"\s*\)', # NSLocalizedString(@"key") + # 方法2: 查找 "key".localized 和 "key".localized(with:) 模式 + localized_patterns = [ + r'"([^"]+)"\s*\.\s*localized\b', # "key".localized + r'"([^"]+)"\s*\.\s*localized\s*\(\s*with:', # "key".localized(with: + r'\'([^\']+)\'\s*\.\s*localized\b', # 'key'.localized + r'\'([^\']+)\'\s*\.\s*localized\s*\(\s*with:', # 'key'.localized(with: ] - for pattern in nslocalizedstring_patterns: + for pattern in localized_patterns: matches = re.findall(pattern, content, re.MULTILINE | re.DOTALL) for match in matches: match = match.strip() if match: - nslocalizedstring_keys.add(match) # 收集所有NSLocalizedString中的key + localized_keys.add(match) # 收集所有.localized中的key if match in all_defined_keys: used_keys.add(match) except Exception as e: print(f"⚠️ 读取文件失败 {file_path}: {e}") - return used_keys, nslocalizedstring_keys + return used_keys, localized_keys def find_all_used_keys(self, all_defined_keys): """在整个项目中查找所有使用的本地化 key""" @@ -90,20 +93,20 @@ class BarkLocalizationAnalyzer: # 提取使用的key used_keys = set() - all_nslocalizedstring_keys = set() # 新增:收集所有NSLocalizedString中的key + all_localized_keys = set() # 收集所有.localized中的key files_with_keys = 0 for file_path in swift_files: - file_keys, nsl_keys = self.extract_used_keys_from_file(file_path, all_defined_keys) + file_keys, localized_keys = self.extract_used_keys_from_file(file_path, all_defined_keys) if file_keys: files_with_keys += 1 used_keys.update(file_keys) - all_nslocalizedstring_keys.update(nsl_keys) + all_localized_keys.update(localized_keys) print(f"🔑 在 {files_with_keys} 个文件中找到 {len(used_keys)} 个使用的key") - # 计算在NSLocalizedString中使用但未在本地化文件中定义的key - missing_in_localization = all_nslocalizedstring_keys - all_defined_keys + # 计算在代码中使用但未在本地化文件中定义的key + missing_in_localization = all_localized_keys - all_defined_keys return used_keys, files_with_keys, missing_in_localization @@ -160,7 +163,7 @@ class BarkLocalizationAnalyzer: print(f"使用中的key数量: {result['used_keys']}") print(f"未使用的key数量: {result['unused_keys']}") print(f"缺失的key数量: {result['missing_keys']} (代码中使用但未定义)") - print(f"NSLocalizedString中缺失的key: {result['missing_in_localization']} 个") + print(f"代码中缺失的key: {result['missing_in_localization']} 个") if result['unused_keys_list']: print(f"\n🗑️ 未使用的翻译key ({result['unused_keys']} 个):") @@ -173,7 +176,7 @@ class BarkLocalizationAnalyzer: print(f" {i:2d}. {key}") if result['missing_in_localization_list']: - print(f"\n❌ NSLocalizedString中使用但未在Localizable.xcstrings中定义的key ({result['missing_in_localization']} 个):") + print(f"\n❌ 代码中使用但未在Localizable.xcstrings中定义的key ({result['missing_in_localization']} 个):") for i, key in enumerate(result['missing_in_localization_list'], 1): print(f" {i:2d}. {key}") @@ -210,7 +213,7 @@ def main(): if result['missing_keys'] > 0: print(f" - 为 {result['missing_keys']} 个缺失的key添加翻译") if result['missing_in_localization'] > 0: - print(f" - 为 {result['missing_in_localization']} 个NSLocalizedString中的key添加本地化定义") + print(f" - 为 {result['missing_in_localization']} 个代码中使用的key添加本地化定义") print(" - 检查是否有动态构建的key名称(脚本可能无法检测)") print(" - 手动检查Storyboard/XIB文件中的硬编码字符串")