Android多语言适配繁体中文

Android多语言适配一般默认是values/drawable目录下的文件是英文语言的资源,如果在中文下使用不同的资源则需要新建values-zh/drawable-zh-xxxdpi这样,res目录下的命名规则是drawable-语言-国家-xxxdpi,在没有特定国家的资源会先找语言相关的目录。但是中文有点特别!这也是一个坑,按常规思维drawable-zh应该是简体中文/繁体中文共有的资源,就是如果没有drawable-zh-rTw或drawable-zh-rHK的资源的话当切到繁体中文时会去drawable-zh查找资源,这样想是大错特错,实际的结果是没有繁体资源时系统会去默认的目录下查找,也就是在drawable或drawable-xxxdpi这些目录找,这个是android的bug还是故意认为HK和TW不是我大中华的?

废话不多话说,实际开发过程中会有这样的需求,就是希望所有的中文不管是繁体还是简体都是共用资源的,根据上面说的规则,如果不分别在zh-rTW和zh-rHK都放入资源的话是不可能做到了,那如果还是想省点资源怎么办呢?下面就是说说图片资源如何做到这点,这里关键要了解android资源的实现,android资源像ImageView查找资源是通过Resources来操作的,来看ImageView查找图片时的关键函数:

 private void resolveUri() {
    if (mDrawable != null) {
        return;
    }

    if (getResources() == null) {
        return;
    }

    Drawable d = null;

    if (mResource != 0) {
        try {
            // 关键的地方
            d = mContext.getDrawable(mResource);
        } catch (Exception e) {
            Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
            // Don't try again.
            mResource = 0;
        }
    } else if (mUri != null) {
        d = getDrawableFromUri(mUri);
        if (d == null) {
            Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri);
            // Don't try again.
            mUri = null;
        }
    } else {
        return;
    }
}
        updateDrawable(d);
    }

可以知道关键的地方是能过context.getDrawable来拿到的,如果我们能重写这个函数是不是就可以搞定了?答案是不能,因为这个函数是final不能被重写的,实现如下:

public final Drawable getDrawable(@DrawableRes int id) {
    return getResources().getDrawable(id, getTheme());
}

能怎么办呢,答案就从上面getDrawable函数的实现找到,getDrawable是能过getResources().getDrawable来实现的,如果能重写getResources,在这里判断是否是繁体,如果是则去zh目录下查找资源,来看getResources的实现:

// Context.java
public abstract Resources getResources();

看到这里,你应该知道这个思路是可以的!于是按思中路实现,首先判断是否是繁体,然后去默认中文目录下查找

第一步:

判断是用什么语言和国家可以用resources获取config

Locale locale = context.getResources().getConfiguration().locale;
if (locale.getLanguage().equals("zh") && !locale.getCountry().equals("CN")) {
// 繁体中文
}

第二步:

去中文目录查找,首先得有一个中文的resources,当前activity的resources是繁体的,是不能直接调用的,实现方法如下:

private static void updateResource(Resources resource, Locale l) {
    Configuration config = resource.getConfiguration();
    config.locale = l;
    resource.updateConfiguration(config, null);
}

private static Resources getApplicationResource(PackageManager pm, String pkgName, Locale l) {
    Resources resourceForApplication = null;
    try {
        resourceForApplication = pm.getResourcesForApplication(pkgName);
        updateResource(resourceForApplication, l);
    } catch (PackageManager.NameNotFoundException e) {

    }
    return resourceForApplication;
}
//得到简体中文的resources,由于简体中文没有资源,所以会去默认的中文下去找
Resources resources = getApplicationResource(context.getApplicationContext().getPackageManager(),
                    context.getPackageName(), new Locale("zh", "CN"));

综合起来是重写Activity的getResources:

@Override
public Resources getResources() {
    Locale locale = context.getResources().getConfiguration().locale;
    if (locale.getLanguage().equals("zh") && !locale.getCountry().equals("CN")) {
        // 繁体中文
        Resources resources = getApplicationResource(context.getApplicationContext().getPackageManager(),
                    context.getPackageName(), new Locale("zh", "CN"));
        if (resources != null) {
            return resources;
        }
    }
    return super.getResources();
}

这样就实现了所有中文上都共用一套资源!上面的示例在xml中指定资源或者在代码里getDrawable可以这么使用,如果是用第三方图片加载库怎么实现?这里展示一下ImageLoader的实现:
ImageLoader加载资源是默认是通过BaseImageLoader去加载的,加载时会调用BaseDownloader去获取资源,我们只要自定义Downloader就可以了:

public class NotePaperImageDownloader extends BaseImageDownloader {
    // 繁体中文时用的resources
    Resources mResources;
    public NotePaperImageDownloader(Context context) {
        super(context);
    }

    public NotePaperImageDownloader(Context context, int connectTimeout, int readTimeout) {
        super(context, connectTimeout, readTimeout);
    }

    @Override
    protected InputStream getStreamFromDrawable(String imageUri, Object extra) {
        Locale locale = context.getResources().getConfiguration().locale;
        if (locale.getLanguage().equals("zh") && !locale.getCountry().equals("CN")) {
            // 繁体中文,使用简体中文的资源进行加载,否则在没有指定繁体资源时默认会去英文下找,会不会去drawable-zh-xx去找
          if (mResources == null) {
                Resources resources = getApplicationResource(context.getApplicationContext().getPackageManager(),
                        context.getPackageName(), new Locale("zh", "CN"));
                if (resources == null) {
                    return super.getStreamFromDrawable(imageUri, extra);
                }
                mResources = resources;
            }
            String drawableIdString = Scheme.DRAWABLE.crop(imageUri);
            int drawableId = Integer.parseInt(drawableIdString);
            return mResources.openRawResource(drawableId);
        } else {
            return super.getStreamFromDrawable(imageUri, extra);
        }
    }
}

总结:

关于android资源的加载,只要熟悉资源加载框架context/resources/assetmanger几个关键的类就可以做很多事。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值