このエントリーをはてなブックマークに追加

2010年2月24日水曜日

XLIFF enables you to replacement characters(2)

[In English]
Previously on my last blog.


<string name="remaining_time_message">Only %d minutes left.</string>

String.format(getResources().getString(R.string.remaining_time_message, 10);



In most cases this code works well except in case of singular.

When minute value is singular, the message 'only 1 minutes left.' will be created.
It's wrong message to be accurate. We hope the message 'only 1 minute left.'

For the solution of this problem, we can write like this way.




<string name="remaining_time_message_one">Only 1 minute left.</string>
<string name="remaining_time_message_other">Only %d minutes left.</string>


if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


This code may work well. But there is something wrong with this solution because for example in our language Japanese, there is no differences between in the singular and in the plural.
Japanese doesn't perceive singular as special.
Therefore more properly you need to write this way.


if (Locale.getDefault() == Locale.US || Locale.getDefault() == ...) {
if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


At last the code works correctly!
But the code above is against total multilingualization because java code is aware of various of languages.

It seems to be difficult to solve it, but with xliff we can write very easy code.

[values] - strings.xml

<plurals name="remaining_time_message">
<item quantity="one">Only 1 minute left.</item>
<item quantity="other">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</item>
</plurals<


[values-ja] - strings.xml

<plurals name="remaining_time_message">
<item quantity="other">残り <xliff:g id="minutes">%d</xliff:g>分</item>
</plurals>



String quantityString = getResources().getQuantityString(R.plurals.remaining_time_message, 10);
String.format(quantityString, minuteValue);


Do you know the merit of this way?
In this way, you don't have to be aware of any languages in Java code.
If you make your program accommodate different languages forward, you don't have to edit Java code at all but just pass translator the xml file and ask for translation. That's all. It's very useful, isn't it?




[In Japanese]

前回のブログの続きです。


<string name="remaining_time_message">Only %d minutes left.</string>

String.format(getResources().getString(R.string.remaining_time_message, 10);


上記のコードはほとんどの場合で正常に動作します。例外は単数形の場合です。
分の数値が1の場合、'only 1 minutes left.'というメッセージが生成される事になります。
これは厳密には間違いで、正しくは'only 1 minute left.'です。

この問題の対処として、次のようなコードを書いたとします。



<string name="remaining_time_message_one">Only 1 minute left.</string>
<string name="remaining_time_message_other">Only %d minutes left.</string>


if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


これも正常に動くように見えます。が、少しだけ問題があります。我々の言語である日本語の場合だと、
単数形の場合と複数形の場合で違うフォーマットのメッセージになるという事はあまりありません。
日本語では単数形を特別扱いしないのです。
なので、より正確には次のようなコードを書く必要があります。


if (Locale.getDefault() == Locale.US || Locale.getDefault() == ...) {
if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


これで正しく動くプログラムが完成しました。
しかし、残念ながらこれは完全な多言語化対応のプログラムとは言えません。なぜなら、Javaのソースの中で言語を意識してしまっているからです。
この種の問題に完全に対処するのは難しいと感じるかもしれませんが、XLIFFを使用すると簡単に解決できます。


[values] - strings.xml

<plurals name="remaining_time_message">
<item quantity="one">Only 1 minute left.</item>
<item quantity="other">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</item>
</plurals<


[values-ja] - strings.xml

<plurals name="remaining_time_message">
<item quantity="other">残り <xliff:g id="minutes">%d</xliff:g>分</item>
</plurals>



String quantityString = getResources().getQuantityString(R.plurals.remaining_time_message, 10);
String.format(quantityString, minuteValue);


今までとの違いが分かるでしょうか?
このやり方だと、Javaのソース上で言語を意識している箇所を排除できます。
つまり、今後色んな言語に対応させる事になった場合でもJavaのソースは修正しなくてよく、翻訳家の方にxmlファイルを渡して翻訳を依頼すればいいだけになります。
すごい恩恵だと思いませんか?

2010年2月21日日曜日

XLIFF enables you to replacement characters(1)

[In English]
Do you know XLIFF?

The purpose of XLIFF is to make localization process easier.
XLIFF can be used in XML.

The rudimentary way to use is as follows.

At first, we need to declare to use xliff.


<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">


And second, use xliff like this.

<string name="remaining_time_message">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</string>


At the end replace it.

getResources().getString(R.string.remaining_time_message, 10);


Like this way we can create the dynamic message from xml.
But wait a minute. Yes I know how you feel. You might feel that there is easier way than that.

1.

<string name="remaining_time_message">Only %d minutes left.</string>


2.

String.format(getResources().getString(R.string.remaining_time_message, 10);


Yes, the result of the both of them is exactly the same.

The former has a number of advantages. But I'll answer it later.
So much for today.



[In Japanese]

XLIFFをご存知ですか?
XLIFFとはローカライズ作業を簡略化してくれる仕組みで、XML中で使用する事ができます。

基本的な使い方は以下の通りです。

まず始めに、XLIFFを使用するという事を宣言します。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">



次に、XML中でXLIFFを使用した記述をします。

<string name="remaining_time_message">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</string>



最後に、XML中のXLIFFで記述された部分を置換します。

getResources().getString(R.string.remaining_time_message, 10);



このようにして動的なメッセージを生成する事ができます。
しかし、もっと簡単な方法があると感じた方もいらっしゃるのではないでしょうか。
そうです、XLIFFを使わずとも、以下のようにするともっと簡単に実現できます。
1.

<string name="remaining_time_message">Only %d minutes left.</string>


2.

String.format(getResources().getString(R.string.remaining_time_message, 10);


両者の違いはなんでしょうか?実はXLIFFを用いた方がメリットが大きいんです。
そのメリットは次回に書くことにします。
お楽しみに。

2010年2月14日日曜日

CursorAdapter requires a column named "_id"

[In English]
When I used SimpleCursorAdapter to display some data on ListView, I had an Exception.


private SQLiteDatabase mDb;
private SimpleCursorAdapter mAdapter;
private ListView mListView;

....
....
Cursor c = mDb.rawQuery(SELECT_SOME_MEMBERS_SQL, null);
startManagingCursor(c);
String[] from = new String[] {MEMBER_NAME, MEMBER_AGE, NOTE};
int[] to = new int[]{R.id.TextView_name, R.id.TextView_age, R.id.TextView_note};
mAdapter = new SimpleCursorAdapter(this, R.layout.members_layout, c, from, to);
mListView.setAdapter(mAdapter);
....
....

The above sample code seems fine. But if "SELECT_SOME_MEMBERS_SQL" does not have "_id" column,
this sample cause IllegalArgumentException.
So if you use Database(SQLite) in Android Applications, it is better to add a column named "_id" to all tables to use CursorAdapter.
Or you need to write sql state "select member_id as _id from member_talbe where ....." to get Cursor.

You also can find this matter at Android Developer Site
"Adapter that exposes data from a Cursor to a ListView widget. The Cursor must include a column named "_id" or this class will not work."



[In Japanese]
SimplerCursorAdapterを使って、ListView上にデータを表示させる際に、例外に遭遇しました。


private SQLiteDatabase mDb;
private SimpleCursorAdapter mAdapter;
private ListView mListView;
....
....
....
Cursor c = mDb.rawQuery(SELECT_SOME_MEMBERS_SQL, null);
startManagingCursor(c);
String[] from = new String[] {MEMBER_NAME, MEMBER_AGE, NOTE};
int[] to = new int[]{R.id.TextView_name, R.id.TextView_age, R.id.TextView_note};
mAdapter = new SimpleCursorAdapter(this, R.layout.members_layout, c, from, to);
mListView.setAdapter(mAdapter);
....
....

上記のサンプルコードは一見正常に動くように見ますが、"SELECT_SOME_MEMBERS_SQL"に"_id"カラムがないとIllegalArgumentExceptionが発生します。
そのため、データベース(SQLite)を使用したAndroidアプリケーションをつくる場合には、全てのテーブルに"_id"カラムを加えておくとよいと思います。
もしくは、"select member_id as _id from member_talbe where ....."のようなSQL文でCursorを取得する必要があります。

Android Developerサイトに本件に関する注意の記載があります。
"Adapter that exposes data from a Cursor to a ListView widget. The Cursor must include a column named "_id" or this class will not work."

2010年2月4日木曜日

Android Emulator key mappings

[In English]
On Android Development, Emulator is necessary to check the display of various size.
So today I wanna write some mappings between the emulator keys and and the keys of PC keyboard that is used many times on emulator development

  • Home : Home

  • Menu : F2 or Page up

  • Back : ESC

  • Call : F3

  • End call : F4

  • Switch Orientation : Ctrl-F11


I think that the the mapping keys(Ctrl-F11) worth remembering because it is necessary to switch the orientation of emulator device.
For all mappings between them, please see the developer site.



[In Japanese]
Androidの開発において、様々な画面サイズでの表示確認をするためにエミュレータの使用が欠かせません。
そこで今回は、エミュレータを使用する上で、使用頻度の高いエミュレータキーとPCキーのマッピングをを紹介したいと思います。

  • Home : Home

  • Menu : F2 or Page up

  • Back : ESC

  • Call : F3

  • End call : F4

  • Switch Orientation : Ctrl-F11


端末の向き(landscape/portrait)の変更は、PCキー(Ctrl-F11)を使う必要があるのでぜひ
覚えておきたい操作だと思います。
全てのキーマッピングについては、デベロッパサイトをご参照下さい。

2010年2月2日火曜日

Vibration and BEEP Tone on Android

[In English]
Today's Blog Theme is about Android Vibration and BEEP Tone function.
I feel the application become a little rich only if Vibration and BEEP Tone are added to it.

At first about Vibration function.

Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);


uses-permission is also needed to add to AndroidManifest to use Vibration function.

<uses-permission android:name="android.permission.VIBRATE"/>


Next about BEEP Tone.

ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);


At last、the following sample code is about the button effect using combination Vibration and BEEP Tone.

public class HogeActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Vibrator vibrator =
(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
ToneGenerator toneGenerator =
new ToneGenerator(
AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
Button button = (Button)findViewById(R.id.button01);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View view) {
vibrator.vibrate(1000);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);
}
});
}
}




[In Japanese]
今回は、バイブレーション機能の使用方法とBEEPトーンを鳴らす方法を紹介したいと思います。
バイブレーションとBEEPトーンを加えるだけで、アプリが少しですがリッチになった気分に
なれます。

先ずは、バイブレーション機能から紹介します。

Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);


バイブレーション機能を使う場合は、AndroidManifest.xmlにuses-permissionにも追加する必要があります。

<uses-permission android:name="android.permission.VIBRATE"/>


次は、BEEPトーンを鳴らす方法です。

ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);


最後に、ボタン押下時にバイブレーションとBEEPトーンの組み合わせで、
効果を出すサンプルを記載します。

public class HogeActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Vibrator vibrator =
(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
ToneGenerator toneGenerator =
new ToneGenerator(
AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
Button button = (Button)findViewById(R.id.button01);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View view) {
vibrator.vibrate(1000);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);
}
});
}
}