欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS文本的多語(yǔ)言適配以及實(shí)踐指南

 更新時(shí)間:2021年09月08日 15:39:37   作者:呂洪陽(yáng)、趙杰  
項(xiàng)目開(kāi)發(fā)中考慮到不同國(guó)家的用戶,不同國(guó)家的語(yǔ)言,因而在APP里面做了多語(yǔ)言,所以下面這篇文章主要給大家介紹了關(guān)于iOS文本的多語(yǔ)言適配以及實(shí)踐的相關(guān)資料,需要的朋友可以參考下

背景

產(chǎn)品被多個(gè)國(guó)家使用,產(chǎn)品方希望產(chǎn)品擁有更好的多語(yǔ)言使用體驗(yàn),所以設(shè)計(jì)師提供多種字體來(lái)適配指定的語(yǔ)言?;谝陨媳尘埃蛻舳诵枰焖俳o出解決方案并且上線。

字體包的多語(yǔ)言適配和實(shí)踐

需求分析

首先,在了解產(chǎn)品需求和設(shè)計(jì)方案之后,結(jié)合業(yè)務(wù)研發(fā)人員的痛點(diǎn),整理出以下需求。

產(chǎn)品和設(shè)計(jì)的需求

  • 不同語(yǔ)言,對(duì)應(yīng)字體包不相同。
  • 全局字體默認(rèn)使用設(shè)計(jì)師指定的字體包。
  • 某些語(yǔ)言的字體包缺少某些字重版本,要求降級(jí)使用下一個(gè)字重版本。
  • 存在某些特殊文案不使用全局字體包(例如:中文,它有專(zhuān)屬的字體包,和語(yǔ)言環(huán)境無(wú)關(guān))。
  • 產(chǎn)品迭代需要快速支持?jǐn)U展,盡量減少研發(fā)投入成本。

設(shè)計(jì)師要求的字體包資源

研發(fā)的痛點(diǎn)和需求

  • 存在公用組件(其他業(yè)務(wù)線都在使用,伴魚(yú)公共業(yè)務(wù)組件目前有50+),不能修改通用組件。
  • 僅殼工程支持且依賴字體包。
  • 字體包資源來(lái)源方式要靈活。

總結(jié)一下,產(chǎn)品和設(shè)計(jì)的需求強(qiáng)調(diào)字體適配的全局性、多樣性、可擴(kuò)展性,研發(fā)關(guān)心的是解耦、職責(zé)單一、靈活性。

技術(shù)設(shè)計(jì)

分析過(guò)后,先確定技術(shù)框架的分層。

垂直分層和水平模塊

如圖所示分3層,1.基礎(chǔ)組件提供核心實(shí)現(xiàn),并支持需求擴(kuò)展 2.業(yè)務(wù)組件(無(wú)相關(guān)修改)3.殼工程提供資源包和代理者。

FontPackage組件要負(fù)責(zé)什么?

  • FontPackageManager,負(fù)責(zé)綁定代理來(lái)獲取資源包,控制流程邏輯。
  • FontPackageExtension,負(fù)責(zé)AOP,增加文本屬性來(lái)滿足特殊場(chǎng)景的多樣性。
  • FontPackageModel,映射字體包資源的配置信息,明確了使用協(xié)議。上層業(yè)務(wù)可以增加和調(diào)整參數(shù)來(lái)配置字體包資源。

殼工程的資源包配置

  • env:國(guó)際編碼, default 表示設(shè)計(jì)師指定的默認(rèn)字體。注意有些國(guó)際編碼代表一種語(yǔ)言,例如英語(yǔ)存在 en-US、en-GB 等多種編碼,需要統(tǒng)一為 en。
  • font:字重類(lèi)型,0:light、1:medium、2:bold。斜體默認(rèn)替換為medium
  • name:字體源文件的名稱(chēng)。例如:GothamRndSSm-Medium

備注:因?yàn)樵O(shè)計(jì)師只要求3種字重,默認(rèn)light字重,這個(gè)和系統(tǒng)提供的 UIFontWeight 不太一致。

//殼工程中的配置文件,反序列化傳回FontPackage層
//appfont.json
{
    "list": [{
        "env" : "vi",
        "note" : "越南語(yǔ),按照國(guó)際編碼:vi、vi-VN。FontPackageManager 判斷國(guó)際編碼來(lái)對(duì)應(yīng)",
        "data" : [{
                "font" : 0,
                "name" : "genjyuu_light(越南細(xì))"
            },{
                "font" : 1,
                "name" : "genjyuu_medium(越南中)"
            },{
                "font" : 2,
                "name" : "genjyuu_bold(越南粗)"
            }
        ]
    }, {
        "env" : "default",
        "note" : "其他語(yǔ)種默認(rèn)使用字體,但優(yōu)先判斷設(shè)備的國(guó)際編碼來(lái)匹配字體包",
        "data" : [{
                "font" : 0,
                "name" : "GothamRndSSm-Light"
            },{
                "font" : 1,
                "name" : "GothamRndSSm-Medium"
            },{
                "font" : 2,
                "name" : "GothamRndSSm-Bold"
            }
        ]
    }
]}

添加字體包和配置文件,還有冷啟動(dòng)流程:

冷啟動(dòng)流程圖

技術(shù)開(kāi)發(fā)

FontPackage 功能組件共3個(gè)Class,200+行代碼。

首先,在冷啟動(dòng)時(shí)候 FontPackage 根據(jù) json 配置緩存語(yǔ)言編碼匹配到的字體包資源 Model。

然后使用 runtime hook UIFont 類(lèi)的幾個(gè)構(gòu)造函數(shù),更換構(gòu)造函數(shù)的 fontName 參數(shù)。目前確定5個(gè)構(gòu)造函數(shù):

//已處理
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize;
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize weight:(UIFontWeight)weight;
+ (UIFont *)boldSystemFontOfSize:(CGFloat)fontSize;
+ (UIFont *)italicSystemFontOfSize:(CGFloat)fontSize;
+ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize;

最后統(tǒng)一使用 +fontWithName:size: 函數(shù)初始化,fontName 為自定義字體包。

函數(shù) -fontpackage_name: 根據(jù)原 fontName 更換為對(duì)應(yīng)的自定義字體包。

//FontPackageExtension.m 
//UIFont+FontPackage.m



+ (UIFont *)xxxFontPackage_systemFontOfSize:(CGFloat)fontSize weight:(UIFontWeight)weight {
    NSString *fontName = @"";
    if (weight == UIFontWeightMedium) {
        fontName = @"medium";
    } else if (weight > UIFontWeightMedium) {
        fontName = @"bold";
    }
    return [self fontWithName:fontName size:fontSize];
}

+ (UIFont *)xxxFontPackage_italicSystemFontOfSize:(CGFloat)fontSize {
    //斜體默認(rèn)是medium
    return [self fontWithName:@"medium" size:fontSize];
}

+ (UIFont *)xxxFontPackage_boldSystemFontOfSize:(CGFloat)fontSize {
    return [self fontWithName:@"bold" size:fontSize];
}

+ (UIFont *)xxxFontPackage_systemFontOfSize:(CGFloat)fontSize {
    return [self fontWithName:@"" size:fontSize];
}

+ (UIFont *)xxxFontPackage_fontWithName:(NSString *)fontName size:(CGFloat)fontSize {
    fontName = [self fontpackage_name:fontName];
    return [self xxxFontPackage_fontWithName:fontName size:fontSize];
}



+ (NSString *)fontpackage_name:(NSString *)fontName {
    fontName = [fontName lowercaseString];
    FontPackageFont replaceFont = FontPackageFontLight; //默認(rèn)light
    if ([fontName containsString:@"medium"]) {
        replaceFont = FontPackageFontMedium;
    } else if ([fontName containsString:@"bold"]) {
        replaceFont = FontPackageFontBold;
    }
    //匹配替換的字體
    NSString *replaceFontName = [[FontPackageManager shareInstance].fontPackageInfo.dataMap objectForKey:@(replaceFont)];
    return replaceFontName;
}

文本信息的多語(yǔ)言適配和實(shí)踐

針對(duì)海外用戶做語(yǔ)言本地化也是一項(xiàng)重要的產(chǎn)品功能,但很多組件在開(kāi)發(fā)之初并未預(yù)留本地化拓展的接口,客戶端需要提供一套優(yōu)雅的解決方案來(lái)應(yīng)對(duì)此問(wèn)題。

需求分析

1、產(chǎn)品和設(shè)計(jì)的需求

  • 語(yǔ)言本地化
  • 未提供本地化的語(yǔ)言,默認(rèn)使用產(chǎn)品指定的語(yǔ)言
  • 快速支持新語(yǔ)言本地化

2、技術(shù)要求

  • 接入成本低,不需要對(duì)成熟組件做改動(dòng)
  • 解耦,其他組件無(wú)需依賴本功能

技術(shù)設(shè)計(jì)

垂直分層和水平模塊

如圖所示分3層:1、基礎(chǔ)組件提供需求擴(kuò)展 2、業(yè)務(wù)組件(基本不需要修改,如有特殊屬性需求可以依賴基礎(chǔ)組件)3、殼工程提供資源包和以及資源包的更新

LocalizedString 組件要負(fù)責(zé)什么?

  • LocalizedString,負(fù)責(zé)文字本地化適配。
  • LocalizedTool,負(fù)責(zé)語(yǔ)言包的配置、讀取、更換功能。
  • LocalizedExtension,負(fù)責(zé)AOP,補(bǔ)充某些屬性。

語(yǔ)言包目錄如下:

語(yǔ)言包目錄

可以看到,語(yǔ)言包是按照語(yǔ)言碼進(jìn)行命名的,方便在使用中及時(shí)定位到對(duì)應(yīng)文件并讀?。ù嬖诙喾N編碼的語(yǔ)言,統(tǒng)一使用其基礎(chǔ)類(lèi))。同時(shí),在殼工程中會(huì)對(duì)本地語(yǔ)言包進(jìn)行刷新,App啟動(dòng)后會(huì)檢查是否有新的語(yǔ)言包可用,如果有會(huì)保證數(shù)據(jù)同步。

配置好語(yǔ)言包后,接下來(lái)需要冷啟動(dòng)時(shí)初始化LocalizedString 組件。啟動(dòng)時(shí)組件任務(wù)流程圖如下:

冷啟動(dòng)流程圖

技術(shù)開(kāi)發(fā)

考慮到字符串最終都會(huì)依托于 UILabel 進(jìn)行展示,[UILabel setText:]會(huì)作為設(shè)置展示文本的唯一收口。所以我們對(duì)[UILabel setText:]進(jìn)行了 hook 和拓展,其內(nèi)部操作流程圖如下:

AOP流程圖

LocalizedString 組件有 NSString、UILabel 分類(lèi)分別做了屬性拓展。具體代碼如下:

@interface UILabel (Localized)
@property (nonatomic, assign) BOOL isAutoLocalized; ///< 設(shè)置的文字是否要自動(dòng)轉(zhuǎn)換成本地化的語(yǔ)言,默認(rèn)YES
@end

@interface NSString (Localized)
@property (nonatomic, copy) NSString *oriStr; ///< 上次本地化的字符串原始值
@property (nonatomic, copy) NSString *localizedStr; ///< oriStr 本地化后的字符串
@end

對(duì) UILabel 的分類(lèi)拓展可以判斷 Label 是否需要被本地化;對(duì) NSString 的分類(lèi)拓展會(huì)對(duì)本地化后的結(jié)果進(jìn)行緩存,當(dāng)同一個(gè) string 對(duì)象再次本地化時(shí),可以快速?gòu)木彺婺玫浇Y(jié)果減少在 map 中的檢索次數(shù)、提高效率。類(lèi)拓展的方式也保證了本組件的侵入性極低。
整個(gè)工程使用了 pod 進(jìn)行集成,基礎(chǔ)組件無(wú)需聲明依賴,對(duì)本組件有依賴要求的只在特定業(yè)務(wù)中出現(xiàn)。hook + pod 的方式保證了本組件的靈活使用和充分解耦。

與NSLocalizedString的兼容

從上面的流程介紹可以看到,本地化替換發(fā)生在對(duì) Label 設(shè)置文本的時(shí)候,不同于 NSLocalizedString 需要先顯式本地化再設(shè)置文本的方式。所以,當(dāng)使用方提前對(duì)文本進(jìn)行了本地化,本組件的自動(dòng)本地化不生效。考慮到本組件主要應(yīng)用于新語(yǔ)言地區(qū),NSLocalizedString 尚未配置對(duì)應(yīng)的結(jié)果,故目前仍然可以使用本組件兜底。我們也會(huì)后續(xù)優(yōu)化本組件,完成與 NSLocalizedString 的兼容,更加方便本組的使用。

拓展

由于上述方法只適用于[UILabel setText:]這種形式的無(wú)侵入調(diào)整,對(duì)于字符串拼接的情況,仍需要開(kāi)發(fā)人員使用 LocalizedString 類(lèi)對(duì)子串進(jìn)行逐一本地化。同時(shí),為了支持以后可能的應(yīng)用內(nèi)變更語(yǔ)言,LocalizedString 也提供了動(dòng)態(tài)變更語(yǔ)言包功能。LocalizedString 主要 API 如下:

/**
 @brief 直接返回指定 key 對(duì)應(yīng)的 本地化文字
 @param key 轉(zhuǎn)譯文件表中的key
 */
+ (NSString *)forKey:(NSString *)key;

 /**
 @brief 根據(jù)指定的 language code,返回key 對(duì)應(yīng)的 本地化文字
 @param key 轉(zhuǎn)譯文件表中的key
 @param langCode語(yǔ)言編碼
 */
+ (NSString *)forKey:(NSString *)key langCode:(NSString *)langCode;

/**
 @brief 設(shè)置當(dāng)前默認(rèn)的語(yǔ)言編碼
 @param langCode語(yǔ)言編碼
 */
+ (void)setCurrentLangCode:(NSString *)langCode;

總結(jié)

在多個(gè)產(chǎn)品同時(shí)的迭代情況下,使用組件化已經(jīng)變得非常普遍,不斷地重構(gòu)優(yōu)化組件來(lái)保證低耦合。當(dāng)面對(duì)國(guó)際化場(chǎng)景時(shí),需要沉淀打磨國(guó)際化適配框架來(lái)支撐業(yè)務(wù)高效迭代,并且不能給其他業(yè)務(wù)造成負(fù)擔(dān)。

目前以上功能都已上線,滿足了產(chǎn)品的需求,解決了研發(fā)的痛點(diǎn)。

到此這篇關(guān)于iOS文本的多語(yǔ)言適配以及實(shí)踐的文章就介紹到這了,更多相關(guān)iOS文本多語(yǔ)言適配內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

作者介紹

  • 呂洪陽(yáng),伴魚(yú) iOS 工程師,伴魚(yú)繪本iOS端負(fù)責(zé)人
  • 趙杰,伴魚(yú) iOS 工程師,負(fù)責(zé)伴魚(yú)繪本客戶端研發(fā),功能降級(jí)框架等工作

參考

  • https://developer.apple.com/documentation/uikit/uifont
  • http://www.lingoes.cn/zh/translator/langcode.htm

相關(guān)文章

  • 詳解iOS游戲開(kāi)發(fā)中Cocos2D的坐標(biāo)位置關(guān)系

    詳解iOS游戲開(kāi)發(fā)中Cocos2D的坐標(biāo)位置關(guān)系

    這篇文章主要介紹了iOS游戲開(kāi)發(fā)中Cocos2D的坐標(biāo)位置關(guān)系,Cocos2D是專(zhuān)門(mén)用來(lái)開(kāi)發(fā)iOS游戲的開(kāi)源框架,文中示例代碼采用Objective-C語(yǔ)言,需要的朋友可以參考下
    2016-02-02
  • iOS 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組的操作方法

    iOS 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組的操作方法

    這篇文章主要介紹了iOS 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組的操作方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-07-07
  • iOS仿抖音視頻加載動(dòng)畫(huà)效果的實(shí)現(xiàn)方法

    iOS仿抖音視頻加載動(dòng)畫(huà)效果的實(shí)現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于iOS視頻加載動(dòng)畫(huà)效果的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Objective-C實(shí)現(xiàn)自定義的半透明導(dǎo)航

    Objective-C實(shí)現(xiàn)自定義的半透明導(dǎo)航

    這篇文章主要為大家詳細(xì)介紹了Objective-C實(shí)現(xiàn)自定義的半透明導(dǎo)航的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • iOS UIScrollView和控制器返回手勢(shì)沖突解決方法

    iOS UIScrollView和控制器返回手勢(shì)沖突解決方法

    這篇文章主要介紹了iOS UIScrollView和控制器返回手勢(shì)沖突解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • IOS中的webView加載HTML

    IOS中的webView加載HTML

    在日常開(kāi)發(fā)中,我們?yōu)榱诵蕰?huì)用到很多很多的WebView,比如在做某個(gè)明細(xì)頁(yè)面的時(shí)候我們返回給你的可能是一個(gè)html字符串,我們就需要將當(dāng)前字符串展示到webView上面,所以我們對(duì)HTML標(biāo)簽需要有一定的認(rèn)識(shí),下面我們來(lái)一起用html標(biāo)簽和JS寫(xiě)一個(gè)打地鼠游戲
    2016-02-02
  • 講解iOS開(kāi)發(fā)中UITableView列表設(shè)計(jì)的基本要點(diǎn)

    講解iOS開(kāi)發(fā)中UITableView列表設(shè)計(jì)的基本要點(diǎn)

    這篇文章主要介紹了講解iOS開(kāi)發(fā)中UITableView列表設(shè)計(jì)的基本要點(diǎn),其中對(duì)列表行操作的常用操作舉例是iOS開(kāi)發(fā)中經(jīng)常用到的基礎(chǔ),需要的朋友可以參考下
    2016-01-01
  • iOS開(kāi)發(fā)之自定義UITextField的方法

    iOS開(kāi)發(fā)之自定義UITextField的方法

    UITextField是IOS開(kāi)發(fā)中用戶交互中重要的一個(gè)控件,常被用來(lái)做賬號(hào)密碼框,輸入信息框等。本文給大家介紹iOS開(kāi)發(fā)之自定義UITextField的方法,感興趣的朋友一起學(xué)習(xí)吧
    2016-05-05
  • iOS開(kāi)發(fā)技巧之WeakSelf宏的進(jìn)化詳解

    iOS開(kāi)發(fā)技巧之WeakSelf宏的進(jìn)化詳解

    在程序中我們經(jīng)常用到Block,但寫(xiě)weak self 時(shí)會(huì)比較繁瑣,下面這篇文章主要給大家介紹了關(guān)于iOS開(kāi)發(fā)技巧之WeakSelf宏的進(jìn)化的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們一起來(lái)看看吧
    2018-05-05
  • iOS統(tǒng)計(jì)項(xiàng)目的代碼總行數(shù)

    iOS統(tǒng)計(jì)項(xiàng)目的代碼總行數(shù)

    最近一個(gè)項(xiàng)目有段時(shí)間了,不知道怎樣可以統(tǒng)計(jì)出寫(xiě)了多少行代碼,如何處理這個(gè)問(wèn)題呢,下面我們來(lái)探討下。
    2015-06-06

最新評(píng)論