Skip to content

Commit f6e9b00

Browse files
committed
Merge pull request #190 from mac-cain13/feature/stringsdict
stringsdict support
2 parents ecffb7e + 4a2af9a commit f6e9b00

17 files changed

+1141
-256
lines changed

Documentation/Examples.md

+8
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ There are some points to keep in mind when using Color palettes, see [About Colo
7878
let welcomeMessage = NSLocalizedString("welcome.message", comment: "")
7979
let settingsTitle = NSLocalizedString("title", tableName: "Settings", comment: "")
8080

81+
// Formatted strings
8182
let welcomeName = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.currentLocale(), "Alice")
83+
84+
// Stringsdict files
85+
let progress = String(format: NSLocalizedString("copy.progress", comment: ""), locale: NSLocale.currentLocale(), 4, 23)
8286
```
8387

8488
*With R.swift*
@@ -87,7 +91,11 @@ let welcomeName = String(format: NSLocalizedString("welcome.withName", comment:
8791
let welcomeMessage = R.string.localizable.welcomeMessage()
8892
let settingsTitle = R.string.settings.title()
8993

94+
// Functions with parameters are generated for format strings
9095
let welcomeName = R.string.localizable.welcomeWithName("Alice")
96+
97+
// Functions with named argument labels are generated for stringsdict keys
98+
let progress = R.string.localizable.copyProgress(completed: 4, total: 23)
9199
```
92100

93101
## Storyboards

R.swift.xcodeproj/project.pbxproj

+24-12
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
5D45C2191CA12913000B8DC9 /* StringsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D997C941C7C291900B2F376 /* StringsGenerator.swift */; };
11-
5D45C21B1CA1294A000B8DC9 /* LocalizableStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D997C961C7C2BEE00B2F376 /* LocalizableStrings.swift */; };
1211
5D997C951C7C291900B2F376 /* StringsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D997C941C7C291900B2F376 /* StringsGenerator.swift */; };
13-
5D997C971C7C2BEE00B2F376 /* LocalizableStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D997C961C7C2BEE00B2F376 /* LocalizableStrings.swift */; };
1412
D5646DE41BE2016E0034F4D7 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5646DE11BE2016E0034F4D7 /* Extensions.swift */; };
1513
D5646DE51BE2016E0034F4D7 /* PBXObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5646DE21BE2016E0034F4D7 /* PBXObject.swift */; };
1614
D5646DE61BE2016E0034F4D7 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5646DE31BE2016E0034F4D7 /* Serialization.swift */; };
@@ -96,17 +94,22 @@
9694
D5F97E4C1C1819160066D7C0 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F97E411C1816360066D7C0 /* Image.swift */; };
9795
D5F97E4D1C1819160066D7C0 /* ResourceFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F97E431C1816790066D7C0 /* ResourceFile.swift */; };
9896
D5F97E4E1C1819160066D7C0 /* Nib.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F97E451C18169E0066D7C0 /* Nib.swift */; };
99-
E2156B8E1CC5254A00F341DC /* FormatSpecifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2156B8D1CC5254A00F341DC /* FormatSpecifier.swift */; };
100-
E2156B8F1CC5255000F341DC /* FormatSpecifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2156B8D1CC5254A00F341DC /* FormatSpecifier.swift */; };
97+
E2156B8E1CC5254A00F341DC /* StringParam.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2156B8D1CC5254A00F341DC /* StringParam.swift */; };
98+
E2156B8F1CC5255000F341DC /* StringParam.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2156B8D1CC5254A00F341DC /* StringParam.swift */; };
10199
E22D43631C9582CA00692FFF /* ColorGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22D43621C9582CA00692FFF /* ColorGenerator.swift */; };
102100
E22D43651C95845200692FFF /* ColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22D43641C95845200692FFF /* ColorPalette.swift */; };
101+
E241E4A11CD6545200F449E3 /* Unifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A918741CD4B61200394F6F /* Unifiable.swift */; };
103102
E24720CB1C96B6A600DF291D /* ColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22D43641C95845200692FFF /* ColorPalette.swift */; };
104103
E24720CC1C96B6AB00DF291D /* ColorGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22D43621C9582CA00692FFF /* ColorGenerator.swift */; };
104+
E2762AC71CCCEC2A0009BCAA /* Locale.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2762AC61CCCEC2A0009BCAA /* Locale.swift */; };
105+
E2762AC91CCCEE120009BCAA /* Locale.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2762AC61CCCEC2A0009BCAA /* Locale.swift */; };
106+
E2762ACF1CCD0B970009BCAA /* LocalizableStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2762ACE1CCD0B970009BCAA /* LocalizableStrings.swift */; };
107+
E2762AD01CCD0CF90009BCAA /* LocalizableStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2762ACE1CCD0B970009BCAA /* LocalizableStrings.swift */; };
108+
E2A918751CD4B61200394F6F /* Unifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A918741CD4B61200394F6F /* Unifiable.swift */; };
105109
/* End PBXBuildFile section */
106110

107111
/* Begin PBXFileReference section */
108112
5D997C941C7C291900B2F376 /* StringsGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringsGenerator.swift; sourceTree = "<group>"; };
109-
5D997C961C7C2BEE00B2F376 /* LocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizableStrings.swift; sourceTree = "<group>"; };
110113
D5646DE11BE2016E0034F4D7 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
111114
D5646DE21BE2016E0034F4D7 /* PBXObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXObject.swift; sourceTree = "<group>"; };
112115
D5646DE31BE2016E0034F4D7 /* Serialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Serialization.swift; sourceTree = "<group>"; };
@@ -153,9 +156,12 @@
153156
D5F97E411C1816360066D7C0 /* Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
154157
D5F97E431C1816790066D7C0 /* ResourceFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResourceFile.swift; sourceTree = "<group>"; };
155158
D5F97E451C18169E0066D7C0 /* Nib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Nib.swift; sourceTree = "<group>"; };
156-
E2156B8D1CC5254A00F341DC /* FormatSpecifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormatSpecifier.swift; sourceTree = "<group>"; };
159+
E2156B8D1CC5254A00F341DC /* StringParam.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringParam.swift; sourceTree = "<group>"; };
157160
E22D43621C9582CA00692FFF /* ColorGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorGenerator.swift; sourceTree = "<group>"; };
158161
E22D43641C95845200692FFF /* ColorPalette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPalette.swift; sourceTree = "<group>"; };
162+
E2762AC61CCCEC2A0009BCAA /* Locale.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Locale.swift; sourceTree = "<group>"; };
163+
E2762ACE1CCD0B970009BCAA /* LocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizableStrings.swift; sourceTree = "<group>"; };
164+
E2A918741CD4B61200394F6F /* Unifiable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unifiable.swift; sourceTree = "<group>"; };
159165
/* End PBXFileReference section */
160166

161167
/* Begin PBXFrameworksBuildPhase section */
@@ -279,14 +285,16 @@
279285
D5F97E3F1C1815E70066D7C0 /* AssetFolder.swift */,
280286
E22D43641C95845200692FFF /* ColorPalette.swift */,
281287
D5F97E391C1812AE0066D7C0 /* Font.swift */,
282-
E2156B8D1CC5254A00F341DC /* FormatSpecifier.swift */,
283288
D5F97E411C1816360066D7C0 /* Image.swift */,
284-
5D997C961C7C2BEE00B2F376 /* LocalizableStrings.swift */,
289+
E2762AC61CCCEC2A0009BCAA /* Locale.swift */,
290+
E2762ACE1CCD0B970009BCAA /* LocalizableStrings.swift */,
285291
D5F97E451C18169E0066D7C0 /* Nib.swift */,
286292
D5F97E431C1816790066D7C0 /* ResourceFile.swift */,
287293
D5F97E371C178A4F0066D7C0 /* Resources.swift */,
288294
D59F723E1C19651F0089767C /* ReusableContainer.swift */,
289295
D5F97E3B1C1813A70066D7C0 /* Storyboard.swift */,
296+
E2156B8D1CC5254A00F341DC /* StringParam.swift */,
297+
E2A918741CD4B61200394F6F /* Unifiable.swift */,
290298
D5B799781C19C082009EA901 /* WhiteListedExtensionsResourceType.swift */,
291299
D5F97E3D1C1815780066D7C0 /* Xcodeproj.swift */,
292300
);
@@ -421,9 +429,11 @@
421429
D5B799771C199755009EA901 /* StoryboardGenerator.swift in Sources */,
422430
D5B799811C1B0943009EA901 /* ErrorOutput.swift in Sources */,
423431
D5F12D431BDACB87009A2C88 /* ResourceGenerator.swift in Sources */,
432+
E2762AC91CCCEE120009BCAA /* Locale.swift in Sources */,
424433
D5F97E4A1C1819160066D7C0 /* Storyboard.swift in Sources */,
425434
5D45C2191CA12913000B8DC9 /* StringsGenerator.swift in Sources */,
426435
D5B129B21C3BA75A00A1C5FC /* Property.swift in Sources */,
436+
E2762AD01CCD0CF90009BCAA /* LocalizableStrings.swift in Sources */,
427437
D59F72401C19651F0089767C /* ReusableContainer.swift in Sources */,
428438
D5B799741C199755009EA901 /* ResourceFileGenerator.swift in Sources */,
429439
D5B799751C199755009EA901 /* ReuseIdentifierGenerator.swift in Sources */,
@@ -435,7 +445,6 @@
435445
D5F97E4B1C1819160066D7C0 /* AssetFolder.swift in Sources */,
436446
D5F12D421BDACB87009A2C88 /* input.swift in Sources */,
437447
D5F795C11BB9983900844EA2 /* MainTests.swift in Sources */,
438-
5D45C21B1CA1294A000B8DC9 /* LocalizableStrings.swift in Sources */,
439448
D59F723D1C1964B20089767C /* Typealias.swift in Sources */,
440449
D5F12D481BDACB8E009A2C88 /* XCProjectFile.swift in Sources */,
441450
D5B7998A1C1B91A9009EA901 /* Module.swift in Sources */,
@@ -448,10 +457,11 @@
448457
D586724A1C21FF7D00A760EC /* TypeSequenceProvider.swift in Sources */,
449458
D5F97E4E1C1819160066D7C0 /* Nib.swift in Sources */,
450459
D59F72311C19644F0089767C /* Function.swift in Sources */,
460+
E241E4A11CD6545200F449E3 /* Unifiable.swift in Sources */,
451461
D5B799721C199755009EA901 /* ImageGenerator.swift in Sources */,
452462
D5B7997A1C19C1BD009EA901 /* WhiteListedExtensionsResourceType.swift in Sources */,
453463
D59F722A1C1963EA0089767C /* Struct.swift in Sources */,
454-
E2156B8F1CC5255000F341DC /* FormatSpecifier.swift in Sources */,
464+
E2156B8F1CC5255000F341DC /* StringParam.swift in Sources */,
455465
D5A0A82E1C4793C20089ED2C /* TypePrinter.swift in Sources */,
456466
D5A0A82D1C4793C20089ED2C /* SwiftCodeConverible.swift in Sources */,
457467
D5B799731C199755009EA901 /* NibGenerator.swift in Sources */,
@@ -473,18 +483,21 @@
473483
files = (
474484
5D997C951C7C291900B2F376 /* StringsGenerator.swift in Sources */,
475485
D5B799831C1B8C78009EA901 /* Module.swift in Sources */,
476-
E2156B8E1CC5254A00F341DC /* FormatSpecifier.swift in Sources */,
486+
E2156B8E1CC5254A00F341DC /* StringParam.swift in Sources */,
477487
D5C5A8EF1BB7196000163E71 /* Core.swift in Sources */,
478488
D58672491C21FC9700A760EC /* TypeSequenceProvider.swift in Sources */,
479489
D5F97E461C18169E0066D7C0 /* Nib.swift in Sources */,
480490
D59F72391C1964950089767C /* Var.swift in Sources */,
481491
D5B7997F1C1B07EB009EA901 /* ErrorOutput.swift in Sources */,
492+
E2A918751CD4B61200394F6F /* Unifiable.swift in Sources */,
482493
D5B129B11C3BA65C00A1C5FC /* Property.swift in Sources */,
483494
E22D43651C95845200692FFF /* ColorPalette.swift in Sources */,
484495
D5F97E421C1816360066D7C0 /* Image.swift in Sources */,
485496
D56F923D1C29421600177FF7 /* TypeVar.swift in Sources */,
486497
D5B7996E1C19940F009EA901 /* ResourceFileGenerator.swift in Sources */,
498+
E2762ACF1CCD0B970009BCAA /* LocalizableStrings.swift in Sources */,
487499
D5F97E401C1815E70066D7C0 /* AssetFolder.swift in Sources */,
500+
E2762AC71CCCEC2A0009BCAA /* Locale.swift in Sources */,
488501
D5F97E3C1C1813A70066D7C0 /* Storyboard.swift in Sources */,
489502
D59F723C1C1964B20089767C /* Typealias.swift in Sources */,
490503
D5B799661C19939D009EA901 /* SegueGenerator.swift in Sources */,
@@ -508,7 +521,6 @@
508521
D5B7996A1C1993E3009EA901 /* NibGenerator.swift in Sources */,
509522
E22D43631C9582CA00692FFF /* ColorGenerator.swift in Sources */,
510523
D5646DE51BE2016E0034F4D7 /* PBXObject.swift in Sources */,
511-
5D997C971C7C2BEE00B2F376 /* LocalizableStrings.swift in Sources */,
512524
D56DC76D1C41758800623437 /* AccessModifier.swift in Sources */,
513525
D5B129AF1C3BA5F900A1C5FC /* Let.swift in Sources */,
514526
D5B7997D1C1B07C3009EA901 /* SanitizedSwiftName.swift in Sources */,

R.swift/Generators/StringsGenerator.swift

+38-33
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,17 @@ struct StringsGenerator: Generator {
5858

5959
// Ahem, this code is a bit of a mess. It might need cleaning up... ;-)
6060
// Maybe when we pick up this issue: https://github.com/mac-cain13/R.swift/issues/136
61-
private static func computeParams(filename: String, strings: [LocalizableStrings]) -> [StringValues]
62-
{
63-
var allParams: [String: [(Locale, String, [FormatSpecifier])]] = [:]
64-
let baseKeys = strings
65-
.filter { $0.locale.isBase }
66-
.map { Set($0.dictionary.keys) }
67-
.first
61+
private static func computeParams(filename: String, strings: [LocalizableStrings]) -> [StringValues] {
62+
63+
var allParams: [String: [(Locale, String, [StringParam])]] = [:]
64+
let baseKeys: Set<String>?
65+
let bases = strings.filter { $0.locale.isBase }
66+
if bases.isEmpty {
67+
baseKeys = nil
68+
}
69+
else {
70+
baseKeys = Set(bases.flatMap { $0.dictionary.keys })
71+
}
6872

6973
// Warnings about duplicates and empties
7074
for ls in strings {
@@ -85,23 +89,23 @@ struct StringsGenerator: Generator {
8589

8690
// Save uniques
8791
for key in groupedKeys.uniques {
88-
if let (value, params) = ls.dictionary[key] {
92+
if let (params, commentValue) = ls.dictionary[key] {
8993
if let _ = allParams[key] {
90-
allParams[key]?.append((ls.locale, value, params))
94+
allParams[key]?.append((ls.locale, commentValue, params))
9195
}
9296
else {
93-
allParams[key] = [(ls.locale, value, params)]
97+
allParams[key] = [(ls.locale, commentValue, params)]
9498
}
9599
}
96100
}
97101
}
98102

99103
// Warnings about missing translations
100-
for ls in strings {
101-
let filenameLocale = ls.locale.withFilename(filename)
104+
for (locale, lss) in strings.groupBy({ $0.locale }) {
105+
let filenameLocale = locale.withFilename(filename)
102106
let sourceKeys = baseKeys ?? Set(allParams.keys)
103107

104-
let missing = sourceKeys.subtract(ls.dictionary.keys)
108+
let missing = sourceKeys.subtract(lss.flatMap { $0.dictionary.keys })
105109

106110
if missing.isEmpty {
107111
continue
@@ -126,12 +130,12 @@ struct StringsGenerator: Generator {
126130
var badFormatSpecifiersKeys = Set<String>()
127131

128132
// Unify format specifiers
129-
for (key, params) in allParams.filter({ includeTranslation($0.0) }).sortBy({ $0.0 }) {
130-
var formatSpecifiers: [FormatSpecifier] = []
133+
for (key, keyParams) in allParams.filter({ includeTranslation($0.0) }).sortBy({ $0.0 }) {
134+
var params: [StringParam] = []
131135
var areCorrectFormatSpecifiers = true
132136

133-
for (locale, _, fs) in params {
134-
if fs.contains(FormatSpecifier.TopType) {
137+
for (locale, _, ps) in keyParams {
138+
if ps.any({ $0.spec == FormatSpecifier.TopType }) {
135139
let name = locale.withFilename(filename)
136140
warn("Skipping string \(key) in \(name), not all format specifiers are consecutive")
137141

@@ -141,13 +145,9 @@ struct StringsGenerator: Generator {
141145

142146
if !areCorrectFormatSpecifiers { continue }
143147

144-
for (_, _, fs) in params {
145-
let length = min(formatSpecifiers.count, fs.count)
146-
147-
if formatSpecifiers.prefix(length) == fs.prefix(length) {
148-
if fs.count > formatSpecifiers.count {
149-
formatSpecifiers = fs
150-
}
148+
for (_, _, ps) in keyParams {
149+
if let unified = params.unify(ps) {
150+
params = unified
151151
}
152152
else {
153153
badFormatSpecifiersKeys.insert(key)
@@ -158,8 +158,8 @@ struct StringsGenerator: Generator {
158158

159159
if !areCorrectFormatSpecifiers { continue }
160160

161-
let vals = params.map { ($0.0, $0.1) }
162-
let values = StringValues(key: key, params: formatSpecifiers, tableName: filename, values: vals )
161+
let vals = keyParams.map { ($0.0, $0.1) }
162+
let values = StringValues(key: key, params: params, tableName: filename, values: vals )
163163
results.append(values)
164164
}
165165

@@ -219,18 +219,23 @@ struct StringsGenerator: Generator {
219219

220220
private static func stringFunctionParams(values: StringValues) -> Function {
221221

222-
let params = values.params.enumerate().map { ix, formatSpecifier -> Function.Parameter in
223-
let name = "value\(ix + 1)"
222+
let params = values.params.enumerate().map { ix, param -> Function.Parameter in
223+
let valueName = "value\(ix + 1)"
224224

225-
if ix == 0 {
226-
return Function.Parameter(name: name, type: formatSpecifier.type)
225+
if let paramName = param.name {
226+
return Function.Parameter(name: paramName, localName: valueName, type: param.spec.type)
227227
}
228228
else {
229-
return Function.Parameter(name: "_", localName: name, type: formatSpecifier.type)
229+
if ix == 0 {
230+
return Function.Parameter(name: valueName, type: param.spec.type)
231+
}
232+
else {
233+
return Function.Parameter(name: "_", localName: valueName, type: param.spec.type)
234+
}
230235
}
231236
}
232237

233-
let args = params.enumerate().map { ix, _ in "value\(ix + 1)" }.joinWithSeparator(", ")
238+
let args = params.map { $0.localName ?? $0.name }.joinWithSeparator(", ")
234239

235240
return Function(
236241
comments: values.comments,
@@ -261,7 +266,7 @@ extension Locale {
261266

262267
private struct StringValues {
263268
let key: String
264-
let params: [FormatSpecifier]
269+
let params: [StringParam]
265270
let tableName: String
266271
let values: [(Locale, String)]
267272

0 commit comments

Comments
 (0)