public static function parse_ordinal_triplet($triplet, $order, $case, $gender, $subject_type, $noun, $with_declension, $custom_gender, $custom_subject_type, $custom_noun) { $numerals = self::$LIBTEXT_GLOBALS['numerals']; $str = array(); assert(bccomp($triplet, '0') == 1); // Triplet must be nonzero $declined = false; $noun_variant = 0; // Varies from 1 to 3 (3rd uses data of 2nd with two exceptions) // Fetch number except hundreds (to check for exceptions between 11 and 19) $remainder = bcmod($triplet, '100'); if (bccomp($remainder, '0') == 1) { if (bccomp('11', $remainder) != 1 && bccomp($remainder, '19') != 1) { // Whether to decline last triplet if ($with_declension) { array_unshift($str, text::fetch_ordinal_word(intval($remainder), $case, $gender, $subject_type)); $declined = true; } else { array_unshift($str, $numerals['cardinal']['exceptions'][$remainder][$case]); // Define noun variant $noun_variant = 3; // Final variant } } else { $ones = bcmod($remainder, '10'); if (bccomp($ones, '0') == 1) { if ($with_declension) { if ($order == 1) { // Final word array_unshift($str, text::fetch_ordinal_word(intval($ones), $case, $gender, $subject_type)); } else { // Final trailing word expected further (like 'тысячный', 'миллионный' ...) if (bccomp($triplet, '1') != 0) { $number = $numerals['cardinal']['ones'][$ones][2]; // Use cardinal numerals in genitive case if (bccomp($ones, '1') == 0) { array_unshift($str, $number[$gender]); // apply gender } else { array_unshift($str, $number); } // use plain value } } $declined = true; } else { $number = $numerals['cardinal']['ones'][$ones][1]; // Use case 1 only // Exception: apply gender and subject type if (bccomp($ones, '1') == 0) { array_unshift($str, $number[$gender]); } elseif (bccomp($ones, '2') == 0) { array_unshift($str, $number[$gender]); } elseif (bccomp($ones, '3') == 0) { array_unshift($str, $number); } elseif (bccomp($ones, '4') == 0) { array_unshift($str, $number); } else { array_unshift($str, $number); } // for all others } // Define noun variant if (bccomp($ones, '1') == 0) { $noun_variant = 1; } elseif (bccomp('2', $ones) != 1 && bccomp($ones, '4') != 1) { $noun_variant = 2; } else { $noun_variant = 3; } // between 5 and 9 } $tens = bcdiv($remainder, '10'); if (bccomp($tens, '0') == 1) { if ($with_declension) { if ($order > 1) { // Final trailing word expected further (like 'тысячный', 'миллионный' ...) array_unshift($str, $numerals['cardinal']['tens'][bcmul($tens, '10')][2]); // Use cardinal numerals in genitive case } elseif (!$declined) { // Final word array_unshift($str, text::fetch_ordinal_word(intval(bcmul($tens, '10')), $case, $gender, $subject_type)); } else { array_unshift($str, $numerals['cardinal']['tens'][bcmul($tens, '10')][1]); // Define noun variant if (empty($noun_variant)) { $noun_variant = 3; } // Assume 3rd, may be overridden further } $declined = true; } else { array_unshift($str, $numerals['cardinal']['tens'][bcmul($tens, '10')][1]); // Define noun variant if (empty($noun_variant)) { $noun_variant = 3; } // Assume 3rd, may be overridden further } } } } // Fetch hundreds $hundreds = bcdiv($triplet, '100'); if (bccomp($hundreds, '0') == 1) { if ($with_declension) { if ($order > 1) { // Final trailing word expected further (like 'тысячный', 'миллионный' ...) array_unshift($str, $numerals['cardinal']['hundreds'][bcmul($hundreds, '100')][2]); // Use cardinal numerals in genitive case } elseif (!$declined) { // Final word array_unshift($str, text::fetch_ordinal_word(intval(bcmul($hundreds, '100')), $case, $gender, $subject_type)); } else { array_unshift($str, $numerals['cardinal']['hundreds'][bcmul($hundreds, '100')][1]); // Define noun variant if not already set if (empty($noun_variant)) { $noun_variant = 3; } // Assume 3rd, may be overridden further } } else { array_unshift($str, $numerals['cardinal']['hundreds'][bcmul($hundreds, '100')][1]); // Define noun variant if not already set if (empty($noun_variant)) { $noun_variant = 3; } // Assume 3rd, may be overridden further } } // Append appropriate noun if ($noun != NULL) { if ($with_declension && $order > 1) { // Actually use special and custom nouns switch ($order) { case 2: $str[] = text::fetch_ordinal_word(1000, $case, $custom_gender, $custom_subject_type); // Add 'тысячный' in the case of custom noun break; case 3: $str[] = text::fetch_ordinal_word(1000000, $case, $custom_gender, $custom_subject_type); // Add 'миллионный' in the case of custom noun break; case 4: $str[] = text::fetch_ordinal_word(1000000000, $case, $custom_gender, $custom_subject_type); // Add 'миллиардный' in the case of custom noun break; } // Actually use custom noun $str[] = ' '; $str[] = $custom_noun[1][$case]; } elseif ($with_declension && $order == 1) { // Actually use custom noun $str[] = $noun[1][$case]; } else { switch ($noun_variant) { case 1: case 2: $str[] = $noun[$noun_variant][1]; break; case 3: // if ($case == 1 || $case == 4) $case = 2; $str[] = $noun[2][2]; break; default: assert(false); // This must not happen! } } } $delimiter = ' '; if ($with_declension && $order > 1) { $delimiter = ''; } // Disable delimiter when complex nouns are used return implode($delimiter, $str); }