-
Notifications
You must be signed in to change notification settings - Fork 13
Localize remaining OTPKit strings and OTP wire tokens #149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <!-- | ||
| iOS resolves an app's language from the main bundle, so a host app that declares no | ||
| localizations pins the process to English and OTPKit's translations are never selected. | ||
| Declaring the locales OTPKit ships lets the demo actually exercise them. | ||
|
|
||
| The remaining Info.plist keys are still generated by the build | ||
| (GENERATE_INFOPLIST_FILE) and merged into this file. | ||
| --> | ||
| <key>CFBundleLocalizations</key> | ||
| <array> | ||
| <string>en</string> | ||
| <string>ar</string> | ||
| <string>es</string> | ||
| <string>fil</string> | ||
| <string>fr</string> | ||
| <string>it</string> | ||
| <string>ko</string> | ||
| <string>pl</string> | ||
| <string>pt-BR</string> | ||
| <string>ru</string> | ||
| <string>vi</string> | ||
| <string>zh-Hans</string> | ||
| <string>zh-Hant</string> | ||
| </array> | ||
| </dict> | ||
| </plist> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
OTPKit/Sources/OTPKit/Core/Extensions/StringExtension.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // | ||
| // StringExtension.swift | ||
| // OTPKit | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| extension String { | ||
| /// Canonicalizes an OTP wire token for enum lookup: trims, uppercases, and treats | ||
| /// spaces as underscores so `"Cable Car"` and `"cable_car"` both match `CABLE_CAR`. | ||
| var normalizedOTPToken: String { | ||
| trimmingCharacters(in: .whitespaces) | ||
| .uppercased() | ||
| .replacingOccurrences(of: " ", with: "_") | ||
| } | ||
|
|
||
| /// Renders an unrecognized OTP token as readable text: `SPIN_AROUND` becomes `Spin Around`. | ||
| /// | ||
| /// Last-resort display fallback for a mode or direction this client doesn't know about. | ||
| /// The result is untranslated English by construction — it exists so a new server-side | ||
| /// token degrades to something readable rather than shouting a raw wire token. | ||
| var humanizedOTPToken: String { | ||
| replacingOccurrences(of: "_", with: " ").capitalized | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // | ||
| // LegMode.swift | ||
| // OTPKit | ||
| // | ||
|
|
||
| import Foundation | ||
| import OSLog | ||
|
|
||
| /// The means of conveyance for a `Leg`, as reported by OTP. | ||
| /// | ||
| /// OTP sends these as uppercase tokens (`CABLE_CAR`). Rendering the token directly leaks | ||
| /// English-shaped data into every locale, so callers should use ``displayName``. | ||
| public enum LegMode: String, CaseIterable, Sendable { | ||
| case walk = "WALK" | ||
| case bicycle = "BICYCLE" | ||
| case car = "CAR" | ||
| case bus = "BUS" | ||
| case tram = "TRAM" | ||
| case subway = "SUBWAY" | ||
| case rail = "RAIL" | ||
| case ferry = "FERRY" | ||
| case cableCar = "CABLE_CAR" | ||
| case gondola = "GONDOLA" | ||
| case funicular = "FUNICULAR" | ||
| case transit = "TRANSIT" | ||
| case airplane = "AIRPLANE" | ||
| case trolleybus = "TROLLEYBUS" | ||
| case monorail = "MONORAIL" | ||
|
|
||
| /// OTP tokens that don't match a case's raw value but mean the same thing. | ||
| private static let aliases: [String: LegMode] = ["BIKE": .bicycle, "TRAIN": .rail] | ||
|
|
||
| /// Creates a mode from an OTP token, tolerating casing, spaces, and the `BIKE`/`TRAIN` aliases. | ||
| public init?(otpMode: String) { | ||
| let normalized = otpMode.normalizedOTPToken | ||
| guard let mode = LegMode(rawValue: normalized) ?? Self.aliases[normalized] else { return nil } | ||
| self = mode | ||
| } | ||
|
|
||
| /// Localized name of the mode. | ||
| /// | ||
| /// The four modes that also exist as request-side ``TransportMode`` values reuse those | ||
| /// translations rather than maintaining a second copy of the same four words. | ||
| public var displayName: String { | ||
| switch self { | ||
| case .walk: | ||
| return TransportMode.walk.displayName | ||
| case .bicycle: | ||
| return TransportMode.bike.displayName | ||
| case .car: | ||
| return TransportMode.car.displayName | ||
| case .transit: | ||
| return TransportMode.transit.displayName | ||
| case .bus: | ||
| return OTPLoc("leg_mode.bus", comment: "Travel mode: bus") | ||
| case .tram: | ||
| return OTPLoc("leg_mode.tram", comment: "Travel mode: tram or streetcar") | ||
| case .subway: | ||
| return OTPLoc("leg_mode.subway", comment: "Travel mode: subway or metro") | ||
| case .rail: | ||
| return OTPLoc("leg_mode.rail", comment: "Travel mode: train") | ||
| case .ferry: | ||
| return OTPLoc("leg_mode.ferry", comment: "Travel mode: ferry") | ||
| case .cableCar: | ||
| return OTPLoc("leg_mode.cable_car", comment: "Travel mode: cable car") | ||
| case .gondola: | ||
| return OTPLoc("leg_mode.gondola", comment: "Travel mode: aerial gondola") | ||
| case .funicular: | ||
| return OTPLoc("leg_mode.funicular", comment: "Travel mode: funicular") | ||
| case .airplane: | ||
| return OTPLoc("leg_mode.airplane", comment: "Travel mode: airplane") | ||
| case .trolleybus: | ||
| return OTPLoc("leg_mode.trolleybus", comment: "Travel mode: trolleybus") | ||
| case .monorail: | ||
| return OTPLoc("leg_mode.monorail", comment: "Travel mode: monorail") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public extension Leg { | ||
| /// Localized name of this leg's mode, falling back to the raw OTP token when unrecognized. | ||
| var modeDisplayName: String { | ||
| guard let legMode = LegMode(otpMode: mode) else { | ||
| Logger.main.warning("Unrecognized OTP leg mode: \(mode)") | ||
| return mode.humanizedOTPToken | ||
| } | ||
| return legMode.displayName | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Make the new OTP model types
Codable.Both newly introduced model enums omit the repository’s required JSON serialization conformance. Add
Codableto both declarations.OTPKit/Sources/OTPKit/Core/Models/OTP/LegMode.swift#L13-L13: addCodable.OTPKit/Sources/OTPKit/Core/Models/OTP/RelativeDirection.swift#L13-L13: addCodable.As per coding guidelines, “All models must conform to
Codablefor JSON serialization.”📍 Affects 2 files
OTPKit/Sources/OTPKit/Core/Models/OTP/LegMode.swift#L13-L13(this comment)OTPKit/Sources/OTPKit/Core/Models/OTP/RelativeDirection.swift#L13-L13🤖 Prompt for AI Agents
Source: Coding guidelines