Skip to content

Commit

Permalink
Merge pull request #33 from AckeeCZ/feature/formattedPlurals
Browse files Browse the repository at this point in the history
Formatted plurals
  • Loading branch information
LukasHromadnik authored Aug 30, 2022
2 parents 827978c + 459b61b commit 4cf85e7
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

## master

### Added
- Add support for formatted plurals ([#33](https://github.com/AckeeCZ/ACKLocalization/pull/33), kudos to @leinhauplk)

## 1.3.0

### Added
Expand Down
17 changes: 15 additions & 2 deletions Sources/ACKLocalizationCore/Model/PluralRuleWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,40 @@ struct PluralRuleWrapper {
}

extension PluralRuleWrapper: Codable {
private enum Constants {
static let stringFormatSpecifier = "%s"
}

func encode(to encoder: Encoder) throws {
// Since the stringDict is completely dynamic
// we cannot use some predefined `struct` to encapsulate the data.
// We need to use `CustomKey` that can take any string as a key.
var container = encoder.container(keyedBy: CustomKey.self)

// If the plural contains string format specifier, then use the positional arguments.
let containsStringSpecifier: Bool = translations.contains(where: {
$0.value.lowercased().contains(Constants.stringFormatSpecifier)
} )
let formatKey = containsStringSpecifier ? "%1$#@inner@" : "%#@inner@"

var items = [
// Mandatory key and the only option
"NSStringFormatSpecTypeKey": "NSStringPluralRuleType",
"NSStringFormatValueTypeKey": "d"
]

translations.forEach {
items[$0.key.rawValue] = $0.value
items[$0.key.rawValue] = $0.value.replacingOccurrences(
of: Constants.stringFormatSpecifier,
with: "%2$@"
)
}

// StringsDicts use variables by default.
// We need to specify the variable that is then
// replaced by the plural rule.
// In this case the variable is `inner` and it's hardcoded.
try container.encode("%#@inner@", forKey: .init(stringValue: "NSStringLocalizedFormatKey"))
try container.encode(formatKey, forKey: .init(stringValue: "NSStringLocalizedFormatKey"))
try container.encode(items, forKey: .init(stringValue: "inner"))
}
}
54 changes: 54 additions & 0 deletions Tests/ACKLocalizationCoreTests/ACKLocalization+Plurals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,58 @@ final class ACKLocalizationPluralsTests: XCTestCase {
XCTAssertEqual(error as? PluralError, PluralError.invalidPluralRule(rows[0].key))
}
}

func testPluralWithStringFormatSpecifier() throws {
// Given
let rows = [
LocRow(key: "key##{many}", value: "%d many"),
]

let expectedResult: [String: Encodable] = [
"NSStringLocalizedFormatKey": "%#@inner@",
"inner": [
"NSStringFormatSpecTypeKey": "NSStringPluralRuleType",
"NSStringFormatValueTypeKey": "d",
"many": "%d many"
]
]
let expectedResultEncoded = try JSONSerialization
.data(withJSONObject: expectedResult, options: .sortedKeys)

// When
let plurals = try ackLocalization.buildPlurals(from: rows)
let encoder = JSONEncoder()
encoder.outputFormatting = .sortedKeys
let encodedData = try encoder.encode(plurals.first?.value)

// Then
XCTAssertEqual(encodedData, expectedResultEncoded)
}

func testPluralWithIntegerFormatSpecifier() throws {
// Given
let rows = [
LocRow(key: "key##{many}", value: "%s many"),
]

let expectedResult: [String: Encodable] = [
"NSStringLocalizedFormatKey": "%1$#@inner@",
"inner": [
"NSStringFormatSpecTypeKey": "NSStringPluralRuleType",
"NSStringFormatValueTypeKey": "d",
"many": "%2$@ many"
]
]
let expectedResultEncoded = try JSONSerialization
.data(withJSONObject: expectedResult, options: .sortedKeys)

// When
let plurals = try ackLocalization.buildPlurals(from: rows)
let encoder = JSONEncoder()
encoder.outputFormatting = .sortedKeys
let encodedData = try encoder.encode(plurals.first?.value)

// Then
XCTAssertEqual(encodedData, expectedResultEncoded)
}
}

0 comments on commit 4cf85e7

Please sign in to comment.