Index: trunk/extensions/Translate/ffs/Gettext.php |
— | — | @@ -361,7 +361,12 @@ |
362 | 362 | * @ingroup FFS |
363 | 363 | */ |
364 | 364 | class GettextFFS extends SimpleFFS { |
| 365 | + protected $offlineMode = false; |
365 | 366 | |
| 367 | + public function setOfflineMode( $value ) { |
| 368 | + $this->offlineMode = $value; |
| 369 | + } |
| 370 | + |
366 | 371 | public function readFromVariable( $data ) { |
367 | 372 | $authors = array(); |
368 | 373 | |
— | — | @@ -520,7 +525,7 @@ |
521 | 526 | $matches = array(); |
522 | 527 | if ( preg_match_all( '/^#(.?) (.*)$/m', $section, $matches, PREG_SET_ORDER ) ) { |
523 | 528 | foreach ( $matches as $match ) { |
524 | | - if ( $match[1] !== ',' ) { |
| 529 | + if ( $match[1] !== ',' && strpos( $match[1], '[Wiki]' ) !== 0 ) { |
525 | 530 | $item['comments'][$match[1]][] = $match[2]; |
526 | 531 | } |
527 | 532 | } |
— | — | @@ -624,61 +629,22 @@ |
625 | 630 | protected function writeReal( MessageCollection $collection ) { |
626 | 631 | $pot = $this->read( 'en' ); |
627 | 632 | $template = $this->read( $collection->code ); |
628 | | - $output = $this->doGettextHeader( $collection, $template ); |
| 633 | + $pluralCount = false; |
| 634 | + $output = $this->doGettextHeader( $collection, $template, $pluralCount ); |
| 635 | + |
629 | 636 | foreach ( $collection as $key => $m ) { |
630 | 637 | $transTemplate = isset( $template['TEMPLATE'][$key] ) ? |
631 | 638 | $template['TEMPLATE'][$key] : array(); |
632 | 639 | $potTemplate = isset( $pot['TEMPLATE'][$key] ) ? |
633 | 640 | $pot['TEMPLATE'][$key] : array(); |
634 | | - |
635 | | - $comments = array(); |
636 | | - if ( isset( $potTemplate['comments'] ) ) { |
637 | | - $comments = $potTemplate['comments']; |
638 | | - } elseif ( isset( $transTemplate['comments'] ) ) { |
639 | | - $comments = $transTemplate['comments']; |
640 | | - } |
641 | | - |
642 | | - $header = ''; |
643 | | - |
644 | | - $header .= self::formatDocumentation( $key ); |
645 | | - foreach ( $comments as $type => $typecomments ) { |
646 | | - foreach ( $typecomments as $comment ) { |
647 | | - if ( strpos( $comment, '[Wiki]' ) === 0 ) continue; |
648 | | - $header .= "#$type $comment\n"; |
649 | | - } |
650 | | - } |
651 | | - |
652 | | - $tags = $m->getTags(); |
653 | | - $flags = isset( $transTemplate['flags'] ) ? $transTemplate['flags'] : array(); |
654 | 641 | |
655 | | - $outFlags = array_unique( array_merge( $tags, $flags ) ); |
656 | | - |
657 | | - if ( $outFlags ) { |
658 | | - sort( $outFlags ); |
659 | | - $header .= "#, " . implode( ', ', $outFlags ) . "\n"; |
660 | | - } |
661 | | - |
662 | | - if ( $header ) { |
663 | | - $output .= $header; |
664 | | - } else { |
665 | | - // Must be at least empty comment |
666 | | - $output .= "#\n"; |
667 | | - } |
668 | | - |
669 | | - if ( isset( $potTemplate['msgctxt'] ) ) { |
670 | | - $output .= 'msgctxt ' . self::escape( $potTemplate['msgctxt'] ) . "\n"; |
671 | | - } |
672 | | - |
673 | | - $translation = str_replace( TRANSLATE_FUZZY, '', $m->translation() ); |
674 | | - |
675 | | - $output .= 'msgid ' . self::escape( $m->definition() ) . "\n"; |
676 | | - $output .= 'msgstr ' . self::escape( $translation ) . "\n\n"; |
| 642 | + $output .= $this->formatMessageBlock( $key, $m, $transTemplate, $potTemplate, $pluralCount ); |
677 | 643 | } |
678 | 644 | |
679 | 645 | return $output; |
680 | 646 | } |
681 | 647 | |
682 | | - protected function doGettextHeader( MessageCollection $collection, $template ) { |
| 648 | + protected function doGettextHeader( MessageCollection $collection, $template, &$pluralCount ) { |
683 | 649 | global $wgSitename, $wgServer; |
684 | 650 | $code = $collection->code; |
685 | 651 | $name = TranslateUtils::getLanguageName( $code ); |
— | — | @@ -722,6 +688,10 @@ |
723 | 689 | $specs['Plural-Forms'] = 'nplurals=2; plural=(n != 1);'; |
724 | 690 | } |
725 | 691 | |
| 692 | + $match = array(); |
| 693 | + preg_match( '/nplurals=(\d+);/', $specs['Plural-Forms'], $match ); |
| 694 | + $pluralCount = $match[1]; |
| 695 | + |
726 | 696 | $output .= 'msgid ""' . "\n"; |
727 | 697 | $output .= 'msgstr ""' . "\n"; |
728 | 698 | $output .= '""' . "\n"; |
— | — | @@ -747,6 +717,70 @@ |
748 | 718 | return $output; |
749 | 719 | } |
750 | 720 | |
| 721 | + protected function formatMessageBlock( $key, $m, $trans, $pot, $pluralCount ) { |
| 722 | + $header = $this->formatDocumentation( $key ); |
| 723 | + |
| 724 | + $comments = self::chainGetter( 'comments', $pot, $trans, array() ); |
| 725 | + foreach ( $comments as $type => $typecomments ) { |
| 726 | + foreach ( $typecomments as $comment ) { |
| 727 | + $header .= "#$type $comment\n"; |
| 728 | + } |
| 729 | + } |
| 730 | + |
| 731 | + $flags = self::chainGetter( 'flags', $pot, $trans, array() ); |
| 732 | + $flags = array_unique( array_merge( $m->getTags(), $flags ) ); |
| 733 | + |
| 734 | + |
| 735 | + $ctxt = self::chainGetter( 'msgctxt', $pot, $trans, false ); |
| 736 | + if ( $ctxt ) { |
| 737 | + $output .= 'msgctxt ' . self::escape( $ctxt ) . "\n"; |
| 738 | + } |
| 739 | + |
| 740 | + $msgid = $m->definition(); |
| 741 | + $msgstr = str_replace( TRANSLATE_FUZZY, '', $m->translation() ); |
| 742 | + |
| 743 | + if ( preg_match( '/{{PLURAL:GETTEXT/i', $msgid ) ) { |
| 744 | + $forms = $this->splitPlural( $msgid, 2 ); |
| 745 | + $content = 'msgid ' . $this->escape( $forms[0] ) . "\n"; |
| 746 | + $content .= 'msgid_plural ' . $this->escape( $forms[1] ) . "\n"; |
| 747 | + |
| 748 | + try { |
| 749 | + $forms = $this->splitPlural( $msgstr, $pluralCount ); |
| 750 | + foreach ( $forms as $index => $form ) { |
| 751 | + $content .= "msgstr[$index] " . $this->escape( $form ) . "\n"; |
| 752 | + } |
| 753 | + } catch ( GettextPluralException $e ) { |
| 754 | + $flags[] = 'x-invalid-plural'; |
| 755 | + for ( $i = 0; $i < $pluralCount; $i++ ) { |
| 756 | + $content .= "msgstr[$i] \"\"\n"; |
| 757 | + } |
| 758 | + } |
| 759 | + |
| 760 | + } else { |
| 761 | + $content = 'msgid ' . self::escape( $msgid ) . "\n"; |
| 762 | + $content .= 'msgstr ' . self::escape( $msgstr ) . "\n"; |
| 763 | + } |
| 764 | + |
| 765 | + if ( $flags ) { |
| 766 | + sort( $flags ); |
| 767 | + $header .= "#, " . implode( ', ', $flags ) . "\n"; |
| 768 | + } |
| 769 | + |
| 770 | + $output = $header ? $header : "#\n"; |
| 771 | + $output .= $content . "\n"; |
| 772 | + return $output; |
| 773 | + } |
| 774 | + |
| 775 | + protected static function chainGetter( $key, $a, $b, $default ) { |
| 776 | + if ( isset( $a[$key] ) ) { |
| 777 | + return $a[$key]; |
| 778 | + } elseif ( isset( $b[$key] ) ) { |
| 779 | + return $b[$key]; |
| 780 | + } else { |
| 781 | + return $default; |
| 782 | + } |
| 783 | + } |
| 784 | + |
751 | 785 | protected static function formatTime( $time ) { |
752 | 786 | $lang = Language::factory( 'en' ); |
753 | 787 | return $lang->sprintfDate( 'xnY-xnm-xnd xnH:xni:xns+0000', $time ); |
— | — | @@ -762,13 +796,15 @@ |
763 | 797 | "; Translate extension (" . TRANSLATE_VERSION . ")"; |
764 | 798 | } |
765 | 799 | |
766 | | - protected static function formatDocumentation( $key ) { |
| 800 | + protected function formatDocumentation( $key ) { |
767 | 801 | global $wgTranslateDocumentationLanguageCode; |
768 | 802 | |
| 803 | + if ( !$this->offlineMode ) return ''; |
| 804 | + |
769 | 805 | $code = $wgTranslateDocumentationLanguageCode; |
770 | 806 | if ( !$code ) return ''; |
771 | 807 | |
772 | | - $documentation = TranslateUtils::getMessageContent( $key, $code ); |
| 808 | + $documentation = TranslateUtils::getMessageContent( $key, $code, $this->group->getNamespace() ); |
773 | 809 | if ( !is_string( $documentation ) ) return ''; |
774 | 810 | |
775 | 811 | $lines = explode( "\n", $documentation ); |
— | — | @@ -805,4 +841,34 @@ |
806 | 842 | return ''; |
807 | 843 | } |
808 | 844 | |
| 845 | + protected function splitPlural( $text, $forms ) { |
| 846 | + if ( $forms === 1 ) { |
| 847 | + return $text; |
| 848 | + } |
| 849 | + |
| 850 | + $splitPlurals = array(); |
| 851 | + for ( $i = 0; $i < $forms; $i++ ) { |
| 852 | + $plurals = array(); |
| 853 | + $match = preg_match_all( '/{{PLURAL:GETTEXT\|(.*)}}/iU', $text, $plurals ); |
| 854 | + |
| 855 | + if ( !$match ) { |
| 856 | + throw new GettextPluralException( "Failed to parse plural for: $text" ); |
| 857 | + } |
| 858 | + |
| 859 | + $pluralForm = $text; |
| 860 | + foreach ( $plurals[0] as $index => $definition ) { |
| 861 | + $parsedFormsArray = explode( '|', $plurals[1][$index] ); |
| 862 | + if ( !isset( $parsedFormsArray[$i] ) ) { |
| 863 | + error_log( "Too few plural forms in: $text" ); |
| 864 | + $pluralForm = ''; |
| 865 | + } else { |
| 866 | + $pluralForm = str_replace( $pluralForm, $definition, $parsedFormsArray[$i] ); |
| 867 | + } |
| 868 | + } |
| 869 | + $splitPlurals[$i] = $pluralForm; |
| 870 | + } |
| 871 | + |
| 872 | + return $splitPlurals; |
| 873 | + } |
| 874 | + |
809 | 875 | } |