How to get String a language in android ?

Chào mọi người. ở một số bài viết trước mình có hướng dẫn và nêu ra các cách mà khi Thay đổi Ngôn ngữ không cần restart activity trên android ? . vậy có một vấn đề đặt ra khi bạn muốn hiển thị nhiều ngôn ngữ trong một activity hoặc một fragment thì sao ? mỗi lần đổi locale dựa vào locale thì app sẽ file string.xml theo locale.

Yêu cầu Đặt ra : làm sao trong một màn hình (Activity) mình có thể hiển thị được cách viết của từ "Việt Nam" được viết bằng ngôn ngữ Lào, Japanese, English hay China ?

Lúc này mình sẽ có 2 cách để làm việc đó:

Cách 1: Đưa tất cả các ngôn ngữ cần lấy vào file string.xml default

  • Ở đoạn code phía dưới mình tiến hành đưa tất cả các cách viết từ "Tiếng Việt" của các nước vào một file string
res/values/string.xml
<resources>
    <string name="app_name">Đây là default</string>
    <string name="app_name_vn">Việt Nam - Đây là Việt Nam</string>
    <string name="app_name_lo">ຫວຽດນາມ - đây là Lào </string>
    <string name="app_name_ja"> ベトナム  - đây là Japanese</string>
    <string name="app_name_en">Vietnam- Đây là M</string>
    <string name="app_name_bo_rcn">越南 - đây là Trung Quốc </string>
</resources>
  • Sau đó trong file code: mình sẽ set cho từng ngôn ngữ cần lấy như ở phía dưới:
        mTextDefault.setText("Locale hien tại của app:" + getResources().getConfiguration().locale);
        mTextVietNam.setText(getResources().getString(R.string.app_name_vn));
        mTextLao.setText(getResources().getString(R.string.app_name_lo));
        mTextJa.setText(getResources().getString(R.string.app_name_ja));
        mTextEn.setText(getResources().getString(R.string.app_name_en));
        mTextBorCN.setText(getResources().getString(R.string.app_name_bo_rcn));
  • Như các bạn có thể thấy. mình lấy text một cách khá đơn giản. nhưng có vẻ cách này k ổn cho lắm vì nếu bạn có support nhiều ngôn ngữ thì bạn cần phải copy tất cả text đó vào các file string ngôn ngữ khác: như vậy theo mình là rất không ổn. hoặc bạn cũng có thể k cần bổ sung nó cho các file string locale khác vì nếu không tìm thấy ở các file locale thì nó sẽ tìm đến file string.xml default. nhưng khi bạn builder thành app sẽ được thông báo thiếu text cho 1 số file locale bạn chưa bổ sung.

Cách 2 : Lấy text theo locale.

  • Cách này mình sẽ tạo những file string theo ngôn ngữ mình cần lấy ra và getString theo từng file

  • Trong android mình không thấy có hỗ trợ việc vào từng file string để lấy text mà text phụ thuộc vào việc khi bạn thay đổi ngôn ngữ app dựa vào locale để lấy file theo ngôn ngữ đó nếu không có thì sẽ lấy file text trong file string default.

  • Mĩnh sẽ tạo một Class Resources để lấy String theo locale

public class ResourcesLocale {
    private final Context mContext;
    private final AssetManager mAssetManager;
    private final DisplayMetrics mMetrics;
    private final Configuration mConfiguration;
    private final Locale mDefaultLocale;
    private Locale mTargetLocale;

    public ResourcesLocale( final Context context,  final Locale defaultLocale,
                       final Locale targetLocale) {
        this.mContext = context;
        final Resources resources = this.mContext.getResources();
        this.mAssetManager = resources.getAssets();
        this.mMetrics = resources.getDisplayMetrics();
        this.mConfiguration = new Configuration(resources.getConfiguration());
        this.mTargetLocale = targetLocale;
        this.mDefaultLocale = defaultLocale;
    }

    public String getString(final int resourceId) {
        if (mTargetLocale == null) return null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            mConfiguration.setLocale(mTargetLocale);
            return mContext.createConfigurationContext(mConfiguration).getResources()
                .getString(resourceId);
        } else {
            mConfiguration.locale = mTargetLocale;
            final String resource =
                new ResourceManager(mAssetManager, mMetrics, mConfiguration).getString(resourceId);
            mConfiguration.locale = mDefaultLocale;  // reset lại locale cũ
            new ResourceManager(mAssetManager, mMetrics, mConfiguration); 
            return resource;
        }
    }

    private final class ResourceManager extends Resources {
        public ResourceManager(final AssetManager assets, final DisplayMetrics metrics,
                               final Configuration config) {
            super(assets, metrics, config);
        }
        
        @Override
        public String getString(final int id, final Object... formatArgs) throws NotFoundException {
            return super.getString(id, formatArgs);
        }

        @Override
        public String getString(final int id) throws NotFoundException {
            return super.getString(id);
        }
    }
}
  • mình giải thích một chút về tham số cần truyền vào:
  • Locale defaultLocale là locale mặc định dùng khi mình lấy xong text đó và muốn locale trở lại file locale của app
  • Locale targetLocale là locale là locale mà bạn muốn lấy file text ra
  • trong file java bạn xử lý
public class MainActivity extends AppCompatActivity {
    private TextView mTextDefault, mTextVietNam, mTextLao, mTextJa, mTextEn, mTextBorCN;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        setText();
    }

    public void initView() {
        mTextDefault = (TextView) findViewById(R.id.text_default);
        mTextVietNam = (TextView) findViewById(R.id.text_vn);
        mTextLao = (TextView) findViewById(R.id.text_lo);
        mTextJa = (TextView) findViewById(R.id.text_ja);
        mTextEn = (TextView) findViewById(R.id.text_en);
        mTextBorCN = (TextView) findViewById(R.id.text_bo_rcn);
    }

    public void setText() {
        mTextDefault.setText("Locale hien tại của app:" + getResources().getConfiguration().locale);
        mTextVietNam.setText(getResources("vi").getString(R.string.app_name)); // vi là locale là bạn muốn lấy
        mTextLao.setText(getResources("lo").getString(R.string.app_name));
        mTextJa.setText(getResources("ja").getString(R.string.app_name));
        mTextEn.setText(getResources("en").getString(R.string.app_name));
        mTextBorCN.setText(getResources("bo-rCN").getString(R.string.app_name));
    }

    public MyResources getResources(String localeTarget) {
        return new MyResources(getBaseContext(), new Locale("en"), new Locale(localeTarget));
    }
}
  • hình ảnh khi lấy được text theo locale
  • Cách 2 có vẻ như rắc rối hơn cách 1 vì phải tạo ra 1 class để set và reset lại locale khi lấy xong. tuy nhiên nếu phải xử dụng nhiều thì mình nghĩ cách này sẽ tốt hơn tránh việc tạo ra nhiều file string trong file String và trông có vẻ nó thông minh hơn 😄 .

Tài liệu tham khảo

https://developer.android.com/guide/topics/resources/multilingual-support.html http://stackoverflow.com