本文介紹了將語言代碼三個字符(ISO 639-2)轉換為兩個字符代碼(ISO 639-1)的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我正在開發一個使用文本到語音(TTS)引擎的Android應用程序。TTS組件以Locale
對象列表的形式返回可用語言列表。
但每個Locale
對象的Locale::getLanguage
和Locale::getISO3Language
兩個方法返回相同的3字符代碼(ISO 639-2)。通常getLanguage()
以2字符格式(ISO 639-1)返回語言代碼,但對于特定設備,代碼為3個字符。國家代碼也是如此。但是,我需要兩個字符格式的語言和國家代碼(ISO 639-1)。
有人知道進行轉換的方法嗎?請注意,我需要一個具有兩個字母格式的語言和國家/地區代碼的相應Locale
對象。
推薦答案
tl;dr
作為一種解決辦法,請根據ISO 639-1將每個已知的Locale
映射到其兩個字母的語言代碼。
new LocaleLookup().lookupTwoLetterLanguageCode( Locale.CANADA_FRENCH )
fr
或可能只分析Locale::toString
的文本。
Locale
.CANADA_FRENCH
.toString() // fr_CA
.split( "_" ) // Array: { "fr" , "CA" }
[ 0 ] // Grab first element in array, "fr".
fr
對于兩個字母的國家/地區代碼,請使用拆分字符串的第二部分。使用1
而不是0
的索引。
Locale
.CANADA_FRENCH
.toString() // fr_CA
.split( "_" ) // Array: { "fr" , "CA" }
[ 1 ] // Grab first element in array, "CA".
CA
錯誤?
Locale::getLanguage
將返回3個字母的代碼似乎是一個錯誤。Javadoc在其代碼示例中使用了兩個字母的代碼。但不幸的是,Javadoc沒有明確指定2個或3個字母。我建議您向OpenJDK項目提交一個請求,以澄清此Java代碼。
解決方法
作為一種解決辦法,您或許可以調用Locale.getISOLanguages
來獲取所有已知語言的兩個字母代碼的數組。然后把那些循環起來。對于每個對象,使用在Javadoc中看到的代碼,傳遞兩個字母的代碼來限制Locale
對象進行比較:
if (locale.getLanguage().equals(new Locale("he").getLanguage()))
從此版本中,您可以在區域設置和兩個字母的代碼之間使用您自己的Map
。
示例類
這是我第一次嘗試這樣的變通地圖。
在構造函數中,我們獲得所有已知區域設置和所有已知2字母ISO 639-1語言代碼的列表。
接下來,我們執行嵌套循環。對于每個地區,我們循環所有兩個字母的語言代碼,直到找到匹配項。注意,我們做的是而不是進行字符串匹配。Javadoc警告我們ISO 639標準不是穩定的;代碼正在更改。報價:
注意:ISO 639不是一個穩定的標準-某些語言的代碼已更改。Locale的構造函數可以識別代碼已更改的語言的新代碼和舊代碼,但此函數始終返回舊代碼。如果要檢查代碼已更改的特定語言,請不要執行以下操作
if (locale.getLanguage().equals("he")) // BAD!
相反,請執行
if (locale.getLanguage().equals(new Locale("he").getLanguage())) // GOOD.
因此,我們的內部循環查看每個已知的兩個字母的語言代碼,并獲取該語言的Locale
對象。然后,if
語句比較getLanguage
的輸出(A)外部循環的Locale
和(B)內部循環生成的僅語言的Locale
(由兩個字母的代碼生成)。在您情況下,您聲稱某個設備正在為我們對getLanguage
的調用輸出3個字母的代碼值。但無論是2個字母還是3個字母,都無關緊要。我們只是在尋找匹配項。
實例化后,我們可以通過調用lookupTwoLetterLanguageCode
方法向LocaleLookup
實例請求匹配特定Locale
的兩個字母的代碼。
LocaleLookup localeLookup = new LocaleLookup();
Locale locale = Locale.CANADA_FRENCH;
String code = localeLookup.lookupTwoLetterLanguageCode( locale );
System.out.println( "Locale: " + locale.toString() + " " + locale.getDisplayName( Locale.getDefault() ) + " | ISO 639-1 code: " + code );
區域設置:FR_CA法語(加拿大)|ISO 639-1代碼:FR
我只是在猜測這一切。我沒有仔細考慮過,也沒有測試過任何這一點。所以買家-當心,這個解決方案值你花的每一分錢。祝你好運。
這是整個類,其中public static void main
用作演示。
package work.basil.example;
import java.util.*;
public class LocaleLookup
{
private Map < Locale, String > mapLocaleToTwoLetterLangCode;
public LocaleLookup ( )
{
this.mapLocaleToTwoLetterLangCode = new HashMap <>( Locale.getAvailableLocales().length );
this.makeMaps();
System.out.println( "mapLocaleToTwoLetterLangCode = " + mapLocaleToTwoLetterLangCode );
}
private void makeMaps ( )
{
// Get all locales.
Set < Locale > locales = Set.of( Locale.getAvailableLocales() );
// Get all languages, per 2-letter code.
Set < String > twoLetterLanguageCodes = Set.of( Locale.getISOLanguages() ); // Returns: An array of ISO 639 two-letter language codes.
for ( Locale locale : locales )
{
for ( String twoLetterLanguageCode : twoLetterLanguageCodes )
{
if ( locale.getLanguage().equals( new Locale( twoLetterLanguageCode ).getLanguage() ) )
{
this.mapLocaleToTwoLetterLangCode.put( locale , twoLetterLanguageCode );
break;
}
}
}
// System.out.println( "locales = " + locales );
// System.out.println( "twoLetterLanguageCodes = " + twoLetterLanguageCodes );
}
public String lookupTwoLetterLanguageCode ( final Locale locale )
{
String code = this.mapLocaleToTwoLetterLangCode.get( locale );
Objects.requireNonNull( code );
return code;
}
public static void main ( String[] args )
{
LocaleLookup localeLookup = new LocaleLookup();
Locale locale = Locale.CANADA_FRENCH;
String code = localeLookup.lookupTwoLetterLanguageCode( locale );
System.out.println( "Locale: " + locale.toString() + " " + locale.getDisplayName( Locale.getDefault() ) + " | ISO 639-1 code: " + code );
}
}
這是我在Java 15預發布版本中生成的映射。注意可能是不正確的,因為我在預發布版本中看到了一些關于區域設置的錯誤。
這篇關于將語言代碼三個字符(ISO 639-2)轉換為兩個字符代碼(ISO 639-1)的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,