我在写多语言支持时用到的东西

我在写多语言支持时用到的东西

絮叨絮叨:好久不来写了,居然支持markdown 了。 我也是在项目里的wiki 里干刚接触了一些, 来这里也试试。

然后悲催的发现,mac 电脑在markdown下直接上传图片有bug @2015-08-19 20:28:13。

一会试一下链接版的吧。 我们的37度手环一不小心要卖到国外去了,自然要支持多国家多语言啦。 等卖到阿拉伯世界的时候,我会再补充RTL(Right To Left)相关的内容。

本文仅涉及安卓(Android)client的实现。 server后台的部分没有介绍。 主要介绍了多语言中文字、图片的使用, 以及怎样改动下拉菜单Spinner。在处理过程中还介绍了经常使用的shell 命令,awk命令,高效工作,高效生活。

安卓(Android)开发本身对多语言有着不错的支持,尤其在新版Android Studio 中还直接增加了多语言编辑器。

处理多语言时是绝对的神器。


官网的支持[Support Multi Language][2]

字符翻译

当然要使用神器 studio中的多语言editor
图1 编辑器打开位置
编辑器打开位置
图2 编辑器界面
编辑器界面
图3 文件夹结构
文件夹结构

带文字的图片处理

和文字的原理一样。分别建立相应语言的图片文件夹
比如相应drawable-xhdpi 不同语言/地区的文件夹是
drawable-ko-xhdpi
drawable-zh-xhdpi
图4 图片多语言文件夹
图片多语言文件夹

真正的多国功能——支持多国短信验证码

准备1 多国区号

多国区号[Country Code][1]

拿来是一个大表,两百多行。整理一下存成markdown 文件,方便以后查看和编辑
一般拷贝出来是制表符 \t 切割的。 我是用vim 一通替换,把数量不等空格 和\t 统统换成 | 。 详细vim的操作命令例如以下:

#在vim 中多次运行,把全部的\t 换成 多个空格
:%s/\t/  |/g
#然后把多个空格 换成|
:%s/   */|/g

这样形成了例如以下格式

$ head CountryNumber.md 
#Country Number table
Countries and Regions|国家或地区|时差|电话代码|国际域名缩写
------------------------|-----------|-----------|-------|-----
Angola|安哥拉|-7|244|AO
Afghanistan|阿富汗|0|93|AF
Albania|阿尔巴尼亚|-7|355|AL
Countries and Regions国家或地区时差电话代码国际域名缩写
Angola安哥拉-7244AO
Afghanistan阿富汗093AF
Albania阿尔巴尼亚-7355AL

准备2 country code 的string-array

分别在各个语言/地区资源文件夹下存储成string-array。这里处理使用awk。分别获取country name 和相应的country code。

详细shell 命令例如以下

$ cat CountryNumber.md | awk -F'|' '{print "<item>"$2"|"$4"</item>"}' > cn.txt
$ cat CountryNumber.md | awk -F'|' '{print "<item>"$1"|"$4"</item>"}' > en.txt
<string-array name="country_code">
    <item>安哥拉|244</item>
    <item>阿富汗|93</item>
    <item>阿尔巴尼亚|355</item>
</string-array>

<string-array name="country_code">
    <item>Angola|244</item>
    <item>Afghanistan|93</item>
    <item>Albania|355</item>
</string-array>
JAVA代码解析,并排序

既然是用| 切割的。 接下来就是代码解析一下, 并在展示之前排序

    public static ArrayList<Country> getCountryCode(Context ctx) {
        ArrayList<Country> retList = new ArrayList<>();
        String[] array = ctx.getResources().getStringArray(R.array.country_code);
        for (String item : array) {
            String[] data = item.split("\\|");
            Country country = new Country();
            country.name = data[0];
            country.code = data[1];
            retList.add(country);
        }
        Collections.sort(retList);
        return retList;
    }

排序须要class Country 实现排序接口comparable
当系统语言使用中文时,使用Collator。能够自己主动按汉字的拼音的排序。

public class Country implements Comparable<Country> {
    public String name;
    public String code;

    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        return buffer.append(name).append(", ")
                .append(code).toString();
    }

    @Override
    public int compareTo(Country another) {
        if (another == null) {
            return -1;
        }
        Collator cmp = Collator.getInstance(Locale.getDefault());
        return cmp.compare(this.name, another.name);
    }
}
自己定义 spinner 下拉选择country code

先看一下实现效果,两种样式的spinner
图 spinner 截图
spinner 截图

spinner 截图

没什么高科技,就是让spinner 按自己的意思来显示。 在不同的地方使用了两种。 灵活运用不就是攻城狮要干的事情么。


spinner 的界面改动主要是两部分:
一个是未展开状态,在getView()中改动,能够更改三角图片,控制显示位置等;
还有一个是展开状态——在getDropdownView() 中改动, 控制展开后的显示内容。

CountrySpinnerAdapter 的实现

public class CountrySpinnerAdapter extends ArrayAdapter<Country> {
    private Context context;
    private ArrayList<Country> mCountryList;
    private Spinner mSpinner;
    private boolean mIsFamilySpinner;

    public CountrySpinnerAdapter(Context context, Spinner spinner, ArrayList<Country> countryList, boolean isFamilySpinner) {
        super(context, R.layout.country_spinner_item, countryList);
        this.context = context;
        mCountryList = countryList;
        mSpinner = spinner;
        this.mIsFamilySpinner = isFamilySpinner;
    }

    public CountrySpinnerAdapter(Context context, Spinner spinner, ArrayList<Country> countryList) {
        this(context, spinner, countryList, false);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = View.inflate(getContext(), mIsFamilySpinner ? R.layout.country_spinner_layout_family : R.layout.country_spinner_layout, null);
        }
        Country country = mCountryList.get(position);
        TextView name = (TextView) convertView.findViewById(R.id.country_name);
        TextView code = (TextView) convertView.findViewById(R.id.country_code);
        name.setText(country.name);
        code.setText("+" + country.code);
        if (mSpinner.getSelectedItemPosition() == position) {
            convertView.setSelected(true);
        } else {
            convertView.setSelected(false);
        }
        return convertView;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = View.inflate(getContext(), mIsFamilySpinner ? R.layout.country_spinner_item_family : R.layout.country_spinner_item, null);
        }
        Country country = (Country) mSpinner.getSelectedItem();
        if (mIsFamilySpinner) {
            TextView code = (TextView) convertView.findViewById(R.id.country_code);
            code.setText("+" + country.code);
        } else {
            TextView name = (TextView) convertView.findViewById(R.id.country_name);
            TextView code = (TextView) convertView.findViewById(R.id.country_code);
            name.setText(country.name);
            code.setText("+" + country.code);
        }
        if (mSpinner.getSelectedItemPosition() == position) {
            convertView.setSelected(true);
        } else {
            convertView.setSelected(false);
        }
        return convertView;
    }
}

分别使用不用的 layout 来控制:

layout/country_spinner_item.xml

一个水平layout 中 包括
两个textview 分别显示name 和code
一个ImageView, ImageView 用来显示下拉的三角

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:background="@drawable/family_spinner_bg"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/country_name"
        android:layout_marginLeft="8dp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:singleLine="true"
        android:text="@string/family_dialog_phone_number"
        android:textColor="@color/family_dialog_message"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/country_code"
        android:layout_marginRight="8dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/family_dialog_message"
        android:textSize="18sp" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/country_spinner_arrow" />
</LinearLayout>
layout/country_spinner_layout.xml

一个水平layout 中 包括
两个textview 分别显示name 和code

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="25dp"
    android:background="@drawable/family_spinner_back"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/country_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_weight="1"
        android:duplicateParentState="false"
        android:ellipsize="end"
        android:singleLine="true"
        android:text="@string/family_dialog_phone_number"
        android:textColor="@color/family_spinner_text"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/country_code"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:duplicateParentState="false"
        android:text="@string/family_dialog_phone_number"
        android:textColor="@color/family_spinner_text"
        android:textSize="18sp" />
</LinearLayout>
能看到这里,说明也是缘分。广告一下。有缘人看过来:这里上有70后靠谱大叔CXO,下有90后萝莉鲜肉,前有各种博士搞定算法硬件,后有脸皮厚猥琐男拿下销售。

如今人手紧缺,安卓开发。IOS 开发,UI/UX。产品经理都须要人,活真的要干只是来了。希望自我驱动力强,能够平衡风险收益的同学欢迎来勾搭。 鄙人37度手环安卓开发,扣扣:84365252。


[1]: https://countrycode.org/ country code
[2]: http://developer.android.com/training/basics/supporting-devices/languages.html Support Multi Languages

<think>我们正在回答用户的问题:“GitHub中在哪里编和展示Markdown内容”。根据用户提供的引用和之前的对话,我们需要指出在GitHub平台上编和展示Markdown的具体位置和方式。 引用内容回顾: [1]:提到Github工程中的Markdown语言应用,包括工具、基本操作等。 [2]:介绍了一款高颜值的Markdown编辑器Notable,但这是第三方工具,不是GitHub内置的。 [3]:提到GitHub上的Markdown语法,并说明文档是用Markdown的。 [4]:提到使用markdown技术文档并部署到GitHub,其中有一个文件_coverpage.md。 用户的问题核心是:在GitHub的哪个位置编和展示Markdown内容。 根据GitHub平台的特性,Markdown文件可以在以下几个位置编和展示: 1. 仓库中的Markdown文件(如README.md, 其他.md文件): - 每个仓库的根目录下通常有一个README.md文件,这是项目的主页,GitHub会自动渲染并显示在仓库首页。 - 其他目录下的.md文件也会被渲染,用户可以通过点击文件查看渲染后的效果。 2. GitHub Wiki: - 每个仓库都有一个Wiki部分,这是一个独立的文档系统,完全使用Markdown。用户可以在Wiki中创建多个页面。 3. GitHub Issues 和 Pull Requests: - 在创建或编辑Issue和PR,描述和评论都可以使用Markdown语法。GitHub会自动渲染。 4. GitHub Discussions: - 类似于Issues,但更侧重于讨论,同样支持Markdown。 5. GitHub Pages: - 用户可以使用Markdown静态网站,通过GitHub Pages部署。通常使用Jekyll(支持Markdown)来构建网站。 6. Gist: - 在Gist(代码片段)中,也可以创建Markdown文件,并以渲染后的形式展示。 编方式: - 在线编辑:在GitHub网站上,可以直接点击文件然后点击编辑按钮(铅笔图标)进行在线编辑。编辑可以看到原始Markdown代码,保存后即可看到渲染效果。 - 本地编辑:使用本地编辑器(如VS Code、Notable等)编Markdown文件,然后通过git推送到GitHub仓库。 特别注意:在GitHub上,Markdown文件的后缀必须是.md(或.markdown)。当用户访问这些文件,GitHub会自动渲染为HTML。 因此,我们可以这样组织回答: 1. 介绍GitHub上可以编和展示Markdown的主要位置。 2. 分别说明每个位置的作用和访问方式。 3. 简要说明在线编辑和本地编辑两种方式。 同,根据用户提供的引用[4],我们还可以提到使用Markdown文档并部署到GitHub Pages,以及使用_coverpage.md作为封面页(这可能是使用了某个文档生成工具,如docsify)。 另外,引用[1]中提到了一些基本操作,我们可以适当提及,但重点在于位置。 最后,生成相关问题。 注意:引用标识要自然地添加在引用内容的末尾。根据用户提供的引用,我们引用[1]是关于GitHub工程中Markdown应用,引用[2]是第三方编辑器,引用[3]是GitHub上Markdown语法的学习,引用[4]是使用Markdown技术文档并部署。我们可以在回答中适当引用这些内容。 由于用户的问题是关于位置,所以引用[1]和[4]更相关。 回答结构: 一、GitHub仓库中的Markdown文件 二、GitHub Wiki 三、GitHub Issues、Pull Requests和Discussions 四、GitHub Pages 五、Gist 然后说明编方式:在线编辑和本地编辑。 最后,相关问题。</think>在 GitHub 平台上,Markdown 内容主要通过以下位置编和展示: ### 一、核心编位置 1. **仓库文件编辑器** - 在仓库中点击 `Add file` → `Create new file` - 文件名必须以 `.md` 结尾(如 `README.md`) - 支持预览(点击预览标签页切换源码/渲染视图)[^1][^3] 2. **Wiki 系统** - 仓库顶部菜单选择 `Wiki` 选项卡 - 点击 `New Page` 创建纯 Markdown 文档 - 自动生成带导航的知识库(示例:`https://github.com/username/repo/wiki`) 3. **Issues/Pull Requests** - 创建或编辑 Issue/PR 在描述框编 - 支持任务列表 `- [ ]`、表情符号 `:bug:` 等扩展语法 - 引用代码:` ```python` 代码块或行内反引号[^3] ### 二、主要展示位置 | 位置 | 访问方式 | 典型文件 | |------|----------|----------| | **仓库首页** | `github.com/用户名/仓库名` | `README.md` | | **文档页面** | `github.com/用户名/仓库名/blob/main/docs/guide.md` | `/docs/` 目录下的 `.md` 文件 | | **GitHub Pages** | `用户名.github.io/仓库名` | 通过 `_config.yml` 配置的 Markdown 文件[^4] | | **项目 Wiki** | 仓库导航栏 > Wiki | 所有 Wiki 页面 | | **Gist 片段** | `gist.github.com/用户名/ID` | 单个 Markdown 文件 | ### 三、特殊应用场景 1. **项目文档站点** 使用 `docsify` 或 `MkDocs` 工具: ```markdown # _coverpage.md ![logo](logo.png) > 项目文档示例 [GitHub](https://github.com/...) ``` 部署后通过 `https://用户名.github.io/仓库名` 访问[^4] 2. **个人主页** - 创建名为 `用户名.github.io` 的特殊仓库 - 在 `index.md` 编内容,自动生成个人主页 3. **GitHub Discussions** 在社区讨论区使用 Markdown: ```markdown **问题描述** ```bash npm install package ``` - [x] 已尝试方案A - [ ] 需要测试方案B ``` ### 四、编辑工具推荐 1. **在线编辑** GitHub 内置编辑器(含实预览) 2. **本地编辑** - VS Code + Markdown All in One 插件 - Notable(开源跨平台编辑器,支持暗黑模式/Zen模式)[^2] ```bash git add README.md git commit -m "更新文档" git push origin main ``` > 提示:所有 Markdown 文件在 GitHub 平台会自动渲染为 HTML 格式,无需额外配置[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值