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>
</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>
</plist>

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

@ -46,15 +46,15 @@ class BarcodeValidator {
formattedContent: formatEAN13(content),
errorMessage: nil,
expectedLength: 13,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
} else {
return ValidationResult(
isValid: false,
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,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
}
}
@ -71,15 +71,15 @@ class BarcodeValidator {
formattedContent: formatEAN8(content),
errorMessage: nil,
expectedLength: 8,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
} else {
return ValidationResult(
isValid: false,
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,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
}
}
@ -96,15 +96,15 @@ class BarcodeValidator {
formattedContent: formatUPCE(content),
errorMessage: nil,
expectedLength: 8,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
} else {
return ValidationResult(
isValid: false,
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,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
}
}
@ -121,15 +121,15 @@ class BarcodeValidator {
formattedContent: formatCode39(content),
errorMessage: nil,
expectedLength: nil,
allowedCharacters: NSLocalizedString("code_39_characters", comment: "Code 39 allowed characters")
allowedCharacters: "code_39_characters".localized
)
} else {
return ValidationResult(
isValid: false,
formattedContent: content,
errorMessage: NSLocalizedString("code_39_only_contains", comment: "Code 39 only contains specific characters"),
errorMessage: "code_39_only_contains".localized,
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),
errorMessage: nil,
expectedLength: nil,
allowedCharacters: NSLocalizedString("code_128_characters", comment: "Code 128 allowed characters")
allowedCharacters: "code_128_characters".localized
)
} else {
return ValidationResult(
isValid: false,
formattedContent: content,
errorMessage: NSLocalizedString("code_128_only_contains", comment: "Code 128 only contains ASCII characters"),
errorMessage: "code_128_only_contains".localized,
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),
errorMessage: nil,
expectedLength: 14,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
} else {
return ValidationResult(
isValid: false,
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,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
)
}
}
@ -198,15 +198,15 @@ class BarcodeValidator {
formattedContent: formatPDF417(content),
errorMessage: nil,
expectedLength: nil,
allowedCharacters: NSLocalizedString("pdf417_characters", comment: "PDF417 allowed characters")
allowedCharacters: "pdf417_characters".localized
)
} else {
return ValidationResult(
isValid: false,
formattedContent: content,
errorMessage: NSLocalizedString("pdf417_only_contains", comment: "PDF417 only contains ASCII characters"),
errorMessage: "pdf417_only_contains".localized,
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 {
switch self {
case .scanned:
return NSLocalizedString("scanned", comment: "Scanned")
return "scanned".localized
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 {
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 {
description += String(format: NSLocalizedString("style_logo_format", comment: "Style logo format"), logo)
description += String(format: "style_logo_format".localized, logo)
}
if hasCustomLogo {
description += NSLocalizedString("custom_logo", comment: "Custom logo")
description += "custom_logo".localized
}
return description
}

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

@ -363,7 +363,7 @@ struct ScannerView: View {
let qrResults = detectedQR.enumerated().map { index, qrCode in
DetectedCode(
type: "QR Code",
content: qrCode.messageString ?? NSLocalizedString("unknown_content", comment: "Unknown content"),
content: qrCode.messageString ?? "unknown_content".localized,
bounds: qrCode.bounds,
source: .image
)
@ -393,7 +393,7 @@ struct ScannerView: View {
}
} else {
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
logWarning("❌ 图片中未检测到二维码或条形码", className: "ScannerView")
}
@ -448,7 +448,7 @@ struct ScannerView: View {
return results.enumerated().map { index, observation in
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")

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

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

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

@ -13,7 +13,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: result.isValid ? "checkmark.circle.fill" : "xmark.circle.fill")
.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)
.foregroundColor(result.isValid ? .green : .red)
.fontWeight(.medium)
@ -36,7 +36,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "number")
.foregroundColor(.blue)
.font(.caption)
Text(String(format: NSLocalizedString("length_requirement", comment: "Length requirement"), expectedLength))
Text(String(format: "length_requirement".localized, expectedLength))
.font(.caption)
.foregroundColor(.blue)
}
@ -47,7 +47,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "character")
.foregroundColor(.blue)
.font(.caption)
Text(String(format: NSLocalizedString("allowed_characters", comment: "Allowed characters"), allowedCharacters))
Text(String(format: "allowed_characters".localized, allowedCharacters))
.font(.caption)
.foregroundColor(.blue)
}
@ -61,7 +61,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "textformat")
.foregroundColor(.green)
.font(.caption)
Text(String(format: NSLocalizedString("formatted_content", comment: "Formatted content"), result.formattedContent))
Text(String(format: "formatted_content".localized, result.formattedContent))
.font(.caption)
.foregroundColor(.green)
.fontWeight(.medium)
@ -74,7 +74,7 @@ struct BarcodeValidationInfoView: View {
Image(systemName: "info.circle")
.foregroundColor(.blue)
.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)
.foregroundColor(.blue)
}
@ -97,7 +97,7 @@ struct BarcodeValidationInfoView: View {
formattedContent: "123 4567 8901 2",
errorMessage: nil,
expectedLength: 13,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
),
barcodeType: .ean13
)
@ -107,9 +107,9 @@ struct BarcodeValidationInfoView: View {
validationResult: BarcodeValidator.ValidationResult(
isValid: false,
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,
allowedCharacters: NSLocalizedString("numbers_0_9", comment: "Numbers 0-9")
allowedCharacters: "numbers_0_9".localized
),
barcodeType: .ean13
)

@ -83,11 +83,11 @@ struct CodeContentInputView: View {
//
HStack {
if let result = validationResult, result.isValid {
Text(NSLocalizedString("format_correct", comment: "Format correct"))
Text("format_correct".localized)
.font(.caption2)
.foregroundColor(.green)
} else if !content.isEmpty {
Text(NSLocalizedString("format_checking", comment: "Format checking"))
Text("format_checking".localized)
.font(.caption2)
.foregroundColor(.orange)
}
@ -229,19 +229,19 @@ struct CodeContentInputView: View {
private func getBarcodeFormatHint() -> String {
switch selectedBarcodeType {
case .ean13:
return NSLocalizedString("ean_13_format_hint", comment: "EAN-13 format hint")
return "ean_13_format_hint".localized
case .ean8:
return NSLocalizedString("ean_8_format_hint", comment: "EAN-8 format hint")
return "ean_8_format_hint".localized
case .upce:
return NSLocalizedString("upc_e_format_hint", comment: "UPC-E format hint")
return "upc_e_format_hint".localized
case .code39:
return NSLocalizedString("code_39_format_hint", comment: "Code 39 format hint")
return "code_39_format_hint".localized
case .code128:
return NSLocalizedString("code_128_format_hint", comment: "Code 128 format hint")
return "code_128_format_hint".localized
case .itf14:
return NSLocalizedString("itf_14_format_hint", comment: "ITF-14 format hint")
return "itf_14_format_hint".localized
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 {
switch selectedBarcodeType {
case .ean13:
return NSLocalizedString("input_13_digits", comment: "Input 13 digits")
return "input_13_digits".localized
case .ean8:
return NSLocalizedString("input_8_digits", comment: "Input 8 digits")
return "input_8_digits".localized
case .upce:
return NSLocalizedString("input_8_digits", comment: "Input 8 digits")
return "input_8_digits".localized
case .code39:
return NSLocalizedString("input_letters_numbers", comment: "Input letters and numbers")
return "input_letters_numbers".localized
case .code128:
return NSLocalizedString("input_any_characters", comment: "Input any characters")
return "input_any_characters".localized
case .itf14:
return NSLocalizedString("input_14_digits", comment: "Input 14 digits")
return "input_14_digits".localized
case .pdf417:
return NSLocalizedString("input_any_characters", comment: "Input any characters")
return "input_any_characters".localized
}
} 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) {
Text(NSLocalizedString("next", comment: "Next"))
Text("next".localized)
.font(.system(size: 18, weight: .semibold))
.foregroundColor(.white)
@ -113,7 +113,7 @@ struct CodeTypeSelectionView: View {
.padding(.horizontal, 20)
.padding(.bottom, 30)
}
.navigationTitle(NSLocalizedString("select_type", comment: "Select type"))
.navigationTitle("select_type".localized)
.navigationBarTitleDisplayMode(.inline)
}
}

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

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

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

@ -199,7 +199,7 @@ struct EmptyStateView: View {
struct LoadingStateView: View {
let message: String
init(message: String = NSLocalizedString("loading", comment: "Loading")) {
init(message: String = "loading".localized) {
self.message = message
}
@ -224,8 +224,8 @@ struct ErrorStateView: View {
let retryAction: (() -> Void)?
init(
title: String = NSLocalizedString("error_occurred", comment: "Error occurred"),
message: String = NSLocalizedString("load_failed_retry", comment: "Load failed, please retry"),
title: String = "error_occurred".localized,
message: String = "load_failed_retry".localized,
retryAction: (() -> Void)? = nil
) {
self.title = title
@ -253,7 +253,7 @@ struct ErrorStateView: View {
if let retryAction = retryAction {
Button(action: retryAction) {
Text(NSLocalizedString("retry", comment: "Retry"))
Text("retry".localized)
.font(.subheadline)
.fontWeight(.medium)
.foregroundColor(.blue)
@ -274,7 +274,7 @@ struct ErrorStateView: View {
#Preview {
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 {
AnyView(
HStack {
@ -293,19 +293,19 @@ struct ErrorStateView: View {
//
EmptyStateView(
icon: "tray",
title: NSLocalizedString("no_data", comment: "No data"),
subtitle: NSLocalizedString("no_content_yet", comment: "No content yet"),
actionTitle: NSLocalizedString("add_content", comment: "Add content"),
title: "no_data".localized,
subtitle: "no_content_yet".localized,
actionTitle: "add_content".localized,
action: {}
)
//
LoadingStateView(message: NSLocalizedString("loading_data", comment: "Loading data"))
LoadingStateView(message: "loading_data".localized)
//
ErrorStateView(
title: NSLocalizedString("network_error", comment: "Network error"),
message: NSLocalizedString("connection_failed_check_network", comment: "Cannot connect to server, please check network connection"),
title: "network_error".localized,
message: "connection_failed_check_network".localized,
retryAction: {}
)
}

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

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

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

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

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

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

@ -168,9 +168,9 @@ struct CharacterCountValidation: View {
Spacer()
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) {
ValidationView.warning(message: NSLocalizedString("near_character_limit", comment: "Near character limit"))
ValidationView.warning(message: "near_character_limit".localized)
} else {
Text("\(currentCount)/\(maxCount)")
.font(.caption)
@ -187,7 +187,7 @@ struct RequiredFieldValidation: View {
var body: some View {
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 {
if !isValid {
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
)
}
.navigationTitle(String(format: NSLocalizedString("create_data_type", comment: "Create data type"), selectedDataType.displayName))
.navigationTitle(String(format: "create_data_type".localized, selectedDataType.displayName))
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(NSLocalizedString("create", comment: "Create")) { createCode() }
Button("create".localized) { createCode() }
.disabled(content.isEmpty)
}
}
.alert(NSLocalizedString("tip", comment: "Tip"), isPresented: $showingAlert) {
Button(NSLocalizedString("confirm", comment: "Confirm")) { }
.alert("tip".localized, isPresented: $showingAlert) {
Button("confirm".localized) { }
} message: { Text(alertMessage) }
.onAppear {
//
@ -60,7 +60,7 @@ struct CreateCodeView: View {
if selectedDataType == .barcode {
let validation = BarcodeValidator.validateBarcode(content, type: selectedBarcodeType)
if !validation.isValid {
alertMessage = validation.errorMessage ?? NSLocalizedString("barcode_format_incorrect", comment: "Barcode format incorrect")
alertMessage = validation.errorMessage ?? "barcode_format_incorrect".localized
showingAlert = true
return
}
@ -79,7 +79,7 @@ struct CreateCodeView: View {
historyItem.qrCodeType = selectedQRCodeType.rawValue
}
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
//
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {

@ -83,7 +83,7 @@ struct CreateQRCodeView: View {
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(NSLocalizedString("create", comment: "Create")) {
Button("create".localized) {
if canCreateQRCode() {
navigateToStyleView = true
}
@ -92,8 +92,8 @@ struct CreateQRCodeView: View {
.font(.system(size: 16, weight: .semibold))
}
}
.alert(NSLocalizedString("tip", comment: "Tip"), isPresented: $showingAlert) {
Button(NSLocalizedString("confirm", comment: "Confirm")) { }
.alert("tip".localized, isPresented: $showingAlert) {
Button("confirm".localized) { }
} message: { Text(alertMessage) }
.background(
NavigationLink(
@ -577,70 +577,70 @@ struct CreateQRCodeView: View {
//
switch selectedQRCodeType {
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 {
mailContent += String(format: NSLocalizedString("email_cc_format", comment: "Email CC format"), emailCc)
mailContent += String(format: "email_cc_format".localized, emailCc)
}
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
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:
var contactContent = NSLocalizedString("contact_content_prefix", comment: "Contact content prefix")
var contactContent = "contact_content_prefix".localized
if !contactFirstName.isEmpty || !contactLastName.isEmpty {
contactContent += "\(contactFirstName) \(contactLastName)"
}
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 {
contactContent += String(format: NSLocalizedString("contact_phone_format", comment: "Contact phone format"), contactPhone)
contactContent += String(format: "contact_phone_format".localized, contactPhone)
}
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 {
contactContent += String(format: NSLocalizedString("contact_company_format", comment: "Contact company format"), contactCompany)
contactContent += String(format: "contact_company_format".localized, contactCompany)
}
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 {
contactContent += String(format: NSLocalizedString("contact_address_format", comment: "Contact address format"), contactAddress)
contactContent += String(format: "contact_address_format".localized, contactAddress)
}
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 {
contactContent += String(format: NSLocalizedString("contact_note_format", comment: "Contact note format"), contactNote)
contactContent += String(format: "contact_note_format".localized, contactNote)
}
historyItem.content = contactContent
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:
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:
historyItem.content = generateSocialMediaContent()
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:
historyItem.content = String(format: NSLocalizedString("url_content_format", comment: "URL content format"), urlString)
historyItem.content = String(format: "url_content_format".localized, urlString)
default:
historyItem.content = content
}
do {
try context.save()
alertMessage = NSLocalizedString("qrcode_created_successfully", comment: "QR code created successfully")
alertMessage = "qrcode_created_successfully".localized
showingAlert = true
//
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
dismiss()
}
} 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
}
}

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

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

@ -241,14 +241,14 @@ struct QRCodeStyleView: View {
VStack(spacing: 24) {
//
colorSelectionSection(
title: NSLocalizedString("foreground_color", comment: "Foreground color"),
title: "foreground_color".localized,
colors: QRCodeColor.foregroundColors,
selectedColor: $selectedForegroundColor
)
//
colorSelectionSection(
title: NSLocalizedString("background_color", comment: "Background color"),
title: "background_color".localized,
colors: QRCodeColor.backgroundColors,
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行重复内容
- **总计**: 删除了615行重复内容确保每个本地化键只出现一次
### 代码优化
- **NSLocalizedString 替换**: 将所有 `NSLocalizedString("key", comment: "comment")` 替换为 `"key".localized`
- **代码简化**: 减少了代码冗长度,提高了可读性
- **统一调用**: 使用统一的 `String.localized` 扩展方法进行本地化
- **维护性提升**: 简化了本地化调用方式,便于后续维护
### 二维码解析器(扩展)
- `wifi_network_info` - Wi-Fi网络信息
- `password_set` - 密码已设置

Loading…
Cancel
Save