20

I have an iOS project that is localized into 16 languages. Only some words are not localized (Mainly those that go into an update and the localization office did not deliver in time). For my keys I do not use the english wording, as this can also change if a translator wishes. So now if I just don't have a translation for a language, if falls back to the key that I used. But as this key is not 'human readable' or at least not 'human enjoyable to read' this is a problem.

I did some research but couldn't find a solution to my exact problem. I have fe.:

Localizable.strings in en.lproj
@"Key1" = @"Value 1"
@"Key2" = @"Value 2"

Localizable.strings in de.lproj
@"Key1" = @"Wert 1"
// Note that @"Key2" is missing here in my de.lproj

I would expect that if I make NSLocalizedString(@"Key2", ...)
and am running on a german phone, it falls back to the english
translation for this key as it exists...

So for now i just copied the english translation into the missing Localizable.strings files. But this is a big hack! But also using the english words as keys seems to be a hack to me!

Is there any way to tell my app, that it should use f.e. english as the fallback if there is no value for a given key? I tried adding a base localization but this doesn't help...

Thanks a lot

Georg
  • 3,664
  • 3
  • 34
  • 75
  • "But also using the english words as keys seems to be a hack to me!" -- not at all. It's a pretty elegant solution, and exactly fixes the problem you're describing. Just because the translator might change the actual words used in the English translation, doesn't mean that the key has to change. That said, the new Base localization that Maxthon mentions is an even better approach most of the time. – Rob Napier Nov 28 '13 at 04:37
  • 2
    Using the word as a key is not an elegant solution. The key has to be unique. Imagine using the work "run" in English as the key. Depending on what you do this could be for example "løpe" og "kjøre" in Norwegian, or the imperative forms of those. There would have to be different keys for each meaning, not one key to cover them all because the English version is incidentally the same. – Hans Terje Bakke Aug 27 '21 at 10:35

4 Answers4

15

As far as I know, there's no "official" way to do it, but I have implemented functions such as this before:

NSString * L(NSString * translation_key) {
    NSString * s = NSLocalizedString(translation_key, nil);
    if (![[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:@"en"] && [s isEqualToString:translation_key]) {
        NSString * path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
        NSBundle * languageBundle = [NSBundle bundleWithPath:path];
        s = [languageBundle localizedStringForKey:translation_key value:@"" table:nil];
    }
    return s;
}

borrowed from: https://stackoverflow.com/a/8784451/1403046

Basically, instead of NSLocalizedString(), which will return the input string, this version will fallback to English if necessary.

Community
  • 1
  • 1
cjwirth
  • 2,015
  • 1
  • 15
  • 24
  • That sucks... :) The problem is if i use L(...) the genstrings (used by Linguan) will not find it... but thanks for your answer... if I will not get an other response that's better, I will accept yours soon. Cheers! – Georg Nov 25 '13 at 15:54
  • You can pass `-s` to genstrings to tell it what function you use instead of NSLocalizedString. – Rob Napier Nov 28 '13 at 04:34
6

Inspired by this and this, my Swift code version:

public func LS(_ key: String) -> String {
    let value = NSLocalizedString(key, comment: "")
    if value != key || NSLocale.preferredLanguages.first == "en" {
        return value
    }

    // Fall back to en
    guard
        let path = Bundle.main.path(forResource: "en", ofType: "lproj"),
        let bundle = Bundle(path: path)
        else { return value }
    return NSLocalizedString(key, bundle: bundle, comment: "")
}

Many developers expect an incomplete translation to fallback on the development language.. but that's not the way Apple choose to behave. I have a pseudocode to help better understand how Apple choose to fallback.

samwize
  • 25,675
  • 15
  • 141
  • 186
  • This solution is obviously WRONG because if key == value (what often happens with European languages) - it will always fall back to english – iago849 Aug 04 '21 at 07:36
  • @iago849 If you create the strings file in peculiar way, it will work. For en, the key is always the same as the value. So if the european language is "Foo" = "Foo", then it will fall back to en, which is also "Foo" = "Foo". While it is wrong to fallback to en, the result is correct. – samwize Aug 08 '21 at 14:52
0

For Swift project SwiftGen tool can be used. It generates string constants that will contain fallback strings from base localisation language. If a string key is not found in the localization file for currently selected language then the fallback string will be used.

Example of a generated constant for CommonTextClose localization key from Localizable.strings file:

internal static let commonTextClose = L10n.tr("Localizable", "CommonTextClose", fallback: "Close")
Igor Kulagin
  • 1,701
  • 15
  • 20
-7

You can use a Base localization and all unlocalized strings will be taken from this.

Maxthon Chan
  • 1,181
  • 8
  • 15
  • 8
    I did add a Base localization for my Localizable.strings but it is not taking the missing localizations from their... I was hoping it would do that, but it's not... Is there any setting I have to activate in Xcode? – Georg Nov 28 '13 at 08:34
  • It is not true. Or I miss something – jlmg5564 May 20 '15 at 17:31
  • No this does not help. [Base Internationalization](https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/InternationalizingYourUserInterface/InternationalizingYourUserInterface.html) simply let's you separate localizable strings from your xibs or storyboards into strings files which is surely a great help but doesn't solve anything here. – JonEasy Aug 07 '15 at 07:29
  • Read the Apple docs on Base Internationalization and you'll see this answer is completely wrong – Michael Sep 18 '17 at 22:14