Skip to content

Commit

Permalink
ISSUE-12 - Improved locale format handling to match RFC 5646
Browse files Browse the repository at this point in the history
- Updated README with instructions on how to migrate locale identifiers
- Added tests for locale validation
- Removed obsolete Swift 4 code (library has Swift 5 as minimum version)
  • Loading branch information
miroslavkovac committed Apr 6, 2022
1 parent e4b032f commit c6f6a80
Show file tree
Hide file tree
Showing 155 changed files with 249 additions and 304 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
</p>

<p align="center">
<img src="https://img.shields.io/badge/swift-5-brightgreen.svg" alt="swift 4"/>
<img src="https://img.shields.io/badge/swift-5-brightgreen.svg" alt="swift 5"/>
<img src="http://img.shields.io/badge/license-MIT-brightgreen.svg" alt="MIT License"/>
</p>

Expand All @@ -23,7 +23,7 @@
* **String interpolation**
* **Flexible data source** (read localizations from a JSON file, database or whatever suites your workflow the best)
* **Default locale** - if the localization for a requested locale is not available, it will fallback to the default one
* **Locale validation** - the library will warn you for using invalid locale identifiers (`en_fr` instead of `en_FR` etc.)
* **Locale validation** - the library will warn you for using invalid locale identifiers (`en-fr` instead of `en-FR` etc.)

## Setup

Expand All @@ -46,7 +46,7 @@ Add the dependency:
```swift
dependencies: [
...,
.Package(url: "https://github.com/miroslavkovac/Lingo.git", majorVersion: 3)
.Package(url: "https://github.com/miroslavkovac/Lingo.git", majorVersion: 4)
]
```

Expand All @@ -56,6 +56,12 @@ Create an instance of `Lingo` object passing the root directory path where the l
let lingo = try Lingo(rootPath: "path/to/localizations", defaultLocale: "en")
```

## Upgrading from version 3 to version 4

In the version 4 the format of locale identifiers was changed to match [RFC 5646](https://datatracker.ietf.org/doc/html/rfc5646). The version 3 used `_` to separate _language code_ and _country code_, and now the version 4 uses `-`.

If you were using any locales which include a country code, you would need to rename related translation files to match the new format.

## Usage

Use the following syntax for defining localizations in a JSON file:
Expand Down Expand Up @@ -115,9 +121,9 @@ print(unread24) // Will print: "You have 24 unread messages."
```

Each language contains custom pluralization rules that define which plural category should be used for which numeric value. Lingo currently implements rules for the following languages:
> ak, am, ar, az, be, bg, bh, bm, bn, bo, br, bs, by, ca, cs, cy, da, de\_AT, de\_CH, de\_DE, de, dz, el, en\_AU, en\_CA, en\_GB, en\_IN, en\_NZ, en, eo, es\_419, es\_AR, es\_CL, es\_CO, es\_CR, es\_EC, es\_ES, es\_MX, es\_NI, es\_PA, es\_PE, es\_US, es\_VE, es, et, eu, fa, ff, fi, fil, fr\_CA, fr\_CH, fr\_FR, fr, ga, gd, gl, guw, gv, he, hi\_IN, hi, hr, hsb, hu, id, ig, ii, it\_CH, it, iu, ja, jv, ka, kab, kde, kea, km, kn, ko, ksh, kw, lag, ln, lo, lt, lv, mg, mk, ml, mn, mo, mr\_IN, ms, mt, my, naq, nb, ne, nl, nn, nso, or, pa, pl, pt, pt_BR, ro, root, ru, sah, se, ses, sg, sh, shi, sk, sl, sma, smi, smj, smn, sms, sr, sv\_SE, sv, sw, th, ti, tl, to, tr, tzm, uk, ur, vi, wa, wo, yo, zh\_CN, zh\_HK, zh\_TW, zh\_YUE, zh
> ak, am, ar, az, be, bg, bm, bn, bo, br, bs, ca, cs, cy, da, de\-AT, de\-CH, de\-DE, de, dz, el, en\-AU, en\-CA, en\-GB, en\-IN, en\-NZ, en, eo, es\-419, es\-AR, es\-CL, es\-CO, es\-CR, es\-EC, es\-ES, es\-MX, es\-NI, es\-PA, es\-PE, es\-US, es\-VE, es, et, eu, fa, ff, fi, fil, fr\-CA, fr\-CH, fr\-FR, fr, ga, gd, gl, gv, he, hi\-IN, hi, hr, hsb, hu, id, ig, ii, it\-CH, it, iu, ja, jv, ka, kab, kde, kea, km, kn, ko, ksh, kw, lag, ln, lo, lt, lv, mg, mk, ml, mn, mr\-IN, ms, mt, my, naq, nb, ne, nl, nn, nso, or, pa, pl, pt, pt-BR, ro, ru, sah, se, ses, sg, shi, sk, sl, smn, sr, sv\-SE, sv, sw, th, ti, to, tr, tzm, uk, ur, vi, wa, wo, yo, zh\-CN, zh\-HK, zh\-TW, zh
The origial seed of pluralization rules was translated from [Rails i18n](https://github.com/svenfuchs/rails-i18n/tree/master/rails/pluralization) into Swift.
The original seed of pluralization rules was translated from [Rails i18n](https://github.com/svenfuchs/rails-i18n/tree/master/rails/pluralization) into Swift.

## Performance

Expand Down
6 changes: 3 additions & 3 deletions Sources/Lingo/Lingo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ extension LocaleIdentifier {

/// Returns `true` if the locale identifier contains both, language and country code
var hasCountryCode: Bool {
return self.components(separatedBy: "_").count == 2
return self.components(separatedBy: "-").count == 2
}

/// Returns language code from the locale identifier string.
/// For locales which contains a country code (en_US, de_CH), the country code is removed.
/// For locales which contains a country code (en-US, de-CH), the country code is removed.
var languageCode: String {
let components = self.components(separatedBy: "_")
let components = self.components(separatedBy: "-")
return components.count == 2 ? components.first! : self
}

Expand Down
24 changes: 14 additions & 10 deletions Sources/Lingo/LocaleValidator.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import Foundation

class LocaleValidator {
final class LocaleValidator {

// On Linux `Locale.availableIdentifiers` throws an exception.
// Issue reported: https://bugs.swift.org/browse/SR-3634
// Pull request with fix: https://github.com/apple/swift-corelibs-foundation/pull/944
// This check can be removed when the changes are available in a new Swift version.
#if os(Linux)
private static let validLocaleIdentifiers = Set<String>()
#else
private static let validLocaleIdentifiers = Set(Locale.availableIdentifiers)
#endif
private static let validLocaleIdentifiers: Set<String> = {
/// Make sure locales are in the correct format as per [RFC 5646](https://datatracker.ietf.org/doc/html/rfc5646)
var correctedLocaleIdentifiers = Locale.availableIdentifiers.map { $0.replacingOccurrences(of: "_", with: "-") }

/// Append missing locales not by default included
correctedLocaleIdentifiers.append(contentsOf: [
"zh-CN",
"zh-HK",
"zh-TW"
])

return Set(correctedLocaleIdentifiers)
}()

/// Checks if given locale is present in Locale.availableIdentifiers
func validate(locale: LocaleIdentifier) -> Bool {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/LocalizationsModel.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class LocalizationsModel {
final class LocalizationsModel {

enum LocalizationResult {
case success(localization: String)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/ak.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class ak: OneWithZeroOther, PluralizationRule {
final class ak: OneWithZeroOther, PluralizationRule {

let locale: LocaleIdentifier = "ak"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/am.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class am: OneWithZeroOther, PluralizationRule {
final class am: OneWithZeroOther, PluralizationRule {

let locale: LocaleIdentifier = "am"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/ar.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class ar: PluralizationRule {
final class ar: PluralizationRule {

let locale: LocaleIdentifier = "ar"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/az.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class az: Other, PluralizationRule {
final class az: Other, PluralizationRule {

let locale: LocaleIdentifier = "az"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/be.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class be: EastSlavic, PluralizationRule {
final class be: EastSlavic, PluralizationRule {

let locale: LocaleIdentifier = "be"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/bg.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class bg: OneOther, PluralizationRule {
final class bg: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "bg"

Expand Down
7 changes: 0 additions & 7 deletions Sources/Lingo/Pluralization/Concrete/bh.swift

This file was deleted.

2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/bm.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class bm: Other, PluralizationRule {
final class bm: Other, PluralizationRule {

let locale: LocaleIdentifier = "bm"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/bn.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class bn: OneOther, PluralizationRule {
final class bn: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "bn"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/bo.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class bo: Other, PluralizationRule {
final class bo: Other, PluralizationRule {

let locale: LocaleIdentifier = "bo"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/br.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class br: PluralizationRule {
final class br: PluralizationRule {

let locale: LocaleIdentifier = "br"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/bs.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class bs: EastSlavic, PluralizationRule {
final class bs: EastSlavic, PluralizationRule {

let locale: LocaleIdentifier = "bs"

Expand Down
7 changes: 0 additions & 7 deletions Sources/Lingo/Pluralization/Concrete/by.swift

This file was deleted.

2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/ca.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class ca: OneOther, PluralizationRule {
final class ca: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "ca"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/cs.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class cs: WestSlavic, PluralizationRule {
final class cs: WestSlavic, PluralizationRule {

let locale: LocaleIdentifier = "cs"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/cy.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class cy: PluralizationRule {
final class cy: PluralizationRule {

let locale: LocaleIdentifier = "cy"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/da.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class da: OneOther, PluralizationRule {
final class da: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "da"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/de.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class de: OneOther, PluralizationRule {
final class de: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "de"

Expand Down
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/de_AT.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class de_AT: OneOther, PluralizationRule {
final class de_AT: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "de_AT"
let locale: LocaleIdentifier = "de-AT"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/de_CH.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class de_CH: OneOther, PluralizationRule {
final class de_CH: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "de_CH"
let locale: LocaleIdentifier = "de-CH"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/de_DE.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class de_DE: OneOther, PluralizationRule {
final class de_DE: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "de_DE"
let locale: LocaleIdentifier = "de-DE"

}
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/dz.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class dz: Other, PluralizationRule {
final class dz: Other, PluralizationRule {

let locale: LocaleIdentifier = "dz"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/el.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class el: OneOther, PluralizationRule {
final class el: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "el"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/en.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class en: OneOther, PluralizationRule {
final class en: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "en"

Expand Down
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/en_AU.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class en_AU: OneOther, PluralizationRule {
final class en_AU: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "en_AU"
let locale: LocaleIdentifier = "en-AU"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/en_CA.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class en_CA: OneOther, PluralizationRule {
final class en_CA: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "en_CA"
let locale: LocaleIdentifier = "en-CA"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/en_GB.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class en_GB: OneOther, PluralizationRule {
final class en_GB: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "en_GB"
let locale: LocaleIdentifier = "en-GB"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/en_IN.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class en_IN: OneOther, PluralizationRule {
final class en_IN: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "en_IN"
let locale: LocaleIdentifier = "en-IN"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/en_NZ.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class en_NZ: OneOther, PluralizationRule {
final class en_NZ: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "en_NZ"
let locale: LocaleIdentifier = "en-NZ"

}
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/eo.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class eo: OneOther, PluralizationRule {
final class eo: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "eo"

Expand Down
2 changes: 1 addition & 1 deletion Sources/Lingo/Pluralization/Concrete/es.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class es: OneOther, PluralizationRule {
final class es: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "es"

Expand Down
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/es_419.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class es_419: OneOther, PluralizationRule {
final class es_419: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "es_419"
let locale: LocaleIdentifier = "es-419"

}
4 changes: 2 additions & 2 deletions Sources/Lingo/Pluralization/Concrete/es_AR.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

class es_AR: OneOther, PluralizationRule {
final class es_AR: OneOther, PluralizationRule {

let locale: LocaleIdentifier = "es_AR"
let locale: LocaleIdentifier = "es-AR"

}
Loading

0 comments on commit c6f6a80

Please sign in to comment.