適用于:
Microsoft ASP.NET 2.0
Microsoft Visual Studio .NET
Microsoft Visual Studio 2005
本地化
摘要: 隨著越來(lái)越多的公司拓展海外業(yè)務(wù),通過(guò) Microsoft ASP.NET 創(chuàng)建全球化的 Web 應(yīng)用程序顯得日益重要。ASP.NET 1.1 通過(guò) ResourceManager 類支持創(chuàng)建本地化的 Web 站點(diǎn)。通過(guò)改進(jìn)的運(yùn)行時(shí)和工具支持,ASP.NET 2.0 使得提供對(duì)多語(yǔ)言和區(qū)域的支持更加容易。
下載本文的源代碼 。

本頁(yè)內(nèi)容
![]() |
使用 .NET 1.x 進(jìn)行本地化 |
![]() |
ASP.NET 2.0 新本地化功能簡(jiǎn)介 |
![]() |
生成本地資源 |
![]() |
共享的應(yīng)用程序資源 |
![]() |
隱式本地化表達(dá)式 |
![]() |
顯式本地化表達(dá)式 |
![]() |
本地化 HTML 元素和靜態(tài)文本 |
![]() |
資源本地化和部署 |
![]() |
運(yùn)行時(shí)資源提供程序 |
![]() |
首選的語(yǔ)言選擇 |
![]() |
小結(jié) |
![]() |
其他資源 |
自從 10 年前出現(xiàn) Internet 以來(lái),企業(yè)團(tuán)體已不斷地開(kāi)拓國(guó)際化的市場(chǎng)。企業(yè)不僅通過(guò)自己的 Web 站點(diǎn)擁有了全球化的網(wǎng)絡(luò)呈現(xiàn)方式,而且越來(lái)越多的企業(yè)也正在發(fā)布和/或許可企業(yè)級(jí) Web 應(yīng)用程序以便最終能向全世界的客戶提供服務(wù)。由于大多數(shù)客戶喜歡在本國(guó)語(yǔ)言和環(huán)境下開(kāi)展業(yè)務(wù),因此有必要準(zhǔn)備本地化的 Web 站點(diǎn)和應(yīng)用程序。毫無(wú)疑問(wèn),不論哪種部署模型(智能客戶端、Web 站點(diǎn)和應(yīng)用程序、Web 服務(wù)),具體而言就是體系結(jié)構(gòu)和設(shè)計(jì),本地化任務(wù)都需要付出時(shí)間和精力。有效的開(kāi)發(fā)工具能影響體系結(jié)構(gòu)的好壞,但奇怪的是,對(duì)于開(kāi)發(fā)用于 Web 應(yīng)用程序本地化的工具這一領(lǐng)域而言,仍然進(jìn)步不足。結(jié)果許多企業(yè)求助于更傳統(tǒng)、更麻煩的本地化方法,而花費(fèi)了大量時(shí)間和金錢。
Microsoft ASP.NET 2.0 版本承諾更好地轉(zhuǎn)變 Web 開(kāi)發(fā)人員實(shí)現(xiàn)本地化的方式。通過(guò)使用更多 Microsoft Visual Studio .NET 環(huán)境內(nèi)置的工具、新的運(yùn)行時(shí)功能以及一個(gè)新的特定于本地化需求的編程 API,開(kāi)發(fā)人員能夠更迅速地從 ASP.NET 頁(yè)面分離可本地化的內(nèi)容,減少為訪問(wèn)可本地化內(nèi)容編寫(xiě)的代碼,擴(kuò)展?jié)M足額外需求的環(huán)境,同時(shí)綜合利用一個(gè)一致的編程模型。本文將帶領(lǐng)您體驗(yàn)新改進(jìn)的準(zhǔn)備本地化應(yīng)用程序的 ASP.NET 開(kāi)發(fā)。
使用 .NET 1.x 進(jìn)行本地化
.NET Framework 1.x 引入一個(gè)新的本地化體系結(jié)構(gòu),它提供語(yǔ)言支持的非插入漸進(jìn)式部署,方法是將其拖放到新的附屬程序集(或只含資源程序集)中。這種輪輻式部署范例允許開(kāi)發(fā)人員依靠公共語(yǔ)言運(yùn)行庫(kù)來(lái)管理通過(guò) ResourceManager 類精確選擇的可本地化內(nèi)容。 ResourceManager 的一個(gè)優(yōu)點(diǎn)是它與一個(gè)封裝的資源回調(diào)機(jī)制進(jìn)行交互,根據(jù)應(yīng)用程序的運(yùn)行時(shí)語(yǔ)言設(shè)置查找最合適語(yǔ)言,因此加載每個(gè) ResourceSet 來(lái)檢索可本地化內(nèi)容的過(guò)程無(wú)需開(kāi)發(fā)人員編寫(xiě)代碼進(jìn)行管理。
Windows 或 Web 應(yīng)用程序可以使用資源來(lái)本地化 Windows 窗體,但是 Visual Studio 2003 使 Windows 開(kāi)發(fā)人員本地化 Windows 窗體的工作變得更加容易。當(dāng)一個(gè)窗體的 Localizable 屬性設(shè)置為 true 時(shí),則用于可本地化的 form 和 control 屬性的資源將自動(dòng)生成。屬性值被壓入默認(rèn)資源以備后來(lái)進(jìn)行翻譯,通過(guò)這些資源,生成的代碼在運(yùn)行時(shí)使用 ResourceManager 類的實(shí)例填充控件。 ResourceManager 先考慮正在執(zhí)行線程的 CurrentUICulture 設(shè)置,然后嘗試在 ResourceSet 中查找匹配語(yǔ)言的資源,最后求助于資源的回調(diào)過(guò)程。
注 請(qǐng)?jiān)? 此處 閱讀有關(guān)資源回調(diào)過(guò)程的信息。
.NET Framework 也包含許多與語(yǔ)言有關(guān)的類,在生成諸如格式化日期、時(shí)間和貨幣值等輸出結(jié)果時(shí)考慮 CurrentUICulture ,從而進(jìn)一步減少開(kāi)發(fā)人員所需的工作量。
注 請(qǐng)從 MSDN 參考資源 中閱讀與語(yǔ)言有關(guān)的類的更多信息。
盡管附屬程序集的部署模型、資源管理器以及與語(yǔ)言有關(guān)的類也能應(yīng)用于 ASP.NET 應(yīng)用程序,可是缺少供開(kāi)發(fā)人員使用的工具將這個(gè)模型集成到 Web 窗體的編程范例中。目前,為 Web 頁(yè)面生成資源實(shí)體、在運(yùn)行時(shí)訪問(wèn)這些資源以及為每個(gè)請(qǐng)求設(shè)置正確的語(yǔ)言需要人工完成。因此 Web 應(yīng)用程序本地化沒(méi)有過(guò)多考慮將資源作為一個(gè)集成部分。本地化 Web 內(nèi)容傳統(tǒng)上造成了重復(fù)整個(gè)特定語(yǔ)言的網(wǎng)站,從而就地本地化靜態(tài)內(nèi)容以及為任何共享代碼編寫(xiě)自定義代碼來(lái)管理本地化數(shù)據(jù)源的檢索。ASP.NET 2.0 極大地改進(jìn)了該方法。
注 后面的 MSDN 文章 討論用于 ASP.NET 1.1 本地化的結(jié)構(gòu)化方法。
ASP.NET 2.0 新本地化功能簡(jiǎn)介
ASP.NET 2.0 在 .NET 1.x 本地化功能的基礎(chǔ)上構(gòu)建,專門改進(jìn)了工作流和 Web 開(kāi)發(fā)人員可用的功能。下面總結(jié)了促進(jìn)下一代本地化支持的設(shè)計(jì)目標(biāo):
? |
為 Web 應(yīng)用程序提供支持資源生成的工具。 |
? |
為資源訪問(wèn)提供新的聲明性和運(yùn)行時(shí)編程構(gòu)造。 |
? |
簡(jiǎn)化對(duì)頁(yè)面請(qǐng)求應(yīng)用正確語(yǔ)言和自動(dòng)實(shí)例化 ResourceManager 的過(guò)程。 |
? |
支持 XCOPY 部署和小型商業(yè)網(wǎng)站的編譯步驟移除。 |
? |
支持具有使用和管理各方面資源的可擴(kuò)展性的企業(yè)級(jí)開(kāi)發(fā)版. |
? |
確保 ASP.NET 控件和其他可應(yīng)用性運(yùn)行時(shí)組件和適配器集成式地支持新本地化功能。 |
Visual Studio 2005 和 ASP.NET 2.0 集成的新功能確保能簡(jiǎn)化 Web 應(yīng)用程序本地化,它提供工具從 Web 頁(yè)面提取可本地化內(nèi)容,為補(bǔ)充無(wú)狀態(tài)請(qǐng)求模型的資源使用提供集成的運(yùn)行時(shí)支持,通過(guò)先進(jìn)的聲明性構(gòu)造將資源綁定到頁(yè)面輸出,為往返過(guò)程提供自動(dòng)選擇語(yǔ)言的新方法。下面的功能專門用于支持這些目標(biāo):
Strongly Typed Resources — 處于 .NET Framework 2.0 版本核心地位的是強(qiáng)類型資源支持,它為開(kāi)發(fā)人員提供智能感知,從而簡(jiǎn)化運(yùn)行時(shí)訪問(wèn)資源所需的代碼。
Managed Resource Editor — Visual Studio .NET 2.0 包含一個(gè)新的資源編輯器,用于更好地創(chuàng)建和管理資源實(shí)例,例如字符串、圖像、外部文件和其他復(fù)雜類型等等。
Resource Generationfor Web Forms — Windows 窗體開(kāi)發(fā)人員已經(jīng)受益于自動(dòng)的國(guó)際化。現(xiàn)在,Visual Studio 2005 將支持快速的國(guó)際化,自動(dòng)生成 Web 窗體、用戶控件和主頁(yè)面的資源。
Improved Runtime Support — ResourceManager 實(shí)例由運(yùn)行時(shí)管理,服務(wù)器代碼可通過(guò)更多可訪問(wèn)的編程接口輕松訪問(wèn)它。
Localization Expressions — 用于 Web 頁(yè)面的先進(jìn)聲明性表達(dá)式將資源實(shí)體映射到控件屬性、HTML 屬性或靜態(tài)的內(nèi)容區(qū)域。這些表達(dá)式也可擴(kuò)展,從而提供了其他方法來(lái)控制將本地化內(nèi)容添加到 HTML 輸出的過(guò)程。
Automatic Culture Selection — 每次 Web 請(qǐng)求的語(yǔ)言選擇能夠自動(dòng)連接到瀏覽器偏愛(ài)來(lái)管理。
Resource Provider Model — 一個(gè)新的資源提供程序模型允許開(kāi)發(fā)人員發(fā)布可選數(shù)據(jù)源(例如,平面文件和數(shù)據(jù)庫(kù)表格)的資源,而訪問(wèn)這些資源的編程模型保持一致。
這些靈活的功能足以為亟需可靠且有效的解決方案的小型企業(yè)提供出盒支持,還仍然以附加的可擴(kuò)展性滿足大型組織應(yīng)用多種部署體系結(jié)構(gòu)的復(fù)雜需求。改進(jìn)的新模型綜合利用了 Web 應(yīng)用程序的資源,聯(lián)合了 Windows 窗體編程模型,還考慮了開(kāi)發(fā)周期和 Web 的運(yùn)行時(shí)需求。以下各部分內(nèi)容詳細(xì)介紹了在 Beta 1 版本中實(shí)現(xiàn)的這些新功能,也評(píng)論了期望在 Beta 2 版本中實(shí)現(xiàn)的改進(jìn)。
生成本地資源
.NET 資源實(shí)現(xiàn)了為特定語(yǔ)言和語(yǔ)言區(qū)域選擇性地替換內(nèi)容,因此同一個(gè)代碼基能夠支持多種語(yǔ)言。然而,為 Web 頁(yè)面生成資源需要大量的人工勞動(dòng),因此很難調(diào)動(dòng)開(kāi)發(fā)人員為 Web 應(yīng)用程序使用這種方法的積極性。ASP.NET 2.0 提供一種簡(jiǎn)單的方法為 Web 頁(yè)面自動(dòng)生成資源,同時(shí)支持各種復(fù)雜的內(nèi)容代理,包括 HTML 元素和屬性、靜態(tài)內(nèi)容和服務(wù)器控件。
為特定的 Web 窗體生成資源,需要從 Visual Studio 2005 的“Tools”菜單選擇 Generate Local Resource ,然后為 Design View 中打開(kāi)的任何頁(yè)面(包括 Web 窗體、用戶控件和主頁(yè)面)創(chuàng)建本地資源。這個(gè)步驟自動(dòng)生成一組頁(yè)面的默認(rèn) .NET XML 資源,將其放置在為本地資源建立的名為 \LocalResources 的專用子目錄下(在 Beta 2 中此目錄名將改變)。

圖 1. Web 窗體、用戶控件和主頁(yè)面能在 Visual Studio .NET 2.0 內(nèi)部國(guó)際化。這個(gè)特定視圖顯示為一些頁(yè)面生成的默認(rèn)資源。
本地資源存儲(chǔ)在 .resx 文件中,文件的命名規(guī)則對(duì)應(yīng)本地資源所服務(wù)的頁(yè)面(參見(jiàn)圖 1)。例如,為名為 site.master 的主頁(yè)面生成資源后,新的名為 site.master.resx 的 .resx 文件出現(xiàn)在 \LocalResources 中。對(duì)于名為 default.aspx 的 Web 窗體而言,生成的資源存儲(chǔ)在名為 default.aspx.resx 的文件中。
Visual Studio 設(shè)計(jì)器檢查頁(yè)面和它的控件(ASP.NET 服務(wù)器控件、自定義控件和設(shè)置為 runat="server" 的 HTML 控件)— 查找標(biāo)記為 LocalizableAttribute 的屬性 — 并填充這些資源:
[Localizable(true)] public virtual string Text { get {...} set {...} }
每個(gè)控件的可本地化屬性自動(dòng)壓入資源,以關(guān)鍵字唯一標(biāo)識(shí)每個(gè)屬性。關(guān)鍵字包含一個(gè)標(biāo)識(shí)頁(yè)面控件名和屬性名的前綴。除非在控件聲明中指定屬性值,否則每個(gè)屬性值均設(shè)置為控件的默認(rèn)值。下列 LinkButton 聲明為 PostBackUrl 和 Text 屬性指定了一個(gè)值:
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server">Change Selected Culture</asp:LinkButton>
圖 2 顯示的是為宿主頁(yè)面生成本地資源后,為 LinkButton 生成的資源(參見(jiàn)示例項(xiàng)目中的 cultureinfo.ascx)。資源存儲(chǔ)在資源文件中(參見(jiàn) cultureinfo.ascx.resx),默認(rèn)情況下排除諸如 PostBackUrl 這樣的非可本地化屬性。
生成資源時(shí),控件聲明也被修改,以便聲明性地使屬性與資源實(shí)體相關(guān)聯(lián)。一些新的聲明性表達(dá)式也為頁(yè)面解析器所識(shí)別,它們觸發(fā)代碼生成,在運(yùn)行時(shí)使用資源值填充控件屬性。聲明性本地化表達(dá)式是 ASP.NET 2.0 的一種新構(gòu)造,類似數(shù)據(jù)綁定語(yǔ)句,是為訪問(wèn)資源而專門設(shè)計(jì)的。這些表達(dá)式具有兩種形式:隱式和顯示。隱式表達(dá)式在本地資源生成時(shí)自動(dòng)插入,而且支持在單個(gè)聲明語(yǔ)句中將多個(gè)資源實(shí)體映射到一組控件屬性中。顯式表達(dá)式是開(kāi)發(fā)人員添加的用于進(jìn)一步控制頁(yè)面本地化的聲明。
下列由 meta:resourcekey 標(biāo)識(shí)的隱式表達(dá)式是為 LinkButton 聲明而生成的,現(xiàn)在,它為這個(gè)控件設(shè)置了資源關(guān)鍵字前綴:
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server" meta:resourcekey="LinkButtonResource1"> Change Selected Culture</asp:LinkButton>
控件屬性的資源實(shí)體使用這個(gè)前綴后,運(yùn)行時(shí)將自動(dòng)映射到正確的控件屬性。控件聲明中的每個(gè)屬性值保持原封不動(dòng),其中也包括那些壓入資源的值。這些默認(rèn)值將出現(xiàn)在 Design View 中,為頁(yè)面內(nèi)的控件提供上下文。解析頁(yè)面時(shí),本地化表達(dá)式生成的代碼將資源應(yīng)用到控件屬性。開(kāi)發(fā)人員無(wú)需編寫(xiě)代碼將 ResourceManager 實(shí)例化,以便在運(yùn)行時(shí)訪問(wèn)這些本地資源。
運(yùn)行時(shí)資源值優(yōu)先,無(wú)資源值時(shí)由默認(rèn)值代替。這對(duì) Web 開(kāi)發(fā)人員而言非常有用,因?yàn)樵谡军c(diǎn)部署完成之前,他們就可以查看頁(yè)面內(nèi)容。在 Properties Window 中,本地化后的內(nèi)容由特殊圖標(biāo)進(jìn)行標(biāo)記,表示它們的值是從資源中提取的。圖 3 顯示一個(gè) ASP.NET ImageButton 控件,其中一些屬性綁定到共享資源(以藍(lán)色標(biāo)識(shí)),另一些綁定到本地資源(以紅色標(biāo)識(shí))。使用表達(dá)式綁定屬性的內(nèi)容將在后面部分深入討論。
到目前為止,討論的焦點(diǎn)是生成本地資源。默認(rèn)情況下,它既為可本地化控件屬性生成隱式本地化表達(dá)式和資源,也將屬性綁定到共享應(yīng)用程序資源。此外,它也可能為非可本地化控件屬性、其他 HTML 元素和靜態(tài)內(nèi)容自動(dòng)生成本地資源。將顯式本地化表達(dá)式應(yīng)用到這些頁(yè)面和控件元素就可以實(shí)現(xiàn)。換句話說(shuō),開(kāi)發(fā)人員能夠聲明性地標(biāo)識(shí)出需要本地化的內(nèi)容,以便頁(yè)面的資源生成中包含這些內(nèi)容或選擇性地從替代源中提取。
共享的應(yīng)用程序資源
為每個(gè)頁(yè)面自動(dòng)生成本地資源會(huì)造成實(shí)體重復(fù)和多余的翻譯工作。幸運(yùn)的是,ASP.NET 2.0 內(nèi)部擁有一個(gè)為主頁(yè)面和用戶控件建立的重用模型,它支持標(biāo)題、菜單、提要欄以及 HTML 其他部分在 Web 窗體間共享。每個(gè)主頁(yè)面、用戶控件和 Web 窗體擁有自己的本地資源集合,這樣就減少了資源重復(fù)。而且,在所有頁(yè)面之間進(jìn)行合并和共享時(shí),資源實(shí)體,例如詞條、錯(cuò)誤信息和功能驅(qū)動(dòng)程序(例如,方向?qū)傩裕⒎浅S杏谩?
每個(gè)頁(yè)面的本地資源通過(guò)設(shè)計(jì)器自動(dòng)生成,而共享的應(yīng)用程序資源則需要手動(dòng)創(chuàng)建。這就意味著將一個(gè)新的應(yīng)用程序資源添加到解決方案中,將其放置在為共享資源指定的名為 \Resources 的專用目錄下(在 Beta 2 中此目錄將更改)。這與 1.x 應(yīng)用程序生成共享資源的方法一致,然而,新的資源編輯器簡(jiǎn)化了創(chuàng)建和編輯資源實(shí)體,共享資源通過(guò)智能感知支持進(jìn)行了強(qiáng)類型化。共享資源也參與新頁(yè)面的解析和 ASP.NET 2.0 的運(yùn)行時(shí)模型。它們能夠通過(guò)顯式本地化表達(dá)式綁定到頁(yè)面,這時(shí), ResourceManager 自動(dòng)進(jìn)行實(shí)例化和緩存,開(kāi)發(fā)人員不必管理運(yùn)行時(shí)訪問(wèn)資源的生命周期。
圖 2 和 圖 4. 顯示 Visual Studio 2005 的一個(gè)新 Managed Resource Editor。圖 2 是資源字符串編輯器,它與 Visual Studio 中的資源編輯器相似。圖 4 說(shuō)明了編輯器支持的預(yù)定義資源種類列表,包括字符串、圖標(biāo)、其他圖像文件類型、音頻文件類型以及含 XML 的其他文件。除了資源編輯器支持的這些預(yù)定義類型,以編程方式將其他復(fù)雜類型插入資源也是可能實(shí)現(xiàn)的。這時(shí),基礎(chǔ)資源文件是基于 XML 的。
通過(guò)編輯器插入的基于文件的資源(例如,圖像、聲音和 XML 文件),在默認(rèn)情況下定義為 ResxFileRef 實(shí)體。例如,下列代碼分別為一個(gè)外部圖像和一個(gè) XML 文件創(chuàng)建資源實(shí)體:
<data name="Spain" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Images\Spain.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> <data name="supportedCultures" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Xml\supportedCultures.xml;System.String, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1</value> </data>
資源編譯器解析每個(gè)文件引用,運(yùn)行時(shí)將引用的文件載入流,并將其轉(zhuǎn)換成正確的數(shù)據(jù)類型。圖像轉(zhuǎn)換后的類型是 System.Drawing.Bitmap ,而 XML 默認(rèn)情況下返回 System.String 類型。對(duì)于預(yù)編譯的 Web 應(yīng)用程序而言,資源是嵌入到輸出程序集中的。這意味著實(shí)際文件無(wú)需與網(wǎng)站一起部署。資源和相關(guān)文件也能夠部署為完整運(yùn)行時(shí)編譯,這與 ASP.NET 2.0 的新編譯模型一致(有關(guān)更多信息,請(qǐng)參見(jiàn) 本文 )。
共享資源最顯著的優(yōu)點(diǎn)是編譯后的強(qiáng)類型類使資源關(guān)鍵字能夠直接訪問(wèn)實(shí)體。例如,名為 Flags.resx 的共享應(yīng)用程序資源以運(yùn)行時(shí)類型 Resources.Flags 來(lái)訪問(wèn)。內(nèi)部的 Resources 類型都支持智能感知,如果類型轉(zhuǎn)換器可用,則資源項(xiàng)將以本機(jī)數(shù)據(jù)類型返回。圖 5 所示圖像的數(shù)據(jù)類型是 System.Drawing.Bitmap 。
圖 5. 共享資源編譯到強(qiáng)類型資源中,通過(guò)內(nèi)部的 Resources 對(duì)象訪問(wèn)。
基于圖像的資源對(duì) Web 控件開(kāi)發(fā)人員而言很有用,因?yàn)樗芊庋b控件使用的嵌入式圖形。然而,它對(duì) Windows 窗體開(kāi)發(fā)人員而言更有用,開(kāi)發(fā)人員能夠很容易地使用二進(jìn)制圖像格式進(jìn)行顯示。總之,強(qiáng)類型資源和智能感知提高了運(yùn)行時(shí)訪問(wèn)資源的效率。例如,圖 5 也闡釋了一個(gè)強(qiáng)類型 Glossary 資源如何使檢索命名的字符串值變得更容易。
本地資源和共享資源都能夠以聲明方式或編程方式訪問(wèn),以便生成本地化內(nèi)容。這些技術(shù)將在以下部分討論。
隱式本地化表達(dá)式
正如之前提到的,本地資源生成時(shí)將觸發(fā)頁(yè)面控件聲明修改。默認(rèn)行為是將隱式本地化表達(dá)式添加到服務(wù)器控件,由解析時(shí)屬性 meta:resourcekey 表示。
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server" meta:resourcekey="LinkButtonResource1"> Change Culture Settings</asp:LinkButton>
這個(gè)表達(dá)式為控件屬性相關(guān)的所有資源實(shí)體設(shè)置了預(yù)期的前綴 —— 因此使用術(shù)語(yǔ) 隱式表達(dá)式 。自動(dòng)的資源生成只考慮可本地化屬性,但是實(shí)際上任何資源實(shí)體,只要使用此前綴加上一個(gè)合法的屬性名,都能綁定到編譯過(guò)的頁(yè)面代碼中的該屬性。在上面的示例中, LinkButtonResource1 是資源關(guān)鍵字前綴,圖 2 顯示的資源為應(yīng)用到同一個(gè)控件實(shí)例(即 LinkButtonResource1.Text )的所有屬性使用了這個(gè)前綴。
這條聲明性的語(yǔ)句( meta:resourcekey )通知 ASP.NET 頁(yè)面解析器生成代碼,用于從默認(rèn)本地資源檢索屬性值。結(jié)果代碼最終在 GetPageResourceObject (在 Beta 2 中此方法名可能更改)的幫助下使用運(yùn)行時(shí)方法訪問(wèn)資源。在提供的示例代碼中,編譯的 cultureinfo.ascx 頁(yè)面使用以下代碼來(lái)創(chuàng)建和實(shí)例化 LinkButton 和 lnkSelectCulture :
LinkButtonbutton1 = new LinkButton(); this.lnkSelectCulture= button1; button1.ID = "lnkSelectCulture"; button1.PostBackUrl= "selectculture.aspx"; button1.AccessKey = ((string) base.GetPageResourceObject("LinkButtonResource1.AccessKey")); button1.SoftkeyLabel = ((string) . base.GetPageResourceObject("LinkButtonResource1.SoftkeyLabel")); button1.Text = ((string) base.GetPageResourceObject("LinkButtonResource1.Text")); button1.ToolTip = ((string) base.GetPageResourceObject("LinkButtonResource1.ToolTip")); button1.Visible = ((bool) base.GetPageResourceObject("LinkButtonResource1.Visible", typeof(Control), "Visible"));
隱式本地化表達(dá)式在生成頁(yè)面資源時(shí)應(yīng)用到所有服務(wù)器控件聲明。您能夠使用下面的替代語(yǔ)法取消這個(gè)行為,它指示出該控件不應(yīng)該進(jìn)行本地化:
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server" meta:localize="false">Change Culture Settings</asp:LinkButton>
對(duì)本地化策略不重要的個(gè)別控件屬性可以使用圖 2 顯示的 Managed Resource Editor 手動(dòng)將其從本地資源中移除。這將減少頁(yè)面解析器生成的將本地資源實(shí)體應(yīng)用到控件屬性的代碼數(shù)量,因?yàn)榇a只反映頁(yè)面的默認(rèn)本地資源中存在的那些實(shí)體。這也意味著添加到本地化資源的附加關(guān)鍵字值在運(yùn)行時(shí)將不會(huì)應(yīng)用,因?yàn)闆](méi)有生成代碼來(lái)實(shí)現(xiàn)這一點(diǎn)。
這類本地化表達(dá)式綜合利用了與 .NET Framework 2.0 一起發(fā)布的新 Expression Builder。隱式本地化表達(dá)式從單個(gè)聲明語(yǔ)句生成代碼來(lái)填充所有可本地化的服務(wù)器控件屬性,為開(kāi)發(fā)人員節(jié)省了時(shí)間。同時(shí)也刪除了目前 1.x Web 應(yīng)用程序所需的一個(gè)手動(dòng)步驟,即通常需要自定義數(shù)據(jù)綁定語(yǔ)句或自定義代碼從本地化資源或數(shù)據(jù)源提取值。下面將預(yù)覽如何為靜態(tài)文本和具體控件屬性(包括那些沒(méi)有 LocalizableAttribute 標(biāo)記的屬性)自動(dòng)生成附加資源。
顯式本地化表達(dá)式
盡管為可本地化控件屬性自動(dòng)生成資源非常容易,可是開(kāi)發(fā)人員也需要一個(gè)支持本地化特定屬性值和其他內(nèi)容塊的解決方案。顯式本地化表達(dá)式以聲明方式將特定資源實(shí)體分配到服務(wù)器控件屬性和其他 HTML 元素。例如,下面的 ImageButton 控件聲明使用了一個(gè)顯式表達(dá)式來(lái)設(shè)置 AlternateText 屬性:
<asp:ImageButton id="btnIDesign" Runat="server" ImageUrl="~/Images/idesignlogo.jpg" AlternateText='<%$ Resources: MissionStatement %>' PostBackUrl="http://www.idesign.net" />
顯式本地化表達(dá)式使用以下語(yǔ)法:
<%$ resources: [applicationkey], resourcekey%>
上例省略了 applicationkey ,因?yàn)? MissionStatement 值從本地資源提取。 resourcekey 值標(biāo)識(shí)提取的資源實(shí)體,而 default 值表示設(shè)計(jì)器默認(rèn)值。設(shè)計(jì)器默認(rèn)值僅在設(shè)計(jì)時(shí)存在,供開(kāi)發(fā)人員或 Web 設(shè)計(jì)者編輯頁(yè)面布局。
顯式表達(dá)式也能夠通過(guò)圖 6 所示的“Properties”窗口中的 Expressions 對(duì)話框生成。這個(gè)對(duì)話框支持創(chuàng)建顯式表達(dá)式值,從而將控件屬性綁定到本地資源或共享資源。
通過(guò)該對(duì)話框,開(kāi)發(fā)人員能使用“Properties”窗口創(chuàng)建顯式表達(dá)式,就像設(shè)置其他控件屬性一樣。如果 Expression Properties 中省略 ClassName(請(qǐng)參見(jiàn)圖 6),下拉列表將顯示可用的本地資源關(guān)鍵字(假定已經(jīng)創(chuàng)建了資源)。否則,本地資源對(duì)應(yīng)的顯式表達(dá)式將生成關(guān)鍵字與 ResourceKey 匹配的本地資源實(shí)體。這又一次減少了開(kāi)發(fā)人員在運(yùn)行時(shí)創(chuàng)建資源實(shí)體和生成填充屬性的代碼所需的工作量。
如果訪問(wèn)共享資源, ClassName 應(yīng)標(biāo)識(shí)全局資源目錄下的一個(gè)合法資源文件名。與本地資源不同的是,共享資源對(duì)應(yīng)的顯式表達(dá)式不自動(dòng)生成這些資源。
隱式和顯式本地化表達(dá)式能混合使用,以便特定屬性從共享資源提取,而其他屬性從本地資源提取。下列代碼示例顯示的是, ImageButton 控件聲明從共享資源 (Glossary.resx) 獲取 AlternateText 屬性,所有其他屬性使用隱式表達(dá)式語(yǔ)法從本地資源提取:
<asp:ImageButton ID="btnIDesign" Runat="server" ImageUrl="~/Images/idesignlogo.jpg" AlternateText='<%$ Resources:Glossary, MissionSatatement%>' PostBackUrl="http://www.idesign.net" meta:resourcekey="ImageButtonResource1" /></td>
使用顯式本地化表達(dá)式后,詳細(xì)控制哪里、哪些屬性被本地化將可能實(shí)現(xiàn)。對(duì)于包含顯式和隱式表達(dá)式兩者的控件聲明,頁(yè)面資源按以下方式生成:
? |
顯式表達(dá)式綁定的屬性,如果指定了一個(gè)共享資源,在本地資源生成中將省略。 |
? |
用于本地資源的顯式表達(dá)式綁定的屬性,生成一個(gè) default 值的 resourcekey 入口點(diǎn)。 |
? |
其余未綁定顯式表達(dá)式的可本地化屬性,用控件聲明或控件的默認(rèn)屬性值生成一個(gè) resourcekey.propertyname 的入口點(diǎn)。 |
正如之前提到的,頁(yè)面解析時(shí),聲明中的代碼自動(dòng)生成,以便從共享或本地資源提取屬性值。在上面的示例代碼中,結(jié)果代碼創(chuàng)建了一個(gè) ImageButton 控件,從 Glossary 共享資源設(shè)置 AlternateText 屬性,其余可本地化屬性通過(guò)本地資源設(shè)置:
ImageButtonbutton1 = new ImageButton(); // other initialization code button1.ID = "btnIDesign"; button1.AccessKey = (string) base.GetPageResourceObject("ImageButtonResource1.AccessKey"); button1.AlternateText= (string) base.GetAppResourceObject("Glossary", "MissionStatement"); button1.ImageUrl = (string) base.GetPageResourceObject("ImageButtonResource1.ImageUrl"); button1.ToolTip = (string) base.GetPageResourceObject("ImageButtonResource1.ToolTip"); button1.Visible = (bool) base.GetPageResourceObject("ImageButtonResource1.Visible", typeof(Control), "Visible");
本地化 HTML 元素和靜態(tài)文本
使用隱式和顯式本地化表達(dá)式,使得為服務(wù)器控件屬性生成資源變得容易。但是,準(zhǔn)備本地化一個(gè)頁(yè)面,也必須考慮諸如 HTML 頁(yè)標(biāo)題、方向?qū)傩院挽o態(tài)內(nèi)容等其他內(nèi)容。本地化表達(dá)式也能應(yīng)用到 @Page 指令和 HTML 其他部分,先于生成頁(yè)面資源,聲明性地標(biāo)識(shí)其他本地化部分。
HTML 控件:
HTML 控件運(yùn)行在服務(wù)器端 ( runat="server" ) 時(shí),才能體現(xiàn)隱式或顯式表達(dá)式的優(yōu)點(diǎn)。一旦標(biāo)記為服務(wù)器端控件,將自動(dòng)生成應(yīng)用于控件的可本地化屬性的本地資源。HTML 服務(wù)器控件與 ASP.NET、自定義服務(wù)器控件一樣,也能綁定到隱式或顯式表達(dá)式,后者可使用前面提到的 Expressions 對(duì)話框生成。
頁(yè)標(biāo)頭的 HTML 元素也能聲明性地綁定到資源,對(duì)于頁(yè)標(biāo)題和樣式表鏈接,這是有用的。HTML 頁(yè)標(biāo)題元素很特殊,因?yàn)樗彩且粋€(gè) Page 屬性,能通過(guò) @Page 指令設(shè)置。默認(rèn)情況下,本地資源生成時(shí),隱式表達(dá)式分配到每個(gè)頁(yè)面:
<%@ Page Language="C#" CodeFile="Default.aspx.cs" Inherits="_Default" meta:resourcekey
這條表達(dá)式也可以修改為顯式表達(dá)式,用于從共享資源(而非本地資源)提取值:
這些表達(dá)式都不能覆蓋 HTML 標(biāo)頭的 < title > 元素值,但是沒(méi)有這些值,表達(dá)式也能夠直接應(yīng)用到 < title > 元素,下面使用的是顯式表達(dá)式:
<head runat="server"> <title> <asp:Literal Text='<% $ Resources: Glossary, DefaultPageTitle %>' runat="server"></asp:Literal> </title> </head>
方向?qū)傩?
改進(jìn)的方向設(shè)置支持是通過(guò)新提供的 Direction 屬性添加的,這個(gè)屬性由諸如 < asp:Panel > 一類的控件支持。因?yàn)槭褂靡粋€(gè)根據(jù)語(yǔ)言標(biāo)識(shí)應(yīng)用程序的整體方向的共享資源,所以在默認(rèn)的共享資源中能標(biāo)識(shí)默認(rèn)的 “LTR” 方向,并依據(jù)能夠指定 “LTR” 的語(yǔ)言覆蓋這個(gè)值。
為了控制瀏覽器滾動(dòng)條的方向并設(shè)置站點(diǎn)的整體方向,下面的顯式表達(dá)式通過(guò)設(shè)計(jì)器默認(rèn)值 “LTR” 從共享資源提取正確的值:
<html runat="server" dir='<% $Resources: Common, Direction %>' > ... </html>
panel 也可以用于設(shè)置所包含控件的方向:
<asp:panel runat="server" direction='<% Resources: Common, Direction %>'> ... </asp:panel>
有關(guān) Visual Studio .NET 方向支持的更多信息,請(qǐng)?jiān)L問(wèn) 此站點(diǎn) 。
靜態(tài)文本
本地化表達(dá)式用于設(shè)置控件屬性和其他 HTML 元素;但是,許多要進(jìn)行本地化的 Web 頁(yè)面已經(jīng)包含大量混有 ASP.NET 控件的靜態(tài)內(nèi)容塊。新的 ASP.NET Localize 控件用于將靜態(tài)內(nèi)容標(biāo)記為可本地化,以便資源生成包含這部分靜態(tài)內(nèi)容。如果控件中 meta:resourcekey 的指定先于生成資源命令的發(fā)布,則使用指定的關(guān)鍵字(同樣適應(yīng)于其他控件):
<asp:Localize id="welcomeContent" runat="server" meta:resourcekey="welcome">Welcome!</asp:Localize>
以上示例為 Localize 控件的 Text 屬性生成了一個(gè)新的本地資源入口點(diǎn),資源前綴是 "welcome" ( welcome.Text )。要從共享資源顯式填充靜態(tài)內(nèi)容,可以通過(guò)一個(gè)顯式本地化表達(dá)式指定 Text 屬性:
<asp:Localize id="welcomeContent" runat="server" text='<%$ resources: Glossary, welcomeText%>'>Welcome!</asp:Localize>
與其他情況一樣,這些聲明性語(yǔ)句解析成代碼來(lái)請(qǐng)求資源設(shè)置控件屬性,這里是 Text 屬性。任何出現(xiàn)在控件聲明語(yǔ)句中的 HTML 標(biāo)記都將包含在資源生成中,這使翻譯過(guò)程變得復(fù)雜,因此最好不要包含標(biāo)記。
Localize 控件比它的基類 Literal 控件優(yōu)越的是,運(yùn)行時(shí)它的處理方式與 Literal 控件很像;然而,設(shè)計(jì)器會(huì)忽略它,并允許開(kāi)發(fā)人員直接在 Design View 中編輯靜態(tài)內(nèi)容(不像 Literal 控件,在 Design View 中它綁定到一個(gè)容器中)。
資源本地化和部署
新的聲明語(yǔ)句、頁(yè)面資源的自動(dòng)生成和強(qiáng)類型共享資源都使開(kāi)發(fā)人員準(zhǔn)備本地化 Web 應(yīng)用程序更輕松。存儲(chǔ)在 \LocalResources 和 \Resources 目錄(分別是本地資源和共享資源)下的默認(rèn)資源能翻譯成支持的語(yǔ)言,翻譯后的資源復(fù)制到源目錄下。翻譯資源的命名規(guī)則遵循 1.x 使用的規(guī)則。翻譯后的 .resx 文件名包含語(yǔ)言代碼。圖 7 顯示的是一個(gè)示例工程的擴(kuò)展視圖,其中的頁(yè)面資源翻譯成了西班牙語(yǔ)、法語(yǔ)和意大利語(yǔ)。
典型的 .NET Framework 1.x 應(yīng)用程序發(fā)布時(shí)附帶本地化的附屬程序集,而 ASP.NET 2.0 還有新的可選部署集:
1. |
ASP.NET 2.0 運(yùn)行時(shí)繼續(xù)支持傳統(tǒng)的部署模型 — \bin 目錄包含本地程序集依賴項(xiàng),每個(gè)支持語(yǔ)言的子目錄包含附屬(只含資源)程序集。 |
2. |
ASP.NET 2.0 預(yù)編譯將 Web 頁(yè)(即頁(yè)面、用戶控件和主頁(yè)面)、本地資源和代碼分隔文件作為一個(gè)單獨(dú)文件進(jìn)行處理 — 將它們編譯到可部署的程序集。共享資源也預(yù)編譯到用于部署的程序集。任何引用的資源入口點(diǎn)(例如,圖像或 XML 文件)編譯到程序集單元中。基本上而言,ASP.NET 2.0 Web 應(yīng)用程序的預(yù)編譯就是一個(gè)二進(jìn)制容器,通過(guò)封裝為源文件提供更高級(jí)別的保護(hù)。 |
3. |
ASP.NET 2.0 也支持完整的運(yùn)行時(shí)編譯。這意味著所有 Web 頁(yè)、代碼分隔文件、其他源代碼、資源(共享和本地)以及其他支持的應(yīng)用程序文件都能以原始格式進(jìn)行部署。然后,運(yùn)行時(shí)編譯器負(fù)責(zé)解析頁(yè)面,隨時(shí)生成程序集。這個(gè)模型提供了最大化的靈活性,但是主要用于輕量型 Web 應(yīng)用程序,這樣的應(yīng)用程序頻繁更改,而且不要求高級(jí)別的源代碼安全。 |
4. |
ASP.NET 2.0 發(fā)布時(shí)也可能實(shí)現(xiàn)混合多項(xiàng)功能。也就是說(shuō),將所有代碼分隔文件和其他資源編譯到用于部署的二進(jìn)制程序集的同時(shí),還能將頁(yè)面和資源部署成源。這樣可以靈活地為一個(gè)或多個(gè)頁(yè)面編輯頁(yè)面布局和資源內(nèi)容或部署新的可本地化資源,而不會(huì)導(dǎo)致不受影響的應(yīng)用程序集進(jìn)行動(dòng)態(tài)地重新編譯。 |
對(duì)于第二、三、四項(xiàng),ASP.NET 2.0 編譯器自動(dòng)將 \LocalResources 和 \Resources 目錄下的 .resx 源文件編譯到程序集。至于第三項(xiàng)和第四項(xiàng),本地資源的編譯先于頁(yè)面的編譯,即第一次訪問(wèn)頁(yè)面或修改了頁(yè)面源(或它的 .resx 文件)時(shí)進(jìn)行的編譯。由于具有 .resx 的編譯提供程序,因此無(wú)需編譯步驟就能進(jìn)行部署。
正如第一項(xiàng)提到的,用于 1.x 程序集的向后可編譯支持、非特定資源和相關(guān)附屬程序集仍然存在。這個(gè)部署模型不使用 2.0 的本地化表達(dá)式,而且訪問(wèn)這些資源也不是通過(guò)默認(rèn)的運(yùn)行時(shí)資源提供程序模型進(jìn)行的。使用表達(dá)式編譯程序和資源提供程序的可擴(kuò)展模型,對(duì)綜合利用 2.0 提供的高效功能和 1.x 支持的資源部署將很有用處。
運(yùn)行時(shí)資源提供程序
為了在 ASP.NET 1.x 應(yīng)用程序中使用 ResourceManager ,需要在執(zhí)行數(shù)據(jù)綁定語(yǔ)句或應(yīng)用從資源檢索值的其他機(jī)制之前,在代碼中實(shí)例化 ResourceManager 。訪問(wèn)本地資源和共享資源時(shí),ASP.NET .0 按需要自動(dòng)實(shí)例化資源管理器,無(wú)需編寫(xiě)代碼來(lái)管理此過(guò)程。因?yàn)槭褂寐暶餍哉Z(yǔ)句以資源值填充控件屬性和 HTML 元素,所以不用編寫(xiě)任何代碼來(lái)生成完全本地化的頁(yè)面!
默認(rèn)的 ResourceProviderFactory 負(fù)責(zé)在設(shè)計(jì)時(shí)使用相關(guān)的設(shè)計(jì)器工廠實(shí)例化資源提供程序,在運(yùn)行時(shí)為頁(yè)面和共享資源實(shí)例化資源提供程序。開(kāi)發(fā)人員能編寫(xiě)代碼來(lái)訪問(wèn)本地資源的值,方法是使用 Beta 1 中 Page 對(duì)象公開(kāi)的 GetPageResourceObject :
if (this.Context.User.Identity.IsAuthenticated) mnuLogin.Text = GetPageResourceObject("Login"); else mnuLogin.Text = String.Format(GetPageResourceObject("LogoutUser", this.Context.User.Identity.Name);
當(dāng)依賴資源的 HTML 輸出需要運(yùn)行時(shí)決策時(shí),它能夠用于覆蓋聲明性本地化表達(dá)式。要訪問(wèn)共享的頁(yè)面資源,可以使用 Page 對(duì)象公開(kāi)的另一個(gè)方法:
string cultures = (string)this.GetAppResourceObject("supportedCultures");
對(duì)于共享資源而言,開(kāi)發(fā)人員更傾向于綜合利用智能感知和強(qiáng)類型資源訪問(wèn),下面的示例是檢索一個(gè)存儲(chǔ)為 String 類型的 XML 資源:
string cultures = Resources.Cultures.supportedCultures;
最終, GetPageResourceObject 和 GetAppResourceObject 通過(guò)配置好的資源提供程序訪問(wèn)正確的資源。如果創(chuàng)建了一個(gè)自定義資源提供程序,這些方法將能夠使用 GetAppResourceObject 從那些共享資源中進(jìn)行檢索。
首選的語(yǔ)言選擇
ASP.NET 1.x 應(yīng)用程序傳統(tǒng)上使用兩種主要的方法選擇每次請(qǐng)求的語(yǔ)言。對(duì)于在特定語(yǔ)言子目錄下復(fù)制整個(gè)站點(diǎn)的應(yīng)用程序,由 web.config 中的 < globalization > 元素來(lái)標(biāo)識(shí)從這些子目錄請(qǐng)求資源的運(yùn)行時(shí)線程所使用的語(yǔ)言和 UI 語(yǔ)言:
<system.web> <globalization culture="es-ES" uiCulture="es"> </system.web>
這些聲明性設(shè)置對(duì)使用單一代碼基的應(yīng)用程序沒(méi)用。而手動(dòng)設(shè)置每個(gè)請(qǐng)求線程的語(yǔ)言需要運(yùn)行時(shí)代碼,以便能為每個(gè)發(fā)出請(qǐng)求的用戶動(dòng)態(tài)地選擇語(yǔ)言。用戶的首選語(yǔ)言能從數(shù)據(jù)庫(kù)配置文件、一個(gè) HTTP cookie 或 Web 瀏覽器的語(yǔ)言設(shè)置中收集。無(wú)論如何,設(shè)置請(qǐng)求線程的 UI 語(yǔ)言決定了在運(yùn)行時(shí) ResourceManager 從哪一個(gè)本地化資源提取資源,而且正如之前提到的,語(yǔ)言設(shè)置影響與語(yǔ)言有關(guān)的格式。
ASP.NET 2.0 引入一個(gè)新功能,能根據(jù) Web 瀏覽器的偏愛(ài)自動(dòng)選擇運(yùn)行時(shí)的語(yǔ)言。 @Page 指令用于標(biāo)識(shí)是否應(yīng)該根據(jù)瀏覽器的偏愛(ài)執(zhí)行特定頁(yè)面,它也支持語(yǔ)言和 UI 語(yǔ)言的設(shè)置:
<%@ Page uiCulture="auto" culture="auto">
應(yīng)用程序的 web.config 文件也能將這項(xiàng)設(shè)置應(yīng)用到整個(gè)應(yīng)用程序中:
<system.web> <globalization culture="auto:en-US" uiCulture="auto:en"> </system.web>
如果 HTTP 頁(yè)眉不可用, auto 后的冒號(hào)允許您指定一個(gè)默認(rèn)的語(yǔ)言。因?yàn)楸仨氃O(shè)置一個(gè)特定的語(yǔ)言,因此上面的示例將 en-US 作為顯示的語(yǔ)言。
最終結(jié)果是運(yùn)行時(shí)自動(dòng)檢測(cè)瀏覽器發(fā)送的 ACCEPT_LANG 頁(yè)眉,在頁(yè)面周期的早期,將線程設(shè)置為用戶語(yǔ)言首選列表中的第一個(gè)語(yǔ)言。如果為應(yīng)用程序的用戶存儲(chǔ)了一個(gè)配置文件,或用戶能夠通過(guò)站點(diǎn)選擇特定的語(yǔ)言,那么開(kāi)發(fā)人員必須編寫(xiě)代碼來(lái)覆蓋運(yùn)行時(shí)處理的 auto 設(shè)置。示例代碼說(shuō)明了這種情況的一個(gè)使用技巧。
小結(jié)
為了更迅速地適應(yīng)未來(lái)遍及全球市場(chǎng)的產(chǎn)品發(fā)布的要求,在開(kāi)發(fā)周期早期就定義一個(gè)全球化策略勢(shì)在必行。使用 ASP.NET .0 這些新的本地化功能,開(kāi)發(fā)人員能夠更輕松地貫徹執(zhí)行本地化應(yīng)用程序的策略,與此同時(shí),減少開(kāi)發(fā)周期的系統(tǒng)開(kāi)銷。頁(yè)面資源的自動(dòng)生成和新的 Managed Resource Editor 使創(chuàng)建 Web 應(yīng)用程序資源變得更自然。使用聲明性本地化表達(dá)式,可能確保本地化所有必要的頁(yè)面元素,并有助于自動(dòng)生成適當(dāng)?shù)捻?yè)面資源。一個(gè)新的運(yùn)行時(shí)模型意味著開(kāi)發(fā)人員能選擇不再編譯附屬程序集,不再實(shí)例化資源管理器,并且不用根據(jù)語(yǔ)言來(lái)設(shè)置請(qǐng)求線程。最終將有利于發(fā)布強(qiáng)健的具有單一代碼集的 Web 應(yīng)用程序,從而降低發(fā)布應(yīng)用于全球化市場(chǎng)的解決方案的成本和付出。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
