More-iOS國際化一站式解決方案

關(guān)于iOS開發(fā)中的國際化(也可稱為多語言)在網(wǎng)上的文章多如牛毛半夷,不過總結(jié)起來就那么一回事婆廊,不是說他們寫的不好我寫的多好,而是說過于零散巫橄。

現(xiàn)在淘邻,我將結(jié)合實(shí)際場(chǎng)景需求進(jìn)行國際化做法詳解∠婊唬可以肯定的是宾舅,Android的國際化做法大同小異,無非也就是各個(gè)語言版本的文件替換彩倚,我們先來分析下真實(shí)的需求是怎么一回事筹我。

國際化需求:

  1. 只提供English和Chinese Simplified兩種語言;
  2. App名稱跟隨系統(tǒng)語言變化帆离;
  3. 用戶首次打開app時(shí)蔬蕊,app的語言與系統(tǒng)語言保持一致(系統(tǒng)語言為非簡體中文,默認(rèn)app都是英文)用戶手動(dòng)更改語言之后哥谷,之后都記憶用戶選擇的語言岸夯;
  4. 用戶在App內(nèi)切換語言后,App本身所有文本信息全部替換成對(duì)應(yīng)語言们妥。

根據(jù)需求猜扮,我比較糾結(jié)的地方是,App的靜態(tài)文本數(shù)據(jù)可以存兩份在本地监婶,也就是English一份Chinese Simplified一份旅赢,但請(qǐng)求的API是同時(shí)返回兩份中英文數(shù)據(jù)or分中英文兩個(gè)接口齿桃?如果是要一個(gè)接口同時(shí)返回了中英文兩份數(shù)據(jù),顯然會(huì)加大數(shù)據(jù)包的大小煮盼,其次用戶很有可能從安裝App的那天開始就不再切換App語言源譬,甚至平均幾個(gè)星期才換一次,同時(shí)返回兩份數(shù)據(jù)是否多余孕似,但是這么做幾乎可以達(dá)到“無感知”數(shù)據(jù)源切換踩娘,相當(dāng)于是說,一旦用戶選擇好了要切換語言喉祭,“啪嗒”點(diǎn)了完成养渴,立馬pop掉當(dāng)前頁面,然后整個(gè)App的數(shù)據(jù)源中英文切換可以幾乎用“瞬間完成”來形容泛烙。

如果是分中英文兩個(gè)接口理卑,實(shí)際上就會(huì)出現(xiàn)微信在進(jìn)行語言切換時(shí)的loading菊花,因?yàn)橐匦吕∮⑽陌鏀?shù)據(jù)蔽氨,不過好處是可以減少上一種做法的數(shù)據(jù)包整體大小藐唠。這兩種做法我都有實(shí)踐過,如果你的App是非常固定鹉究,不會(huì)頻繁出現(xiàn)語言切換的需求宇立,那么可以使用第二種;如果App有一天之內(nèi)可能會(huì)頻繁切換多次語言的情況自赔,第一種無疑妈嘹。

經(jīng)過一番探討,雖然要供給拉美绍妨、北美和歐洲的同學(xué)使用润脸,但是不會(huì)出現(xiàn)頻繁切換語言的情況,所以他去,最終我們選擇了第二種解決方案毙驯。先來看一張最終成果gif圖,

image

從上圖中可以看到其實(shí)并沒有對(duì)數(shù)據(jù)源進(jìn)行切換灾测,因?yàn)楸邸!P惺T始帷:笈_(tái)沒寫完??。

不過也不影響我們的講解蛾号,首先稠项,明確一個(gè)概念,我們能夠做的國際化語言支持iOS系統(tǒng)中自帶的所有語言鲜结,只要你能在系統(tǒng)設(shè)置中找到的語言展运,就能夠?qū)δ愕腁pp做對(duì)應(yīng)版本的國際化適配活逆;其次,每對(duì)App適配一種語言拗胜,就要單創(chuàng)建出一個(gè)語言文件(要不然會(huì)引起沖突)蔗候。OK,我們正式進(jìn)入講解埂软。

首先創(chuàng)建一個(gè)工程

我起名為languageTest锈遥。

工程初始化

// AppDelegate.m

#import "navOneViewController.h"
#import "navTwoViewController.h"

@interface AppDelegate ()

@property (nonatomic, strong) UITabBarController *rootTabBar;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.rootTabBar = [[UITabBarController alloc]init];
    self.rootTabBar.delegate = (id)self;
    self.window.rootViewController = self.rootTabBar;
    [[UITabBar appearance] setBarTintColor:[UIColor whiteColor]];

    navOneViewController *navOneController = [navOneViewController new];
    UINavigationController *nav1 = [[UINavigationController alloc] initWithRootViewController:navOneController];
    nav1.title = @"首頁";

    navTwoViewController *navTwoController = [navTwoViewController new];
    UINavigationController *nav2 = [[UINavigationController alloc] initWithRootViewController:navTwoController];
    nav2.title = @"發(fā)現(xiàn)";

    self.rootTabBar.viewControllers = @[nav1, nav2];

    [self.window makeKeyAndVisible];

    return YES;
}

Appdelegate中,我們創(chuàng)建一個(gè)具備基本展示功能的tabBar及掛載在其之上的VC勘畔,

// navOneViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor blueColor];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 20)];
    [self.view addSubview:label];
    label.font = [UIFont systemFontOfSize:25];
    label.textColor = [UIColor whiteColor];
    label.text = @"這是首頁";

}


// navTwoViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor orangeColor];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 20)];
    [self.view addSubview:label];
    label.font = [UIFont systemFontOfSize:25];
    label.textColor = [UIColor whiteColor];
    label.text = @"這是發(fā)現(xiàn)";

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 100, 100)];
    [self.view addSubview:button];
    [button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
    button.backgroundColor = [UIColor blueColor];
    [button setTitle:@"改變語言" forState:UIControlStateNormal];

}

- (void)buttonClick {

}

在各自對(duì)應(yīng)的VC中寫下相關(guān)UI所灸,并預(yù)留相關(guān)Button點(diǎn)擊事件即可。

創(chuàng)建語言文件

創(chuàng)建路徑: file -> new -> file... -> String File炫七,文件名嚴(yán)格命名為——“Localizable”爬立,創(chuàng)建好該文件后,點(diǎn)擊該文件万哪,并打開Xcode的右邊功能區(qū)(不知道應(yīng)該叫啥)侠驯,在Localization功能區(qū)勾選語言版本,如果此時(shí)你并未看到或者只有English可選奕巍,我們需要到PROJECT -> info -> Localization吟策,添加需要的語言。

添加完成后伍绳,會(huì)在之前創(chuàng)建的Localization.string文件下看到多出來的語言文件踊挠,我選擇了English和Chinese Simplified≌Ч穑現(xiàn)在冲杀,我們已經(jīng)可以在對(duì)應(yīng)生成的語言文件中進(jìn)行需要多語言替換的字段編寫了。

// Localizable.string/English文件

"home" = "home";
"homeString" = "I'm home";

"discover" = "discover";
"discoverString" = "I'm discover";

"change" = "change";

// Localizable.string/Chinese(Simplified)文件

"home" = "首頁";
"homeString" = "我是首頁";

"discover" = "發(fā)現(xiàn)";
"discoverString" = "我是發(fā)現(xiàn)";

"change" = "改變語言";

并新建一個(gè)pch文件睹酌,pch文件同樣也是頭文件权谁,不過這是一個(gè)特殊頭文件,是一個(gè)預(yù)編譯文件憋沿,位于該文件中的所有內(nèi)容旺芽,能夠被其他所有源文件共享和訪問,相信你也看出來了辐啄,如果在pch文件中寫了大量的不是必須文件采章,則會(huì)延長編譯期時(shí)間,我們可以在.pch文件中放:

  1. 全局宏壶辜;
  2. 整個(gè)工程中都能用上的頭文件悯舟;
  3. 動(dòng)態(tài)更加當(dāng)前App運(yùn)行的環(huán)境切換相關(guān)宏(debug or release)。

因此砸民,我們需要?jiǎng)?chuàng)建一個(gè)pch文件去存放接下來要在整個(gè)工程中都要用到的判斷語言環(huán)境的中英文宏抵怎。創(chuàng)建一個(gè)pch文件的方式為奋救,file -> new -> file... -> 搜“pch”關(guān)鍵字,創(chuàng)建它反惕。

進(jìn)入工程配置 -> TARGET -> Build Settings -> 搜pch關(guān)鍵詞 -> 在“Apple LLVM 9.0 - Language”下的Prefix Header中尝艘,雙擊輸入你的.pch文件路徑,我寫的是$(SRCROOT)/PrefixHeader.pch姿染,填寫完畢背亥,回車,會(huì)看到生成的絕對(duì)路徑悬赏,確定pch文件路徑是否正確隘梨。一切都沒問題后,編譯通過即可舷嗡。

在pch文件中轴猎,寫入以下宏定義,
```objc
#define AppLanguage @"appLanguage"
#define PJLocalString(key) \
[[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults] objectForKey:@"appLanguage"]] ofType:@"lproj"]] localizedStringForKey:(key) value:@"" table:nil]

首先定義了一個(gè)AppLanguage宏进萄,推薦大家的命名更加多樣化一些捻脖,因?yàn)镺C并沒有namespace,如果我們的命名過于簡單中鼠,就會(huì)導(dǎo)致和Apple本身自定義的NSUserDefaults默認(rèn)值產(chǎn)生沖突可婶。

PJLocalString(key)這個(gè)宏“定義”了一個(gè)更長的方法,我們也都明確了一個(gè)概念援雇,在iOS中的每個(gè)國際化語言矛渴,就對(duì)應(yīng)著一個(gè)文件,這個(gè)文件就保存在App沙盒的根目錄中惫搏,我們要做的就是在某個(gè)時(shí)機(jī)替換系統(tǒng)所采用的語言文件即可具温,而PJLocalString(key)這個(gè)宏所做的事情,就是替換筐赔!先從NSUserDefaults中取出對(duì)應(yīng)的語言key(en還是zh-Hans)铣猩,根據(jù)語言key去索引到對(duì)應(yīng)的.lproj文件,最后把要替換的關(guān)鍵詞傳入茴丰,拋出找到的對(duì)應(yīng)值(我覺得找的這個(gè)過程用的結(jié)構(gòu)應(yīng)該不是hashmap达皿,真的很快。??)

多語言文件有了贿肩,宏也有了峦椰,那怎么用呢?舉個(gè)例子汰规!

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor blueColor];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 20)];
    [self.view addSubview:label];
    label.font = [UIFont systemFontOfSize:25];
    label.textColor = [UIColor whiteColor];
    label.text = PJLocalString(@"homeString");

}

只需要在多語言文字的地方調(diào)用PJLocalString()宏汤功,傳入對(duì)應(yīng)key即可。但是此時(shí)運(yùn)行工程控轿,會(huì)發(fā)現(xiàn)啥都沒了冤竹,是因?yàn)槲覀儾⑽磳?duì)NSUserDefaults中做當(dāng)前語言的設(shè)置拂封,這就導(dǎo)致了取出的值為nil。所以鹦蠕,還需要在AppDelegate文件中設(shè)置初始語言冒签,

if(![[NSUserDefaults standardUserDefaults] objectForKey:AppLanguage]){
        [[NSUserDefaults standardUserDefaults] setObject:@"zh-Hans" forKey:AppLanguage];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

這樣,我們即可完成第一次進(jìn)入App時(shí)初始化基礎(chǔ)語言钟病,如果我們想要實(shí)時(shí)更改呢萧恕?這就需要用到了通知,使用通知機(jī)制去給監(jiān)聽語言設(shè)置改變的監(jiān)聽者進(jìn)行相應(yīng)的處理肠阱,

// 給Appdelegate.m更新以下方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if(![[NSUserDefaults standardUserDefaults] objectForKey:AppLanguage]){
        [[NSUserDefaults standardUserDefaults] setObject:@"zh-Hans" forKey:AppLanguage];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.rootTabBar = [[UITabBarController alloc]init];
    self.rootTabBar.delegate = (id)self;
    self.window.rootViewController = self.rootTabBar;
    [[UITabBar appearance] setBarTintColor:[UIColor whiteColor]];

    navOneViewController *navOneController = [navOneViewController new];
    UINavigationController *nav1 = [[UINavigationController alloc] initWithRootViewController:navOneController];
    nav1.title = PJLocalString(@"home");

    navTwoViewController *navTwoController = [navTwoViewController new];
    UINavigationController *nav2 = [[UINavigationController alloc] initWithRootViewController:navTwoController];
    nav2.title = PJLocalString(@"discover");

    self.rootTabBar.viewControllers = @[nav1, nav2];

    // 新增監(jiān)聽方法
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeLanguage:) name:@"changeLanguage" object:nil];

    [self.window makeKeyAndVisible];

    return YES;
}

- (void)changeLanguage:(NSNotification *)notify {
    self.rootTabBar.viewControllers[0].tabBarItem.title = PJLocalString(@"home");
    self.rootTabBar.viewControllers[1].tabBarItem.title = PJLocalString(@"discover");
}


// navOneViewController.m更新以下方法

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor blueColor];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 20)];
    [self.view addSubview:label];
    label.font = [UIFont systemFontOfSize:25];
    label.textColor = [UIColor whiteColor];
    label.text = PJLocalString(@"homeString");

    // 新增監(jiān)聽方法
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeLanguage:) name:@"changeLanguage" object:nil];
}

- (void)changeLanguage:(NSNotification *)notify {
    self.label.text = PJLocalString(@"discoverString");
}


// navTwoViewController.m更新以下方法

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor orangeColor];

    self.label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 20)];
    [self.view addSubview:self.label];
    self.label.font = [UIFont systemFontOfSize:25];
    self.label.textColor = [UIColor whiteColor];
    self.label.text = PJLocalString(@"discoverString");

    self.button = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 100, 100)];
    [self.view addSubview:self.button];
    [self.button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
    self.button.backgroundColor = [UIColor blueColor];
    [self.button setTitle:PJLocalString(@"change") forState:UIControlStateNormal];

    // 新增監(jiān)聽方法
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeLanguage:) name:@"changeLanguage" object:nil];
}

- (void)changeLanguage:(NSNotification *)notify {
    self.label.text = PJLocalString(@"discoverString");
    [self.button setTitle:PJLocalString(@"change") forState:UIControlStateNormal];
}

- (void)buttonClick {
    [[NSUserDefaults standardUserDefaults] setObject:@"zh-Hans" forKey:AppLanguage];
    [[NSUserDefaults standardUserDefaults] synchronize];

    // 同步完NSUserDefault后票唆,發(fā)送語言更改通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"changeLanguage" object:nil];
}

編譯運(yùn)行吧,見證奇跡的時(shí)刻到了~點(diǎn)擊“更改語言”button屹徘,怎么樣走趋,是不是瞬間全都改過了。噪伊。??

但是現(xiàn)在只完成了第一和第四個(gè)需求簿煌,我們接著來完成第三個(gè)需求,“用戶首次打開app時(shí)鉴吹,app的語言與系統(tǒng)語言保持一致(系統(tǒng)語言為非簡體中文姨伟,默認(rèn)app都是英文)用戶手動(dòng)更改語言之后,之后都記憶用戶選擇的語言”豆励。

分析一下夺荒,該需求的重點(diǎn)在于用戶第一次打開App時(shí)整體App語言設(shè)置跟隨系統(tǒng)語言設(shè)置,非簡體中文之外的語言良蒸,都設(shè)置成英文技扼,因此,我們需要對(duì)AppDelegate.m文件進(jìn)行改造诚啃,


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // App第一次啟動(dòng)跟隨系統(tǒng)語言設(shè)置
    if(![[NSUserDefaults standardUserDefaults] boolForKey:@"firstLaunch"]){
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"firstLaunch"];
        NSArray *allLanguages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"];
        NSString *preferredLanguage = allLanguages[0];
        if([preferredLanguage rangeOfString:@"zh-Hans"].location != NSNotFound) {
            [[NSUserDefaults standardUserDefaults] setObject:@"zh-Hans" forKey:AppLanguage];
        } else {
            [[NSUserDefaults standardUserDefaults] setObject:@"en" forKey:AppLanguage];
        }
    }

    ........

接下來完成最后一個(gè)需求淮摔,把App的名稱也做國際化適配,如果你之前有過在info.plist文件中修改過App的名字始赎,我們現(xiàn)在要做的事情同樣也是改名字,而且是針對(duì)info.plist整個(gè)文件做國際化仔燕,同樣新建一個(gè)string file文件造垛,命名嚴(yán)格填寫為infoPlist.strings,并且在Xcode的右邊拓展欄中選擇Localizable晰搀,點(diǎn)擊生成English和Chinese Simplified多語言文件

// 在English中寫下
CFBundleName = "your english name";
CFBundleDisplayName = "your english name";


// 在Chinese Simplified中寫下
CFBundleName = "你的中文名";
CFBundleDisplayName = "你的中文名";

OK五辽,以上就是本篇文章所要表達(dá)的所有內(nèi)容,當(dāng)然這些都是demo級(jí)別的code外恕,如果此文對(duì)你有幫助杆逗,記得對(duì)其進(jìn)行多多改造乡翅!

demo地址:
https://github.com/windstormeye/iOSMorePractices/tree/master/languageTest

原文鏈接:pjhubs.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市罪郊,隨后出現(xiàn)的幾起案子蠕蚜,更是在濱河造成了極大的恐慌,老刑警劉巖悔橄,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靶累,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡癣疟,警方通過查閱死者的電腦和手機(jī)挣柬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來睛挚,“玉大人邪蛔,你說我怎么就攤上這事≡” “怎么了店溢?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長委乌。 經(jīng)常有香客問我床牧,道長,這世上最難降的妖魔是什么遭贸? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任戈咳,我火速辦了婚禮,結(jié)果婚禮上壕吹,老公的妹妹穿的比我還像新娘著蛙。我一直安慰自己,他們只是感情好耳贬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布踏堡。 她就那樣靜靜地躺著,像睡著了一般咒劲。 火紅的嫁衣襯著肌膚如雪顷蟆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天腐魂,我揣著相機(jī)與錄音帐偎,去河邊找鬼。 笑死蛔屹,一個(gè)胖子當(dāng)著我的面吹牛削樊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼漫贞,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼甸箱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起迅脐,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤芍殖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后仪际,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體围小,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年树碱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肯适。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡成榜,死狀恐怖框舔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赎婚,我是刑警寧澤刘绣,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站挣输,受9級(jí)特大地震影響纬凤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撩嚼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一停士、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧完丽,春花似錦恋技、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至聘鳞,卻和暖如春薄辅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搁痛。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工长搀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸡典。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像枪芒,于是被迫代替她去往敵國和親彻况。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谁尸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容