Our iOS app is translated into 19 languages, and recently I found an issue where two buttons on a screen had the same title - which mean that users couldn't tell which to press!
I want to write a unit test that will check two NSLocalizedString keys in a particular locale, and make sure they don't collide.
How can I lookup the value of an NSLocalizedString in an arbitrary locale?
(For example, let's say I want to find the translated versions of "Delete" and "Remove", or something like that, and make sure those two translated strings aren't the same.)
(I'm guessing that the answer is going to involve something with Bundle?)
Here's the pseudocode of what I'm looking for:
class TranslationTest: XCTest {
func testNoTranslationCollision() {
let allLocales = // list of all supported locales in the app
allLocales.forEach { locale in
let translatedStringA = "Remove".asTranslatedIn(locale)
let translatedStringB = "Delete".asTranslatedIn(locale)
XCTAssertNotEqual(
translatedStringA,
translatedStringB,
"The translations for these different strings shouldn't be identical!"
)
}
}
}
Now in Xcode 11 you can define different configurations for each test with Test Plans. So define different configurations that each one launch the app with specific language. If specific language like persian not shown in Application Language, add its language code in Arguments Passed On Launch like this:
-AppleLanguages (en)
In Your case first you need to create an array of your supported language codes and traverse through array and set language and compare your strings
let stringA = NSLocalizedString("Remove",comment: "stringA")
let stringB = NSLocalizedString("Delete",comment: "stringB")
XCTAssertNotEqual(
stringA,
stringB,
"The translations for these different strings shouldn't be identical!"
)
Related
I have an app that is used to track/manage livestock. It currently supports one species, Sheep. We want to begin supporting multiple different species, like Goats, and Cattle. My first thought was to create something similar to NSLocalizedString(text, comment) like SpeciesString(text, species, comment) which would take the English string and the species name and translate the Sheep term Ram to the Cattle term Bull. And internal to that, I could use NSLocalizedString() to then further translate that to the proper language so that in the future I could support multiple languages as well.
I see that I can pass a tableName to NSLocalizedString() so that it will use a different file other than Localizeable.strings and that would allow me to programmatically pull values from a Spanish language file that is focused on Cattle instead of Sheep (something like Localizeable-sheep.strings and Localizeable-cattle.strings), but that won't help me with all of the text that is in the storyboard.
I know that there is built-in support for localization with the storyboard, but the problem I'm having is that when the text comes to my code, for example in viewDidLoad, it will already have been translated to the other language, for example Spanish. I would prefer to find a way to make the text in my views already have the right Language+Species combination by the time it gets to my code. But even if I did rely on programmatically swapping out the strings to use the right Species, the English will already been changed to Spanish and I'll get Carnero instead of Ram and if I try to pass that through to my SpeciesString() it won't match my underlying data, because my underlying data is keying off of the English version of the text.
Is there a way to create a custom language? I've seen this code that is used to change the localization language on the fly, and it works for swapping between en and es, but I can't create my own fake languages like en-sheep and es-sheep.
Is there either:
a) a way to create my own custom language so that the localization system will just pick my correct Language+Species combination?
or
b) a way to tell the Storyboard which table name/filename to pull strings from? So that instead of just having a strings file for my Main.storyboard be called es.lproj/Main.strings but I could instead have
es.lproj/Main-sheep.strings and es.lproj/Main-cattle.strings?
I think my inability to get my "custom language" to work was just an accidental oversight. I created an es-sheep.lproj/Main.strings and used the other SO post to programmatically set my language to es-sheep and it didn't seem to work...
... but it turned out that I had created those directories and files, but forgotten to add them to the project. Once I manually added them to the project, it started working and I was able to use my custom localizations.
I am currently working on an iOS app and localizing it into multiple languages but have faced an annoying (not breaking) issue.
When i would add a new localization for my storyboard xcode will automatically populate the strings, which is very nice. The issue i am having is that i have multiple interfaces which both have a back button. The text on these is of course the same and their translations are as well.
The question i was wondering about, is it possible, without using strings.localizable, to somehow merge multiple object translations into one?
This is how it would currently look:
"Pnu-Ec-HAj.normalTitle" = "Back";
"Rtx-fT-rdc.normalTitle" = "Back";
But it would be way easier if there was a syntax such as
"Pnu-Ec-HAj.normalTitle", "Rtx-fT-rdc.normalTitle" = "Back";
(this syntax is not correct obviously)
I have looked around quite a while but have not found any answers to this question yet.
Thanks for reading.
I'd recommend referencing every text in your storyboard in code, and setting the text on viewDidLoad like, e.g.:
buyButton.titleLabel.text = NSLocalizedString(#"SHOP_BUY_BUTTON_TEXT",#"Button for buying product in detail view");
It's loads of work if you have huge storyboards, but in the end you have a clean Localizable.strings with concise keys and comments, providing necessary context for your translators.
I prefix the key with the section of the app, so for example SHOP_***, USER_SETTINGS_***, etc.
In addition, we use a service like OneSky to organize our translations online and update them from the cloud (not affiliated with them, and it's not without its teething problems either).
Unfortunately the .strings files are key-value files and, by nature, there must be a key (that is composed by the nib ID of the element followed by the property) and the associated string value.
As Apple describes in the precedent link:
The standard strings file format consists of one or more key-value pairs along with optional comments. The key and value in a given pair are strings of text enclosed in double quotation marks and separated by an equal sign.
then, your idea is not supported by the .strings files.
The only way to support that feature is by using the NSLocalizedString in code.
With the iPhone 6s, Apple has introduced a new feature called "3D Touch". App developers are able to use this technology by using it within their apps or provide so-called UIApplicationShortcutItems on the home screen which appear when you 3D Touch the corresponding app icon. I've seen quite a few people out there who wanted to know how you would be able to localize those. Here's how.
What you have to do is, if you haven't already, create a new strings file called InfoPlist.strings, then you localize this strings file to the languages you wish via the File Inspector on the right.
Now, you write down a key (for example: ADD_ITEM_SHORTCUT_TITLE or ADD_ITEM_SHORTCUT_DESCRIPTION) and the correct translation for each localized file. For example:
English file:
ADD_ITEM_SHORTCUT_TITLE = "Add";
ADD_ITEM_SHORTCUT_DESCRIPTION = "a new item";
German file:
ADD_ITEM_SHORTCUT_TITLE = "Füge hinzu";
ADD_ITEM_SHORTCUT_DESCRIPTION = "ein neues Item";
Then, go to your Info.plist and enter your key to the corresponding field. For example:
That way, you get localized UIApplicationShortcutItems. Now, they look like this:
Phone language English:
Phone language German:
Here's the scenario. I have a set of settings in an app. For example consider my app as a video player. So there are settings like allow full screen, display subtitles etc. All these settings have boolean values since you either turn on or off them.
These settings should display inside the app in a table view. And if any of them are activated or when the user taps on them to activate/deactivate, you show it by setting the checkmark accessory view of that cell.
Since I need the settings to be displayed this way and only within the app, I cannot simply use Settings bundles. There's also another catch. I need these settings to be localized.
What I initially thought was to have separate plists for the languages I support.
Settings_en.plist (English)
Settings_sv.plist (Swedish)
Then fetch the plist name depending on the system language and display its values.
let filePath = NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent(NSLocalizedString("SETTINGS_PLIST", comment: ""))
But this is not ideal because say I'm running in Swedish and I change the Subtitles setting to on. Now i have to update this in both plists. This will quickly become even messier if I add more languages in the future.
Is there a better way to store settings which is easier to save and fetch and also supports localization?
I was able to find an answer elsewhere. Here are the steps taken to resolve this issue.
Instead of multiple plists, create one plist and have the keys in English language.
Then have the localized strings in your string files with the same English keys.
Localizable.strings (English)
FULL_SCREEN = "Full Screen";
SUBTITLES = "Subtitles";
Localizable.strings (Swedish)
FULL_SCREEN = "Helskärm";
SUBTITLES = "Undertexter";
In the code when you're displaying the values in a table view, refer to them by that key.
let setting = settings[indexPath.row] as [String: Bool]
let title = setting.keys.first
cell.textLabel?.text = NSLocalizedString(title!, comment: "")
My iOS application has language selection option.
Its a server based application that receives all the strings from server that are to be displayed in the app.
In one of the view, i've to convert text to "upper case", for that I'm using NSString's upperCaseString method. This is working good for English. But for other languages like French, Chinese, Russian, German etc, it might create problem. So, I've to use "uppercaseStringWithLocale" to provider appropriate upper case string.
My question is how to create the NSLocate and pass it to "upperCaseStringWithLocale" method based on the language name. I know what's the language of the app that user has selected. Can I create locale object based on language name.?
I think you are looking for:
NSString *theLocaleIdentifier = #"es_ES_PREEURO";
[[NSLocale alloc] initWithLocaleIdentifier:theLocaleIdentifier];