Selaa lähdekoodia

Localization tests

Jonas Björkert 1 vuosi sitten
vanhempi
commit
8dda5a10ec
2 muutettua tiedostoa jossa 81 lisäystä ja 0 poistoa
  1. 4 0
      Trio.xcodeproj/project.pbxproj
  2. 77 0
      TrioTests/LocalizationTests.swift

+ 4 - 0
Trio.xcodeproj/project.pbxproj

@@ -615,6 +615,7 @@
 		DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC62D05127500D99BF4 /* FontExtensions.swift */; };
 		DDBD53FC2DAA903100F940A6 /* OverviewStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDBD53FB2DAA903100F940A6 /* OverviewStepView.swift */; };
 		DDC38E102D9B377800ADCB46 /* OnboardingView+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC38E0F2D9B376900ADCB46 /* OnboardingView+Util.swift */; };
+		DDC6CA6D2DD90A2A0060EE25 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC6CA6C2DD90A2A0060EE25 /* LocalizationTests.swift */; };
 		DDCAE8332D78D4A800B1BB51 /* TherapySettingsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCAE8322D78D49C00B1BB51 /* TherapySettingsUtil.swift */; };
 		DDCE790F2D6F97FC000A4D7A /* SubmodulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE790E2D6F97F7000A4D7A /* SubmodulesView.swift */; };
 		DDCEBF5B2CC1B76400DF4C36 /* LiveActivity+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCEBF5A2CC1B76400DF4C36 /* LiveActivity+Helper.swift */; };
@@ -1430,6 +1431,7 @@
 		DDB37CC62D05127500D99BF4 /* FontExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontExtensions.swift; sourceTree = "<group>"; };
 		DDBD53FB2DAA903100F940A6 /* OverviewStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewStepView.swift; sourceTree = "<group>"; };
 		DDC38E0F2D9B376900ADCB46 /* OnboardingView+Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnboardingView+Util.swift"; sourceTree = "<group>"; };
+		DDC6CA6C2DD90A2A0060EE25 /* LocalizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationTests.swift; sourceTree = "<group>"; };
 		DDCAE8322D78D49C00B1BB51 /* TherapySettingsUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySettingsUtil.swift; sourceTree = "<group>"; };
 		DDCE790E2D6F97F7000A4D7A /* SubmodulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmodulesView.swift; sourceTree = "<group>"; };
 		DDCEBF5A2CC1B76400DF4C36 /* LiveActivity+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LiveActivity+Helper.swift"; sourceTree = "<group>"; };
@@ -2557,6 +2559,7 @@
 		38FCF3EE25E9028E0078B0D1 /* TrioTests */ = {
 			isa = PBXGroup;
 			children = (
+				DDC6CA6C2DD90A2A0060EE25 /* LocalizationTests.swift */,
 				3B997DD22DC02AEF006B6BB2 /* JSONImporterData */,
 				BD8FC05C2D6618BE00B95AED /* BolusCalculatorTests */,
 				BD8FC0552D66187700B95AED /* CoreDataTests */,
@@ -4632,6 +4635,7 @@
 				CEE9A65E2BBC9F6500EB5194 /* CalibrationsTests.swift in Sources */,
 				BD8FC0622D6619E600B95AED /* OverrideStorageTests.swift in Sources */,
 				BD8FC0592D66189700B95AED /* TestAssembly.swift in Sources */,
+				DDC6CA6D2DD90A2A0060EE25 /* LocalizationTests.swift in Sources */,
 				3B997DCF2DC00A3A006B6BB2 /* JSONImporterTests.swift in Sources */,
 				BD8FC0662D661A0000B95AED /* GlucoseStorageTests.swift in Sources */,
 				BD8FC05B2D6618AF00B95AED /* DeterminationStorageTests.swift in Sources */,

+ 77 - 0
TrioTests/LocalizationTests.swift

@@ -0,0 +1,77 @@
+
+import Foundation
+import Testing
+
+private let bundle = Bundle.main
+
+@Suite("Localization Tests", .serialized) struct LocalizationTests {
+    @Test("No stray % inside format strings") func testNoStrayPercent() {
+        // Array to collect strings with issues
+        var offenders: [(lang: String, key: String, value: String, file: String)] = []
+
+        // Regular expression patterns
+        let placeholderPattern = "%[0-9]*\\$?[.,]?[0-9]*[a-zA-Z@]" // Matches placeholders like %@, %d, %1$@
+        let escapedPercentPattern = "%%" // Matches escaped percent signs
+        let percentPattern = "%" // Matches any percent sign
+
+        // Compile regexes (force-unwrapped since patterns are static and valid)
+        let placeholderRegex = try! NSRegularExpression(pattern: placeholderPattern)
+        let escapedPercentRegex = try! NSRegularExpression(pattern: escapedPercentPattern)
+        let percentRegex = try! NSRegularExpression(pattern: percentPattern)
+
+        // Assume 'bundle' is accessible, e.g., Bundle.main
+        for locale in bundle.localizations where locale != "Base" {
+            guard let lproj = bundle.path(forResource: locale, ofType: "lproj"),
+                  let files = FileManager.default.enumerator(atPath: lproj) else { continue }
+
+            // Iterate over .strings files in the localization directory
+            for case let f as String in files where f.hasSuffix(".strings") {
+                let path = (lproj as NSString).appendingPathComponent(f)
+                guard let table = NSDictionary(contentsOfFile: path) as? [String: String] else { continue }
+
+                // Check each key-value pair in the .strings file
+                for (key, value) in table {
+                    let nsValue = value as NSString
+                    let range = NSRange(location: 0, length: nsValue.length)
+
+                    // Determine if the value contains any placeholders
+                    let hasPlaceholders = placeholderRegex.firstMatch(in: value, range: range) != nil
+
+                    // Only check for stray % if the value has placeholders
+                    if hasPlaceholders {
+                        // Find all ranges covered by placeholders and escaped %%
+                        let placeholderMatches = placeholderRegex.matches(in: value, range: range)
+                        let escapedMatches = escapedPercentRegex.matches(in: value, range: range)
+                        let coveredRanges = (placeholderMatches + escapedMatches).map(\.range)
+
+                        // Find all % signs in the value
+                        let percentMatches = percentRegex.matches(in: value, range: range)
+
+                        // Check each % to see if it's stray (not covered by a placeholder or %%)
+                        for percentMatch in percentMatches {
+                            let percentLocation = percentMatch.range.location
+                            let isCovered = coveredRanges.contains { NSLocationInRange(percentLocation, $0) }
+                            if !isCovered {
+                                offenders.append((lang: locale, key: key, value: value, file: f))
+                                break // Stop checking this string after finding an issue
+                            }
+                        }
+                    }
+                    // If no placeholders, skip the check (single % is allowed)
+                }
+            }
+        }
+
+        // Assert that no offenders were found using Testing's #expect
+        #expect(
+            offenders.isEmpty,
+            """
+            Found \(offenders.count) string(s) that still have a single % although \
+            the value contains printf placeholders:
+
+            \(offenders.map { "\($0.lang) – \($0.file)\n⟨key⟩   \($0.key)\n⟨value⟩ \($0.value)" }
+                .joined(separator: "\n\n"))
+            """
+        )
+    }
+}