2017-05-18 100 views
2

由於某些政府指南(醫療與健康措辭),我目前正在幫助客戶需要更改其應用程序中的語言。他們的應用程序非常龐大,所有的字符串都包含在代碼中,即(stringWithFormat/hardcoded),它們都不在外部表中。這意味着這將是一項巨大的手動任務。NSString子類或包裝類或類別

在未來一個未定的時間點,客戶相信他們將獲得批准返回到他們當前的措辭,並希望將字符串切換回來。從字面上看,大部分的變化都是將一個有問題的單詞轉換成一個不太成問題的單詞。

我想,也許如果我可以在運行時基於bool開關更改字符串,它可能會消除所涉及的手動工作,並且可以讓我在需要時切換回語言。

第一次嘗試:

+ (instancetype)stringWithFormat:(NSString *)format, ... 
{ 
    va_list args; 
    va_start(args,format); 
    //todo check flag if we're changing the language 
    //todo replace problematic word from 'format' 
    NSString *result = [NSString stringWithFormat:format,args]; 

    return result; 
} 

我第一次迅速編寫了一個類別覆蓋stringWithFormat更換有問題的話。我忘了我會失去stringWithFormat的原始實現。這導致無盡的遞歸。

下一次嘗試(子類):

我開始試圖子類的NSString打了一個計算器後說,如果我的解決辦法是繼承一個類簇,那麼我沒有因爲繼承類簇明白我的問題幾乎從未完成。

最後一個選項(包裝):

我的最後一次嘗試是寫一個包裝類,但那種失敗的初衷是要求避免手動尋求在應用程序的每個字符串。

我不太確定如何解決這個問題了。如果我需要爲其中一個核心類添加/覆蓋功能,該怎麼辦?

+1

相關:有沒有什麼辦法猴補丁或調酒一個NSArray或其他類簇?](http://stackoverflow.com/q/11751473) –

回答

1

有一個更簡單的解決方案,看起來更合適。使用NSLocalizedString,用鍵而不是實際的字符串:

displayString *NSString = NSLocalizedString(@"displayString", nil); 
cancelButtonTitle *NSString = NSLocalizedString(@"cancelButtonTitle", nil); 

然後創建一個在您的應用程序一個Localizable.strings文件,並定義應顯示的實際值:

"displayString" = "The string to display in English" 
"cancelButtonTitle" = "Cancel" 

你把本地化。應用程序包中的字符串文件,應用程序使用它在運行時進行字符串替換。

您還可以爲不同的語言定義Localizable.strings的不同版本,例如,如果用戶已將其語言設置爲西班牙語,則調用NSLocalizedString()會爲您提供西班牙語版本。 (你已經提到過,NSString是一個類的集羣,這意味着它是一個公共接口,用於各種不同的私有子類,當你創建一個NSString時,你不能確定你得到的是哪個私有子類,這使得它是一個壞主意嘗試子類。)

1

對於硬編碼的字符串,你沒有別的辦法,只能通過將它們分配給某種類型的字符串轉換器類來手動修改它們。所以那些:

yourmom.text = @"Hi Mom"; 
yourdad.text = [NSString stringWithFormat:@"%@ and Dad!",yourmom.text]; 

你需要這些分配類型更改爲類似

yourmom.text = [StringConverter string:@"Hi Mom"]; 
yourdad.text = [StringConverter string:@"%@ and Dad!" placeHolder:yourmom.text]; 

至於在故事板或xibs字符串,可以在viewDidLoad中通過迭代循環改變它們。祝你好運。

1

你的第一次嘗試的想法沒有什麼錯,只是在執行過程中出現了一點小錯誤。更改:

NSString *result = [NSString stringWithFormat:format,args]; 

到:

NSString *result = [NSString alloc] initWithFormat:format arguments:args]; 

這是stringWithFormat:擴張和攔截將工作。

有關類集羣思想是在這種特殊情況下一個紅色的鯡魚,爲集羣(NSString)必須提供類的方法實現(+stringWithFormat:)前級,這樣你就可以用一個簡單的類來攔截他們。

然而,已經截獲+stringWithFormat:小心。一個簡單的測試會告訴你它被框架使用了很多,你不想破壞它們 - 因爲我的第一個簡單的測試是通過簡單地將「d」更改爲「c」,它將「window」更改爲「wincow」,這反過來打破了綁定設置的Xcode的默認應用程序綁定屬性「窗口」...

如果你正在改變健康相關的話你可能會好,整個字符串會更好。

一個更好的方法可能是簡單地編寫一個RE來匹配代碼中的所有文字字符串,並將其替換爲function(string)用於您編寫的某個函數(而不是方法)以執行轉換。

HTH

+0

然而,對於這個解決方案工作的大部分我遇到了一個障礙。 **由於未捕獲的異常'NSInvalidArgumentException'而終止應用程序,原因:'嘗試用appendString變異不可變對象:' 所以我做了這些更改,這是錯誤。與crashlytics /織物有關。所以你是對的......它確實打破了一些框架。 :D – Atomhax

+0

這是stringWithFormat還與NSMutableString一起使用,我只是從這個重寫的函數返回一個NSString?所以我需要改變實現來考慮Mutable Strings。 – Atomhax

+1

您是否嘗試過向'NSMutableString'添加類別?對打破框架的擔憂不是攔截*本身*,而是如何修改方法的*行爲*。我不會說替換這個方法是最好的方法,但它確實具有您似乎正在尋求的最小源代碼變更的好處。 – CRD