Refactor localization implementation by replacing all instances of NSLocalizedString with a String.localized extension method across multiple files. This change simplifies the localization process, enhances code readability, and ensures consistency in the app's interface. Updated various views to utilize the new localization approach, improving maintainability and reducing redundancy.

main
v504 2 months ago
parent 562f0efd9d
commit 510dd6d49a

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5817662E2E54241200C1B687"
BuildableName = "MyQrCode.app"
BlueprintName = "MyQrCode"
ReferencedContainer = "container:MyQrCode.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5817663B2E54241300C1B687"
BuildableName = "MyQrCodeTests.xctest"
BlueprintName = "MyQrCodeTests"
ReferencedContainer = "container:MyQrCode.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "581766452E54241300C1B687"
BuildableName = "MyQrCodeUITests.xctest"
BlueprintName = "MyQrCodeUITests"
ReferencedContainer = "container:MyQrCode.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5817662E2E54241200C1B687"
BuildableName = "MyQrCode.app"
BlueprintName = "MyQrCode"
ReferencedContainer = "container:MyQrCode.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5817662E2E54241200C1B687"
BuildableName = "MyQrCode.app"
BlueprintName = "MyQrCode"
ReferencedContainer = "container:MyQrCode.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -10,5 +10,23 @@
<integer>0</integer> <integer>0</integer>
</dict> </dict>
</dict> </dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>5817662E2E54241200C1B687</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>5817663B2E54241300C1B687</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>581766452E54241300C1B687</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict> </dict>
</plist> </plist>

@ -13,7 +13,7 @@ enum Language: String, CaseIterable {
case .english: case .english:
return "English" return "English"
case .chinese: case .chinese:
return NSLocalizedString("chinese_language", comment: "Chinese language") return "chinese_language".localized
case .thai: case .thai:
return "ไทย" return "ไทย"
} }

@ -46,15 +46,15 @@ class BarcodeValidator {
formattedContent: formatEAN13(content), formattedContent: formatEAN13(content),
errorMessage: nil, errorMessage: nil,
expectedLength: 13, expectedLength: 13,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("ean_13_must_be_13_digits", comment: "EAN-13 must be 13 digits"), errorMessage: "ean_13_must_be_13_digits".localized,
expectedLength: 13, expectedLength: 13,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} }
} }
@ -71,15 +71,15 @@ class BarcodeValidator {
formattedContent: formatEAN8(content), formattedContent: formatEAN8(content),
errorMessage: nil, errorMessage: nil,
expectedLength: 8, expectedLength: 8,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("ean_8_must_be_8_digits", comment: "EAN-8 must be 8 digits"), errorMessage: "ean_8_must_be_8_digits".localized,
expectedLength: 8, expectedLength: 8,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} }
} }
@ -96,15 +96,15 @@ class BarcodeValidator {
formattedContent: formatUPCE(content), formattedContent: formatUPCE(content),
errorMessage: nil, errorMessage: nil,
expectedLength: 8, expectedLength: 8,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("upc_e_must_be_8_digits", comment: "UPC-E must be 8 digits"), errorMessage: "upc_e_must_be_8_digits".localized,
expectedLength: 8, expectedLength: 8,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} }
} }
@ -121,15 +121,15 @@ class BarcodeValidator {
formattedContent: formatCode39(content), formattedContent: formatCode39(content),
errorMessage: nil, errorMessage: nil,
expectedLength: nil, expectedLength: nil,
allowedCharacters: NSLocalizedString("code_39_characters", comment: "Code 39 allowed characters") allowedCharacters: "code_39_characters".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("code_39_only_contains", comment: "Code 39 only contains specific characters"), errorMessage: "code_39_only_contains".localized,
expectedLength: nil, expectedLength: nil,
allowedCharacters: NSLocalizedString("code_39_characters", comment: "Code 39 allowed characters") allowedCharacters: "code_39_characters".localized
) )
} }
} }
@ -148,15 +148,15 @@ class BarcodeValidator {
formattedContent: formatCode128(content), formattedContent: formatCode128(content),
errorMessage: nil, errorMessage: nil,
expectedLength: nil, expectedLength: nil,
allowedCharacters: NSLocalizedString("code_128_characters", comment: "Code 128 allowed characters") allowedCharacters: "code_128_characters".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("code_128_only_contains", comment: "Code 128 only contains ASCII characters"), errorMessage: "code_128_only_contains".localized,
expectedLength: nil, expectedLength: nil,
allowedCharacters: NSLocalizedString("code_128_characters", comment: "Code 128 allowed characters") allowedCharacters: "code_128_characters".localized
) )
} }
} }
@ -173,15 +173,15 @@ class BarcodeValidator {
formattedContent: formatITF14(content), formattedContent: formatITF14(content),
errorMessage: nil, errorMessage: nil,
expectedLength: 14, expectedLength: 14,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("itf_14_must_be_14_digits", comment: "ITF-14 must be 14 digits"), errorMessage: "itf_14_must_be_14_digits".localized,
expectedLength: 14, expectedLength: 14,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
) )
} }
} }
@ -198,15 +198,15 @@ class BarcodeValidator {
formattedContent: formatPDF417(content), formattedContent: formatPDF417(content),
errorMessage: nil, errorMessage: nil,
expectedLength: nil, expectedLength: nil,
allowedCharacters: NSLocalizedString("pdf417_characters", comment: "PDF417 allowed characters") allowedCharacters: "pdf417_characters".localized
) )
} else { } else {
return ValidationResult( return ValidationResult(
isValid: false, isValid: false,
formattedContent: content, formattedContent: content,
errorMessage: NSLocalizedString("pdf417_only_contains", comment: "PDF417 only contains ASCII characters"), errorMessage: "pdf417_only_contains".localized,
expectedLength: nil, expectedLength: nil,
allowedCharacters: NSLocalizedString("pdf417_characters", comment: "PDF417 allowed characters") allowedCharacters: "pdf417_characters".localized
) )
} }
} }

@ -100,9 +100,9 @@ public enum DataSource: String, CaseIterable {
var displayName: String { var displayName: String {
switch self { switch self {
case .scanned: case .scanned:
return NSLocalizedString("scanned", comment: "Scanned") return "scanned".localized
case .created: case .created:
return NSLocalizedString("manually_created", comment: "Manually created") return "manually_created".localized
} }
} }
@ -195,12 +195,12 @@ public struct QRCodeStyleData: Codable {
// //
public var styleDescription: String { public var styleDescription: String {
var description = String(format: NSLocalizedString("style_description_format", comment: "Style description format"), foregroundColor, backgroundColor, dotType, eyeType) var description = String(format: "style_description_format".localized, foregroundColor, backgroundColor, dotType, eyeType)
if let logo = logo { if let logo = logo {
description += String(format: NSLocalizedString("style_logo_format", comment: "Style logo format"), logo) description += String(format: "style_logo_format".localized, logo)
} }
if hasCustomLogo { if hasCustomLogo {
description += NSLocalizedString("custom_logo", comment: "Custom logo") description += "custom_logo".localized
} }
return description return description
} }

@ -220,7 +220,7 @@ class QRCodeParser {
// //
return ParsedQRData( return ParsedQRData(
type: .text, type: .text,
title: NSLocalizedString("text_information", comment: "Text information"), title: "text_information".localized,
subtitle: trimmedContent.count > 50 ? String(trimmedContent.prefix(50)) + "..." : trimmedContent, subtitle: trimmedContent.count > 50 ? String(trimmedContent.prefix(50)) + "..." : trimmedContent,
icon: "text.quote" icon: "text.quote"
) )
@ -245,8 +245,8 @@ class QRCodeParser {
} }
} }
let title = NSLocalizedString("wifi_network", comment: "Wi-Fi network") let title = "wifi_network".localized
let subtitle = String(format: NSLocalizedString("wifi_network_info", comment: "Wi-Fi network information"), ssid, encryption, password.isEmpty ? NSLocalizedString("not_set", comment: "Not set") : NSLocalizedString("password_set", comment: "Password set")) let subtitle = String(format: "wifi_network_info".localized, ssid, encryption, password.isEmpty ? "not_set".localized : "password_set".localized)
return ParsedQRData( return ParsedQRData(
type: .wifi, type: .wifi,
@ -262,7 +262,7 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .mail, type: .mail,
title: NSLocalizedString("email_address", comment: "Email address"), title: "email_address".localized,
subtitle: email, subtitle: email,
icon: "envelope" icon: "envelope"
) )
@ -274,7 +274,7 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .phone, type: .phone,
title: NSLocalizedString("phone_number", comment: "Phone number"), title: "phone_number".localized,
subtitle: phone, subtitle: phone,
icon: "phone" icon: "phone"
) )
@ -288,8 +288,8 @@ class QRCodeParser {
let phone = components.first ?? "" let phone = components.first ?? ""
let message = components.count > 1 ? components[1] : "" let message = components.count > 1 ? components[1] : ""
let title = NSLocalizedString("sms", comment: "SMS") let title = "sms".localized
let subtitle = String(format: NSLocalizedString("sms_number_content", comment: "SMS number and content"), phone, message) let subtitle = String(format: "sms_number_content".localized, phone, message)
return ParsedQRData( return ParsedQRData(
type: .sms, type: .sms,
@ -350,13 +350,13 @@ class QRCodeParser {
} }
var subtitle = "" var subtitle = ""
if !name.isEmpty { subtitle += String(format: NSLocalizedString("contact_name", comment: "Contact name"), name) + "\n" } if !name.isEmpty { subtitle += String(format: "contact_name".localized, name) + "\n" }
if !phone.isEmpty { subtitle += String(format: NSLocalizedString("contact_phone", comment: "Contact phone"), phone) + "\n" } if !phone.isEmpty { subtitle += String(format: "contact_phone".localized, phone) + "\n" }
if !email.isEmpty { subtitle += String(format: NSLocalizedString("contact_email", comment: "Contact email"), email) + "\n" } if !email.isEmpty { subtitle += String(format: "contact_email".localized, email) + "\n" }
if !company.isEmpty { subtitle += String(format: NSLocalizedString("contact_company", comment: "Contact company"), company) + "\n" } if !company.isEmpty { subtitle += String(format: "contact_company".localized, company) + "\n" }
if !title.isEmpty { subtitle += String(format: NSLocalizedString("contact_title", comment: "Contact title"), title) + "\n" } if !title.isEmpty { subtitle += String(format: "contact_title".localized, title) + "\n" }
if !address.isEmpty { subtitle += String(format: NSLocalizedString("contact_address", comment: "Contact address"), address) + "\n" } if !address.isEmpty { subtitle += String(format: "contact_address".localized, address) + "\n" }
if !website.isEmpty { subtitle += String(format: NSLocalizedString("contact_website", comment: "Contact website"), website) + "\n" } if !website.isEmpty { subtitle += String(format: "contact_website".localized, website) + "\n" }
// //
if subtitle.hasSuffix("\n") { if subtitle.hasSuffix("\n") {
@ -365,7 +365,7 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .vcard, type: .vcard,
title: NSLocalizedString("contact_information", comment: "Contact information"), title: "contact_information".localized,
subtitle: subtitle, subtitle: subtitle,
icon: "person.crop.rectangle" icon: "person.crop.rectangle"
) )
@ -418,7 +418,7 @@ class QRCodeParser {
let year = String(birthdayValue.prefix(4)) let year = String(birthdayValue.prefix(4))
let month = String(birthdayValue.dropFirst(4).prefix(2)) let month = String(birthdayValue.dropFirst(4).prefix(2))
let day = String(birthdayValue.dropFirst(6)) let day = String(birthdayValue.dropFirst(6))
birthday = String(format: NSLocalizedString("birthday_format", comment: "Birthday format"), year, month, day) birthday = String(format: "birthday_format".localized, year, month, day)
} else { } else {
birthday = birthdayValue birthday = birthdayValue
} }
@ -428,15 +428,15 @@ class QRCodeParser {
} }
var subtitle = "" var subtitle = ""
if !name.isEmpty { subtitle += String(format: NSLocalizedString("contact_name", comment: "Contact name"), name) + "\n" } if !name.isEmpty { subtitle += String(format: "contact_name".localized, name) + "\n" }
if !nickname.isEmpty { subtitle += String(format: NSLocalizedString("contact_nickname", comment: "Contact nickname"), nickname) + "\n" } if !nickname.isEmpty { subtitle += String(format: "contact_nickname".localized, nickname) + "\n" }
if !phone.isEmpty { subtitle += String(format: NSLocalizedString("contact_phone", comment: "Contact phone"), phone) + "\n" } if !phone.isEmpty { subtitle += String(format: "contact_phone".localized, phone) + "\n" }
if !email.isEmpty { subtitle += String(format: NSLocalizedString("contact_email", comment: "Contact email"), email) + "\n" } if !email.isEmpty { subtitle += String(format: "contact_email".localized, email) + "\n" }
if !company.isEmpty { subtitle += String(format: NSLocalizedString("contact_company", comment: "Contact company"), company) + "\n" } if !company.isEmpty { subtitle += String(format: "contact_company".localized, company) + "\n" }
if !address.isEmpty { subtitle += String(format: NSLocalizedString("contact_address", comment: "Contact address"), address) + "\n" } if !address.isEmpty { subtitle += String(format: "contact_address".localized, address) + "\n" }
if !website.isEmpty { subtitle += String(format: NSLocalizedString("contact_website", comment: "Contact website"), website) + "\n" } if !website.isEmpty { subtitle += String(format: "contact_website".localized, website) + "\n" }
if !birthday.isEmpty { subtitle += String(format: NSLocalizedString("contact_birthday", comment: "Contact birthday"), birthday) + "\n" } if !birthday.isEmpty { subtitle += String(format: "contact_birthday".localized, birthday) + "\n" }
if !note.isEmpty { subtitle += String(format: NSLocalizedString("contact_note", comment: "Contact note"), note) + "\n" } if !note.isEmpty { subtitle += String(format: "contact_note".localized, note) + "\n" }
// //
if subtitle.hasSuffix("\n") { if subtitle.hasSuffix("\n") {
@ -445,7 +445,7 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .mecard, type: .mecard,
title: NSLocalizedString("contact_information", comment: "Contact information"), title: "contact_information".localized,
subtitle: subtitle, subtitle: subtitle,
icon: "person.crop.rectangle" icon: "person.crop.rectangle"
) )
@ -478,13 +478,13 @@ class QRCodeParser {
let formattedStartTime = formatCalendarTime(startTime) let formattedStartTime = formatCalendarTime(startTime)
let formattedEndTime = formatCalendarTime(endTime) let formattedEndTime = formatCalendarTime(endTime)
let title = NSLocalizedString("calendar_event", comment: "Calendar event") let title = "calendar_event".localized
var subtitle = String(format: NSLocalizedString("calendar_event_info", comment: "Calendar event information"), summary, formattedStartTime, formattedEndTime) var subtitle = String(format: "calendar_event_info".localized, summary, formattedStartTime, formattedEndTime)
if !location.isEmpty { if !location.isEmpty {
subtitle += String(format: NSLocalizedString("calendar_event_location", comment: "Calendar event location"), location) subtitle += String(format: "calendar_event_location".localized, location)
} }
if !description.isEmpty { if !description.isEmpty {
subtitle += String(format: NSLocalizedString("calendar_event_description", comment: "Calendar event description"), description) subtitle += String(format: "calendar_event_description".localized, description)
} }
return ParsedQRData( return ParsedQRData(
@ -518,8 +518,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .instagram, type: .instagram,
title: NSLocalizedString("instagram", comment: "Instagram"), title: "instagram".localized,
subtitle: String(format: NSLocalizedString("instagram_username", comment: "Instagram username"), username), subtitle: String(format: "instagram_username".localized, username),
icon: "camera" icon: "camera"
) )
} }
@ -530,8 +530,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .facebook, type: .facebook,
title: NSLocalizedString("facebook", comment: "Facebook"), title: "facebook".localized,
subtitle: String(format: NSLocalizedString("facebook_profile_id", comment: "Facebook profile ID"), profileId), subtitle: String(format: "facebook_profile_id".localized, profileId),
icon: "person.2" icon: "person.2"
) )
} }
@ -542,8 +542,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .spotify, type: .spotify,
title: NSLocalizedString("spotify", comment: "Spotify"), title: "spotify".localized,
subtitle: String(format: NSLocalizedString("spotify_search_query", comment: "Spotify search query"), searchQuery), subtitle: String(format: "spotify_search_query".localized, searchQuery),
icon: "music.note" icon: "music.note"
) )
} }
@ -560,8 +560,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .twitter, type: .twitter,
title: NSLocalizedString("x", comment: "X"), title: "x".localized,
subtitle: String(format: NSLocalizedString("twitter_username", comment: "Twitter username"), username), subtitle: String(format: "twitter_username".localized, username),
icon: "bird" icon: "bird"
) )
} }
@ -572,8 +572,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .whatsapp, type: .whatsapp,
title: NSLocalizedString("whatsapp", comment: "WhatsApp"), title: "whatsapp".localized,
subtitle: String(format: NSLocalizedString("whatsapp_phone_number", comment: "WhatsApp phone number"), phone), subtitle: String(format: "whatsapp_phone_number".localized, phone),
icon: "message.circle" icon: "message.circle"
) )
} }
@ -584,8 +584,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .viber, type: .viber,
title: NSLocalizedString("viber", comment: "Viber"), title: "viber".localized,
subtitle: String(format: NSLocalizedString("viber_phone_number", comment: "Viber phone number"), phone), subtitle: String(format: "viber_phone_number".localized, phone),
icon: "bubble.left.and.bubble.right" icon: "bubble.left.and.bubble.right"
) )
} }
@ -596,8 +596,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .snapchat, type: .snapchat,
title: NSLocalizedString("snapchat", comment: "Snapchat"), title: "snapchat".localized,
subtitle: String(format: NSLocalizedString("snapchat_username", comment: "Snapchat username"), username), subtitle: String(format: "snapchat_username".localized, username),
icon: "camera.viewfinder" icon: "camera.viewfinder"
) )
} }
@ -620,8 +620,8 @@ class QRCodeParser {
return ParsedQRData( return ParsedQRData(
type: .tiktok, type: .tiktok,
title: NSLocalizedString("tiktok", comment: "TikTok"), title: "tiktok".localized,
subtitle: String(format: NSLocalizedString("tiktok_username", comment: "TikTok username"), username), subtitle: String(format: "tiktok_username".localized, username),
icon: "music.mic" icon: "music.mic"
) )
} }
@ -630,7 +630,7 @@ class QRCodeParser {
private static func parseURL(_ content: String) -> ParsedQRData { private static func parseURL(_ content: String) -> ParsedQRData {
return ParsedQRData( return ParsedQRData(
type: .url, type: .url,
title: NSLocalizedString("url_link", comment: "URL link"), title: "url_link".localized,
subtitle: content, subtitle: content,
icon: "link" icon: "link"
) )
@ -644,8 +644,8 @@ class QRCodeParser {
let latitude = coords.first ?? "" let latitude = coords.first ?? ""
let longitude = coords.count > 1 ? coords[1] : "" let longitude = coords.count > 1 ? coords[1] : ""
let title = NSLocalizedString("geolocation", comment: "Geolocation") let title = "geolocation".localized
let subtitle = String(format: NSLocalizedString("geolocation_coordinates", comment: "Geolocation coordinates"), latitude, longitude) let subtitle = String(format: "geolocation_coordinates".localized, latitude, longitude)
return ParsedQRData( return ParsedQRData(
type: .location, type: .location,

@ -363,7 +363,7 @@ struct ScannerView: View {
let qrResults = detectedQR.enumerated().map { index, qrCode in let qrResults = detectedQR.enumerated().map { index, qrCode in
DetectedCode( DetectedCode(
type: "QR Code", type: "QR Code",
content: qrCode.messageString ?? NSLocalizedString("unknown_content", comment: "Unknown content"), content: qrCode.messageString ?? "unknown_content".localized,
bounds: qrCode.bounds, bounds: qrCode.bounds,
source: .image source: .image
) )
@ -393,7 +393,7 @@ struct ScannerView: View {
} }
} else { } else {
self.isDecodingImage = false self.isDecodingImage = false
self.decodeFailureMessage = NSLocalizedString("no_codes_detected_in_image", comment: "No codes detected in image") self.decodeFailureMessage = "no_codes_detected_in_image".localized
self.showDecodeFailure = true self.showDecodeFailure = true
logWarning("❌ 图片中未检测到二维码或条形码", className: "ScannerView") logWarning("❌ 图片中未检测到二维码或条形码", className: "ScannerView")
} }
@ -448,7 +448,7 @@ struct ScannerView: View {
return results.enumerated().map { index, observation in return results.enumerated().map { index, observation in
let barcodeType = getBarcodeTypeString(from: observation.symbology) let barcodeType = getBarcodeTypeString(from: observation.symbology)
let content = observation.payloadStringValue ?? NSLocalizedString("unknown_content", comment: "Unknown content") let content = observation.payloadStringValue ?? "unknown_content".localized
logInfo("检测到条形码 #\(index + 1): 类型=\(barcodeType), 内容=\(content)", className: "ScannerView") logInfo("检测到条形码 #\(index + 1): 类型=\(barcodeType), 内容=\(content)", className: "ScannerView")

@ -85,7 +85,7 @@ struct ScanningBottomButtonsView: View {
Image(systemName: "photo.on.rectangle.angled") Image(systemName: "photo.on.rectangle.angled")
.font(.system(size: 16, weight: .semibold)) .font(.system(size: 16, weight: .semibold))
Text(NSLocalizedString("image_decode", comment: "Image decode")) Text("image_decode".localized)
.font(.subheadline) .font(.subheadline)
.fontWeight(.medium) .fontWeight(.medium)
} }
@ -118,7 +118,7 @@ struct ScanningStyleSelectorView: View {
var body: some View { var body: some View {
VStack(spacing: 12) { VStack(spacing: 12) {
// //
Text(NSLocalizedString("scanning_line_style", comment: "Scanning line style")) Text("scanning_line_style".localized)
.font(.caption) .font(.caption)
.foregroundColor(.white.opacity(0.8)) .foregroundColor(.white.opacity(0.8))
.padding(.bottom, 4) .padding(.bottom, 4)

@ -29,7 +29,7 @@ struct BarcodeDetailView: View {
} }
.padding() .padding()
} }
.navigationTitle(NSLocalizedString("barcode_detail", comment: "Barcode detail")) .navigationTitle("barcode_detail".localized)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
@ -51,8 +51,8 @@ struct BarcodeDetailView: View {
ShareSheet(activityItems: [historyItem.content ?? ""]) ShareSheet(activityItems: [historyItem.content ?? ""])
} }
} }
.alert(NSLocalizedString("tip", comment: "Tip"), isPresented: $showingAlert) { .alert("tip".localized, isPresented: $showingAlert) {
Button(NSLocalizedString("confirm", comment: "Confirm")) { } Button("confirm".localized) { }
} message: { } message: {
Text(alertMessage) Text(alertMessage)
} }
@ -78,7 +78,7 @@ struct BarcodeDetailView: View {
) )
} }
Text(NSLocalizedString("scan_this_barcode", comment: "Scan this barcode")) Text("scan_this_barcode".localized)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
@ -92,7 +92,7 @@ struct BarcodeDetailView: View {
.font(.title2) .font(.title2)
.foregroundColor(.green) .foregroundColor(.green)
Text(NSLocalizedString("barcode_type", comment: "Barcode type")) Text("barcode_type".localized)
.font(.headline) .font(.headline)
Spacer() Spacer()
@ -129,7 +129,7 @@ struct BarcodeDetailView: View {
.font(.title2) .font(.title2)
.foregroundColor(.blue) .foregroundColor(.blue)
Text(NSLocalizedString("barcode_content", comment: "Barcode content")) Text("barcode_content".localized)
.font(.headline) .font(.headline)
Spacer() Spacer()
@ -142,14 +142,14 @@ struct BarcodeDetailView: View {
.font(.title3) .font(.title3)
.foregroundColor(.blue) .foregroundColor(.blue)
Text(String(format: NSLocalizedString("content_length", comment: "Content length"), content.count)) Text(String(format: "content_length".localized, content.count))
.font(.title3) .font(.title3)
.fontWeight(.medium) .fontWeight(.medium)
Spacer() Spacer()
} }
Text(NSLocalizedString("data_content", comment: "Data content")) Text("data_content".localized)
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(.secondary)
.padding(.top, 4) .padding(.top, 4)
@ -173,7 +173,7 @@ struct BarcodeDetailView: View {
.font(.title2) .font(.title2)
.foregroundColor(.purple) .foregroundColor(.purple)
Text(NSLocalizedString("original_content", comment: "Original content")) Text("original_content".localized)
.font(.headline) .font(.headline)
Spacer() Spacer()
@ -208,7 +208,7 @@ struct BarcodeDetailView: View {
Image(systemName: historyItem.isFavorite ? "heart.fill" : "heart") Image(systemName: historyItem.isFavorite ? "heart.fill" : "heart")
.foregroundColor(historyItem.isFavorite ? .red : .gray) .foregroundColor(historyItem.isFavorite ? .red : .gray)
Text(historyItem.isFavorite ? NSLocalizedString("unfavorite", comment: "Unfavorite") : NSLocalizedString("favorite", comment: "Favorite")) Text(historyItem.isFavorite ? "unfavorite".localized : "favorite".localized)
.fontWeight(.medium) .fontWeight(.medium)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -224,7 +224,7 @@ struct BarcodeDetailView: View {
Image(systemName: "doc.on.doc") Image(systemName: "doc.on.doc")
.foregroundColor(.blue) .foregroundColor(.blue)
Text(NSLocalizedString("copy_content", comment: "Copy content")) Text("copy_content".localized)
.fontWeight(.medium) .fontWeight(.medium)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -243,7 +243,7 @@ struct BarcodeDetailView: View {
Image(systemName: "photo") Image(systemName: "photo")
.foregroundColor(.green) .foregroundColor(.green)
Text(NSLocalizedString("share_barcode_image", comment: "Share barcode image")) Text("share_barcode_image".localized)
.fontWeight(.medium) .fontWeight(.medium)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -283,7 +283,7 @@ struct BarcodeDetailView: View {
historyItem.isFavorite.toggle() historyItem.isFavorite.toggle()
coreDataManager.save() coreDataManager.save()
let message = historyItem.isFavorite ? NSLocalizedString("added_to_favorites", comment: "Added to favorites") : NSLocalizedString("removed_from_favorites", comment: "Removed from favorites") let message = historyItem.isFavorite ? "added_to_favorites".localized : "removed_from_favorites".localized
alertMessage = message alertMessage = message
showingAlert = true showingAlert = true
} }
@ -292,7 +292,7 @@ struct BarcodeDetailView: View {
private func copyContent() { private func copyContent() {
if let content = historyItem.content { if let content = historyItem.content {
UIPasteboard.general.string = content UIPasteboard.general.string = content
alertMessage = NSLocalizedString("content_copied_to_clipboard", comment: "Content copied to clipboard") alertMessage = "content_copied_to_clipboard".localized
showingAlert = true showingAlert = true
} }
} }

@ -24,11 +24,11 @@ struct BarcodePreviewView: View {
.font(.system(size: 32)) .font(.system(size: 32))
.foregroundColor(.gray) .foregroundColor(.gray)
Text(NSLocalizedString("cannot_generate_barcode", comment: "Cannot generate barcode")) Text("cannot_generate_barcode".localized)
.font(.caption) .font(.caption)
.foregroundColor(.gray) .foregroundColor(.gray)
Text(NSLocalizedString("check_input_format", comment: "Please check input content format")) Text("check_input_format".localized)
.font(.caption2) .font(.caption2)
.foregroundColor(.gray) .foregroundColor(.gray)
} }

@ -13,7 +13,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: result.isValid ? "checkmark.circle.fill" : "xmark.circle.fill") Image(systemName: result.isValid ? "checkmark.circle.fill" : "xmark.circle.fill")
.foregroundColor(result.isValid ? .green : .red) .foregroundColor(result.isValid ? .green : .red)
Text(result.isValid ? NSLocalizedString("format_correct", comment: "Format correct") : NSLocalizedString("format_error", comment: "Format error")) Text(result.isValid ? "format_correct".localized : "format_error".localized)
.font(.caption) .font(.caption)
.foregroundColor(result.isValid ? .green : .red) .foregroundColor(result.isValid ? .green : .red)
.fontWeight(.medium) .fontWeight(.medium)
@ -36,7 +36,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "number") Image(systemName: "number")
.foregroundColor(.blue) .foregroundColor(.blue)
.font(.caption) .font(.caption)
Text(String(format: NSLocalizedString("length_requirement", comment: "Length requirement"), expectedLength)) Text(String(format: "length_requirement".localized, expectedLength))
.font(.caption) .font(.caption)
.foregroundColor(.blue) .foregroundColor(.blue)
} }
@ -47,7 +47,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "character") Image(systemName: "character")
.foregroundColor(.blue) .foregroundColor(.blue)
.font(.caption) .font(.caption)
Text(String(format: NSLocalizedString("allowed_characters", comment: "Allowed characters"), allowedCharacters)) Text(String(format: "allowed_characters".localized, allowedCharacters))
.font(.caption) .font(.caption)
.foregroundColor(.blue) .foregroundColor(.blue)
} }
@ -61,7 +61,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "textformat") Image(systemName: "textformat")
.foregroundColor(.green) .foregroundColor(.green)
.font(.caption) .font(.caption)
Text(String(format: NSLocalizedString("formatted_content", comment: "Formatted content"), result.formattedContent)) Text(String(format: "formatted_content".localized, result.formattedContent))
.font(.caption) .font(.caption)
.foregroundColor(.green) .foregroundColor(.green)
.fontWeight(.medium) .fontWeight(.medium)
@ -74,7 +74,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "info.circle") Image(systemName: "info.circle")
.foregroundColor(.blue) .foregroundColor(.blue)
.font(.caption) .font(.caption)
Text(String(format: NSLocalizedString("please_enter_valid_format", comment: "Please enter valid format"), barcodeType.displayName)) Text(String(format: "please_enter_valid_format".localized, barcodeType.displayName))
.font(.caption) .font(.caption)
.foregroundColor(.blue) .foregroundColor(.blue)
} }
@ -97,7 +97,7 @@ struct BarcodeValidationInfoView: View {
formattedContent: "123 4567 8901 2", formattedContent: "123 4567 8901 2",
errorMessage: nil, errorMessage: nil,
expectedLength: 13, expectedLength: 13,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
), ),
barcodeType: .ean13 barcodeType: .ean13
) )
@ -107,9 +107,9 @@ struct BarcodeValidationInfoView: View {
validationResult: BarcodeValidator.ValidationResult( validationResult: BarcodeValidator.ValidationResult(
isValid: false, isValid: false,
formattedContent: "12345", formattedContent: "12345",
errorMessage: NSLocalizedString("ean_13_must_be_13_digits", comment: "EAN-13 must be 13 digits"), errorMessage: "ean_13_must_be_13_digits".localized,
expectedLength: 13, expectedLength: 13,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9") allowedCharacters: "numbers_0_9".localized
), ),
barcodeType: .ean13 barcodeType: .ean13
) )

@ -83,11 +83,11 @@ struct CodeContentInputView: View {
// //
HStack { HStack {
if let result = validationResult, result.isValid { if let result = validationResult, result.isValid {
Text(NSLocalizedString("format_correct", comment: "Format correct")) Text("format_correct".localized)
.font(.caption2) .font(.caption2)
.foregroundColor(.green) .foregroundColor(.green)
} else if !content.isEmpty { } else if !content.isEmpty {
Text(NSLocalizedString("format_checking", comment: "Format checking")) Text("format_checking".localized)
.font(.caption2) .font(.caption2)
.foregroundColor(.orange) .foregroundColor(.orange)
} }
@ -229,19 +229,19 @@ struct CodeContentInputView: View {
private func getBarcodeFormatHint() -> String { private func getBarcodeFormatHint() -> String {
switch selectedBarcodeType { switch selectedBarcodeType {
case .ean13: case .ean13:
return NSLocalizedString("ean_13_format_hint", comment: "EAN-13 format hint") return "ean_13_format_hint".localized
case .ean8: case .ean8:
return NSLocalizedString("ean_8_format_hint", comment: "EAN-8 format hint") return "ean_8_format_hint".localized
case .upce: case .upce:
return NSLocalizedString("upc_e_format_hint", comment: "UPC-E format hint") return "upc_e_format_hint".localized
case .code39: case .code39:
return NSLocalizedString("code_39_format_hint", comment: "Code 39 format hint") return "code_39_format_hint".localized
case .code128: case .code128:
return NSLocalizedString("code_128_format_hint", comment: "Code 128 format hint") return "code_128_format_hint".localized
case .itf14: case .itf14:
return NSLocalizedString("itf_14_format_hint", comment: "ITF-14 format hint") return "itf_14_format_hint".localized
case .pdf417: case .pdf417:
return NSLocalizedString("pdf417_format_hint", comment: "PDF417 format hint") return "pdf417_format_hint".localized
} }
} }
@ -249,22 +249,22 @@ struct CodeContentInputView: View {
if selectedDataType == .barcode { if selectedDataType == .barcode {
switch selectedBarcodeType { switch selectedBarcodeType {
case .ean13: case .ean13:
return NSLocalizedString("input_13_digits", comment: "Input 13 digits") return "input_13_digits".localized
case .ean8: case .ean8:
return NSLocalizedString("input_8_digits", comment: "Input 8 digits") return "input_8_digits".localized
case .upce: case .upce:
return NSLocalizedString("input_8_digits", comment: "Input 8 digits") return "input_8_digits".localized
case .code39: case .code39:
return NSLocalizedString("input_letters_numbers", comment: "Input letters and numbers") return "input_letters_numbers".localized
case .code128: case .code128:
return NSLocalizedString("input_any_characters", comment: "Input any characters") return "input_any_characters".localized
case .itf14: case .itf14:
return NSLocalizedString("input_14_digits", comment: "Input 14 digits") return "input_14_digits".localized
case .pdf417: case .pdf417:
return NSLocalizedString("input_any_characters", comment: "Input any characters") return "input_any_characters".localized
} }
} else { } else {
return NSLocalizedString("please_enter_content", comment: "Please enter content") return "please_enter_content".localized
} }
} }

@ -95,7 +95,7 @@ struct CodeTypeSelectionView: View {
)) ))
) { ) {
HStack(spacing: 8) { HStack(spacing: 8) {
Text(NSLocalizedString("next", comment: "Next")) Text("next".localized)
.font(.system(size: 18, weight: .semibold)) .font(.system(size: 18, weight: .semibold))
.foregroundColor(.white) .foregroundColor(.white)
@ -113,7 +113,7 @@ struct CodeTypeSelectionView: View {
.padding(.horizontal, 20) .padding(.horizontal, 20)
.padding(.bottom, 30) .padding(.bottom, 30)
} }
.navigationTitle(NSLocalizedString("select_type", comment: "Select type")) .navigationTitle("select_type".localized)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
} }
} }

@ -262,41 +262,41 @@ struct InputComponentFactory {
static func getPlaceholderText(for qrCodeType: QRCodeType) -> String { static func getPlaceholderText(for qrCodeType: QRCodeType) -> String {
switch qrCodeType { switch qrCodeType {
case .text: case .text:
return NSLocalizedString("input_any_text_content", comment: "Input any text content") return "input_any_text_content".localized
case .phone: case .phone:
return NSLocalizedString("input_phone_number", comment: "Input phone number") return "input_phone_number".localized
case .sms: case .sms:
return NSLocalizedString("input_sms_content", comment: "Input SMS content") return "input_sms_content".localized
case .wifi: case .wifi:
return NSLocalizedString("input_wifi_info", comment: "Input WiFi information") return "input_wifi_info".localized
case .vcard: case .vcard:
return NSLocalizedString("input_contact_info", comment: "Input contact information") return "input_contact_info".localized
case .mecard: case .mecard:
return NSLocalizedString("input_contact_info", comment: "Input contact information") return "input_contact_info".localized
case .location: case .location:
return NSLocalizedString("input_location_info", comment: "Input location information") return "input_location_info".localized
case .calendar: case .calendar:
return NSLocalizedString("input_calendar_event_info", comment: "Input calendar event information") return "input_calendar_event_info".localized
case .instagram: case .instagram:
return NSLocalizedString("input_instagram_username", comment: "Input Instagram username") return "input_instagram_username".localized
case .facebook: case .facebook:
return NSLocalizedString("input_facebook_user_id_or_link", comment: "Input Facebook user ID or link") return "input_facebook_user_id_or_link".localized
case .spotify: case .spotify:
return NSLocalizedString("input_artist_and_song_info", comment: "Input artist and song information") return "input_artist_and_song_info".localized
case .twitter: case .twitter:
return NSLocalizedString("input_x_info", comment: "Input X information") return "input_x_info".localized
case .whatsapp: case .whatsapp:
return NSLocalizedString("input_whatsapp_phone_number", comment: "Input WhatsApp phone number") return "input_whatsapp_phone_number".localized
case .viber: case .viber:
return NSLocalizedString("input_viber_phone_number", comment: "Input Viber phone number") return "input_viber_phone_number".localized
case .snapchat: case .snapchat:
return NSLocalizedString("input_snapchat_info", comment: "Input Snapchat information") return "input_snapchat_info".localized
case .tiktok: case .tiktok:
return NSLocalizedString("input_tiktok_info", comment: "Input TikTok information") return "input_tiktok_info".localized
case .mail: case .mail:
return NSLocalizedString("input_email_content", comment: "Input email content") return "input_email_content".localized
case .url: case .url:
return NSLocalizedString("input_website_url", comment: "Input website URL") return "input_website_url".localized
} }
} }

@ -173,15 +173,15 @@ extension InputFieldView {
#Preview { #Preview {
VStack(spacing: 16) { VStack(spacing: 16) {
InputFieldView.text( InputFieldView.text(
title: NSLocalizedString("username", comment: "Username"), title: "username".localized,
isRequired: true, isRequired: true,
placeholder: NSLocalizedString("enter_username", comment: "Please enter username"), placeholder: "enter_username".localized,
text: .constant(""), text: .constant(""),
icon: "person" icon: "person"
) )
InputFieldView.email( InputFieldView.email(
title: NSLocalizedString("email_address", comment: "Email address"), title: "email_address".localized,
isRequired: true, isRequired: true,
placeholder: "user@example.com", placeholder: "user@example.com",
text: .constant(""), text: .constant(""),
@ -189,7 +189,7 @@ extension InputFieldView {
) )
InputFieldView.phone( InputFieldView.phone(
title: NSLocalizedString("phone_number", comment: "Phone number"), title: "phone_number".localized,
isRequired: true, isRequired: true,
placeholder: "+1 (555) 123-4567", placeholder: "+1 (555) 123-4567",
text: .constant(""), text: .constant(""),
@ -197,9 +197,9 @@ extension InputFieldView {
) )
InputFieldView.password( InputFieldView.password(
title: NSLocalizedString("password", comment: "Password"), title: "password".localized,
isRequired: true, isRequired: true,
placeholder: NSLocalizedString("enter_password", comment: "Please enter password"), placeholder: "enter_password".localized,
text: .constant(""), text: .constant(""),
icon: "lock" icon: "lock"
) )

@ -54,7 +54,7 @@ struct KeyboardToolbarView: View {
} }
if showDoneButton { if showDoneButton {
Button(NSLocalizedString("done", comment: "Done"), action: onDone) Button("done".localized, action: onDone)
.foregroundColor(.blue) .foregroundColor(.blue)
.font(.system(size: 16, weight: .medium)) .font(.system(size: 16, weight: .medium))
} }
@ -98,7 +98,7 @@ struct KeyboardToolbarView: View {
} }
if showDoneButton { if showDoneButton {
Button(NSLocalizedString("done", comment: "Done"), action: onDone) Button("done".localized, action: onDone)
.foregroundColor(.blue) .foregroundColor(.blue)
.font(.system(size: 16, weight: .medium)) .font(.system(size: 16, weight: .medium))
} }
@ -143,7 +143,7 @@ extension KeyboardToolbarButton {
position: ButtonPosition = .left position: ButtonPosition = .left
) -> KeyboardToolbarButton { ) -> KeyboardToolbarButton {
KeyboardToolbarButton( KeyboardToolbarButton(
title: NSLocalizedString("clear", comment: "Clear"), title: "clear".localized,
icon: "trash", icon: "trash",
color: .red, color: .red,
position: position position: position
@ -157,7 +157,7 @@ extension KeyboardToolbarButton {
position: ButtonPosition = .left position: ButtonPosition = .left
) -> KeyboardToolbarButton { ) -> KeyboardToolbarButton {
KeyboardToolbarButton( KeyboardToolbarButton(
title: NSLocalizedString("copy", comment: "Copy"), title: "copy".localized,
icon: "doc.on.doc", icon: "doc.on.doc",
color: .blue, color: .blue,
position: position position: position
@ -171,7 +171,7 @@ extension KeyboardToolbarButton {
position: ButtonPosition = .left position: ButtonPosition = .left
) -> KeyboardToolbarButton { ) -> KeyboardToolbarButton {
KeyboardToolbarButton( KeyboardToolbarButton(
title: NSLocalizedString("paste", comment: "Paste"), title: "paste".localized,
icon: "doc.on.clipboard", icon: "doc.on.clipboard",
color: .green, color: .green,
position: position position: position
@ -187,7 +187,7 @@ extension KeyboardToolbarButton {
position: ButtonPosition = .right position: ButtonPosition = .right
) -> KeyboardToolbarButton { ) -> KeyboardToolbarButton {
KeyboardToolbarButton( KeyboardToolbarButton(
title: NSLocalizedString("next", comment: "Next"), title: "next".localized,
icon: "arrow.right", icon: "arrow.right",
color: .blue, color: .blue,
position: position, position: position,
@ -200,7 +200,7 @@ extension KeyboardToolbarButton {
position: ButtonPosition = .left position: ButtonPosition = .left
) -> KeyboardToolbarButton { ) -> KeyboardToolbarButton {
KeyboardToolbarButton( KeyboardToolbarButton(
title: NSLocalizedString("previous", comment: "Previous"), title: "previous".localized,
icon: "arrow.left", icon: "arrow.left",
color: .blue, color: .blue,
position: position, position: position,
@ -257,16 +257,16 @@ extension KeyboardToolbarView {
#Preview { #Preview {
VStack(spacing: 16) { VStack(spacing: 16) {
Text(NSLocalizedString("simple_toolbar", comment: "Simple toolbar")) Text("simple_toolbar".localized)
.font(.headline) .font(.headline)
Text(NSLocalizedString("toolbar_with_clear", comment: "Toolbar with clear button")) Text("toolbar_with_clear".localized)
.font(.headline) .font(.headline)
Text(NSLocalizedString("toolbar_with_copy_paste", comment: "Toolbar with copy/paste")) Text("toolbar_with_copy_paste".localized)
.font(.headline) .font(.headline)
Text(NSLocalizedString("toolbar_with_navigation", comment: "Toolbar with navigation")) Text("toolbar_with_navigation".localized)
.font(.headline) .font(.headline)
} }
.padding() .padding()

@ -199,7 +199,7 @@ struct EmptyStateView: View {
struct LoadingStateView: View { struct LoadingStateView: View {
let message: String let message: String
init(message: String = NSLocalizedString("loading", comment: "Loading")) { init(message: String = "loading".localized) {
self.message = message self.message = message
} }
@ -224,8 +224,8 @@ struct ErrorStateView: View {
let retryAction: (() -> Void)? let retryAction: (() -> Void)?
init( init(
title: String = NSLocalizedString("error_occurred", comment: "Error occurred"), title: String = "error_occurred".localized,
message: String = NSLocalizedString("load_failed_retry", comment: "Load failed, please retry"), message: String = "load_failed_retry".localized,
retryAction: (() -> Void)? = nil retryAction: (() -> Void)? = nil
) { ) {
self.title = title self.title = title
@ -253,7 +253,7 @@ struct ErrorStateView: View {
if let retryAction = retryAction { if let retryAction = retryAction {
Button(action: retryAction) { Button(action: retryAction) {
Text(NSLocalizedString("retry", comment: "Retry")) Text("retry".localized)
.font(.subheadline) .font(.subheadline)
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(.blue) .foregroundColor(.blue)
@ -274,7 +274,7 @@ struct ErrorStateView: View {
#Preview { #Preview {
VStack(spacing: 20) { VStack(spacing: 20) {
// //
ListView(data: Array(1...5).map { ListItemData(id: $0, title: String(format: NSLocalizedString("item_format", comment: "Item format"), $0)) }) { item in ListView(data: Array(1...5).map { ListItemData(id: $0, title: String(format: "item_format".localized, $0)) }) { item in
ListItem<AnyView>.standard { ListItem<AnyView>.standard {
AnyView( AnyView(
HStack { HStack {
@ -293,19 +293,19 @@ struct ErrorStateView: View {
// //
EmptyStateView( EmptyStateView(
icon: "tray", icon: "tray",
title: NSLocalizedString("no_data", comment: "No data"), title: "no_data".localized,
subtitle: NSLocalizedString("no_content_yet", comment: "No content yet"), subtitle: "no_content_yet".localized,
actionTitle: NSLocalizedString("add_content", comment: "Add content"), actionTitle: "add_content".localized,
action: {} action: {}
) )
// //
LoadingStateView(message: NSLocalizedString("loading_data", comment: "Loading data")) LoadingStateView(message: "loading_data".localized)
// //
ErrorStateView( ErrorStateView(
title: NSLocalizedString("network_error", comment: "Network error"), title: "network_error".localized,
message: NSLocalizedString("connection_failed_check_network", comment: "Cannot connect to server, please check network connection"), message: "connection_failed_check_network".localized,
retryAction: {} retryAction: {}
) )
} }

@ -52,7 +52,7 @@ extension SimplePickerView {
icon: String? = "lock" icon: String? = "lock"
) -> SimplePickerView<WiFiInputView.WiFiEncryptionType> { ) -> SimplePickerView<WiFiInputView.WiFiEncryptionType> {
SimplePickerView<WiFiInputView.WiFiEncryptionType>( SimplePickerView<WiFiInputView.WiFiEncryptionType>(
title: NSLocalizedString("encryption_type", comment: "Encryption type"), title: "encryption_type".localized,
selection: selection, selection: selection,
options: WiFiInputView.WiFiEncryptionType.allCases, options: WiFiInputView.WiFiEncryptionType.allCases,
optionTitle: { $0.displayName }, optionTitle: { $0.displayName },
@ -65,7 +65,7 @@ extension SimplePickerView {
icon: String? = "globe" icon: String? = "globe"
) -> SimplePickerView<SocialInputView.SocialPlatform> { ) -> SimplePickerView<SocialInputView.SocialPlatform> {
SimplePickerView<SocialInputView.SocialPlatform>( SimplePickerView<SocialInputView.SocialPlatform>(
title: NSLocalizedString("social_platform", comment: "Social platform"), title: "social_platform".localized,
selection: selection, selection: selection,
options: SocialInputView.SocialPlatform.allCases, options: SocialInputView.SocialPlatform.allCases,
optionTitle: { $0.displayName }, optionTitle: { $0.displayName },
@ -78,7 +78,7 @@ extension SimplePickerView {
icon: String? = "phone" icon: String? = "phone"
) -> SimplePickerView<PhoneInputView.PhoneInputType> { ) -> SimplePickerView<PhoneInputView.PhoneInputType> {
SimplePickerView<PhoneInputView.PhoneInputType>( SimplePickerView<PhoneInputView.PhoneInputType>(
title: NSLocalizedString("phone_type", comment: "Phone type"), title: "phone_type".localized,
selection: selection, selection: selection,
options: PhoneInputView.PhoneInputType.allCases, options: PhoneInputView.PhoneInputType.allCases,
optionTitle: { $0.displayName }, optionTitle: { $0.displayName },

@ -9,7 +9,7 @@ struct QRCodePreviewView: View {
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
HStack { HStack {
InputTitleView.required(NSLocalizedString("preview", comment: "Preview"), icon: "eye") InputTitleView.required("preview".localized, icon: "eye")
.padding(.horizontal, 20) .padding(.horizontal, 20)
Spacer() Spacer()
@ -37,7 +37,7 @@ struct QRCodePreviewView: View {
Image(systemName: "qrcode") Image(systemName: "qrcode")
.font(.system(size: 40)) .font(.system(size: 40))
.foregroundColor(.secondary) .foregroundColor(.secondary)
Text(NSLocalizedString("cannot_generate_qrcode", comment: "Cannot generate QR code")) Text("cannot_generate_qrcode".localized)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
@ -47,7 +47,7 @@ struct QRCodePreviewView: View {
// //
VStack(alignment: .leading, spacing: 8) { VStack(alignment: .leading, spacing: 8) {
HStack { HStack {
Text(NSLocalizedString("content", comment: "Content")) Text("content".localized)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)
@ -83,7 +83,7 @@ struct QRCodePreviewView: View {
#Preview { #Preview {
QRCodePreviewView( QRCodePreviewView(
qrCodeImage: nil, qrCodeImage: nil,
formattedContent: NSLocalizedString("sample_content", comment: "Sample content"), formattedContent: "sample_content".localized,
qrCodeType: .text qrCodeType: .text
) )
} }

@ -205,19 +205,19 @@ struct SocialInputView: View {
private func getInputLabel() -> String { private func getInputLabel() -> String {
switch platform { switch platform {
case .instagram: case .instagram:
return "instagram_username".localized return String(format:"instagram_username".localized, "")
case .facebook: case .facebook:
return "user_id_or_link".localized return "user_id_or_link".localized
case .twitter: case .twitter:
return "x_username".localized return "x_username".localized
case .tiktok: case .tiktok:
return "tiktok_username".localized return String(format:"tiktok_username".localized, "")
case .snapchat: case .snapchat:
return "snapchat_username".localized return String(format: "snapchat_username".localized, "")
case .whatsapp: case .whatsapp:
return "whatsapp_phone_number".localized return String(format: "whatsapp_phone_number".localized, "")
case .viber: case .viber:
return "viber_phone_number".localized return String(format: "viber_phone_number".localized, "")
case .spotify: case .spotify:
return "song_link_or_id".localized return "song_link_or_id".localized
} }

@ -173,25 +173,25 @@ extension TextEditorView {
#Preview { #Preview {
VStack(spacing: 16) { VStack(spacing: 16) {
TextEditorView.description( TextEditorView.description(
title: NSLocalizedString("description", comment: "Description"), title: "description".localized,
isRequired: true, isRequired: true,
placeholder: NSLocalizedString("enter_description_content", comment: "Enter description content"), placeholder: "enter_description_content".localized,
text: .constant(""), text: .constant(""),
icon: "text.quote" icon: "text.quote"
) )
TextEditorView.longText( TextEditorView.longText(
title: NSLocalizedString("long_text", comment: "Long text"), title: "long_text".localized,
isRequired: false, isRequired: false,
placeholder: NSLocalizedString("enter_long_text_content", comment: "Enter long text content"), placeholder: "enter_long_text_content".localized,
text: .constant(""), text: .constant(""),
icon: "doc.text" icon: "doc.text"
) )
TextEditorView.emailBody( TextEditorView.emailBody(
title: NSLocalizedString("email_body", comment: "Email body"), title: "email_body".localized,
isRequired: true, isRequired: true,
placeholder: NSLocalizedString("enter_email_body_content", comment: "Enter email body content"), placeholder: "enter_email_body_content".localized,
text: .constant(""), text: .constant(""),
icon: "envelope" icon: "envelope"
) )

@ -104,7 +104,7 @@ struct TextInputView: View {
#Preview { #Preview {
TextInputView( TextInputView(
content: .constant(""), content: .constant(""),
placeholder: NSLocalizedString("text_placeholder", comment: "Input any text content"), placeholder: "text_placeholder".localized,
maxCharacters: 150 maxCharacters: 150
) )
} }

@ -102,18 +102,18 @@ extension Date {
if let day = components.day, day > 0 { if let day = components.day, day > 0 {
if day == 1 { if day == 1 {
return NSLocalizedString("yesterday", comment: "Yesterday") return "yesterday".localized
} else if day < 7 { } else if day < 7 {
return String(format: NSLocalizedString("days_ago", comment: "Days ago"), day) return String(format: "days_ago".localized, day)
} else { } else {
return self.formattedString(style: .short) return self.formattedString(style: .short)
} }
} else if let hour = components.hour, hour > 0 { } else if let hour = components.hour, hour > 0 {
return String(format: NSLocalizedString("hours_ago", comment: "Hours ago"), hour) return String(format: "hours_ago".localized, hour)
} else if let minute = components.minute, minute > 0 { } else if let minute = components.minute, minute > 0 {
return String(format: NSLocalizedString("minutes_ago", comment: "Minutes ago"), minute) return String(format: "minutes_ago".localized, minute)
} else { } else {
return NSLocalizedString("just_now", comment: "Just now") return "just_now".localized
} }
} }
} }
@ -277,11 +277,11 @@ enum PasswordStrength {
var description: String { var description: String {
switch self { switch self {
case .weak: case .weak:
return NSLocalizedString("weak", comment: "Weak") return "weak".localized
case .medium: case .medium:
return NSLocalizedString("medium", comment: "Medium") return "medium".localized
case .strong: case .strong:
return NSLocalizedString("strong", comment: "Strong") return "strong".localized
} }
} }

@ -168,9 +168,9 @@ struct CharacterCountValidation: View {
Spacer() Spacer()
if currentCount >= maxCount { if currentCount >= maxCount {
ValidationView.error(message: NSLocalizedString("max_characters_reached", comment: "Maximum characters reached")) ValidationView.error(message: "max_characters_reached".localized)
} else if currentCount >= Int(Double(maxCount) * warningThreshold) { } else if currentCount >= Int(Double(maxCount) * warningThreshold) {
ValidationView.warning(message: NSLocalizedString("near_character_limit", comment: "Near character limit")) ValidationView.warning(message: "near_character_limit".localized)
} else { } else {
Text("\(currentCount)/\(maxCount)") Text("\(currentCount)/\(maxCount)")
.font(.caption) .font(.caption)
@ -187,7 +187,7 @@ struct RequiredFieldValidation: View {
var body: some View { var body: some View {
if isEmpty { if isEmpty {
ValidationView.error(message: String(format: NSLocalizedString("field_required", comment: "Field is required"), fieldName)) ValidationView.error(message: String(format: "field_required".localized, fieldName))
} }
} }
} }
@ -211,7 +211,7 @@ struct FormatValidation: View {
var body: some View { var body: some View {
if !isValid { if !isValid {
ValidationView.error( ValidationView.error(
message: errorMessage ?? String(format: NSLocalizedString("field_format_incorrect", comment: "Field format is incorrect"), fieldName) message: errorMessage ?? String(format: "field_format_incorrect".localized, fieldName)
) )
} }
} }

@ -31,16 +31,16 @@ struct CreateCodeView: View {
isContentFieldFocused: $isContentFieldFocused isContentFieldFocused: $isContentFieldFocused
) )
} }
.navigationTitle(String(format: NSLocalizedString("create_data_type", comment: "Create data type"), selectedDataType.displayName)) .navigationTitle(String(format: "create_data_type".localized, selectedDataType.displayName))
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
Button(NSLocalizedString("create", comment: "Create")) { createCode() } Button("create".localized) { createCode() }
.disabled(content.isEmpty) .disabled(content.isEmpty)
} }
} }
.alert(NSLocalizedString("tip", comment: "Tip"), isPresented: $showingAlert) { .alert("tip".localized, isPresented: $showingAlert) {
Button(NSLocalizedString("confirm", comment: "Confirm")) { } Button("confirm".localized) { }
} message: { Text(alertMessage) } } message: { Text(alertMessage) }
.onAppear { .onAppear {
// //
@ -60,7 +60,7 @@ struct CreateCodeView: View {
if selectedDataType == .barcode { if selectedDataType == .barcode {
let validation = BarcodeValidator.validateBarcode(content, type: selectedBarcodeType) let validation = BarcodeValidator.validateBarcode(content, type: selectedBarcodeType)
if !validation.isValid { if !validation.isValid {
alertMessage = validation.errorMessage ?? NSLocalizedString("barcode_format_incorrect", comment: "Barcode format incorrect") alertMessage = validation.errorMessage ?? "barcode_format_incorrect".localized
showingAlert = true showingAlert = true
return return
} }
@ -79,7 +79,7 @@ struct CreateCodeView: View {
historyItem.qrCodeType = selectedQRCodeType.rawValue historyItem.qrCodeType = selectedQRCodeType.rawValue
} }
coreDataManager.addHistoryItem(historyItem) coreDataManager.addHistoryItem(historyItem)
alertMessage = String(format: NSLocalizedString("data_type_created_successfully", comment: "Data type created successfully"), selectedDataType.displayName) alertMessage = String(format: "data_type_created_successfully".localized, selectedDataType.displayName)
showingAlert = true showingAlert = true
// //
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {

@ -83,7 +83,7 @@ struct CreateQRCodeView: View {
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
Button(NSLocalizedString("create", comment: "Create")) { Button("create".localized) {
if canCreateQRCode() { if canCreateQRCode() {
navigateToStyleView = true navigateToStyleView = true
} }
@ -92,8 +92,8 @@ struct CreateQRCodeView: View {
.font(.system(size: 16, weight: .semibold)) .font(.system(size: 16, weight: .semibold))
} }
} }
.alert(NSLocalizedString("tip", comment: "Tip"), isPresented: $showingAlert) { .alert("tip".localized, isPresented: $showingAlert) {
Button(NSLocalizedString("confirm", comment: "Confirm")) { } Button("confirm".localized) { }
} message: { Text(alertMessage) } } message: { Text(alertMessage) }
.background( .background(
NavigationLink( NavigationLink(
@ -577,70 +577,70 @@ struct CreateQRCodeView: View {
// //
switch selectedQRCodeType { switch selectedQRCodeType {
case .mail: case .mail:
var mailContent = String(format: NSLocalizedString("email_content_format", comment: "Email content format"), emailAddress, emailSubject, emailBody) var mailContent = String(format: "email_content_format".localized, emailAddress, emailSubject, emailBody)
if !emailCc.isEmpty { if !emailCc.isEmpty {
mailContent += String(format: NSLocalizedString("email_cc_format", comment: "Email CC format"), emailCc) mailContent += String(format: "email_cc_format".localized, emailCc)
} }
if !emailBcc.isEmpty { if !emailBcc.isEmpty {
mailContent += String(format: NSLocalizedString("email_bcc_format", comment: "Email BCC format"), emailBcc) mailContent += String(format: "email_bcc_format".localized, emailBcc)
} }
historyItem.content = mailContent historyItem.content = mailContent
case .wifi: case .wifi:
historyItem.content = String(format: NSLocalizedString("wifi_content_format", comment: "WiFi content format"), wifiSSID, wifiEncryptionType.displayName) historyItem.content = String(format: "wifi_content_format".localized, wifiSSID, wifiEncryptionType.displayName)
case .vcard, .mecard: case .vcard, .mecard:
var contactContent = NSLocalizedString("contact_content_prefix", comment: "Contact content prefix") var contactContent = "contact_content_prefix".localized
if !contactFirstName.isEmpty || !contactLastName.isEmpty { if !contactFirstName.isEmpty || !contactLastName.isEmpty {
contactContent += "\(contactFirstName) \(contactLastName)" contactContent += "\(contactFirstName) \(contactLastName)"
} }
if !contactNickname.isEmpty { if !contactNickname.isEmpty {
contactContent += String(format: NSLocalizedString("contact_nickname_format", comment: "Contact nickname format"), contactNickname) contactContent += String(format: "contact_nickname_format".localized, contactNickname)
} }
if !contactPhone.isEmpty { if !contactPhone.isEmpty {
contactContent += String(format: NSLocalizedString("contact_phone_format", comment: "Contact phone format"), contactPhone) contactContent += String(format: "contact_phone_format".localized, contactPhone)
} }
if !contactEmail.isEmpty { if !contactEmail.isEmpty {
contactContent += String(format: NSLocalizedString("contact_email_format", comment: "Contact email format"), contactEmail) contactContent += String(format: "contact_email_format".localized, contactEmail)
} }
if !contactCompany.isEmpty { if !contactCompany.isEmpty {
contactContent += String(format: NSLocalizedString("contact_company_format", comment: "Contact company format"), contactCompany) contactContent += String(format: "contact_company_format".localized, contactCompany)
} }
if !contactTitle.isEmpty { if !contactTitle.isEmpty {
contactContent += String(format: NSLocalizedString("contact_title_format", comment: "Contact title format"), contactTitle) contactContent += String(format: "contact_title_format".localized, contactTitle)
} }
if !contactAddress.isEmpty { if !contactAddress.isEmpty {
contactContent += String(format: NSLocalizedString("contact_address_format", comment: "Contact address format"), contactAddress) contactContent += String(format: "contact_address_format".localized, contactAddress)
} }
if !contactWebsite.isEmpty { if !contactWebsite.isEmpty {
contactContent += String(format: NSLocalizedString("contact_website_format", comment: "Contact website format"), contactWebsite) contactContent += String(format: "contact_website_format".localized, contactWebsite)
} }
if !contactNote.isEmpty { if !contactNote.isEmpty {
contactContent += String(format: NSLocalizedString("contact_note_format", comment: "Contact note format"), contactNote) contactContent += String(format: "contact_note_format".localized, contactNote)
} }
historyItem.content = contactContent historyItem.content = contactContent
case .location: case .location:
historyItem.content = String(format: NSLocalizedString("location_content_format", comment: "Location content format"), locationLatitude, locationLongitude) historyItem.content = String(format: "location_content_format".localized, locationLatitude, locationLongitude)
case .calendar: case .calendar:
historyItem.content = String(format: NSLocalizedString("calendar_content_format", comment: "Calendar content format"), eventTitle) historyItem.content = String(format: "calendar_content_format".localized, eventTitle)
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok, .whatsapp, .viber: case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok, .whatsapp, .viber:
historyItem.content = generateSocialMediaContent() historyItem.content = generateSocialMediaContent()
case .phone, .sms: case .phone, .sms:
historyItem.content = String(format: NSLocalizedString("phone_content_format", comment: "Phone content format"), phoneNumber) historyItem.content = String(format: "phone_content_format".localized, phoneNumber)
case .url: case .url:
historyItem.content = String(format: NSLocalizedString("url_content_format", comment: "URL content format"), urlString) historyItem.content = String(format: "url_content_format".localized, urlString)
default: default:
historyItem.content = content historyItem.content = content
} }
do { do {
try context.save() try context.save()
alertMessage = NSLocalizedString("qrcode_created_successfully", comment: "QR code created successfully") alertMessage = "qrcode_created_successfully".localized
showingAlert = true showingAlert = true
// //
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
dismiss() dismiss()
} }
} catch { } catch {
alertMessage = String(format: NSLocalizedString("save_failed_error", comment: "Save failed with error"), error.localizedDescription) alertMessage = String(format: "save_failed_error".localized, error.localizedDescription)
showingAlert = true showingAlert = true
} }
} }

@ -28,17 +28,17 @@ struct HistoryView: View {
var displayName: String { var displayName: String {
switch self { switch self {
case .all: case .all:
return NSLocalizedString("all", comment: "All") return "all".localized
case .barcode: case .barcode:
return NSLocalizedString("barcode", comment: "Barcode") return "barcode".localized
case .qrcode: case .qrcode:
return NSLocalizedString("qrcode", comment: "QR Code") return "qrcode".localized
case .scanned: case .scanned:
return NSLocalizedString("scanned", comment: "Scanned") return "scanned".localized
case .created: case .created:
return NSLocalizedString("created", comment: "Created") return "created".localized
case .favorites: case .favorites:
return NSLocalizedString("favorites", comment: "Favorites") return "favorites".localized
} }
} }
@ -108,7 +108,7 @@ struct HistoryView: View {
historyList historyList
} }
} }
.navigationTitle(NSLocalizedString("history_records", comment: "History records")) .navigationTitle("history_records".localized)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
.navigationBarTitleDisplayMode(.large) .navigationBarTitleDisplayMode(.large)
.toolbar { .toolbar {
@ -171,9 +171,9 @@ struct HistoryView: View {
onConfirm: clearHistory onConfirm: clearHistory
) )
} }
.alert(NSLocalizedString("delete_confirmation", comment: "Delete confirmation"), isPresented: $showingDeleteAlert) { .alert("delete_confirmation".localized, isPresented: $showingDeleteAlert) {
Button(NSLocalizedString("cancel", comment: "Cancel"), role: .cancel) { } Button("cancel".localized, role: .cancel) { }
Button(NSLocalizedString("delete", comment: "Delete"), role: .destructive) { Button("delete".localized, role: .destructive) {
if let item = itemToDelete { if let item = itemToDelete {
deleteHistoryItem(item) deleteHistoryItem(item)
itemToDelete = nil itemToDelete = nil
@ -181,7 +181,7 @@ struct HistoryView: View {
} }
} message: { } message: {
if let item = itemToDelete { if let item = itemToDelete {
Text(String(format: NSLocalizedString("confirm_delete_record", comment: "Confirm delete record"), item.content ?? "")) Text(String(format: "confirm_delete_record".localized, item.content ?? ""))
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
} }
} }
@ -292,7 +292,7 @@ struct HistoryView: View {
Image(systemName: "magnifyingglass") Image(systemName: "magnifyingglass")
.foregroundColor(.gray) .foregroundColor(.gray)
TextField(NSLocalizedString("search_history_records", comment: "Search history records"), text: $searchText) TextField("search_history_records".localized, text: $searchText)
.textFieldStyle(RoundedBorderTextFieldStyle()) .textFieldStyle(RoundedBorderTextFieldStyle())
} }
.padding(.horizontal) .padding(.horizontal)
@ -330,7 +330,7 @@ struct HistoryView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
ProgressView() ProgressView()
.scaleEffect(1.2) .scaleEffect(1.2)
Text(NSLocalizedString("loading", comment: "Loading")) Text("loading".localized)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
@ -373,13 +373,13 @@ struct HistoryView: View {
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundColor(.gray) .foregroundColor(.gray)
Text(NSLocalizedString("no_history_records", comment: "No history records")) Text("no_history_records".localized)
.font(.title2) .font(.title2)
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(.gray) .foregroundColor(.gray)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
Text(NSLocalizedString("scan_or_create_to_start", comment: "Scan or create to start")) Text("scan_or_create_to_start".localized)
.font(.body) .font(.body)
.foregroundColor(.gray) .foregroundColor(.gray)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@ -388,7 +388,7 @@ struct HistoryView: View {
NavigationLink(destination: CodeTypeSelectionView()) { NavigationLink(destination: CodeTypeSelectionView()) {
HStack { HStack {
Image(systemName: "plus.circle.fill") Image(systemName: "plus.circle.fill")
Text(NSLocalizedString("create_first_record", comment: "Create first record")) Text("create_first_record".localized)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
} }
.font(.headline) .font(.headline)
@ -580,7 +580,7 @@ struct HistoryItemRow: View {
} }
.padding(.vertical, 8) .padding(.vertical, 8)
.swipeActions(edge: .trailing, allowsFullSwipe: false) { .swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button(NSLocalizedString("delete", comment: "Delete"), role: .destructive) { Button("delete".localized, role: .destructive) {
onDelete() onDelete()
} }
} }
@ -625,13 +625,13 @@ struct ClearHistoryConfirmView: View {
.foregroundColor(.red) .foregroundColor(.red)
// //
Text(NSLocalizedString("clear_history", comment: "Clear history")) Text("clear_history".localized)
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
// //
Text(NSLocalizedString("clear_history_warning", comment: "Clear history warning")) Text("clear_history_warning".localized)
.font(.body) .font(.body)
.foregroundColor(.secondary) .foregroundColor(.secondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@ -648,7 +648,7 @@ struct ClearHistoryConfirmView: View {
}) { }) {
HStack { HStack {
Image(systemName: "trash.fill") Image(systemName: "trash.fill")
Text(NSLocalizedString("confirm_delete", comment: "Confirm delete")) Text("confirm_delete".localized)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -662,7 +662,7 @@ struct ClearHistoryConfirmView: View {
Button(action: { Button(action: {
isPresented = false isPresented = false
}) { }) {
Text(NSLocalizedString("cancel", comment: "Cancel")) Text("cancel".localized)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding() .padding()
.background(Color(.systemGray5)) .background(Color(.systemGray5))
@ -672,13 +672,13 @@ struct ClearHistoryConfirmView: View {
} }
} }
.padding(20) .padding(20)
.navigationTitle(NSLocalizedString("confirm_delete", comment: "Confirm delete")) .navigationTitle("confirm_delete".localized)
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true) .navigationBarBackButtonHidden(true)
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarLeading) { ToolbarItem(placement: .navigationBarLeading) {
Button(NSLocalizedString("close", comment: "Close")) { Button("close".localized) {
isPresented = false isPresented = false
} }
.id(languageManager.refreshTrigger) .id(languageManager.refreshTrigger)

@ -49,8 +49,8 @@ struct QRCodeDetailView: View {
.sheet(isPresented: $showingShareSheet) { .sheet(isPresented: $showingShareSheet) {
ShareSheet(activityItems: [historyItem.content ?? ""]) ShareSheet(activityItems: [historyItem.content ?? ""])
} }
.alert(NSLocalizedString("tip", comment: "Tip"), isPresented: $showingAlert) { .alert("tip".localized, isPresented: $showingAlert) {
Button(NSLocalizedString("confirm", comment: "Confirm")) { } Button("confirm".localized) { }
} message: { } message: {
Text(alertMessage) Text(alertMessage)
} }
@ -89,7 +89,7 @@ struct QRCodeDetailView: View {
) )
} }
Text(NSLocalizedString("scan_this_qr_code", comment: "Scan this QR code")) Text("scan_this_qr_code".localized)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
@ -105,7 +105,7 @@ struct QRCodeDetailView: View {
.font(.title2) .font(.title2)
.foregroundColor(.green) .foregroundColor(.green)
Text(NSLocalizedString("parsed_info", comment: "Parsed Information")) Text("parsed_info".localized)
.font(.headline) .font(.headline)
Spacer() Spacer()
@ -153,7 +153,7 @@ struct QRCodeDetailView: View {
.font(.title2) .font(.title2)
.foregroundColor(.purple) .foregroundColor(.purple)
Text(NSLocalizedString("original_content", comment: "Original Content")) Text("original_content".localized)
.font(.headline) .font(.headline)
Spacer() Spacer()
@ -199,7 +199,7 @@ struct QRCodeDetailView: View {
// //
HStack(spacing: 8) { HStack(spacing: 8) {
Label(NSLocalizedString("custom", comment: "Custom"), systemImage: "paintpalette") Label("custom".localized, systemImage: "paintpalette")
.font(.caption) .font(.caption)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 4) .padding(.vertical, 4)
@ -225,7 +225,7 @@ struct QRCodeDetailView: View {
.shadow(radius: 4) .shadow(radius: 4)
} }
Label(NSLocalizedString("standard", comment: "Standard"), systemImage: "qrcode") Label("standard".localized, systemImage: "qrcode")
.font(.caption) .font(.caption)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 4) .padding(.vertical, 4)
@ -250,7 +250,7 @@ struct QRCodeDetailView: View {
Image(systemName: historyItem.isFavorite ? "heart.fill" : "heart") Image(systemName: historyItem.isFavorite ? "heart.fill" : "heart")
.foregroundColor(historyItem.isFavorite ? .red : .gray) .foregroundColor(historyItem.isFavorite ? .red : .gray)
Text(historyItem.isFavorite ? NSLocalizedString("unfavorite", comment: "Unfavorite") : NSLocalizedString("favorite", comment: "Favorite")) Text(historyItem.isFavorite ? "unfavorite".localized : "favorite".localized)
.fontWeight(.medium) .fontWeight(.medium)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -266,7 +266,7 @@ struct QRCodeDetailView: View {
Image(systemName: "doc.on.doc") Image(systemName: "doc.on.doc")
.foregroundColor(.blue) .foregroundColor(.blue)
Text(NSLocalizedString("copy_content", comment: "Copy Content")) Text("copy_content".localized)
.fontWeight(.medium) .fontWeight(.medium)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -283,7 +283,7 @@ struct QRCodeDetailView: View {
Image(systemName: "arrow.up.right.square") Image(systemName: "arrow.up.right.square")
.foregroundColor(.green) .foregroundColor(.green)
Text(NSLocalizedString("open_link", comment: "Open Link")) Text("open_link".localized)
.fontWeight(.medium) .fontWeight(.medium)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -327,7 +327,7 @@ struct QRCodeDetailView: View {
historyItem.isFavorite.toggle() historyItem.isFavorite.toggle()
coreDataManager.save() coreDataManager.save()
let message = historyItem.isFavorite ? NSLocalizedString("added_to_favorites", comment: "Added to favorites") : NSLocalizedString("removed_from_favorites", comment: "Removed from favorites") let message = historyItem.isFavorite ? "added_to_favorites".localized : "removed_from_favorites".localized
alertMessage = message alertMessage = message
showingAlert = true showingAlert = true
} }
@ -336,7 +336,7 @@ struct QRCodeDetailView: View {
private func copyContent() { private func copyContent() {
if let content = historyItem.content { if let content = historyItem.content {
UIPasteboard.general.string = content UIPasteboard.general.string = content
alertMessage = NSLocalizedString("content_copied_to_clipboard", comment: "Content copied to clipboard") alertMessage = "content_copied_to_clipboard".localized
showingAlert = true showingAlert = true
} }
} }
@ -637,26 +637,26 @@ extension QRCodeDetailView {
private func getColorDisplayName(_ colorString: String) -> String { private func getColorDisplayName(_ colorString: String) -> String {
if let color = QRCodeColor(rawValue: colorString) { if let color = QRCodeColor(rawValue: colorString) {
switch color { switch color {
case .black: return NSLocalizedString("black", comment: "Black") case .black: return "black".localized
case .white: return NSLocalizedString("white", comment: "White") case .white: return "white".localized
case .red: return NSLocalizedString("red", comment: "Red") case .red: return "red".localized
case .blue: return NSLocalizedString("blue", comment: "Blue") case .blue: return "blue".localized
case .green: return NSLocalizedString("green", comment: "Green") case .green: return "green".localized
case .yellow: return NSLocalizedString("yellow", comment: "Yellow") case .yellow: return "yellow".localized
case .purple: return NSLocalizedString("purple", comment: "Purple") case .purple: return "purple".localized
case .orange: return NSLocalizedString("orange", comment: "Orange") case .orange: return "orange".localized
case .pink: return NSLocalizedString("pink", comment: "Pink") case .pink: return "pink".localized
case .cyan: return NSLocalizedString("cyan", comment: "Cyan") case .cyan: return "cyan".localized
case .magenta: return NSLocalizedString("magenta", comment: "Magenta") case .magenta: return "magenta".localized
case .brown: return NSLocalizedString("brown", comment: "Brown") case .brown: return "brown".localized
case .gray: return NSLocalizedString("gray", comment: "Gray") case .gray: return "gray".localized
case .navy: return NSLocalizedString("navy", comment: "Navy") case .navy: return "navy".localized
case .teal: return NSLocalizedString("teal", comment: "Teal") case .teal: return "teal".localized
case .indigo: return NSLocalizedString("indigo", comment: "Indigo") case .indigo: return "indigo".localized
case .lime: return NSLocalizedString("lime", comment: "Lime") case .lime: return "lime".localized
case .maroon: return NSLocalizedString("maroon", comment: "Maroon") case .maroon: return "maroon".localized
case .olive: return NSLocalizedString("olive", comment: "Olive") case .olive: return "olive".localized
case .silver: return NSLocalizedString("silver", comment: "Silver") case .silver: return "silver".localized
} }
} }
return colorString return colorString
@ -698,7 +698,7 @@ extension QRCodeDetailView {
let qrCodeType = QRCodeType(rawValue: qrCodeTypeString) { let qrCodeType = QRCodeType(rawValue: qrCodeTypeString) {
return qrCodeType.displayName return qrCodeType.displayName
} }
return NSLocalizedString("qr_code_detail", comment: "QR Code Detail") return "qr_code_detail".localized
} }
// MARK: - Decorate code // MARK: - Decorate code
@ -712,7 +712,7 @@ extension QRCodeDetailView {
.font(.title2) .font(.title2)
.foregroundColor(.white) .foregroundColor(.white)
Text(NSLocalizedString("decorate_code", comment: "Decorate Code")) Text("decorate_code".localized)
.font(.headline) .font(.headline)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.white) .foregroundColor(.white)
@ -744,7 +744,7 @@ extension QRCodeDetailView {
.font(.caption) .font(.caption)
.foregroundColor(.orange) .foregroundColor(.orange)
Text(NSLocalizedString("qr_code_has_style", comment: "This QR code has custom style, tap to edit")) Text("qr_code_has_style".localized)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)

@ -241,14 +241,14 @@ struct QRCodeStyleView: View {
VStack(spacing: 24) { VStack(spacing: 24) {
// //
colorSelectionSection( colorSelectionSection(
title: NSLocalizedString("foreground_color", comment: "Foreground color"), title: "foreground_color".localized,
colors: QRCodeColor.foregroundColors, colors: QRCodeColor.foregroundColors,
selectedColor: $selectedForegroundColor selectedColor: $selectedForegroundColor
) )
// //
colorSelectionSection( colorSelectionSection(
title: NSLocalizedString("background_color", comment: "Background color"), title: "background_color".localized,
colors: QRCodeColor.backgroundColors, colors: QRCodeColor.backgroundColors,
selectedColor: $selectedBackgroundColor selectedColor: $selectedBackgroundColor
) )

@ -314,6 +314,32 @@
- 保持了所有必要的本地化键 - 保持了所有必要的本地化键
- 提高了文件的可维护性 - 提高了文件的可维护性
### 30. NSLocalizedString 替换为 String.localized
- **问题**: 项目中大量使用 `NSLocalizedString("key", comment: "comment")` 语法,代码冗长且不够简洁
- **修复**: 将所有 `NSLocalizedString` 调用替换为 `String.localized` 扩展方法
- **修复的文件**: 所有包含 `NSLocalizedString` 的 Swift 文件,包括:
- `MyQrCode/Views/CreateQRCodeView.swift`
- `MyQrCode/Views/CreateCodeView.swift`
- `MyQrCode/Views/HistoryView.swift`
- `MyQrCode/Views/QRCodeDetailView.swift`
- `MyQrCode/Views/CodeContentInputView.swift`
- `MyQrCode/Views/BarcodePreviewView.swift`
- `MyQrCode/Views/CodeTypeSelectionView.swift`
- `MyQrCode/Views/QRCodeStyleView.swift`
- `MyQrCode/ScannerView/ScanningOverlayView.swift`
- `MyQrCode/Models/QRCodeParser.swift`
- `MyQrCode/Models/HistoryEnums.swift`
- `MyQrCode/Models/BarcodeValidator.swift`
- 以及其他所有相关文件
- **替换模式**:
- `NSLocalizedString("key", comment: "comment")``"key".localized`
- `String(format: NSLocalizedString("key", comment: "comment"), args...)``String(format: "key".localized, args...)`
- **修复效果**:
- 代码更加简洁易读
- 统一了本地化调用方式
- 提高了代码的可维护性
- 减少了代码重复
## 新增的本地化键 ## 新增的本地化键
### 验证消息 ### 验证消息
@ -511,6 +537,12 @@
- **泰文文件**: 从836行清理到686行删除了150行重复内容 - **泰文文件**: 从836行清理到686行删除了150行重复内容
- **总计**: 删除了615行重复内容确保每个本地化键只出现一次 - **总计**: 删除了615行重复内容确保每个本地化键只出现一次
### 代码优化
- **NSLocalizedString 替换**: 将所有 `NSLocalizedString("key", comment: "comment")` 替换为 `"key".localized`
- **代码简化**: 减少了代码冗长度,提高了可读性
- **统一调用**: 使用统一的 `String.localized` 扩展方法进行本地化
- **维护性提升**: 简化了本地化调用方式,便于后续维护
### 二维码解析器(扩展) ### 二维码解析器(扩展)
- `wifi_network_info` - Wi-Fi网络信息 - `wifi_network_info` - Wi-Fi网络信息
- `password_set` - 密码已设置 - `password_set` - 密码已设置

Loading…
Cancel
Save