https://github.com/steelkiwi/sklocalizable
Localization add-on for native iOS components
https://github.com/steelkiwi/sklocalizable
Last synced: 7 months ago
JSON representation
Localization add-on for native iOS components
- Host: GitHub
- URL: https://github.com/steelkiwi/sklocalizable
- Owner: steelkiwi
- License: mit
- Created: 2018-10-03T18:22:05.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2020-06-15T13:41:00.000Z (over 5 years ago)
- Last Synced: 2025-03-23T18:54:11.856Z (7 months ago)
- Language: Swift
- Size: 62.5 KB
- Stars: 8
- Watchers: 4
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# SKLocalizable
## Requirements
- iOS 9.0+
- Swift 4.1+
## 1. Installation
### 1.1 CocoaPods
```ruby
pod 'SKLocalizable', :git => "https://github.com/steelkiwi/SKLocalizable.git"
```
### 1.2 Swift Package Manager
Will be available later
### 1.3 Manually
Just copy `Sources` Folder to your Project
## 2. Usage
### 2.1 Localizable.strings
**Localizable.strings forming recommendations:**
```
/*
* 1. Group logic blocks to sections. Ex: Enums, Errors, Screens, etc
*
* 2. Section name format:
* // ======
* // 'MARK: - Section Name
* // ======
*
* 3. Separate subsections using 2 newlines and MARK
*
* 4. Lines format:
* /* *'/ - comment about string
* "Key" = "Value";
*
* Optional: 'Key' should contain name of screen and identifier (any number of words), separated with "." symbol
*
* 5. Parameters in strings should be named using format:
* $(ParameterNameKey) - it will be automatically replaced with value from passed dict while localization
* Avoid using parameters, wrapped in parameters syntax
* Example: $($(parameter)) - this won't be handled correctly
*
* 6. Localize plural numbers in Localizable.stringsdict
* How to use plural localization - https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html
* Plural rules - http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
*/
```
**Localizable.strings file example:**
```
// ======
// 'MARK: - Demo screen
// ======
// MARK - Language Buttons
/* Button, that switches to English language */
"DemoVC.LanguageButton.English" = "English";
/* Button, that switches to Russian language */
"DemoVC.LanguageButton.Russian" = "Русский";
// MARK - UI Components
/* Label, whose text value is set in the code */
"DemoVC.CodeLabel.Text" = "Label - Code";
/* Label, whose text value is set in the IB file */
"DemoVC.IBLabel.Text" = "Label - Storyboard";
/* Button, whose title value is set in the IB file */
"DemoVC.Button.Title" = "Button - Storyboard";
/* TextField, whose placeholder value is set in the IB file */
"DemoVC.TextField.Placeholder" = "TextField - Storyboard - Placeholder";
/* TextField, whose text value is set in the code */
"DemoVC.TextField.Text" = "TextField - Code - Text";
```
### 2.2 Localization File
`localizationFile` value is used for defining specific `.strings` file.
Default value is `nil`, so `Localizable.strings` file will be used
### 2.3 Localization Key
Use one of the described options for components localization:
- Set `localizationKey` in IB:

- Set `localizationKey` manually in code:
```swift
label.localizationKey = "DemoVC.CodeLabel.Text"
```
### 2.4 Localized Value
You can set localized value directly in code using String `localized` method:
```swift
/// Get self as key and return related localized value
///
/// - Parameter tableName: .strings file name
/// - Parameter bundle: language bundle, from where should be taken value. Default is Bundle.localiztion
/// - Parameter arguments: JSON, where:
/// - key - is key in localized string value from .strings file
/// - value - string, which will be used for replacing key in localized string
/// - Returns: localized value if found. Key (self) otherwise
public func localized(tableName: String? = nil, bundle: Bundle = .localization, arguments: Dictionary? = nil) -> String
```
Example:
`textField.text = "DemoVC.TextField.Text".localized()`
### 2.5 Localized Plural value
If you need to use plurals in your project, use String method `localizedPlural`:
```swift
/// Load formatted string value from tableName.stringsDict and paste arguments at corresponding places in format string
///
/// - Parameter tableName: .strings file name
/// - Parameter arguments: set of parameters, which should be use for plural replacement
public func localizedPlural(tableName: String? = nil, arguments: CVarArg...) -> String {
return String.localizedStringWithFormat(self.localized(tableName: tableName), arguments)
}
```
Example:
`Localizable.stringsdict` contains the following key:
```
Date.UnitPlural.Hour
NSStringLocalizedFormatKey
%#@hours@
hours
NSStringFormatSpecTypeKey
NSStringPluralRuleType
NSStringFormatValueTypeKey
d
one
%d hour
other
%d hours
```
Usage: `"Date.UnitPlural.Hour".localizedPlural(arguments: hoursIntValue)`
`Date.UnitPlural.Hour` will return "%d hour" string if `hoursIntValue` == 1 and "%d hours" otherwise. After that, value `hoursIntValue` will be inserted at `%d` place and we will receive "1 hour" / "5 hours" result string
Useful links about plurals:
- [How to use plural localization](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html)
- [Plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html)
### 2.6 NotificationCenter - `languageChanged` notification
For language changing use **Bundle.localization**. It's default value is .main
Setting new language: `Bundle.localization = Bundle.init(languageCode: languageCode)`, where `languageCode` is 2-symbol presentation of language. If you're not sure about code, you can take it from `.lproj` folder name after adding a new project language
When new value is set, `languageChanged`, notification will be send via `NotificationCenter.default`
Components with defined `localizationKey` will change their value automatically
You can also subscribe to `languageChanged` notification and handle this event manually:
```swift
NotificationCenter.default.addObserver(self, selector: #selector(languageChanged(_:)), name: .languageChanged, object: nil)
```
```swift
@objc
private func languageChanged(_ notification: Notification) {
// Manually set localized values
}
```
## 3. Components
`Localizable` protocol is just a list of required methods for localization. It isn't used directly because of external module.
`UIView` implement methods from `Localizable` protocol, so any of it's subclasses can expand localization functionality
### 3.1 Componentes, localized out of the box
There exist components that are already localized:
- UILabel - `text`
- UIButton - `title`
- UITextField - `placeholder`
- UIViewController - `title`
- UITabBarItem - `title`
- UIBarButtonItem - `title`
- UISearchBar - `placeholder`
All mentioned components implement required method `localize` in which they set localized text to corresponding property in a required way.
Example of UILabel implementation:
```swift
@objc
public override func localize() {
self.text = localizationKey?.localized(tableName: self.localizationFile)
}
```
Also this components overrides `localizationKey` property of `UIView`. The main purpose of this override - is make property `IBInspectable`
### 3.2 Localize Custom components
You can easily append `Localizable` behaviour to any custom component of yours
#### 3.2.1 Component is a subclass of `NSObject`
Just make an extension which will override `localize` method and will set localized value to corresponding field of your component. The only thing in this case is you should save `open` access modifier.
Example:
```swift
extension UIPickerView {
open override func localize() {
// Localization logic here
}
}
```
Also, you can add `IBInspectable` attributes to `localizationKey` or `localizationFile ` via overriding (check [UILabel+Localizable.swift](https://github.com/steelkiwi/SKLocalizable/blob/master/Sources/UIControls/UILabel+Localizable.swift) file for example)
#### 3.2.2 Component is a subclass of already localized component
Just override `localize` method. Saving `open` is not required.
Example:
```swift
class CustomButton: UIButton {
override func localize() {
// Localization logic here
}
}
```
#### 3.2.3 Component isn't a subclass of `NSObject`
In this case, you can duplicate [NSObject+Localizable.swift](https://github.com/steelkiwi/SKLocalizable/blob/master/Sources/NSObject+Localizable.swift) implementation for your class
## 4. FAQ
- **XCode error `Value of type .. has no member ..`**
It happens when module wasn't imported automatically. Just add `import SKLocalizable` to your project
- **How I can localize another native or mine custom component, except mentioned in #3.1?**
Please check item #3.2.
If you have localized native component, not available in #3.1 list, we will be very grateful if you make a Pull Request to with your add-on
- **I want to localize several properties of component. Do you have default solution?**
It's a pretty complex thing to handle automatically, so we don't.
You can use notification `.languageChanged` and implement this case manually
## License
SKLocalizable is released under the [MIT license](https://github.com/steelkiwi/SKLocalizable/blob/master/LICENSE)
Created by [Viktor Olesenko](https://github.com/OlesenkoViktor) on 03.10.18