Skip to content

Commit 275404a

Browse files
authored
Change localization interpolation (#161)
* Change the string interpolation for the localization * Avoid type casting by using a type erasure * Return the fallback literal instead of throwing an error * Try to solve the test errors * Replace the argument placeholders with the format specifiers used in swift
1 parent 18061c6 commit 275404a

19 files changed

Lines changed: 335 additions & 164 deletions

File tree

Sources/HTMLKit/Abstraction/Elements/BodyElements.swift

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,8 +1745,8 @@ extension Heading1: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute
17451745

17461746
extension Heading1: Localizable {
17471747

1748-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
1749-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
1748+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
1749+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
17501750
}
17511751
}
17521752

@@ -2027,8 +2027,8 @@ extension Heading2: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute
20272027

20282028
extension Heading2: Localizable {
20292029

2030-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
2031-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
2030+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
2031+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
20322032
}
20332033
}
20342034

@@ -2309,8 +2309,8 @@ extension Heading3: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute
23092309

23102310
extension Heading3: Localizable {
23112311

2312-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
2313-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
2312+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
2313+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
23142314
}
23152315
}
23162316

@@ -2591,8 +2591,8 @@ extension Heading4: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute
25912591

25922592
extension Heading4: Localizable {
25932593

2594-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
2595-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
2594+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
2595+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
25962596
}
25972597
}
25982598

@@ -2873,8 +2873,8 @@ extension Heading5: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute
28732873

28742874
extension Heading5: Localizable {
28752875

2876-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
2877-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
2876+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
2877+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
28782878
}
28792879
}
28802880

@@ -3155,8 +3155,8 @@ extension Heading6: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute
31553155

31563156
extension Heading6: Localizable {
31573157

3158-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
3159-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
3158+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
3159+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
31603160
}
31613161
}
31623162

@@ -4537,8 +4537,8 @@ extension Paragraph: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribut
45374537

45384538
extension Paragraph: Localizable {
45394539

4540-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
4541-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
4540+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
4541+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
45424542
}
45434543
}
45444544

@@ -5368,8 +5368,8 @@ extension Blockquote: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribu
53685368

53695369
extension Blockquote: Localizable {
53705370

5371-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
5372-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
5371+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
5372+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
53735373
}
53745374
}
53755375

@@ -6977,8 +6977,8 @@ extension Anchor: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes,
69776977

69786978
extension Anchor: Localizable {
69796979

6980-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
6981-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
6980+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
6981+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
69826982
}
69836983
}
69846984

@@ -7809,8 +7809,8 @@ extension Small: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes {
78097809

78107810
extension Small: Localizable {
78117811

7812-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
7813-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
7812+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
7813+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
78147814
}
78157815
}
78167816

@@ -8015,8 +8015,8 @@ extension StrikeThrough: GlobalAttributes, GlobalEventAttributes {
80158015

80168016
extension StrikeThrough: Localizable {
80178017

8018-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
8019-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
8018+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
8019+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
80208020
}
80218021
}
80228022

@@ -12612,8 +12612,8 @@ extension Italic: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes
1261212612

1261312613
extension Italic: Localizable {
1261412614

12615-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
12616-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
12615+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
12616+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
1261712617
}
1261812618
}
1261912619

@@ -12894,8 +12894,8 @@ extension Bold: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes {
1289412894

1289512895
extension Bold: Localizable {
1289612896

12897-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
12898-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
12897+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
12898+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
1289912899
}
1290012900
}
1290112901

@@ -13176,8 +13176,8 @@ extension Underline: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribut
1317613176

1317713177
extension Underline: Localizable {
1317813178

13179-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
13180-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
13179+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
13180+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
1318113181
}
1318213182
}
1318313183

Sources/HTMLKit/Abstraction/Elements/FormElements.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,8 @@ extension Label: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes,
631631

632632
extension Label: Localizable {
633633

634-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
635-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
634+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
635+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
636636
}
637637
}
638638

@@ -1549,8 +1549,8 @@ extension Button: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes,
15491549

15501550
extension Button: Localizable {
15511551

1552-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
1553-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
1552+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
1553+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
15541554
}
15551555
}
15561556

Sources/HTMLKit/Abstraction/Elements/TableElements.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,7 +2478,7 @@ extension HeaderCell: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribu
24782478

24792479
extension HeaderCell: Localizable {
24802480

2481-
public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
2482-
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
2481+
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
2482+
self.content = [LocalizedString(key: localizedKey, table: tableName)]
24832483
}
24842484
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Foundation
2+
3+
/// An enum that represents the data types of arguments used in interpolation.
4+
///
5+
/// Each case corresponds to a specific data type and provides a placeholder
6+
/// that can be used for replacing values in the localized string.
7+
@_documentation(visibility: internal)
8+
public enum InterpolationArgument {
9+
10+
/// Holds an integer value
11+
case int(Int)
12+
13+
/// Holds a string value
14+
case string(String)
15+
16+
/// Holds a double value
17+
case double(Double)
18+
19+
/// Holds a float value
20+
case float(Float)
21+
22+
/// Holds a date value
23+
case date(Date)
24+
25+
/// The placeholder used for string interpolation
26+
internal var placeholder: String {
27+
28+
switch self {
29+
case .int(_):
30+
return "%lld"
31+
32+
case .string(_):
33+
return "%@"
34+
35+
case .double(_):
36+
return "%f"
37+
38+
case .float(_):
39+
return "%f"
40+
41+
case .date(_):
42+
return "%@"
43+
}
44+
}
45+
}

Sources/HTMLKit/Framework/Localization/Localizable.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@ public protocol Localizable {
77
/// - Parameters:
88
/// - localizedKey: The string key to be translated
99
/// - tableName: The name of the translation table
10-
/// - interpolation: A variadic list of values used to replace placeholders within the translation string
11-
init(_ localizedKey: String, tableName: String?, interpolation: Any...)
10+
init(_ localizedKey: LocalizedStringKey, tableName: String?)
1211
}

Sources/HTMLKit/Framework/Localization/Localization.swift

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -137,46 +137,52 @@ public class Localization {
137137
return localizationTables
138138
}
139139

140+
/// Replace the value with the placeholder
141+
///
142+
/// - Parameters:
143+
/// - placeholder: The placeholder to be replaced in
144+
/// - value: The value to replace the placeholder with
145+
/// - translation: The string in which the replacement will occur
146+
private func replace(placeholder: String, with value: String, on translation: inout String) {
147+
148+
if let range = translation.range(of: placeholder) {
149+
translation = translation.replacingCharacters(in: range, with: value)
150+
}
151+
}
152+
140153
/// Apply interpolation values to the translation for the given locale
141154
///
142155
/// - Parameters:
143-
/// - arguments: An array of values used to replace placeholders within the translation string
144-
/// - translation: The translation string
145-
/// - locale: The locale
146-
private func interpolate(arguments: [Any], to translation: inout String, for locale: Locale) {
156+
/// - arguments: The arguments to replace the placeholders with
157+
/// - translation: The string in which the interpolation will occur
158+
/// - locale: The locale to respect during interpolation
159+
private func interpolate(arguments: [InterpolationArgument], to translation: inout String, for locale: Locale) {
147160

148161
for argument in arguments {
149-
162+
150163
switch argument {
151-
case let stringValue as String:
164+
case .int(let int):
152165

153-
if let range = translation.range(of: "%st") {
154-
translation = translation.replacingCharacters(in: range, with: stringValue)
155-
}
166+
replace(placeholder: argument.placeholder, with: String(int), on: &translation)
156167

157-
case let dateValue as Date:
168+
case .string(let string):
158169

159-
let formatter = DateFormatter()
160-
formatter.dateFormat = locale.dateFormat
170+
replace(placeholder: argument.placeholder, with: string, on: &translation)
161171

162-
if let range = translation.range(of: "%dt") {
163-
translation = translation.replacingCharacters(in: range, with: formatter.string(from: dateValue))
164-
}
172+
case .double(let double):
165173

166-
case let doubleValue as Double:
174+
replace(placeholder: argument.placeholder, with: String(double), on: &translation)
167175

168-
if let range = translation.range(of: "%do") {
169-
translation = translation.replacingCharacters(in: range, with: String(doubleValue))
170-
}
176+
case .float(let float):
171177

172-
case let intValue as Int:
178+
replace(placeholder: argument.placeholder, with: String(float), on: &translation)
173179

174-
if let range = translation.range(of: "%in") {
175-
translation = translation.replacingCharacters(in: range, with: String(intValue))
176-
}
180+
case .date(let date):
177181

178-
default:
179-
break
182+
let formatter = DateFormatter()
183+
formatter.dateFormat = locale.dateFormat
184+
185+
replace(placeholder: argument.placeholder, with: formatter.string(from: date), on: &translation)
180186
}
181187
}
182188
}
@@ -188,7 +194,7 @@ public class Localization {
188194
/// - locale: The locale to use when retrieving the translation
189195
///
190196
/// - Returns: The translation
191-
public func localize(key: LocalizedStringKey, for locale: Locale? = nil) throws -> String {
197+
public func localize(string: LocalizedString, for locale: Locale? = nil) throws -> String {
192198

193199
guard let fallback = self.locale else {
194200
throw Errors.noFallback
@@ -204,17 +210,17 @@ public class Localization {
204210
throw Errors.missingTable(currentLocale.tag)
205211
}
206212

207-
if let table = key.table {
213+
if let table = string.table {
208214

209215
guard let translationTable = translationTables.first(where: { $0.name == table }) else {
210216
throw Errors.unknownTable(table, currentLocale.tag)
211217
}
212218

213-
guard var translation = translationTable.retrieve(for: key.key) else {
214-
throw Errors.missingKey(key.key, currentLocale.tag)
219+
guard var translation = translationTable.retrieve(for: string.key.value) else {
220+
throw Errors.missingKey(string.key.value, currentLocale.tag)
215221
}
216222

217-
if let interpolation = key.interpolation {
223+
if let interpolation = string.key.interpolation {
218224
interpolate(arguments: interpolation, to: &translation, for: currentLocale)
219225
}
220226

@@ -224,17 +230,16 @@ public class Localization {
224230

225231
for translationTable in translationTables {
226232

227-
if var translation = translationTable.retrieve(for: key.key) {
233+
if var translation = translationTable.retrieve(for: string.key.value) {
228234

229-
if let interpolation = key.interpolation {
235+
if let interpolation = string.key.interpolation {
230236
interpolate(arguments: interpolation, to: &translation, for: currentLocale)
231237
}
232238

233239
return translation
234240
}
235241
}
236242

237-
throw Errors.missingKey(key.key, currentLocale.tag)
243+
throw Errors.missingKey(string.key.value, currentLocale.tag)
238244
}
239245
}
240-
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Foundation
2+
3+
/// A type thats holds the information for the localization
4+
@_documentation(visibility: internal)
5+
public struct LocalizedString: Content {
6+
7+
/// The key of the translation value
8+
internal let key: LocalizedStringKey
9+
10+
/// The name of the translation table
11+
internal let table: String?
12+
13+
/// Initializes a localized string with context
14+
///
15+
/// - Parameters:
16+
/// - key: The string key to be translated
17+
/// - table: The table where the string key should be looked up. Default is nil.
18+
public init(key: LocalizedStringKey, table: String? = nil) {
19+
20+
self.key = key
21+
self.table = table
22+
}
23+
}

0 commit comments

Comments
 (0)