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

Overview

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

  • Pluralization support - Without using stringdict files
  • Length variations support - Supported since iOS 8.0 (instead of iOS 9.0 like system does) and avoids using stringsdict files
  • Expressions - inequality and regular expressions
  • Shared Expressions
  • Built-in Expressions
  • Works similarly to NSLocalizedString()
  • Uses JSON files to minimize boilerplate code
  • Comprehensive Unit Test Coverage
  • 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": "1 car",
	"ie:x=0": "no cars",
	"ie:x>1": "%d cars"
}

Inequality Extended Expressions

This is extended version of inequality expression. It is composed of 2 values, one value "marker" and two inequality signs.

  • iex: - prefix of inequality extended expression
  • x - place for number that will be matched. Works with Ints and floating point numbers.
  • Only < and <= are accepted.

Expample:

"tomatos": {
	"iex:2<x<10": "%d tomatos is between 2 and 10"
}

Regex Expressions

This is the most powerful type of expression. It takes regular expression ;)

  • exp: - prefix of regex expression
  • string - it takes string with regular expression

Example: (police cars in Polish language)

"police-cars": {
	"exp:^1$": "1 samochód policyjny",
	"exp:(((?!1).[2-4]{1})$)|(^[2-4]$)": "%d samochody policyjne",
	"exp:(.*(?=1).[0-9]$)|(^[05-9]$)|(.*(?!1).[0156789])": "%d samochodów policyjnych"
}

Powerful stuff, isn't it? :>

PS. There is built-in solution for Polish language so you can use it with doing just this:

"police-cars": {
	"one": "1 samochód policyjny",
	"few": "%d samochody policyjne",
	"many": "%d samochodów policyjnych"
}

This is called "Shared Built-In Expression" and is covered below.

Shared Expressions

Shared expressions are expressions available among all the localization files. They are declared in expressions.json file divided by language and you can use them in localization files.

The functionality allows developer to observance of DRY principle and to avoid mistakes that exist because of reapeating the code in many places.

Normally you declare expression like this:

...
"ie:x>1": "Localized String"
...

If you want to use the same expression in multiple files there is no necessity to repeat the expression elsewhere. This is even problematic when you decide to improve/change expression to handle another cases you forget about - you would have to change expression in multiple places. Because of that there are Shared Expression. These feature allows you to create expression just in one place and use identifier of it in multiple places where you normally should put this expression.

What you need to do is to create expressions.json file with following structure:

{
	"base": {
		"one": "ie:x>1"
	},

	"pl": {
		// ... other than "one" because "one" is available here too.
	}
}

Now in pl.json, en.json and so on you have to use it as below:

...
"one": "Localized String"
...

Before you decide to create your own expression take a look if there is no built-in one with the same name or whether there is such expression but named differently. Maybe you don't need to do this at all and just use it.

Built-in expressions

Built-in expressions as name suggest are shared expressions built into framework and available to use with zero configuration. They are separated by country and not all country have its own built-in expressions. For now there are e.g. Base built-in expressions and Polish built-in expressions. Base expressions are available in every country and there are very generic to match all countries pluralization/cardinal numbering logic.

List of supported built-in shared expressions:

Base (English fits to this completely)
- one - detects if number is equal 1
- >one - detects if number is greater than 1
- two - detects if number is equal 2
- other - detects if number is not 1, so 0, 2, 3 and so on.

Polish
- few - matches (2-4), (22-24), (32-4), ..., (..>22, ..>23, ..>24)
- many - matches 0, (5-9), (10-21), (25-31), ..., (..0, ..1, ..5-9)

As you can see polish has no "one", ">one", etc. because it inherits from Base by default.

Getting Started

This chapter shows you how to start using Swifternalization and how to intergrate it with your code.

Documentation

Documentation covers 100% of the code, Yay! There are two types of documentation. First covers only public API which is for those who only want to use the framework without looking inside. The second one covers all the API - public, internal and private.

You can find Public API and Full documentation with docset here in docs directory.

It is also hosted on my blog:

Docsets:

Installation

It works with iOS 8.0 and newer.

With CocoaPods:

pod 'Swifternalization', '~> 1.3.1'

If you are not using CocoaPods just import files from Swifternalization/Swifternalization directory to your project.

Swifternalization also supports Carthage.

Configuration - Optional

Before you get a first localized string you have to configure Swifternalization by passing to it the bundle where localized json files are placed. If you do not call configure() it will use NSBundle.mainBundle() by default internally.

It will get languages from bundle which was used to configure it. So, if it does not translate you string, please make sure that you added Localizations in Project > Info > Localizations section - the same place like for regular localizations.

I18n.configure(bundle) // if files are in another bundle

Creating file with Shared Expressions

Shared Expressions must be placed in expressions.json. Syntax of a file looks like below:

{
    "base": {
        "ten": "ie:x=10",
        ">20": "ie:x>20",
        "custom-pl-few": "exp:(.*(?=1).[0-9]$)|(^[05-9]$)|(.*(?!1).[0156789])"
    },

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

In pseudo-language:

{
	"language-1": {
		"shared-expression-key-1": "expression-1",
		"shared-expression-key-2": "expression-2"
	},

	"language-2": {
		"shared-expression-key-1": "expression-1"
	}
}

Expressions from the files may be used inside localizable files. All the shared expressions for different languages are placed in the same file because there will be just few expressions for every language. Mostly the expression will be defined in base variant because if expression is in base it is also available in every other language too. So, "ten" is available in "pl", but "three" is not available in "base".

Creating file with localization per country

Localizable file contains translations for specific language. The files might look like below:

{
    "welcome-key": "welcome",

    "cars": {
        "one": "one car",
        "ie:x>=2": "%d cars",
        "ie:x<=-2": "minus %d cars"
    }
}

Name of a file should be the same like country code. e.g. for English it is en.json, for Polish it is pl.json, for base localization it is base.json, etc.

There are few things that you can place in such files. More complex file will look like below:

{
	"welcome": "welcome",

	"cars": {
		"one": {
			"@100": "one car",
			"@200": "You have one car",
			"@400": "You have got one car"
		},

		"other": "%d cars"
	}
}

In pseudo-language:

{
	"key": "value",

	"key": {
		"expression-1": {
			"length-variation-1": "value-1",
			"length-variation-2": "value-2",
			"length-variation-3": "value-3"
		},

		"expression-2": "value"
	}
}

Getting localized string

Swifternalization allows you to work with its one class method which exposes all the methods you need to localize an app.

These methods have many optional paramters and you can omit them if you want. There are few common parameters:

  • key - A key of localized string.
  • fittingWidth - A width of a screen or place where you want to put a localized string. It is integer.
  • defaultValue - A value that will be returned if there is no localized string for a key passed to the method. If this is not specified then key is returned.
  • comment - A comment used just by developer to know a context of translation.

First method called localizedString(_:fittingWidth:defaultValue:comment:) allows you to get value for simple key without expression.

Examples:

I18n.localizedString("welcome")
I18n.localizedString("welcome", fittingWidth: 200)
I18n.localizedString("welcome", defaultValue: "Welcome", comment: "Displayed on app start")

Next method localizedString(_:stringValue:fittingWidth:defaultValue:comment:) allows you to get a localized string for string value that match an expression. Actually the string value will contain number inside in most cases or some other string that you would like to match.

I18n.localizedString("cars", stringValue: "5")
// Other cases similar to above example

The last method localizedString(_:intValue:fittingWidth:defaultValue:comment:) allows you to get a localized string for int value. This method calls the above one and just turn the int value into string because all the framework operates on strings.

I18n.localizedString("cars", intValue: 5)

Contribution

Swifternalization is open sourced so everyone may contribute if want to. If you want to develop it just fork the repo, do your work and create pull request. If you have some idea or question feel free to create issue and add proper tag for it.

There is no guide for contributors but if you added new functionality you must write unit tests for it.

Things to do in future releases

  • Add more built-in expressions for another countries.
  • Add support for float numbers in built in expressions that uses regular expressions.

LICENSE

Swifternalization is released under the MIT license.

Comments
  • New type of files for next Swifternalization to reduce boilerplate code

    New type of files for next Swifternalization to reduce boilerplate code

    I would like to decrease level of boilerplate code that people have to write. To do this I have to stop using .strings file and create own file types.

    I also would like to support new iOS 9 feature for string length variations described on my blog recently: http://szulctomasz.com/ios-strings-with-length-variations/

    I was playing with current Localizable.strings and Expressions.strings and tried to add support for string length variations and there was a lot of repeating identifiers everywhere. I sad "No, I don't want to do this even to my enemy! I want to keep it simple".

    And there you go. I started to thinking about new file type that will be loaded by framework and let's say "compiled" to check whether file is valid (has valid structure) and expressions and key-value pairs will be loaded.

    This is how "expressions" file look like for now. File contains group of expressions. Every group has name as language code, so: "pl", "en", "de", etc. The same names as Xcode is creating for .lproj directories.

    "base" {
        "one": "ie:x=1"
        "two": "ie:x=2"
        "more": "exp:(^[^1])|(^\\d{2,})" 
    }
    
    "pl" {
        "few": "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)"
    }
    

    And there is second file which contains key-value pairs for localization. Every file contains key-value pairs for specified language. You can e.g. have "base", "pl", "en", "de" files.

    Here is example for "base":

    /* 
    Displayed at welcome screen
    */
    "welcome": "welcome"
    
    /* 
    Displays string with number of cars
    1 car or X cars
    */
    "cars" {
        "one": "1 car"
        "ie:x=2": "2 cars"
        "more": "%d cars"
    }
    
    /*
    Forgot password sentence displayed on login form
    */
    "forgot-password" {
        @100: "Forgot Password? Help."
        @200: "Forgot Password? Get password Help."
        @300: "Forgotten Your Password? Get password Help."
    }
    
    /*
    Sentence about cars
    */
    "car-sentence" {
        "one" {
            @100: "one car"
            @200: "just one car"
            @300: "you've got just one car"
        }
    
        "more" {
            @100: "%d cars"
            @300: "you've got %d cars"
        }
    }
    

    The file can contain simple key-value pairs like "welcome" or extended one like "car-sentence".

    The "car-sentence" uses shared expressions like "one" and "more". And you can see there is also support for string length variations (100, 200, 300) which stand for: up to 100 width, up to 200 width, up to 300 width or bigger.

    I think this files looks nice and maintaining this will be easier than extended Localizable.strings. As you can see it also avoid using .stringsdict which I don't like a lot.

    The first questions are:

    • Is presented files content good? Is it easy to use for devs?
    • Can we improve the files a bit?

    I am thinking about loading it and parsing. I think I should implement some kind of compiler which will take a file and check whether it has correct structure/content and then will parse it and another part of framework will get expressions and key-value pairs from them.

    The question from me is: How to correctly and in some easy way at least for beginning check correctness of the files? What are popular approach when doing this?

    enhancement help wanted 
    opened by tomkowz 4
  • Inequality Expressions not working

    Inequality Expressions not working

    I have on my base.json:

    "post": { "ie:x=1": "1 post", "ie:x=0": "No posts", "ie:x>1": "%d posts" }

    then on the code:

    let localizedStr = Swifternalization.localizedString("post", intValue: postCount, fittingWidth: nil, defaultValue: "", comment: nil)

    and I get:

    "1 post", "No posts" but I get the literal "%d posts"

    opened by NSCabezon 2
  • Doesn't parse the label

    Doesn't parse the label "other"

    Hi tomkowz

    Could you help me with this issue?

    Here's the code to reproduce it:

    base.json

    "FollowRequest": {
        "one": "1 Follow Request",
        "other": "%d Follow Requests"
    }
    

    code inside ViewController:

        let string1 = I18n.localizedString("FollowRequest", intValue: 1)
        let stringOther = I18n.localizedString("FollowRequest", intValue: 34)
        print(string1)
        print(stringOther)
    

    code inside AppDelegate

    I18n.configure(NSBundle.mainBundle())

    The print results are as follows:

    1 Follow Request %d Follow Requests

    and the results are similar if you have any other language json files. Just the numbers are becoming %d

    It seems to me that the numbers are not parsed correctly, am I doing something wrong here?

    Many thanks

    opened by dumbfingers 2
  • Fix support for Swift2

    Fix support for Swift2

    Uses new instance methods advancedBy and distanceTo

    https://developer.apple.com/library/prerelease/ios/releasenotes/General/iOS81APIDiffs/modules/Swift.html

    Fixes #13

    opened by jlhonora 2
  • Swift4

    Swift4

    Hey @tomkowz ,

    I understand the swift3 branch never made it to master which is a shame. It'd be great if we can re-activate this project. It's a pretty awesome library and I would love it to go forward.

    About this pull request, you now have Swift 4 compatibility available + all the changes from swift3 branch.

    opened by TheCoordinator 1
  • UPDATE: Swift 2

    UPDATE: Swift 2

    in the meanwhile you can put this in the Podfile:

    pod 'Swifternalization', :git => "https://github.com/nykho/Swifternalization.git", :branch => "swift2"

    opened by nicarq 1
  • Swift2 branch not working on XCode 7.0

    Swift2 branch not working on XCode 7.0

    I'm facing issues using Swifternalization on XCode 7 with Cocoapods:

    screen shot 2015-09-22 at 5 11 11 pm

    Podfile:

    pod 'Swifternalization', git: 'https://github.com/tomkowz/Swifternalization.git', branch: 'swift2'
    

    Podfile.lock:

      Swifternalization:
        :commit: 8ab949ebd260709e23c23792c5cbfe20a10bbc1f
        :git: https://github.com/tomkowz/Swifternalization.git
    

    Which corresponds to the latest commit on the swift2 branch. Any hints on getting it to work? Thanks in advance, great lib.

    opened by jlhonora 1
  • Failing Travis CI builds

    Failing Travis CI builds

    I see that sometimes for the same commit Travis builds can pass and fail in the next moment. Is somebody familiar with this situation? On my local environment all is always passing when executing tests from the Terminal. Odd behaviour...

    help wanted 
    opened by tomkowz 1
  • Improve Inequality Extended Expressions

    Improve Inequality Extended Expressions

    I'm writing tests for floating point numbers support and noticed that framework could only support these kind of extended expressions:

    -10<x<5
    5.5<=x<=9.7
    4.3<x<=9
    5=x=10
    -20<x<-10
    

    There is no sense to keep support for e.g. -10<x>-20 because it can be rewritten to the last one from examples.

    enhancement 
    opened by tomkowz 0
  • Support floating point numbers

    Support floating point numbers

    Swifternalization should support expressions like:

    %d<10.14
    10.00<%d<99.99
    

    Also to simplify expressions and not check if value is Int or Float/Double change expression to these:

    x<10.4
    10<x<99.99
    
    enhancement 
    opened by tomkowz 0
  • Create documentation for the framework

    Create documentation for the framework

    I browsed the web today and found nice tool for generating documentation called Jazzy. I started working on documenting public, internal and private API to make it easy to understand, so also easy to extend in the future. After all is documented I'll push it to the repo and include link to the documentation in podspec file.

    You can find documentation in progress here on documentation branch.

    • [x] Add note about documentation to the master repo with link to it.

    Write documentation for:

    • [x] Expression
    • [x] ExpressionMatcher
    • [x] ExpressionParser
    • [x] InequalityExpressionMatcher
    • [x] InequalityExpressionParser
    • [x] InequalityExtendedExpressionMatcher
    • [x] InequalityExtendedExpressionParser
    • [x] InequalitySign
    • [x] InternalPatterns (Change name to InternalPattern) !!!
    • [x] KeyValue
    • [x] LocalizableFilesLoader
    • [x] Regex
    • [x] RegexExpressionMatcher
    • [x] RegexExpressionParser
    • [x] SharedBaseExpression
    • [x] SharedExpression
    • [x] SharedPolishExpression
    • [x] Swifternalization
    • [x] SharedExpressionsConfigurator
    • [x] TranslatablePair
    • [x] ValueType

    I am thinking how documentation should look like. Meaning, should it be only one version of documentation which cover public, internal and private classes, methods, enums, etc? Or would it be better to create one which contains entire framework and one just with public interface that will be used by people that want to just use the framework without looking what's going on inside? I think the latter is the better option.

    If this is the correct and best approach I would like to create following files structure:

    docs/framework/... docs/public/...

    Any advices, thoughts, comments?

    enhancement 
    opened by tomkowz 0
  • Allow supporting other preferred languages

    Allow supporting other preferred languages

    Instead of just using the first supported language, look at all the preferred ones, trying to return one for which the language file exists. And if we have none, just return the first one.

    This solves the problem where your project has localized something else in a region specific language, but still want to use the a general language (without region) for the base translations. For Example:

    • You localize fr-FR on one file that should be specific to France.
    • But you still want to use fr.json for the base translations.
    • This will try to grab fr-FR.json, but if it doesn't exist will use fr.json, assuming that is another supported language in your project.
    opened by paulrolfe 0
  • Xcode8 + Carthage

    Xcode8 + Carthage

    I try with latest version and compile process fail, see below details:

    ** BUILD FAILED **

    The following build commands failed: Check dependencies (1 failure) A shell task (/usr/bin/xcrun xcodebuild -project /Users/omarcafini/Documents/Code/ksenia-user/Carthage/Checkouts/Swifternalization/Swifternalization.xcodeproj -scheme Swifternalization -configuration Release -sdk iphoneos ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES clean build) failed with exit code 65: ** CLEAN FAILED **

    opened by OmarCaf 6
Releases(v1.4.0)
  • v1.3.2(Oct 21, 2016)

    Swift 3 is supported (#25) on swift3 branch only. No cocoapods available yet since I have issues with pushing podspec using trunk and Xcode8. Will try to solve a problem soon.

    Thank you @peymankh.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.1(Feb 13, 2016)

    • Avoid calling configure(bundle:) before using localized strings. Swifternalization will configure itself with NSBundle.mainBundle() internally if you do not call this method after localizedString... method is called #12
    • Suppressed several Xcode 7.3/Swift 3 warnings.
    Source code(tar.gz)
    Source code(zip)
  • v1.3(Nov 15, 2015)

  • v1.2(Aug 2, 2015)

    • Dropped Localizable.strings support and uses JSON files instead. See README file for details.
    • Added support for strings length variations that are supported in iOS 9 by the system. The framework has its own implementation and supports such feature in iOS 8.0 and newer.
    • Updated Public API and Framework documentations.
    • Code cleanup.
    Source code(tar.gz)
    Source code(zip)
  • v1.1(Jul 15, 2015)

    • Improved regular expressions. Now they work 4x faster.
    • Added support for floating point numbers! Now it is possible to use expressions like x<9.99, -3.5<x<99.4, etc.
    • Changed %d in expressions to just simple x since %d might be confusing when added support for floating point numbers.
    • Inequality extended expressions matches can work only with < and <= inequality signs. It has been simplified and other confusing cases with >, >= and = are unsupported now.
    • Fixed bug that might cause that inequality extended expression might not be validated correctly because of complications with using unsupported now inequality signs.
    • Removed ValueType enum. It is no longer needed after adding floating point numbers.
    • Updated docs
    • Framework on swift2 branch works with Xcode 7 beta 3.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2.1(Jun 30, 2015)

    • This is a minor update which includes documentation of the framework. It contains "Public API" and "Full" documentation. Go to README for details.
    • Pod version has been updated to v1.0.2.1 to add info about public docs.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Jun 29, 2015)

  • v1.0.1(Jun 29, 2015)

    • Swifternalization will not crash anymore when pattern cannot be parsed because it has incorrect format. Instead message is printed in the consol.
    • Swifternalization will not crash anymore when shared expression for some not defined key cannot be found. Will print message to the console instead.
    • Inequality and Inequality Extended expressions supports negative numbers
    • Add comment paramterer to match NSLocalizedString() macro and make it able to work with genstrings.
    • Fix many shared expression in SharedPolishExpression.
    • Fix typo in class name. TranslablePair to TranslatablePair.
    • More comments in the code.
    • Cleanup in the code.
    Source code(tar.gz)
    Source code(zip)
Owner
Tomasz Szulc
iOS/tvOS developer
Tomasz Szulc
Simple solution to localize your iOS App.

Hodor is a simple solution to localize your iOS App quickly, allow you to change language of project in-app without quiting the app, Just like WeChat.

Aufree 545 Dec 24, 2022
Localize your views directly in Interface Builder with IBLocalizable

Localize your views easily in Interface Builder with IBLocalizable. With IBLocalizable, you can localize your views in Interface Builder easily. Simpl

Chris Jimenez 461 Dec 29, 2022
Super lightweight library that helps you to localize strings, even directly in storyboards!

Translatio Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements iOS 9 or higher. Swi

Andrea Mario Lufino 19 Jan 29, 2022
Localization/I18n: Incrementally update/translate your Strings files from .swift, .h, .m(m), .storyboard or .xib files.

Installation • Configuration • Usage • Build Script • Donation • Migration Guides • Issues • Contributing • License BartyCrouch BartyCrouch incrementa

Flinesoft 1.3k Jan 1, 2023
Android/iOS Apps created to practice with different iOS/Android Tech. These apps were built to have similar feature sets using native Android/iOS.

AgilityFitTodayApp Android/iOS Apps created to practice with different iOS/Android Tech. These apps were built to have similar feature sets using nati

Lauren Yew 1 Feb 25, 2022
Check Localizable.strings files of iOS Apps

Rubustrings Check the format and consistency of the Localizable.strings files of iOS Apps with multi-language support Rubustrings is also available fo

David Cordero 110 Nov 12, 2022
Localizable.strings files generator

Localizable.strings files generator When we want to internationalize our project always is a headache to maintain the Localizable.strings files. This

humdrum 30 Dec 18, 2022
Localizations is an OS X app that manages your Xcode project localization files (.strings)

Localizations 0.2 Localizations is an OS X app that manages your Xcode project localization files (.strings). It focuses on keeping .strings files in

Arnaud Thiercelin 129 Jul 19, 2022
Lists missing keys from .strings files.

strings-check A simple command line utility to check if translation strings are missing, or if extra translations are present in a set of .strings fil

Dave Clayton-Wagner 3 Nov 22, 2022
Semi-automated Text Translator for Websites and Apps

macOS/Ubuntu/Windows: attranslate is a semi-automated tool for "synchronizing" translation-files. attranslate is optimized for fast and smooth rollout

Felix Kirchengast 272 Dec 21, 2022
Demo project of Swift language crash using Release build on iOS 14

Demo project of Swift language crash using Release build on iOS 14 Repro steps O

Daohan Chong 0 Mar 24, 2022
A micro framework for integrating with the Google Translate api

GoogleTranslateSwift About This is a micro library for integrating with the Google Cloud Translation API. I currently only use it for personal project

Daniel Saidi 7 Dec 19, 2022
Will Powell 1.2k Dec 29, 2022
iOS localization swift code generation project

code-gen-library - localization-swift module code-gen-library - localization-swift module with Python bash script execute to localization swift files(

umut boz 0 Oct 26, 2021
Crowdin iOS SDK delivers all new translations from Crowdin project to the application immediately

Crowdin iOS SDK Crowdin iOS SDK delivers all new translations from Crowdin project to the application immediately. So there is no need to update this

Crowdin 98 Dec 14, 2022
transai is a localization tool on Android and iOS.

transai transai is a command line tool to help you do Android and iOS translation management. You can extract string files to csv format, or generate

Jintin 56 Nov 12, 2022
iOS implementation of the Catrobat language

Catty Catty, also known as Pocket Code for iOS, is an on-device visual programming system for iPhones. Catrobat is a visual programming language and s

null 74 Dec 25, 2022
Swift friendly localization and i18n with in-app language switching

Localize-Swift Localize-Swift is a simple framework that improves i18n and localization in Swift iOS apps - providing cleaner syntax and in-app langua

Roy Marmelstein 2.9k Dec 29, 2022
NoOptionalInterpolation gets rid of "Optional(...)" and "nil" in Swift's string interpolation

NoOptionalInterpolation gets rid of "Optional(...)" and "nil" in Swift's string interpolation

Thanh Pham 48 Jun 5, 2022