Skip to content

Commit

Permalink
Add SharedExpressionsLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
tomkowz committed Jul 26, 2015
1 parent eed66f3 commit 3208b88
Show file tree
Hide file tree
Showing 14 changed files with 223 additions and 56 deletions.
62 changes: 46 additions & 16 deletions Swifternalization.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ class SharedBaseExpression: SharedExpressionProtocol {
return [

/// Matches value equals 1.
SharedExpression(key: "one", pattern: "ie:x=1"),
SharedExpression(identifier: "one", pattern: "ie:x=1"),

/// Matches value greater than 1.
SharedExpression(key: ">one", pattern: "ie:x>1"),
SharedExpression(identifier: ">one", pattern: "ie:x>1"),

/// Matches value equals 2.
SharedExpression(key: "two", pattern: "ie:x=2"),
SharedExpression(identifier: "two", pattern: "ie:x=2"),

/// Matches value other than 1.
SharedExpression(key: "other", pattern: "exp:(^[^1])|(^\\d{2,})")
SharedExpression(identifier: "other", pattern: "exp:(^[^1])|(^\\d{2,})")
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SharedPolishExpression: SharedExpressionProtocol {
- 22 samochody, 1334 samochody, 53 samochody
- 2 minuty, 4 minuty, 23 minuty
*/
SharedExpression(key: "few", pattern: "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)"),
SharedExpression(identifier: "few", pattern: "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)"),

/**
0, (5-9), (10-21), (25-31), ..., (..0, ..1, ..5-9)
Expand All @@ -28,7 +28,7 @@ class SharedPolishExpression: SharedExpressionProtocol {
- 0 samochodów, 10 samochodów, 26 samochodów, 1147 samochodów
- 5 minut, 18 minut, 117 minut, 1009 minut
*/
SharedExpression(key: "many", pattern: "exp:(^[05-9]$)|(.*(?=1).[0-9]$)|(^[0-9]{1}.*[0156789]$)"),
SharedExpression(identifier: "many", pattern: "exp:(^[05-9]$)|(.*(?=1).[0-9]$)|(^[0-9]{1}.*[0156789]$)"),
]
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
//
// SharedExpression.swift
// ProcessableSharedExpression.swift
// Swifternalization
//
// Created by Tomasz Szulc on 28/06/15.
// Created by Tomasz Szulc on 26/07/15.
// Copyright (c) 2015 Tomasz Szulc. All rights reserved.
//

import Foundation

/**
Protocol that is implemented by classes that contains shared expressions.
Shared expressions are built-in expressions that user can easily use when
Protocol that is implemented by classes/structs that contains shared expressions.
Shared expressions are built-in expressions that user can easily use when
localizing app.

Rules: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
Expand All @@ -22,21 +23,16 @@ protocol SharedExpressionProtocol {
/**
Represents built-in expression and expressions from Expressions.strings file.
*/
struct SharedExpression {
/// Key of expression.
let key: Key
struct SharedExpression: ExpressionRepresentationType, ExpressionPatternType {
/// Identifier of expression.
let identifier: String

/// Pattern of expression.
let pattern: ExpressionPattern
let pattern: String

/**
Creates shared expression.

:param: key A key of expression.
:param: pattern A pattern of expression.
*/
init(key: Key, pattern: ExpressionPattern) {
self.key = key
/// Creates expression.
init(identifier: String, pattern: String) {
self.identifier = identifier
self.pattern = pattern
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation
/**
Used to load content from `expressions.json` file for specified language.
*/
final class ExpressionsLoader: JSONFileLoader {
final class SharedExpressionsLoader: JSONFileLoader {

/**
Loads expressions for specified language.
Expand All @@ -12,12 +12,12 @@ final class ExpressionsLoader: JSONFileLoader {

:returns: array of loaded expressions.
*/
class func loadExpressions(countryCode: CountryCode, bundle: NSBundle) -> [ProcessableExpression] {
var expressions = [ProcessableExpression]()
class func loadExpressions(countryCode: CountryCode, bundle: NSBundle) -> [SharedExpression] {
var expressions = [SharedExpression]()
if let json = self.load("expressions", bundle: bundle),
let expressionsDict = json[countryCode] as? Dictionary<String, String> {
for (identifier, pattern) in expressionsDict {
expressions.append(ProcessableExpression(identifier: identifier, pattern: pattern))
expressions.append(SharedExpression(identifier: identifier, pattern: pattern))
}
} else {
println("expressions.json file structure is incorrect.")
Expand Down
4 changes: 2 additions & 2 deletions Swifternalization/SharedExpressionsConfigurator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class SharedExpressionsConfigurator {
private class func convert(expressionsDict: KVDict) -> [SharedExpression] {
var result = [SharedExpression]()
for (key, pattern) in expressionsDict {
result.append(SharedExpression(key: key, pattern: pattern))
result.append(SharedExpression(identifier: key, pattern: pattern))
}
return result
}
Expand Down Expand Up @@ -117,7 +117,7 @@ class SharedExpressionsConfigurator {
*/
private class func mergeExpressions(var source: [SharedExpression], additional: [SharedExpression]) -> [SharedExpression] {
for additionalExp in additional {
if source.filter({$0.key == additionalExp.key}).first == nil {
if source.filter({$0.identifier == additionalExp.identifier}).first == nil {
source.append(additionalExp)
}
}
Expand Down
104 changes: 104 additions & 0 deletions Swifternalization/SharedExpressionsProcessor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// ExpressionsProcessor.swift
// Swifternalization
//
// Created by Tomasz Szulc on 26/07/15.
// Copyright (c) 2015 Tomasz Szulc. All rights reserved.
//

import Foundation

/**
Swifternalization contains some built-in country-related shared expressions.
Developer can create its own expressions in expressions.json file for
base and preferred languages.

The class is responsible for proper loading the built-in shared ones and
those loaded from project's files. It handles overriding of built-in and loads
those from Base and preferred language version.

It always load base expressions, then looking for language specific.
If in Base are some expressions that overrides built-ins, that's fine.
The class adds developer's custom expressions and adds only those of built-in
that are not contained in the Base.

The same is for preferred languages but also here what is important is that
at first preferred language file expressions are loaded, then if something
different is defined in Base it will be also loaded and then the built-in
expression that differs.
*/
class SharedExpressionsProcessor {

/**
Method takes expression for both Base and preferred language localizations
and also internally loads built-in expressions, combine them and returns
expressions for Base and prefered language.

:param: preferedLanguage A user device's language.
:param: preferedLanguageExpressions Expressions from expressions.json
:param: baseLanguageExpressions Expressions from base section of
expression.json.

:returns: array of shared expressions for Base and preferred language.
*/
class func processSharedExpression(preferedLanguage: CountryCode, preferedLanguageExpressions: [SharedExpression], baseLanguageExpressions: [SharedExpression]) -> [SharedExpression] {
/*
Get unique base expressions that are not presented in prefered language
expressions. Those from base will be used in a case when programmer
will ask for string localization and when there is no such expression
in prefered language section defined.

It means two things:
1. Programmer make this expression shared through prefered language
and this is good as base expression.
2. He forgot to define such expression for prefered language.
*/
var uniqueBaseExpressions = baseLanguageExpressions
if preferedLanguageExpressions.count > 0 {
uniqueBaseExpressions = baseLanguageExpressions.filter({
let pref = $0
return preferedLanguageExpressions.filter({$0.identifier == pref.identifier}).count == 0
})
}

// Expressions from json files.
var loadedExpressions = uniqueBaseExpressions + preferedLanguageExpressions


// Load prefered language nad base built-in expressions. Get unique.
let prefBuiltInExpressions = loadBuiltInExpressions(preferedLanguage)
let baseBuiltInExpressions = SharedBaseExpression.allExpressions()
let uniqueBaseBuiltInExpressions = baseBuiltInExpressions.filter({
let pref = $0
return prefBuiltInExpressions.filter({$0.identifier == pref.identifier}).count == 0
})

// Unique built-in expressions made of base + prefered language.
let builtInExpressions = uniqueBaseBuiltInExpressions + prefBuiltInExpressions

/*
To get it done we must get only unique built-in expressions that are not
in loaded expressions.
*/
let uniqueBuiltInExpressions = builtInExpressions.filter({
let builtIn = $0
return loadedExpressions.filter({$0.identifier == builtIn.identifier}).count == 0
})

return loadedExpressions + uniqueBuiltInExpressions
}

/**
Method loads built-in framework's built-in expressions for specific language.

:param: language A preferred user's language.
:returns: Shared expressions for specific language. If there is no
expression for passed language empty array is returned.
*/
private class func loadBuiltInExpressions(language: Language) -> [SharedExpression] {
switch language {
case "pl": return SharedPolishExpression.allExpressions()
default: return []
}
}
}
2 changes: 1 addition & 1 deletion Swifternalization/Swifternalization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public class Swifternalization {
for (tKey, tValue) in translatableDict {
// Check if there is expression in tKey
if let expressionPattern = Expression.parseExpressionPattern(tKey),
let sharedExpression = expressions.filter({$0.key == expressionPattern}).first,
let sharedExpression = expressions.filter({$0.identifier == expressionPattern}).first,
// Create expression with pattern from Expressions.strings and
// it it is correct use it.
let updatedExpression = Expression.expressionFromString("{" + sharedExpression.pattern + "}"),
Expand Down
13 changes: 13 additions & 0 deletions Swifternalization/TranslationsProcessor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// TranslationsProcessor.swift
// Swifternalization
//
// Created by Tomasz Szulc on 26/07/15.
// Copyright (c) 2015 Tomasz Szulc. All rights reserved.
//

import Foundation

class TranslationsProcessor {

}
8 changes: 4 additions & 4 deletions SwifternalizationTests/SharedBaseExpressionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import Swifternalization
class SharedBaseExpressionTests: XCTestCase {

func testOne() {
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.key == "one"}).first!
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.identifier == "one"}).first!
let expression = Expression(pattern: sharedExp.pattern)!

XCTAssertTrue(expression.validate("1"), "Should match 1")
XCTAssertFalse(expression.validate("2"), "Should not match 2")
}

func testMoreThanOne() {
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.key == ">one"}).first!
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.identifier == ">one"}).first!
let expression = Expression(pattern: sharedExp.pattern)!

XCTAssertTrue(expression.validate("2"), "Should match 2")
Expand All @@ -30,15 +30,15 @@ class SharedBaseExpressionTests: XCTestCase {
}

func testTwo() {
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.key == "two"}).first!
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.identifier == "two"}).first!
let expression = Expression(pattern: sharedExp.pattern)!

XCTAssertTrue(expression.validate("2"), "Should match 2")
XCTAssertFalse(expression.validate("1"), "Should not match 1")
}

func testOther() {
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.key == "other"}).first!
let sharedExp = SharedBaseExpression.allExpressions().filter({$0.identifier == "other"}).first!
let expression = Expression(pattern: sharedExp.pattern)!

XCTAssertTrue(expression.validate("0"), "Should match 0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@
import UIKit
import XCTest

class ExpressionsLoaderTests: XCTestCase {
class SharedExpressionsLoaderTests: XCTestCase {

func testShouldLoadBase() {
let content = ExpressionsLoader.loadExpressions("base", bundle: NSBundle.testBundle())
let content = SharedExpressionsLoader.loadExpressions("base", bundle: NSBundle.testBundle())
XCTAssertTrue(content.count > 0, "")
}

func testShouldLoadPL() {
let content = ExpressionsLoader.loadExpressions("pl", bundle: NSBundle.testBundle())
let content = SharedExpressionsLoader.loadExpressions("pl", bundle: NSBundle.testBundle())
XCTAssertTrue(content.count > 0, "")
}

func testShouldNotLoadDE() {
let content = ExpressionsLoader.loadExpressions("de", bundle: NSBundle.testBundle())
let content = SharedExpressionsLoader.loadExpressions("de", bundle: NSBundle.testBundle())
XCTAssertFalse(content.count > 0, "")
}
}
22 changes: 22 additions & 0 deletions SwifternalizationTests/SharedExpressionsProcessorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// SharedExpressionsProcessor.swift
// Swifternalization
//
// Created by Tomasz Szulc on 26/07/15.
// Copyright (c) 2015 Tomasz Szulc. All rights reserved.
//

import Foundation
import XCTest

class SharedExpressionsProcessorTests: XCTestCase {

func testThatAllExpressionsShouldBeLoadedCorreclty() {
let baseExpressions = SharedExpressionsLoader.loadExpressions("base", bundle: NSBundle.testBundle())
let preferedExpressions = SharedExpressionsLoader.loadExpressions("pl", bundle: NSBundle.testBundle())

let sharedExpressions = SharedExpressionsProcessor.processSharedExpression("pl", preferedLanguageExpressions: preferedExpressions, baseLanguageExpressions: baseExpressions)

XCTAssertEqual(sharedExpressions.count, 8, "")
}
}
4 changes: 2 additions & 2 deletions SwifternalizationTests/SharedPolishExpressionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import XCTest
class SharedPolishExpressionTests: XCTestCase {

func testFew() {
let sharedExp = SharedPolishExpression.allExpressions().filter({$0.key == "few"}).first!
let sharedExp = SharedPolishExpression.allExpressions().filter({$0.identifier == "few"}).first!
let expression = Expression(pattern: sharedExp.pattern)!

XCTAssertTrue(expression.validate("2"), "Should match 2")
Expand All @@ -27,7 +27,7 @@ class SharedPolishExpressionTests: XCTestCase {
}

func testMany() {
let sharedExp = SharedPolishExpression.allExpressions().filter({$0.key == "many"}).first!
let sharedExp = SharedPolishExpression.allExpressions().filter({$0.identifier == "many"}).first!
let expression = Expression(pattern: sharedExp.pattern)!

XCTAssertTrue(expression.validate("10"), "Should match 10")
Expand Down
4 changes: 3 additions & 1 deletion SwifternalizationTests/expressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
},

"pl": {
"few": "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)"
"few": "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)",
"two": "ie:x=2",
"three": "ie:x=3"
}
}

0 comments on commit 3208b88

Please sign in to comment.