SkillAgentSearch skills...

Swifternalization

Localize iOS apps in a smarter way using JSON files. Swift framework.

Install / Use

/learn @tomkowz/Swifternalization
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Swifternalization: localize apps smarter

CocoaPods Status

Swifternalization

Swift library that helps in localizing apps in a different, better, simpler, more powerful way than system localization does. It uses json files instead of strings files.

Swift 3

Swift 3 compatible version is available on swift3 branch. No pod available yet, though. Encountering issue with code sign and xcode 8 during validating podspec. Will try to solve it.

Features

  • [x] Pluralization support - Without using stringdict files
  • [x] Length variations support - Supported since iOS 8.0 (instead of iOS 9.0 like system does) and avoids using stringsdict files
  • [x] Expressions - inequality and regular expressions
  • [x] Shared Expressions
  • [x] Built-in Expressions
  • [x] Works similarly to NSLocalizedString()
  • [x] Uses JSON files to minimize boilerplate code
  • [x] Comprehensive Unit Test Coverage
  • [x] Full documentation

Table of Contents

Introduction

Swifternalization helps in localizing apps in a smarter way. It has been created because of necessity to solve Polish language internalization problems but it is universal and works with every language very well.

It uses JSON files and expressions that avoid writing code to handle some cases that you have to write when not using this framework. It makes localizing process simpler.

Practical Usage Example

Description of practical usage example will use things that are covered later in the document so keep reading it to the end and then read about details/features presented here.

Problem

Let's assume the app supports English and Polish languages. Naturally app contains two Localizable.strings files. One is for Base localization which contains English translation and one is Polish language.

App displays label with information which says when object from the backend has been updated for the last time, e.g. "2 minutes ago", "3 hours ago", "1 minute ago", etc.

Analysis

The label displays number and a hour/minute/second word in singular or plural forms with "ago" suffix. Different languages handles pluralization/cardinal numbering in slight different ways. Here we need to support English and Polish languages.

In English there are just two cases to cover per hour/minute/second word:

  • 1 - "one second ago"
  • 0, 2, 3... "%d seconds ago"
  • Same with minutes and hours.

In Polish it is more tricky because the cardinal numbers are more complicated:

  • 1 - "jedną sekundę temu"
  • 0, (5 - 21) - "%d sekund temu"
  • (2 - 4), (22-24), (32-34), (42, 44), ..., (162-164), ... - "%d sekundy temu"
  • Same logic for minutes and hours.

Following chapters will present solution without and with Swifternalization framework. Each solution describes Base (English) and Polish localizations.

Here is a table with Language Plural Rules which covers cardinal forms of numbers in many languages - Many language handle plurality in their own way.

Solution without Swifternalization

Localizable.strings (Base)
--------------------------
"one-second" = "1 second ago";
"many-seconds" = "%d seconds ago";

"one-minute" = "1 minute ago";    
"many-minutes" = "%d minutes ago";

"one-hour" = "1 hour ago";
"many-hours" = "%d hours ago";

Localizable.strings (Polish)
-------------------------    	    	
"one-second" = "1 sekundę temu"
"few-seconds" = "%d sekundy temu"
"many-seconds" = "%d sekund temu""    	    	

"one-minute" = "1 minutę temu"
"few-minutes" = "%d minuty temu	"
"many-minutes" = "%d minut temu" 	    	

"one-hours" = "1 godzinę temu"
"few-hours" = "%d godziny temu"
"many-hours" = "%d godzin temu";

There are 6 cases in English and 9 cases in Polish. Notice that without additional logic we're not able to detect which version of a string for hour/minute/second the app should display. The logic differs among different languages. We would have to add some lines of code that handle the logic for all the languages we're using in the app. What if there are more than 2 languages? Don't even think about it - this might be not so easy.

The logic is already implemented in Swifternalization framework and it fits to every language.

Solution with Swifternalization

This is how localizable files will look:

base.json
---------
"time-seconds": {
    "one": "%d second ago"
    "other": "%d seconds ago"
},

"time-minutes": {
    "one": "%d minute ago"
    "other": "%d minutes ago"
},

"time-hours": {
    "one": "%d hours ago"
    "other": "%d hours ago"
}

pl.json
-------
"time-seconds": {
	"one": "1 sekundę temu",
	"few": "%d sekundy temu",
	"many": "%d sekund temu"
},

"time-minutes": {
	"one": "1 minutę temu",
	"few": "%d minuty temu",
	"many": "%d minut temu"
},

"time-hours": {
	"one": "1 godzinę temu",
	"few": "%d godziny temu",
	"many": "%d godzin temu"
}
  • "one", "few", "many", "other" - those are shared expressions already built into Swifternalization - covered below.
  • You can add own expressions to handle specific cases - covered below.

As mentioned the logic is implemented into framework so if you want to get one of a localized string you have to make a simple call.

Swifternalization.localizedString("time-seconds", intValue: 10)

or with I18n typealias (I-18-letters-n, Internalization):

I18n.localizedString("time-seconds", intValue: 10)

The key and intValue parameters are validated by loaded expressions and proper version of a string is returned - covered below.

Features

Pluralization

Swifternalization drops necessity of using stringdicts files like following one to support pluralization in localized strings. Instead of that you can simply define expressions that cover such cases.

<plist version="1.0">
    <dict>
        <key>%d file(s) remaining</key>
        <dict>
            <key>NSStringLocalizedFormatKey</key>
            <string>%#@files@</string>
            <key>files</key>
            <dict>
                <key>NSStringFormatSpecTypeKey</key>
                <string>NSStringPluralRuleType</string>
                <key>NSStringFormatValueTypeKey</key>
                <string>d</string>
                <key>one</key>
                <string>%d file remaining</string>
                <key>other</key>
                <string>%d files remaining</string>
            </dict>
        </dict>
    </dict>
</plist>

No more stringsdict files!

Length Variations

iOS 9 provides new way to select proper localized string variation depending on a screen width. It uses stringsdict file with NSStringVariableWidthRuleType key.

Swifternalization drops necessity of using such file and it is not necessary to use this new key to use the feature.

With Swifternalization this length variations feature is available since iOS 8.0 because the framework has its own implementation of length variations.

To use length variations feature your translation file should has entries like this:

base.json
---------
"forgot-password": {
	"@200": "Forgot Password? Help.",
	"@300": "Forgot Your Password? Use Help.",
	"@400": "Do not remember Your Password?" Use Help.""
}

The number after @ sign is max width of a screen or bounds that a string fits to. E.g. the second string will be returned if passed fitting width as a paramter is be greater than 200 and less or equal 300.

To get the second localized string the call looks like below:

I18n.localizedString("forgot-password", fittingWidth: 300) // 201 - 300

You can mix expressions with length variations. Following example shows it:

base.json
---------
"car": {
    "ie:x=1": {
        @100: "One car",
        @200: "You've got one car"
    },

    "more": "You've got few cars"
}

Expressions

There are few expression types. Every expression type has their own parser and matcher but they work internally so you don't need to worry about them.

There are 3 types of expressions:

  • inequality - handles simple inequalities like: x<3, x>10, x=5, x<=3, and so on. Work with integer and float numbers.
  • inequality extended - extended version of inequality with syntax like this: 2<x<10, 4<=x<6. Work with integer and float numbers.
  • regex - uses regular expression. This is the most powerful ;)

Inequality Expressions

It is composed of several elements:

  • ie: - prefix of inequality expression
  • x - you have to always pass it, this means here is the place for a number that will be matched. Works with Ints and floating point numbers.
  • <, <=, =, >=, > - use one of inequality signs
  • 1, 3, 5, 6, ... - value to match is the last one in this expression

Example:

"cars": {
	"ie:x=1":
View on GitHub
GitHub Stars574
CategoryDevelopment
Updated1mo ago
Forks46

Languages

Swift

Security Score

95/100

Audited on Feb 10, 2026

No findings