勉強がてら、gettextのngettext()関数を参考に、PHPで文法数(grammatical number)の切り替え機能を書いてみます。関数number()
を作り、に整数を入れると、数量にあった形式(0 ~ 3)を導く処理を作ります。形式は主に単数・複数・双数(dual)ですが、拡張性(新たなパターンの言語の対応)を考えて、形式には0~3の抽象的な値を割り振っておきます。例えば、0は単数形・1は複数形の場合、0は単数形・1は双数形・2は複数形の場合などがあります。
- 0 : 形式 A
- 1 : 形式 B
- 2 : 形式 C
- 3 : 形式 D
言語によって、使い分ける形式の数が異なります。少ない言語で1つの形式を、多い言語で4つの形式を使い分けます。また、形式の数が同じでも、先行する数字によって、形式の使い分け方が言語によって異なります。この点を総括すると、11パターンが考えられます。
- パターン1 : 形式が1つ
- パターン2.1 : 形式が2つ » 単数形が1に使われる
- パターン2.2 : 形式が2つ » 単数形が0と1に使われる
- パターン3.1 : 形式が3つ » 0が特別
- パターン3.2 : 形式が3つ » 1と2が特別
- パターン3.3 : 形式が3つ »
/00$/
と/[2-9][0-9]$/
が特別 - パターン3.4 : 形式が3つ »
/1[2-9]$/
が特別 - パターン3.5 : 形式が3つ »
/1$/
と/[2-4]$/
が特別 (/1[1-4]$/
以外) - パターン3.6 : 形式が3つ » 1と2, 3, 4が特別
- パターン3.7 : 形式が3つ »
/[2-4]$/
が特別 - パターン4.1 : 形式が4つ »
/0*[2]$/
と/0*[3-4]$/
が特別
それでは、以上の順にしたがって、それぞれのパターンの実装を書いていきます。もし、誤りがあれば教えてください m(_ _ )m
パターン1 : 形式が1つ
数の文法カテゴリがなく、ひとつの形式で表す言語です。アジア型の言語に多いです。日本人にとっては一番身近なパターンです。
- 対象言語
- 日本語・韓国語・ベトナム語・トルコ語など
<php function number($int) { return 0; } ?>
パターン2 : 形式が2つ
数を表すのに2つの形式を使い分ける言語です。ヨーロッパ型の言語の中でも西ヨーロッパに多いです。日本人にとって、このパターンも理解しやすいほうだと思います。
パターン2.1 : 単数形が1に使われる
- 対象言語
- 英語・オランダ語・ドイツ語・エストニア語・フィンランド語・ギリシャ語・イタリア語・ポルトガル語・スペイン語・エスペラント語など
<php function number($int) { if ( $int == 1 ) { return 0; // 1 } return 1; } ?>
パターン2.2 : 単数形が0と1に使われる
- 対象言語
- フランス語・ブラジルポルトガル語など
<php function number($int) { if ( $int <= 1 ) { return 0; } return 1; } ?>
パターン3 : 形式が3つ
数を表すのに3つの形式を使い分ける言語です。ヨーロッパ型の言語の中でも東ヨーロッパに多いです。これらの言語の中には、単数・複数に加え、双数の概念があります。この言語では、基本的には、双数が2で、複数は3以上です。極端なことを言うと、英語などが「1, いっぱい」と数えるのに対して、「1, 2, いっぱい」という数え方をする言語ということになります。
また、ヨーロッパ型の言語では、1~19まで数えて20以降は数字を組み合わせるといった20進法的な面があり、そのため1~19に関わる数字が不規則になることがあるようです。
パターン3.1 : 0が特別
- 対象言語
- ラトビア語
<php function number($int) { // 1, 21, 31, 41, 51, 61, 71, 81, 91, // 101, 121, 131, 141, 151, 161, 171, 181, 191, // 201, 221, 231, 241, 251, ... if ( $int % 10 == 1 and $int % 100 != 11 ) { return 0; } // 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // 12, 13, 14, 15, 16, 17, 18, 19, 20, // 22, 23, 24, 25, 26, 27, 28, 29, 30, ... elseif ( $int != 0 ) { return 1; } // 0 [特別] return 2; } ?>
パターン3.2 : 1と2が特別
- 対象言語
- アイルランド語
<?php function number($int) { // 1 [特別] if ( $int == 1 ) { return 0; } // 2 [特別] elseif ( $int == 2 ) { return 1; } // 0, 3, 4, 5, 6, 7, 8, 9, // 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ... return 2; } ?>
パターン3.3 : /00$/と/[2-9][0-9]$/が特別
- 対象言語
- ルーマニア語
つまり、ルーマニア語では、2から19までは形式1になります。
<?php function number($int) { // 1 if ( $int == 1 ) { return 0; } // 0, 2, 3, 4, 5, 6, 7, 8, 9, // 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 101, 102, 103, 104, 105, 106, 107, 108, 109, // 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, ... elseif ( $int == 0 or ( $int % 100 > 0 and $int % 100 < 20 ) ) { return 1; } // 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, [特別] // 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, ... // 100, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, ... return 2; } ?>
パターン3.4 : /1[2-9]$/が特別
- 対象言語
- リトアニア語
うーん、これであってるか心配。
<?php function number($int) { // 1, 21, 31, 41, 51, 61, 71, 81, 91, 101, 121, ... if ( $int % 10 == 1 and $int % 100 != 11 ) { return 0; } // 2, 3, 4, 5, 6, 7, 8, 9, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, ... elseif ( $int % 10 >= 2 and ( $int % 100 < 10 or $int % 100 >= 20 ) ) { return 1; } // 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, [特別] // 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 110, // 111, 112, 113, 114, 115, 116, 117, 118, 119 120, ... return 2; } ?>
パターン3.5 : /1$/と/[2-4]$/が特別 (/1[1-4]$/以外)
- 対象言語
- クロアチア語・セルビア語・ロシア語・ウクライナ語
<?php function number($int) { // 1, 21, 31, 41, 51, 61, 71, 81, 91, [特別] // 101, 121, 131, 141, 151, 161, 171, 181, 191, // 201, 221, 231, 241, 251, ... if ( $int %10 == 1 and $int % 100 != 11 ) { return 0; } // 2, 3, 4, 22, 23, 24, 32, 33, 34, 42, 43, 44, [特別] // 52, 53, 54, 62, 63, 64, 72, 73, 74, 82, 83, 84, // 92, 93, 94, 102, 103, 104, 122, 123, 124, ... elseif ( $int % 10 >= 2 and $int % 10 <= 4 and ( $int % 100 < 10 or $int % 100 >= 20 ) ) { return 1; } // 0, 5, 6, 7, 8, 9, 10, // 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, // 25, 26, 27, 28, 29, 30, 35, 36, 37, 38, 39, ... return 2; } ?>
パターン3.6 : 1と2, 3, 4が特別
- 対象言語
- スロバキア語・チェコ語
<?php function number($int) { // 1 [特別] if ( $int == 1 ) { return 0; } // 2, 3, 4 [特別] elseif ( $int >= 2 and $int <= 4 ) { return 1; } // 0, 5, 6, 7, 8, 9, // 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, ... return 2; } ?>
パターン3.7 : /[2-4]$/が特別
- 対象言語
- ポーランド語
<?php function number($int) { // 1 if ( $int == 1 ) { return 0; } // 2, 3, 4, 22, 23, 24, 32, 33, 34, [特別] // 42, 43, 44, 52, 53, 54, 62, 63, 64, // 72, 73, 74, 82, 83, 84, 92, 93, 94, ... elseif ( $int % 10 >= 2 and $int % 10 <= 4 and ( $int % 100 < 10 or $int % 100 >= 20 ) ) { return 1; } // 0, 5, 6, 7, 8, 9, 10, // 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20, 21, 25, 26, 27, 28, 29, // 30, 31, 35, 36, 37, 38, 39, ... return 2; } ?>
パターン4 : 形式が4つ
数を表すのに4つの形式を使い分ける言語です。
パターン4 .1 : /0*[2]$/と/0*[3-4]$/が特別
- 対象言語
- スロベニア語
<?php function number($int) { // 1, 101, 201, ... if ( $int % 100 == 1 ) { return 0; } // 2, 102, 202, ... [特別] elseif ( $int % 100 == 2 ) { return 1; } // 3, 4, 103, 104, 203, 204, ... [特別] elseif ( $int % 100 == 3 or $int % 100 == 4 ) { return 2; } // 0, 5, 6, 7, 8, 9, // 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, ... return 3; } ?>