2010-05-15 8 views
7

Mam zlokalizowane ciąg znaków, który musi wziąć kilka zmiennych. Jednak w lokalizacji ważne jest, aby kolejność zmiennych mogła zmieniać się z języka na język.Jak utworzyć sformatowany zlokalizowany ciąg?

Więc to nie jest dobry pomysł:

NSString *text = NSLocalizedString(@"My birthday is at %@ %@ in %@", nil); 

W niektórych językach niektóre słowa przychodzą przed ludźmi, podczas gdy w innych jest odwrotnie. W tej chwili brak mi dobrego przykładu.

Jak mogę podać zmienne NAMED w sformatowanym ciągu znaków? Czy jest jakiś sposób, aby to zrobić bez ciężkich, samodzielnie wykonanych zastępów smyczków? Nawet niektóre zmienne numerowane, takie jak {% @ 1}, {% @ 2} itd. Byłyby wystarczające ... czy istnieje rozwiązanie?

Odpowiedz

12

Dlatego NSLocalizedString przyjmuje dwa parametry. Użyj drugiego parametru, aby dołączyć komentarz opisujący znaczenie zmiennych w języku ojczystym. Następnie tłumacz może zmienić ich kolejność, korzystając z konstrukcji numeru $ +. Zobacz Apple's Notes for Localizers.

Jednak nie można pominąć parametrów w jednym języku. Na przykład, jeśli masz 3 parametry w języku angielskim i 4 w języku francuskim, a trzeci nie jest potrzebny w języku angielskim, nie można formatować jak %[email protected] %[email protected] and %[email protected]. Możesz pominąć tylko ostatnią.

3

Rozwiązałem to w projekcie kilka tygodni temu, tworząc własny prosty system szablonów z NSScanner. Metoda wykorzystuje system szablonów, który znajduje zmienne ze składnią ${name}. Zmienne są dostarczane do metody przez NSDictionary.

- (NSString *)localizedStringFromTemplateString:(NSString *)string variables:(NSDictionary *)variables { 
    NSMutableString *result = [NSMutableString string]; 
    // Create scanner with the localized string 
    NSScanner *scanner = [[NSScanner alloc] initWithString:NSLocalizedString(string, nil)]; 
    [scanner setCharactersToBeSkipped:nil]; 

    NSString *output; 

    while (![scanner isAtEnd]) { 
     output = NULL; 
     // Find ${variable} templates 
     if ([scanner scanUpToString:@"${" intoString:&output]) { 
      [result appendString:output]; 

      // Skip syntax 
      [scanner scanString:@"${" intoString:NULL]; 

      output = NULL; 

      if ([scanner scanUpToString:@"}" intoString:&output]) { 
       id variable = nil; 
       // Check for the variable 
       if ((variable = [variables objectForKey:output])) { 
        if ([variable isKindOfClass:[NSString class]]) { 
         // NSString, append 
         [result appendString:variable]; 
        } else if ([variable respondsToSelector:@selector(description)]) { 
         // Not a NSString, but can handle description, append 
         [result appendString:[variable description]]; 
        } 
       } else { 
        // Not found, localize the template key and append 
        [result appendString:NSLocalizedString(output, nil)]; 
       } 
       // Skip syntax 
       [scanner scanString:@"}" intoString:NULL]; 
      } 
     } 
    } 

    [scanner release]; 

    return result; 
} 

z plikiem Zlokalizuj wygląda tak:

"born message" = "I was born in ${birthYear} on a ${birthWeekDay}. ${byebye}"; 
"byebye"  = "Cheers!"; 

Możemy osiągnąć następujące wyniki ...

NSDictionary *variables = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1986], @"birthYear", @"monday", @"birthWeekDay", nil]; 
NSString *finalString [self localizedStringFromTemplateString:@"born message" variables:variables]; 
NSLog(@"%@", finalString); // "I was born in 1986 on a monday. Cheers!" 

Jak widać, dodałem kilka dodatkowych funkcjonalności także. Po pierwsze, wszelkie zmienne, które nie zostaną znalezione (${byebye} w moim przykładzie) zostaną zlokalizowane i dołączone do wyników. Zrobiłem to, ponieważ ładowałem w plikach HTML z mojego pakietu aplikacji i uruchamiam je metodą zlokalizowania (podczas tego nie lokalizuję łańcucha wejściowego podczas tworzenia skanera). Dodałem też możliwość wysyłania obiektów innych niż obiekty NSString, co zapewnia dodatkową elastyczność.

Kod ten może nie jest najlepiej realizujące lub najładniejszy napisane, ale spełnia swoje zadanie bez żadnych zauważalnych skutków wydajności :)

10

sformatowany zlokalizowane przykład wyrażenie:

NSString *today = [MyHandWatch today]; 
NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"Today is %@", @""), today]; 

genstrings będą generować tę linię w pliku Localizable.strings:

"Today is %@" = "Today is %@"; 
+0

to po prostu nie działa, to returnes ten sam ciąg – user2159978

+0

@ user2159978 Czy Naprawdę po prostu skopiuj ostatnią linię? OCZYWIŚCIE zwróci ten sam ciąg ... –