简体   繁体   English

本机模式下的 GraalVM Quarkus 语言环境

[英]GraalVM Quarkus Locale in native mode

I have an unexpected behavior with available locales when native build.在本地构建时,我对可用的语言环境有意外的行为。 I have only one locale available in native mode.在本机模式下,我只有一个可用的语言环境。

My application is very simple:我的应用程序非常简单:

@ApplicationPath("/api")
public class ApplicationPathConfiguration extends Application {
}

@Path("/locales")
public class LocaleController {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Locale[] get() {
        return Locale.getAvailableLocales();
    }

}

After checkout if I launch the application in dev mode:结帐后,如果我在开发模式下启动应用程序:

mvn quarkus:dev

You can call the endpoint: http://localhost:8080/api/locales可以调用端点: http://localhost:8080/api/locales

curl http://localhost:8080/api/locales

This endpoint return a lot of locales:此端点返回许多语言环境:

["","nn","ar_JO","bg","kea","nds","zu","am_ET","fr_DZ","ti_ET","bo_CN","hsb","qu_EC","ta_SG","lv","en_NU","zh_SG_#Hans","en_MS","en_GG","en_JM","vo","kkj","sr_ME","sv_SE","es_BO","dz_BT","mer","sah","en_ZM","fr_ML","br","ha_NG","ar_SA","fa_AF","dsb_DE","sk","os_GE","ml","en_MT","en_LR","ar_TD","en_GH","en_IL","sv","cs","el","tzm_MA","af","sw_UG","ses_ML","smn","tk_TM","sr_ME_#Cyrl","ar_EG","dsb","lkt_US","vai_LR_#Latn","ji_001","yo_NG","se_NO","khq","sw_CD","vo_001","en_PW","pl_PL","fil_PH","it_VA","sr_CS","ne_IN","es_PH","es_ES","es_CO","bg_BG","ji","ar_EH","bs_BA_#Latn","en_VC","nds_DE","nb_SJ","es_US","agq","hsb_DE","en_US_POSIX","en_150","ar_SD","en_KN","ha_NE","pt_MO","ebu","ro_RO","zh__#Hans","lb_LU","sr_ME_#Latn","es_GT","so_KE","dje_NE","bas_CM","fr_PM","ar_KM","fr_MG","no_NO_NY","es_CL","mn","agq_CM","kam_KE","teo","tr_TR","eu","fa_IR","en_MO","wo","shi__#Tfng","en_BZ","sq_AL","ar_MR","es_DO","ru","twq_NE","az","nmg_CM","fa","kl_GL","en_NR","nd","kk","az__#Cyrl","en_MP","en_GD","tk","hy","shi__#Latn","en_BW","en_AU","en_CY","kab_DZ","kde_TZ","ta_MY","ti_ER","nus_SS","en_RW","nd_ZW","sv_FI","ksb","luo","lb","ne","en_IE","zh_SG","ln_CD","en_KI","nnh_CM","om_ET","no","ja_JP","my","ka","ar_IL","mgh","or_IN","fr_MF","shi","kl","en_SZ","rwk_TZ","zh","es_PE","mgh_MZ","saq","az__#Latn","ta","en_GB","lag","zh_HK_#Hant","ar_SY","ksf_CM","bo","kk_KZ","es_PA","tt_RU","om_KE","ar_PS","en_AS","fr_VU","zh_TW","bez","kln","fr_MC","kw","pt_MZ","fr_NE","vai__#Latn","ksb_TZ","ksh","ur_IN","ln","en_JE","gsw_CH","ln_CF","en_CX","luy_KE","pt","en_AT","gl","kkj_CM","sr__#Cyrl","yue_CN_#Hans","es_GQ","kn_IN","ar_YE","to","en_SX","ga","qu","ru_KZ","en_TZ","et","en_PR","mua","ko_KP","in","ps","sn","nl_SR","rof","en_BS","km","zgh","fr_NC","be","gv","es","dua","gd_GB","jgo","nl_BQ","fr_CM","gsw","uz_UZ_#Cyrl","pa_IN_#Guru","en_KE","guz","mfe","asa_TZ","teo_UG","ja","fr_SN","or","brx","fr_MA","pt_LU","fr_BL","en_NL","mgo_CM","ln_CG","te","sl","ko_KR","el_CY","mr_IN","ha","es_MX","lrc_IR","gsw_FR","es_HN","hu_HU","ff_SN","sbp","sq_MK","sr_BA_#Cyrl","fi","uz","bs__#Cyrl","et_EE","sr__#Latn","en_SS","sw","bo_IN","fy_NL","ar_OM","tr_CY","nmg","rm","en_MG","fr_BI","uz_UZ_#Latn","bn","dua_CM","de_IT","lrc_IQ","vai__#Vaii","kn","fr_TN","sr_RS","de_CH","bn_BD","nnh","fr_PF","en_ZA","gu","pt_GQ","vun_TZ","jmc_TZ","en_TV","lo","fr_FR","en_PN","en_MH","fr_BJ","zh__#Hant","cu_RU","zh_HK_#Hans","nl_NL","sah_RU","en_GY","ps_AF","bs__#Latn","ky","mas","dyo_SN","os","bs_BA_#Cyrl","nl_CW","ar_DZ","sk_SK","pt_CH","fr_GQ","ff_CM","am","en_NG","fr_CI","ki_KE","en_PK","zh_CN","en_LC","rw","brx_IN","wo_SN","iw","gv_IM","mk_MK","en_TT","dav","sl_SI","fr_HT","te_IN","nl_SX","lrc","ses","ce","fr_CG","fr_BE","jgo_CM","mt_MT","es_VE","mg","mr","mer_KE","ko","nds_NL","en_BM","nb_NO","ak","seh","kde","dz","kea_CV","mgo","vi_VN","en_VU","en_US","to_TO","mfe_MU","seh_MZ","fr_BF","pa__#Guru","it_SM","fr_YT","gu_IN","ii_CN","pa_PK_#Arab","ast","fr_RE","fi_FI","yue__#Hans","ca_FR","sr_BA_#Latn","bn_IN","fr_GP","pa","zgh_MA","uk_UA","fr_DJ","rn","tg","rwk","hu","fr_CH","en_NF","twq","ha_GH","sr_XK_#Cyrl","bm","ar_SS","en_GU","nl_AW","de_BE","en_AI","en_CM","xog_UG","cs_CZ","tr","ca_ES","cgg","rm_CH","nyn_UG","ru_MD","ms_MY","ta_LK","ksf","en_TO","cy","en_PG","fr_CF","pt_TL","sq","fr","tg_TJ","en_ER","qu_PE","sr_BA","es_PY","de","es_EC","kok_IN","lg_UG","zu_ZA","fr_TG","sr_XK_#Latn","en_PH","ig_NG","fr_GN","prg_001","cgg_UG","zh_MO_#Hans","ksh_DE","lg","ru_RU","se_FI","ff","en_DM","en_CK","sd","ar_MA","ga_IE","en_BI","en_AG","fr_TD","en_WS","fr_LU","ebu_KE","bem_ZM","xog","ewo_CM","fr_CD","so","rn_BI","en_NA","ar_ER","kab","ms","nus","sn_ZW","prg","iw_IL","ug","es_EA","th_TH_TH_#u-nu-thai","hi","fr_SC","ca_IT","lag_TZ","en_SL","teo_KE","no_NO","ca_AD","zh_MO_#Hant","en_SH","vai","qu_BO","haw_US","vi","fr_CA","de_LU","sq_XK","dyo","en_KY","mt","it_CH","de_DE","si_LK","luo_KE","en_DK","yav","so_DJ","lt_LT","it_IT","eo","kam","ar_SO","en_ZW","ro","eo_001","ee","en_UM","nn_NO","fr_MU","pl","se_SE","en_TK","en_SI","mua_CM","ur","uz__#Arab","vai_LR_#Vaii","saq_KE","se","pt_GW","lo_LA","chr","ar_LB","af_ZA","ms_SG","ee_TG","ln_AO","be_BY","ff_GN","yue__#Hant","in_ID","es_BZ","ar_AE","hr_HR","luy","as","rof_TZ","it","pt_CV","ks_IN","uk","my_MM","ur_PK","mn_MN","da_DK","en_FM","es_PR","wae_CH","mzn","en_BE","ii","tt","fr_WF","ru_BY","mzn_IR","naq","fo_DK","en_SG","ee_GH","ar_BH","kln_KE","tzm","fur","om","hi_IN","en_CH","asa","yo_BJ","fo_FO","ast_ES","fr_KM","bez_TZ","fr_MQ","en_SD","es_AR","en_MY","ja_JP_JP_#u-ca-japanese","es_SV","pt_BR","ml_IN","sbp_TZ","fil","en_FK","uz__#Cyrl","is_IS","yue_HK_#Hant","hy_AM","en_GM","en_DG","fo","ne_NP","hr","pt_ST","ak_GH","lt","uz_AF_#Arab","fur_IT","ta_IN","ccp","en_SE","fr_GF","lkt","zh_CN_#Hans","is","es_419","si","pt_AO","en_001","en","guz_KE","gsw_LI","ccp_BD","es_IC","ca","ru_KG","fr_MR","ar_TN","ks","zh_TW_#Hant","bm_ML","kw_GB","ug_CN","as_IN","es_BR","zh_HK","khq_ML","sw_KE","en_SB","th_TH","rw_RW","chr_US","shi_MA_#Tfng","ar_IQ","nyn","yue","jmc","en_MW","naq_NA","mk","en_IO","ar_QA","en_DE","pa__#Arab","en_CC","bs","ro_MD","en_FI","pt_PT","fy","az_AZ_#Cyrl","th","dav_KE","ckb_IQ","shi_MA_#Latn","es_CU","ar","en_SC","en_VI","haw","eu_ES","en_UG","en_NZ","dje","es_UY","bas","mas_KE","ru_UA","sg_CF","el_GR","yav_CM","uz__#Latn","sg","da_GL","en_FJ","de_LI","en_BB","km_KH","smn_FI","hr_BA","de_AT","ckb_IR","nl","lu_CD","ca_ES_VALENCIA","ar_001","so_SO","lv_LV","ckb","es_CR","fr_GA","ar_KW","sr","ar_LY","sr_RS_#Cyrl","bem","en_MU","da","wae","gl_ES","en_IM","az_AZ_#Latn","en_LS","ig","en_HK","en_GI","ce_RU","en_CA","gd","ka_GE","fr_SY","sw_TZ","fr_RW","so_ET","nl_BE","ar_DJ","mg_MG","cy_GB","en_VG","cu","os_RU","sr_RS_#Latn","en_TC","ky_KG","sv_AX","af_NA","vun","en_IN","lu","ki","yo","es_NI","nb","ff_MR","sd_PK","mas_TZ","ti","kok","ewo","ms_BN","ccp_IN","br_FR"]

If I do the same in native mode:如果我在本机模式下做同样的事情:

mvn clean package -Pnative && ./target/QuarkusLocale-1.0-SNAPSHOT-runner

I obtain only one locale:我只获得一个语言环境:

["fr_US"]

How can I obtain all available locale?如何获取所有可用的语言环境?

Moreover, because of this behavior I have another problem.此外,由于这种行为,我还有另一个问题。 As you can see if I tried to develop a service who want use locale.如您所见,我是否尝试开发想要使用语言环境的服务。 Locale is not use and I can't apply currency format.未使用区域设置,我无法应用货币格式。 To demonstrate that, I develop CurrencyController.为了证明这一点,我开发了 CurrencyController。

@Path("/currency")
public class CurrencyController {

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public String get(String localeString) {
        String[] localeArray = localeString.split("-");
        Locale locale = new Locale(localeArray[0], localeArray[1]);

        NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
        numberFormat.setCurrency(Currency.getInstance("USD"));
        return numberFormat.format(1337);
    }

}

You can call it with curl:您可以使用 curl 调用它:

curl -X POST http://localhost:8080/api/currency -H "Content-Type: application/json" -d "en-GB"
> US$1,337.00

curl -X POST http://localhost:8080/api/currency -H "Content-Type: application/json" -d "en-US
> $1,337.00

If I do the same in native mode:如果我在本机模式下做同样的事情:

curl -X POST http://localhost:8080/api/currency -H "Content-Type: application/json" -d "en-GB"
> US$1,337.00

curl -X POST http://localhost:8080/api/currency -H "Content-Type: application/json" -d "en-US
> US$1,337.00
  • Running Quarkus native-image plugin on GraalVM Version 19.3.1 CE在 GraalVM 版本 19.3.1 CE 上运行 Quarkus 本机映像插件
  • Quarkus 1.4.1.Final Quarkus 1.4.1.Final

This is a very well-known issue on GraalVM .这是GraalVM 上一个非常知名的问题 Currently, the only way to bypass it is to create Feature that will scan all locales at run time:目前,绕过它的唯一方法是创建将在运行时扫描所有语言环境的功能:

  1. Add maven dependency添加 maven 依赖
        <dependency>
            <groupId>org.graalvm.nativeimage</groupId>
            <artifactId>svm</artifactId>
            <version>19.3.1</version>
        </dependency>
  1. Create Feature class创建特征 class
package org.example;

import com.oracle.svm.core.annotate.AutomaticFeature;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;

import java.util.Locale;

@AutomaticFeature
public class NativeLanguageFeature implements Feature {

    @Override
    public void beforeAnalysis(BeforeAnalysisAccess access) {
        ImageSingletons.lookup(RuntimeClassInitializationSupport.class).initializeAtBuildTime(SupportedLocales.class, "__");

        final Locale[] availableLocales = Locale.getAvailableLocales();
        final SupportedLocales supportedLocales = new SupportedLocales();
        supportedLocales.locales = availableLocales;
        ImageSingletons.add(SupportedLocales.class, supportedLocales);
    }

    public static class SupportedLocales {
        public Locale[] locales;
    }
}
  1. In a place where you want to access locales, check if SupportedLocales present in ImageSingletons在您要访问语言环境的地方,检查ImageSingletons中是否存在 SupportedLocales
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Locale[] get() {
        if(ImageSingletons.contains(NativeLanguageFeature.SupportedLocales.class)){
            final NativeLanguageFeature.SupportedLocales lookup = ImageSingletons.lookup(NativeLanguageFeature.SupportedLocales.class);
            return lookup.locales;
        }
        return Locale.getAvailableLocales();
    }

You probably will need to do same thing with money as well.你可能也需要用钱做同样的事情。

This happens to keep the native executable small as possible, so only the default locale is added to the bundle.这恰好使本机可执行文件尽可能小,因此仅将默认语言环境添加到包中。 The GraalVM allows you to add more custom locales at build time with -H:IncludeLocales=fr,en,... . GraalVM 允许您在构建时使用-H:IncludeLocales=fr,en,...添加更多自定义语言环境。

More information in https://www.graalvm.org/22.1/reference-manual/native-image/Resources/#locales https 中的更多信息://www.graalvm.org/22.1/reference-manual/native-image/Resources/#locales

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM