您好,登錄后才能下訂單哦!
流行好用的軟件應(yīng)該能夠適用于不同地區(qū)的市場。下面記錄一些在項(xiàng)目中國際化的應(yīng)用,有關(guān)圖片和文本資源的自適應(yīng)。
Android采用XML資源文件來管理所有字符串消息,如果系統(tǒng)設(shè)置的Custom Locale,沒有對應(yīng)的本地化資源文件,那么程序就會取默認(rèn)的res\values\strings.xml。在此我們默認(rèn)的strings為英文,如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">L10NTest</string> <string name="action_settings">Settings</string> <string name="hello_world">Hello world!</string> <string name="I_love_you">I love you.</string> </resources>
我們添加有關(guān)中文的字符串資源,這需要為values目錄添加中文的語言國家版本。values文件夾的命名方式為:values-語言代碼-r國家代碼。
如果想要支持中文的話,則需要在res目錄下添加values-zh-rCN。該文件夾中的strings如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">國際化測試</string> <string name="action_settings">設(shè)置</string> <string name="hello_world">世界,你好!</string> <string name="I_love_you">我愛你.</string> </resources>
如果希望應(yīng)用的圖片也能隨語言環(huán)境改變,則需要為drawable目錄添加其他的語言國家版本。drawable文件夾的命名方式為:drawable-語言代碼-r國家代碼。同樣支持中文的話需要在res目錄下添加drawable-zh-rCN。
如果還需要為drawable目錄按照分辨率提供文件夾,可以在其后追加分辨率后綴,如:drawable-zh-rCN-mdpi、drawable-en-rUS-xhdpi等等。
主Activity中沒有寫任何東西,下面是它的XML布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/country" tools:ignore="ContentDescription" /> <!-- tools:ignore="ContentDescription",屏蔽掉對View設(shè)置備注說明的提示 --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/I_love_you" android:textSize="20sp" /> </LinearLayout>
在android ADT 16.0以后的控件中,沒有文本描述的view如果不加android:contentDescription="@string/……"的話就會有黃 色的下劃線,提示“[Accessibility] Missing contentDescription attribute on p_w_picpath”。加“ tools:ignore="ContentDescription"“便是屏蔽掉該提示。這句代碼不加也沒什么影響,在界面上不會有其他效果,當(dāng)然也可以寫一些字符串?dāng)?shù)據(jù)做提示,方便他人閱讀?;蛘咧苯訉懗桑?/p>
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@null" android:src="@drawable/country" />
也可。
以下是應(yīng)用的res結(jié)構(gòu):
我增加了”drawable-en-rUS“、”drawable-zh-rCN“和”values-zh-rCN“三個(gè)文件夾,其中前兩個(gè)文件夾中放了名稱都是”country“的圖片,只是前者為美國國旗圖片,后者為中國國旗圖片。第三個(gè)文件夾中的strings文件上面已給出。
運(yùn)行程序,如果設(shè)置系統(tǒng)的語言和輸入為中文,效果圖如下:
如果設(shè)置為英文,效果圖如下:
我并沒有增加有關(guān)英文的本地化資源文件,所以程序就會取res\values\下的strings.xml,當(dāng)然也可以增加對應(yīng)的文件夾為:values-en-rUS,其中放置相關(guān)文本資源。
如果是其他國家的語言環(huán)境,那文件夾該如何命名呢,以字符串資源為例,如下:
中文(中國):values-zh-rCN
中文(臺灣):values-zh-rTW
中文(香港):values-zh-rHK
英語(美國):values-en-rUS
英語(英國):values-en-rGB
英文(澳大利亞):values-en-rAU
英文(加拿大):values-en-rCA
英文(愛爾蘭):values-en-rIE
英文(印度):values-en-rIN
英文(新西蘭):values-en-rNZ
英文(新加坡):values-en-rSG
英文(南非):values-en-rZA
阿拉伯文(埃及):values-ar-rEG
阿拉伯文(以色列):values-ar-rIL
保加利亞文: values-bg-rBG
加泰羅尼亞文:values-ca-rES
捷克文:values-cs-rCZ
丹麥文:values-da-rDK
德文(奧地利):values-de-rAT
德文(瑞士):values-de-rCH
德文(德國):values-de-rDE
德文(列支敦士登):values-de-rLI
希臘文:values-el-rGR
西班牙文(西班牙):values-es-rES
西班牙文(美國):values-es-rUS
芬蘭文(芬蘭):values-fi-rFI
法文(比利時(shí)):values-fr-rBE
法文(加拿大):values-fr-rCA
法文(瑞士):values-fr-rCH
法文(法國):values-fr-rFR
希伯來文:values-iw-rIL
印地文:values-hi-rIN
克羅里亞文:values-hr-rHR
匈牙利文:values-hu-rHU
印度尼西亞文:values-in-rID
意大利文(瑞士):values-it-rCH
意大利文(意大利):values-it-rIT
日文:values-ja-rJP
韓文:values-ko-rKR
立陶宛文:valueslt-rLT
拉脫維亞文:values-lv-rLV
挪威博克馬爾文:values-nb-rNO
荷蘭文(比利時(shí)):values-nl-BE
荷蘭文(荷蘭):values-nl-rNL
波蘭文:values-pl-rPL
葡萄牙文(巴西):values-pt-rBR
葡萄牙文(葡萄牙):values-pt-rPT
羅馬尼亞文:values-ro-rRO
俄文:values-ru-rRU
斯洛伐克文:values-sk-rSK
斯洛文尼亞文:values-sl-rSI
塞爾維亞文:values-sr-rRS
瑞典文:values-sv-rSE
泰文:values-th-rTH
塔加洛語:values-tl-rPH
土耳其文:values--r-rTR
烏克蘭文:values-uk-rUA
越南文:values-vi-rVN
事實(shí)上可以通過程序獲取JAVA所有支持的語言和國家的,程序代碼如下:
import java.util.Locale; public class Test { public static void main(String[] args) { //調(diào)用Locale類的getAvailableLocales方法獲取,該方法返回一個(gè)數(shù)組,其中包含JAVA支持的語言和國家 Locale[] localeList = Locale.getAvailableLocales(); //依次獲取所支持的國家和語言 for (int i = 0; i < localeList.length; i++) { System.out.println(localeList[i].getDisplayCountry() + "=" + localeList[i].getCountry() + "" + localeList[i].getDisplayLanguage() + "=" + localeList[i].getLanguage()); } } }
輸出結(jié)果如下(有些國家可能會使用多種語言):
馬來西亞=MY馬來文=ms 卡塔爾=QA阿拉伯文=ar 冰島=IS冰島文=is 芬蘭=FI芬蘭文=fi =波蘭文=pl 馬耳他=MT英文=en 瑞士=CH意大利文=it 比利時(shí)=BE荷蘭文=nl 沙特阿拉伯=SA阿拉伯文=ar 伊拉克=IQ阿拉伯文=ar 波多黎哥=PR西班牙文=es 智利=CL西班牙文=es =芬蘭文=fi 奧地利=AT德文=de =丹麥文=da 英國=GB英文=en 巴拿馬=PA西班牙文=es =塞爾維亞文=sr 也門=YE阿拉伯文=ar 馬其頓王國=MK馬其頓文=mk =馬其頓文=mk 加拿大=CA英文=en 越南=VN越南文=vi 荷蘭=NL荷蘭文=nl 美國=US西班牙文=es 中國=CN中文=zh 洪都拉斯=HN西班牙文=es 美國=US英文=en =法文=fr =泰文=th =阿拉伯文=ar 摩洛哥=MA阿拉伯文=ar =拉托維亞文(列托)=lv =德文=de 印度尼西亞=ID印度尼西亞文=in =克羅地亞文=hr 南非=ZA英文=en 韓國=KR朝鮮文=ko 突尼斯=TN阿拉伯文=ar =印度尼西亞文=in =日文=ja 塞爾維亞=RS塞爾維亞文=sr 白俄羅斯=BY白俄羅斯文=be 臺灣地區(qū)=TW中文=zh 蘇丹=SD阿拉伯文=ar =葡萄牙文=pt =冰島文=is 日本=JP日文=ja 玻利維亞=BO西班牙文=es 阿爾及利亞=DZ阿拉伯文=ar =馬來文=ms 阿根廷=AR西班牙文=es 阿拉伯聯(lián)合酋長國=AE阿拉伯文=ar 加拿大=CA法文=fr =斯洛文尼亞文=sl =西班牙文=es 立陶宛=LT立陶宛文=lt 黑山=ME塞爾維亞文=sr 敘利亞=SY阿拉伯文=ar 俄羅斯=RU俄文=ru 比利時(shí)=BE法文=fr 西班牙=ES西班牙文=es =保加利亞文=bg 以色列=IL希伯來文=iw =瑞典文=sv =英文=en =希伯來文=iw 丹麥=DK丹麥文=da 哥斯達(dá)黎加=CR西班牙文=es 香港=HK中文=zh =中文=zh 西班牙=ES加泰羅尼亞文=ca 泰國=TH泰文=th 烏克蘭=UA烏克蘭文=uk 多米尼加共和國=DO西班牙文=es 委內(nèi)瑞拉=VE西班牙文=es 波蘭=PL波蘭文=pl 利比亞=LY阿拉伯文=ar 約旦=JO阿拉伯文=ar =意大利文=it =烏克蘭文=uk 匈牙利=HU匈牙利文=hu =愛爾蘭文=ga 危地馬拉=GT西班牙文=es 巴拉圭=PY西班牙文=es 保加利亞=BG保加利亞文=bg 克羅地亞=HR克羅地亞文=hr 波斯尼亞和黑山共和國=BA塞爾維亞文=sr 羅馬尼亞=RO羅馬尼亞文=ro 盧森堡=LU法文=fr =挪威文=no =立陶宛文=lt 新加坡=SG英文=en 厄瓜多爾=EC西班牙文=es 波斯尼亞和黑山共和國=BA塞爾維亞文=sr 尼加拉瓜=NI西班牙文=es =斯洛伐克文=sk =俄文=ru =馬耳他文=mt 薩爾瓦多=SV西班牙文=es =荷蘭文=nl 印度=IN印地文=hi =愛沙尼亞文=et 希臘=GR希臘文=el 斯洛文尼亞=SI斯洛文尼亞文=sl 意大利=IT意大利文=it 日本=JP日文=ja 盧森堡=LU德文=de 瑞士=CH法文=fr 馬耳他=MT馬耳他文=mt 巴林=BH阿拉伯文=ar =阿爾巴尼亞文=sq =越南文=vi 黑山=ME塞爾維亞文=sr 巴西=BR葡萄牙文=pt 挪威=NO挪威文=no =希臘文=el 瑞士=CH德文=de 新加坡=SG中文=zh 科威特=KW阿拉伯文=ar 埃及=EG阿拉伯文=ar 愛爾蘭=IE愛爾蘭文=ga 秘魯=PE西班牙文=es 捷克共和國=CZ捷克文=cs 土耳其=TR土耳其文=tr =捷克文=cs 烏拉圭=UY西班牙文=es 愛爾蘭=IE英文=en 印度=IN英文=en 阿曼=OM阿拉伯文=ar 塞爾維亞及黑山=CS塞爾維亞文=sr =加泰羅尼亞文=ca =白俄羅斯文=be =塞爾維亞文=sr =朝鮮文=ko 阿爾巴尼亞=AL阿爾巴尼亞文=sq 葡萄牙=PT葡萄牙文=pt 拉脫維亞=LV拉托維亞文(列托)=lv 塞爾維亞=RS塞爾維亞文=sr 斯洛伐克=SK斯洛伐克文=sk 墨西哥=MX西班牙文=es 澳大利亞=AU英文=en 挪威=NO挪威文=no 新西蘭=NZ英文=en 瑞典=SE瑞典文=sv =羅馬尼亞文=ro 黎巴嫩=LB阿拉伯文=ar 德國=DE德文=de 泰國=TH泰文=th =土耳其文=tr 哥倫比亞=CO西班牙文=es 菲律賓=PH英文=en 愛沙尼亞=EE愛沙尼亞文=et 塞浦路斯=CY希臘文=el =匈牙利文=hu 法國=FR法文=fr
在做項(xiàng)目時(shí),我遇到這樣一種情況,字符串資源需要JAVA代碼來控制,而不是在XML文件中獲取,下面提供該方法:
創(chuàng)建ConstantBase類來定義你需要的字符串,如下:
package com.example.l10ntest; public class ConstantBase { public String PUT_NAME; public String SAY_LOVE; public String NEXT; public String Second_Page; }
中英文的字符串類分別命名如下,中文:
package com.example.l10ntest; public class ConstantCH extends ConstantBase { public ConstantCH() { //此處定義需要的中文字符串 PUT_NAME = "請輸入你的名字。"; SAY_LOVE = "我愛你"; NEXT = "下一頁"; Second_Page = "第二頁"; } }
英文:
package com.example.l10ntest; public class ConstantEN extends ConstantBase { public ConstantEN() { // 此處定義需要的英文字符串 PUT_NAME = "Please put your name."; SAY_LOVE = "I love you"; NEXT = "next"; Second_Page = "The second page"; } }
我在新創(chuàng)建的Constant類中寫了本地語言的判斷方法,該類如下:
package com.example.l10ntest; import java.util.Locale; public class Constant { public static ConstantBase string = produceConstant(); public static ConstantBase produceConstant() { if (isLocalLanguageZH()) { string = new ConstantCH(); } else { string = new ConstantEN(); } return string; } //判斷本地語言是否是中文 public static boolean isLocalLanguageZH() { if (Locale.getDefault().getLanguage().contains("zh") && Locale.getDefault().getCountry().contains("CN")) { return true; } return false; } }
主類的XML文件做一下修改(暫時(shí)將ImageView屏蔽掉,后面增加了一個(gè)Button),如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <!-- <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@null" android:src="@drawable/country" /> --> <!-- tools:ignore="ContentDescription",屏蔽掉對View設(shè)置備注說明的提示 --> <TextView android:id="@+id/putName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@null" android:textSize="20sp" /> <TextView android:id="@+id/iloveyou" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@null" android:textSize="20sp" /> <Button android:id="@+id/next" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
在主類中,寫如下代碼:
((TextView) findViewById(R.id.putName)) .setText(Constant.string.PUT_NAME); ((TextView) findViewById(R.id.iloveyou)) .setText(Constant.string.SAY_LOVE);
這樣便可以通過JAVA代碼來控制字符串的獲取了。但是發(fā)現(xiàn)一個(gè)問題,就是當(dāng)程序切換到后臺時(shí),你將手機(jī)終端的語言修改,比如當(dāng)前中文修改為英文,再從后臺將該程序拉起時(shí),顯示的文本信息并不會隨著變換,如果以前是中文,修改系統(tǒng)語言后還是中文,國際化似乎不生效。最后發(fā)現(xiàn)只有將該程序進(jìn)程殺死,再次啟動,國際化才會生效。但是每次切換一下終端語言就人為殺進(jìn)程重啟應(yīng)用,顯然是不合理的。
事實(shí)上當(dāng)locale信息改變之后,系統(tǒng)會發(fā)廣播消息Intent.ACTION_LOCALE_CHANGED,我們可以寫接收該廣播的代碼,并做一些操作。
不妨多寫幾個(gè)Activity頁面做測試,我寫了兩個(gè),MainActivity經(jīng)過修改的XML前面已經(jīng)給出了,MainActivity如下:
package com.example.l10ntest; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((TextView) findViewById(R.id.putName)) .setText(Constant.string.PUT_NAME); ((TextView) findViewById(R.id.iloveyou)) .setText(Constant.string.SAY_LOVE); Button btn = (Button) findViewById(R.id.next); btn.setText(Constant.string.NEXT); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this,SecondActivity.class)); } }); } }
第二個(gè)Activity(SecondActivity)我沒有寫XML布局,代碼如下:
package com.example.l10ntest; import android.os.Bundle; import android.view.Gravity; import android.widget.TextView; public class SecondActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setGravity(Gravity.CENTER); textView.setText(Constant.string.Second_Page); textView.setTextSize(30); setContentView(textView); } }
事實(shí)上一個(gè)應(yīng)用一般不會只有一個(gè)Activity的,我將兩個(gè)Activity都繼承了BaseActivity,在BaseActivity中對這兩個(gè)Activity做統(tǒng)一管理,BaseActivity如下:
package com.example.l10ntest; import android.app.Activity; import android.os.Bundle; public class BaseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Utils.addToList(this); } }
只調(diào)用了Utils類里的一個(gè)方法,在Activity創(chuàng)建后,將它添加到List里面。Utils類代碼如下:
package com.example.l10ntest; import java.util.ArrayList; import java.util.Iterator; import android.app.Activity; import android.util.Log; public class Utils { private static String TAG = "Utils"; // 創(chuàng)建存放Activity的集合 private static ArrayList<Activity> activityList = new ArrayList<Activity>(); public static void addToList(Activity activity) { Log.i(TAG, "activity name:" + activity.getClass().getName()); activityList.add(activity); } public static void stopApp() { Iterator<Activity> itr = activityList.iterator(); Activity a = null; while (itr.hasNext()) { a = itr.next(); a.finish(); } Log.i(TAG, "stopApp end."); System.exit(0); } }
這里面有兩個(gè)方法,一個(gè)就是添加Activity做統(tǒng)一管理,第二個(gè)是停止程序的方法,先將List中的Activity依次殺死,再殺死進(jìn)程退出程序。
下面就是比較重要的接收系統(tǒng)廣播的類了,代碼如下:
package com.example.l10ntest; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class AppExitReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent == null || intent.getAction() == null) return; if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) { Utils.stopApp(); } } }
AndroidManifest.xml文件如下,配置了一個(gè)廣播接收。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.l10ntest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.l10ntest.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.example.l10ntest.SecondActivity" android:label="@string/app_name" > </activity> <receiver android:name="com.example.l10ntest.AppExitReceiver" > <intent-filter> <action android:name="android.intent.action.LOCALE_CHANGED" /> </intent-filter> </receiver> </application> </manifest>
整理一下思路:
寫了兩個(gè)Activity,這兩個(gè)Activity都用到了文本資源,如“((TextView) findViewById(R.id.iloveyou)).setText(Constant.string.SAY_LOVE);”和“textView.setText(Constant.string.Second_Page);”MainActivity中增加了跳轉(zhuǎn)到SecondActivity的按鈕。兩個(gè)Activity都繼承了BaseActivity,當(dāng)它們創(chuàng)建后,會通過BaseActivity中的“Utils.addToList(this)”將它們依次添加到Utils類中的activityList里。
在終端切換系統(tǒng)語言,發(fā)送Intent.ACTION_LOCALE_CHANGED廣播后,我們創(chuàng)建AppExitReceiver類來接收該廣播,并調(diào)用“Utils.stopApp()“來將創(chuàng)建的Activity依次關(guān)閉,并且退出應(yīng)用程序,這樣不管該程序從后臺切回來還是點(diǎn)擊該程序的圖標(biāo),程序都會重新啟動,顯示的文本信息會隨著系統(tǒng)語言的變換而變換。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。