Merge "RELEASE-NOTES-1.31: Add notes for I94377faa51"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 3 May 2018 20:01:35 +0000 (20:01 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 3 May 2018 20:01:35 +0000 (20:01 +0000)
31 files changed:
Gruntfile.js
RELEASE-NOTES-1.32
includes/skins/Skin.php
includes/specials/forms/EditWatchlistNormalHTMLForm.php
languages/classes/LanguageCrh.php
languages/data/CrhExceptions.php
languages/i18n/ace.json
languages/i18n/az.json
languages/i18n/bho.json
languages/i18n/ce.json
languages/i18n/gl.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/io.json
languages/i18n/lv.json
languages/i18n/mk.json
languages/i18n/nah.json
languages/i18n/zgh.json
package.json
resources/Resources.php
resources/src/jquery/jquery.makeCollapsible.css
resources/src/jquery/jquery.makeCollapsible.js
resources/src/jquery/jquery.makeCollapsible.styles.less [new file with mode: 0644]
resources/src/jquery/jquery.tablesorter.less
resources/src/jquery/jquery.tablesorter.styles.less [new file with mode: 0644]
resources/src/mediawiki/mediawiki.jqueryMsg.js
tests/phpunit/languages/classes/LanguageCrhTest.php
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
tests/selenium/.eslintrc.json
tests/selenium/README.md
tests/selenium/selenium.sh

index 69a123c..898b48f 100644 (file)
@@ -13,7 +13,6 @@ module.exports = function ( grunt ) {
        grunt.loadNpmTasks( 'grunt-jsonlint' );
        grunt.loadNpmTasks( 'grunt-karma' );
        grunt.loadNpmTasks( 'grunt-stylelint' );
-       grunt.loadNpmTasks( 'grunt-webdriver' );
 
        karmaProxy[ wgScriptPath ] = {
                target: wgServer + wgScriptPath,
@@ -104,15 +103,7 @@ module.exports = function ( grunt ) {
                                        return require( 'path' ).join( dest, src.replace( 'resources/', '' ) );
                                }
                        }
-               },
-
-               // Configure WebdriverIO task
-               webdriver: {
-                       test: {
-                               configFile: './tests/selenium/wdio.conf.js'
-                       }
                }
-
        } );
 
        grunt.registerTask( 'assert-mw-env', function () {
index c7bec8d..8e5022c 100644 (file)
@@ -68,6 +68,8 @@ changes to languages because of Phabricator reports.
   * Revision::getRawUser()
   * Revision::getRawUserText()
   * Revision::getRawComment()
+* window.gM() from mediawiki.jqueryMsg was removed (deprecated in 1.23).
+  Use mw.msg() or mw.message() instead.
 
 === Deprecations in 1.32 ===
 * Use of a StartProfiler.php file is deprecated in favour of placing
index 9c4ac50..2247cc2 100644 (file)
@@ -179,7 +179,9 @@ abstract class Skin extends ContextSource {
                        // Styles key sets render blocking styles
                        // Unlike other keys in this definition it is an associative array
                        // where each key is the group name and points to a list of modules
-                       'styles' => [],
+                       'styles' => [
+                               'content' => [],
+                       ],
                        // modules not specific to any specific skin or page
                        'core' => [
                                // Enforce various default modules for all pages and all skins
@@ -208,11 +210,13 @@ abstract class Skin extends ContextSource {
                // Preload jquery.tablesorter for mediawiki.page.ready
                if ( strpos( $out->getHTML(), 'sortable' ) !== false ) {
                        $modules['content'][] = 'jquery.tablesorter';
+                       $modules['styles']['content'][] = 'jquery.tablesorter.styles';
                }
 
                // Preload jquery.makeCollapsible for mediawiki.page.ready
                if ( strpos( $out->getHTML(), 'mw-collapsible' ) !== false ) {
                        $modules['content'][] = 'jquery.makeCollapsible';
+                       $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
                }
 
                if ( $out->isTOCEnabled() ) {
index 723093a..b60882a 100644 (file)
@@ -19,9 +19,9 @@
  */
 
 /**
- * Extend HTMLForm purely so we can have a more sane way of getting the section headers
+ * Extend OOUIHTMLForm purely so we can have a more sane way of getting the section headers
  */
-class EditWatchlistNormalHTMLForm extends HTMLForm {
+class EditWatchlistNormalHTMLForm extends OOUIHTMLForm {
        public function getLegend( $namespace ) {
                $namespace = substr( $namespace, 2 );
 
@@ -29,8 +29,4 @@ class EditWatchlistNormalHTMLForm extends HTMLForm {
                        ? $this->msg( 'blanknamespace' )->escaped()
                        : htmlspecialchars( $this->getContext()->getLanguage()->getFormattedNsText( $namespace ) );
        }
-
-       public function getBody() {
-               return $this->displaySection( $this->mFieldTree, '', 'editwatchlist-' );
-       }
 }
index 01a5a79..1698b9f 100644 (file)
  */
 class CrhConverter extends LanguageConverter {
        // Defines working character ranges
-       const WORD_BEGINS = '\r\s\"\'\(\)\-<>\[\]\/.,:;!?';
-       const WORD_ENDS = '\r\s\"\'\(\)\-<>\[\]\/.,:;!?';
 
        // Cyrillic
        const C_UC = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'; # Crimean Tatar Cyrillic uppercase
        const C_LC = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'; # Crimean Tatar Cyrillic lowercase
        const C_CONS_UC = 'БВГДЖЗЙКЛМНПРСТФХЦЧШЩCÑ'; # Crimean Tatar Cyrillic + CÑ uppercase consonants
        const C_CONS_LC = 'бвгджзйклмнпрстфхцчшщcñ'; # Crimean Tatar Cyrillic + CÑ lowercase consonants
-       const C_M_CONS = 'бгкмпшcБГКМПШC'; # Crimean Tatar Cyrillic M-type consonants
+       const C_M_CONS = 'бгкмшcБГКМШC'; # Crimean Tatar Cyrillic M-type consonants
 
-       # Crimean Tatar Cyrillic + CÑ consonants
+       // Crimean Tatar Cyrillic + CÑ consonants
        const C_CONS = 'бвгджзйклмнпрстфхцчшщcñБВГДЖЗЙКЛМНПРСТФХЦЧШЩCÑ';
 
        // Latin
@@ -50,9 +48,9 @@ class CrhConverter extends LanguageConverter {
        const L_N_CONS_LC = 'çnrstz'; # Crimean Tatar Latin N-type lower case consonants
        const L_N_CONS = 'çnrstzÇNRSTZ'; # Crimean Tatar Latin N-type consonants
        const L_M_CONS = 'bcgkmpşBCGKMPŞ'; # Crimean Tatar Latin M-type consonants
-       const L_CONS_UC = 'BCÇDFGHJKLMNÑPRSŞTVZ'; # Crimean Tatar Latin uppercase consonants
-       const L_CONS_LC = 'bcçdfghjklmnñprsştvz'; # Crimean Tatar Latin lowercase consonants
-       const L_CONS = 'bcçdfghjklmnñprsştvzBCÇDFGHJKLMNÑPRSŞTVZ'; # Crimean Tatar Latin consonants
+       const L_CONS_UC = 'BCÇDFGĞHJKLMNÑPQRSŞTVZ'; # Crimean Tatar Latin uppercase consonants
+       const L_CONS_LC = 'bcçdfgğhjklmnñpqrsştvz'; # Crimean Tatar Latin lowercase consonants
+       const L_CONS = 'bcçdfgğhjklmnñpqrsştvzBCÇDFGĞHJKLMNÑPQRSŞTVZ'; # Crimean Tatar Latin consonants
        const L_VOW_UC = 'AÂEIİOÖUÜ'; # Crimean Tatar Latin uppercase vowels
        const L_VOW = 'aâeıioöuüAÂEIİOÖUÜ'; # Crimean Tatar Latin vowels
        const L_F_UC = 'EİÖÜ'; # Crimean Tatar Latin uppercase front vowels
@@ -133,9 +131,12 @@ class CrhConverter extends LanguageConverter {
 
                ];
 
-       public $mExceptions = [];
+       public $mCyrl2LatnExceptions = [];
+       public $mLatn2CyrlExceptions = [];
+
        public $mCyrl2LatnPatterns = [];
        public $mLatn2CyrlPatterns = [];
+
        public $mCyrlCleanUpRegexes = [];
 
        public $mExceptionsLoaded = false;
@@ -155,9 +156,9 @@ class CrhConverter extends LanguageConverter {
 
                $this->mExceptionsLoaded = true;
                $crhExceptions = new MediaWiki\Languages\Data\CrhExceptions();
-               list( $this->mExceptions, $this->mCyrl2LatnPatterns, $this->mLatn2CyrlPatterns,
-                       $this->mCyrlCleanUpRegexes ) = $crhExceptions->loadExceptions( self::L_LC . self::C_LC,
-                       self::L_UC . self::C_UC );
+               list( $this->mCyrl2LatnExceptions, $this->mLatn2CyrlExceptions,
+                       $this->mCyrl2LatnPatterns, $this->mLatn2CyrlPatterns, $this->mCyrlCleanUpRegexes ) =
+                       $crhExceptions->loadExceptions( self::L_LC . self::C_LC, self::L_UC . self::C_UC );
        }
 
        /**
@@ -197,17 +198,12 @@ class CrhConverter extends LanguageConverter {
         * @return string
         */
        function translate( $text, $toVariant ) {
-               $letters = '';
                switch ( $toVariant ) {
                        case 'crh-cyrl':
-                               $letters = self::L_UC . self::L_LC . "\'";
-                               break;
                        case 'crh-latn':
-                               $letters = self::C_UC . self::C_LC . "";
                                break;
                        default:
                                return $text;
-                               break;
                }
 
                if ( !$this->mTablesLoaded ) {
@@ -218,48 +214,41 @@ class CrhConverter extends LanguageConverter {
                        throw new MWException( "Broken variant table: " . implode( ',', array_keys( $this->mTables ) ) );
                }
 
-               // check for roman numbers like VII, XIX...
-               // Lookahead assertion ensures $roman doesn't match the empty string
-               $roman = '/^(?=[MDCLXVI])M{0,4}(C[DM]|D?C{0,3})(X[LC]|L?X{0,3})(I[VX]|V?I{0,3})$/u';
-
-               # match any sub-string of the relevant letters and convert it
-               $matches = preg_split( '/(\b|^)[^' . $letters . ']+(\b|$)/u',
-                       $text, -1, PREG_SPLIT_OFFSET_CAPTURE );
-               $mstart = 0;
-               $ret = '';
-               foreach ( $matches as $m ) {
-                       # copy over the non-matching bit
-                       $ret .= substr( $text, $mstart, $m[1] - $mstart );
-                       # skip certain classes of strings
-
-                       if ( array_key_exists( $m[0], $this->mExceptions ) ) {
-                               # if it's an exception, just copy down the right answer
-                               $ret .= $this->mExceptions[$m[0]];
-                       } elseif ( ! $m[0] || # empty strings
-                                        preg_match( $roman, $m[0] ) || # roman numerals
-                                        preg_match( '/[^' . $letters . ']/', $m[0] ) # mixed orthography
-                                       ) {
-                               $ret .= $m[0];
-                       } else {
-                               # convert according to the rules
-                               $token = $this->regsConverter( $m[0], $toVariant );
-                               $ret .= parent::translate( $token, $toVariant );
-                       }
-                       $mstart = $m[1] + strlen( $m[0] );
-               }
-
-               # pick up stray quote marks
                switch ( $toVariant ) {
                        case 'crh-cyrl':
-                               $ret = strtr( $ret, [ '“' => '«', '”' => '»', ] );
-                               $ret = $this->regsConverter( $ret, 'cyrl-cleanup' );
-                               break;
-                       case 'crh-latn':
-                               $ret = strtr( $ret, [ '«' => '"', '»' => '"', ] );
-                               break;
-               }
+                               /* Check for roman numbers like VII, XIX...
+                                * Only need to split on Roman numerals when converting to Cyrillic
+                                * Lookahead assertion ensures $roman doesn't match the empty string, and
+                                * non-period after first "Roman" character allows initials to be converted
+                                */
+                               $roman = '(?=[MDCLXVI]([^.]|$))M{0,4}(C[DM]|D?C{0,3})(X[LC]|L?X{0,3})(I[VX]|V?I{0,3})';
+
+                               $breaks = '([^\w\x80-\xff])';
+
+                               // allow for multiple Roman numerals in a row; rare but it happens
+                               $romanRegex = '/^' . $roman . '$|^(' . $roman . $breaks . ')+|(' . $breaks . $roman . ')+$|' .
+                                       $breaks . '(' . $roman . $breaks . ')+/';
+
+                               $matches = preg_split( $romanRegex, $text, -1, PREG_SPLIT_OFFSET_CAPTURE );
+                               $mstart = 0;
+                               $ret = '';
+                               foreach ( $matches as $m ) {
+                                       // copy over Roman numerals
+                                       $ret .= substr( $text, $mstart, $m[1] - $mstart );
+
+                                       // process everything else
+                                       if ( $m[0] !== '' ) {
+                                               $ret .= $this->regsConverter( $m[0], $toVariant );
+                                       }
+
+                                       $mstart = $m[1] + strlen( $m[0] );
+                               }
 
-               return $ret;
+                               return $ret;
+                       default:
+                               // Just process the whole string in one go
+                               return $this->regsConverter( $text, $toVariant );
+               }
        }
 
        private function regsConverter( $text, $toVariant ) {
@@ -269,16 +258,20 @@ class CrhConverter extends LanguageConverter {
                $rep = [];
                switch ( $toVariant ) {
                        case 'crh-latn':
+                               $text = strtr( $text, $this->mCyrl2LatnExceptions );
                                foreach ( $this->mCyrl2LatnPatterns as $pat => $rep ) {
                                        $text = preg_replace( $pat, $rep, $text );
                                }
+                               $text = parent::translate( $text, $toVariant );
+                               $text = strtr( $text, [ '«' => '"', '»' => '"', ] );
                                return $text;
                        case 'crh-cyrl':
+                               $text = strtr( $text, $this->mLatn2CyrlExceptions );
                                foreach ( $this->mLatn2CyrlPatterns as $pat => $rep ) {
                                        $text = preg_replace( $pat, $rep, $text );
                                }
-                               return $text;
-                       case 'cyrl-cleanup':
+                               $text = parent::translate( $text, $toVariant );
+                               $text = strtr( $text, [ '“' => '«', '”' => '»', ] );
                                foreach ( $this->mCyrlCleanUpRegexes as $pat => $rep ) {
                                        $text = preg_replace( $pat, $rep, $text );
                                }
index d656528..e3bb156 100644 (file)
@@ -17,7 +17,9 @@ class CrhExceptions {
                $this->loadRegs();
        }
 
-       public $exceptionMap = [];
+       public $Cyrl2LatnExceptions = [];
+       public $Latn2CyrlExceptions = [];
+
        public $Cyrl2LatnPatterns = [];
        public $Latn2CyrlPatterns = [];
 
@@ -59,10 +61,12 @@ class CrhExceptions {
        private function addMappings( $mapArray, &$A2B, &$B2A, $exactCase = false,
                        $prePat = '', $postPat = '' ) {
                foreach ( $mapArray as $WordA => $WordB ) {
-                       $ucA = $this->myUc( $WordA );
-                       $ucWordA = $this->myUcWord( $WordA );
-                       $ucB = $this->myUc( $WordB );
-                       $ucWordB = $this->myUcWord( $WordB );
+                       if ( ! $exactCase ) {
+                               $ucA = $this->myUc( $WordA );
+                               $ucWordA = $this->myUcWord( $WordA );
+                               $ucB = $this->myUc( $WordB );
+                               $ucWordB = $this->myUcWord( $WordB );
+                       }
 
                        # if there are regexes, only map toward backregs
                        if ( ! preg_match( '/\$[1-9]/', $WordA ) ) {
@@ -86,94 +90,130 @@ class CrhExceptions {
        function loadExceptions( $lcChars, $ucChars ) {
                # init lc and uc, as needed
                $this->initLcUc( $lcChars, $ucChars );
-               # load C2L and L2C whole-word exceptions into the same array, since it's just a look up
-               # no regex prefix/suffix needed
-               $this->addMappings( $this->wordMappings, $this->exceptionMap, $this->exceptionMap );
-               $this->addMappings( $this->exactCaseMappings, $this->exceptionMap, $this->exceptionMap, true );
 
-               # load C2L and L2C bidirectional prefix mappings
+               # no regex prefix/suffix needed
+               $this->addMappings( $this->ManyToOneC2LMappings,
+                       // reverse exception mapping order to handle many-to-one C2L mappings
+                       $this->Latn2CyrlExceptions, $this->Cyrl2LatnExceptions );
+               $this->addMappings( $this->multiCaseMappings,
+                       $this->Cyrl2LatnExceptions, $this->Latn2CyrlExceptions );
+               $this->addMappings( $this->exactCaseMappings,
+                       $this->Cyrl2LatnExceptions, $this->Latn2CyrlExceptions, true );
+
+               # load C2L and L2C bidirectional affix mappings
                $this->addMappings( $this->prefixMapping,
-                       $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/^', '/u' );
+                       $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/\b', '/u' );
                $this->addMappings( $this->suffixMapping,
-                       $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/', '$/u' );
+                       $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/', '\b/u' );
 
                # tack on one-way mappings to the ends of the prefix and suffix patterns
                $this->Cyrl2LatnPatterns += $this->Cyrl2LatnRegexes;
                $this->Latn2CyrlPatterns += $this->Latn2CyrlRegexes;
 
-               return [ $this->exceptionMap, $this->Cyrl2LatnPatterns,
+               return [ $this->Cyrl2LatnExceptions, $this->Latn2CyrlExceptions, $this->Cyrl2LatnPatterns,
                        $this->Latn2CyrlPatterns, $this->CyrlCleanUpRegexes ];
        }
 
-       # map Cyrillic to Latin and back, whole word match only
+       # map Latin to Cyrillic and back, simple string match only (no regex)
        # variants: all lowercase, all uppercase, first letter capitalized
-       # items with capture group refs (e.g., $1) are only mapped from the
-       # regex to the reference
-       private $wordMappings = [
+       private $ManyToOneC2LMappings = [
+               # Carefully ordered many-to-one mappings
+               # these are ordered so C2L is correct (the later Latin one)
+               # see also L2C mappings below
+               'fevqülade' => 'февкъульаде', 'fevqulade' => 'февкъульаде',
+               'beyude' => 'бейуде', 'beyüde' => 'бейуде',
+               'curat' => 'джурьат', 'cürat' => 'джурьат',
+               'mesul' => 'месуль', 'mesül' => 'месуль',
+       ];
+
+       # map Cyrillic to Latin and back, simple string match only (no regex)
+       # variants: all lowercase, all uppercase, first letter capitalized
+       private $multiCaseMappings = [
 
-               #### originally Cyrillic to Latin
+               #### Cyrillic to Latin
                'аджыумер' => 'acıümer', 'аджыусеин' => 'acıüsein', 'алейкум' => 'aleyküm',
-               'бейуде' => 'beyüde', 'боливия' => 'boliviya', 'большевик' => 'bolşevik', 'борис' => 'boris',
-               'борнен' => 'bornen', 'бугун' => 'bugün', 'бузкесен' => 'buzkesen', 'буксир' => 'buksir',
-               'бульбуль' => 'bülbül', 'бульвар' => 'bulvar', 'бульдозер' => 'buldozer', 'бульон' => 'bulyon',
+               'бозтюс' => 'boztüs', 'боливия' => 'boliviya', 'большевик' => 'bolşevik', 'борис' => 'boris',
+               'борнен' => 'bornen', 'бублик' => 'bublik', 'буддизм' => 'buddizm', 'буддист' => 'buddist',
+               'буженина' => 'bujenina', 'бузкесен' => 'buzkesen', 'букинист' => 'bukinist',
+               'буксир' => 'buksir', 'бульбул' => 'bülbül', 'бульвар' => 'bulvar', 'бульдог' => 'buldog',
+               'бульдозер' => 'buldozer', 'бульон' => 'bulyon', 'бумеранг' => 'bumerang',
                'бунен' => 'bunen', 'буннен' => 'bunnen', 'бус-бутюн' => 'büs-bütün',
-               'бутерброд' => 'buterbrod', 'буфер' => 'bufer', 'буфет' => 'bufet', 'гонъюл' => 'göñül',
-               'горизонт' => 'gorizont', 'госпиталь' => 'gospital', 'гуливер' => 'guliver', 'гуна' => 'güna',
-               'гунях' => 'günâh', 'гургуль' => 'gürgül', 'гуя' => 'güya', 'демирёл' => 'demiryol',
-               'джуньджу' => 'cüncü', 'ёлнен' => 'yolnen', 'зумбуль' => 'zümbül', 'ильи' => 'ilyi', 'ишунь' =>
-               'işün', 'кодекс' => 'kodeks', 'кодифик' => 'kodifik', 'койлю' => 'köylü', 'коккоз' =>
-               'kökköz', 'коккозь' => 'kökköz', 'коккозю' => 'kökközü', 'кокос' => 'kokos',
-               'коллег' => 'kolleg', 'коллект' => 'kollekt', 'коллекц' => 'kollekts', 'кольцов' => 'koltsov',
-               'комбин' => 'kombin', 'комедия' => 'komediya', 'коменда' => 'komenda', 'комета' => 'kometa',
-               'комис' => 'komis', 'комит' => 'komit', 'комите' => 'komite', 'коммент' => 'komment',
-               'коммерс' => 'kommers', 'коммерц' => 'kommerts', 'компенс' => 'kompens', 'компил' => 'kompil',
-               'компьютер' => 'kompyuter', 'конвейер' => 'konveyer', 'конвен' => 'konven',
-               'конверт' => 'konvert', 'конденс' => 'kondens', 'кондитер' => 'konditer',
-               'кондиц' => 'kondits', 'коник' => 'konik', 'консерв' => 'konserv', 'контейнер' => 'konteyner',
-               'континент' => 'kontinent', 'конфе' => 'konfe', 'конфискац' => 'konfiskats',
-               'концен' => 'kontsen', 'концерт' => 'kontsert', 'конъюктур' => 'konyuktur',
-               'коньки' => 'konki', 'коньяк' => 'konyak', 'копирле' => 'kopirle', 'копия' => 'kopiya',
-               'корбекул' => 'körbekül', 'кореиз' => 'koreiz', 'коренн' => 'korenn', 'корея' => 'koreya',
-               'коридор' => 'koridor', 'корнеев' => 'korneyev', 'корре' => 'korre', 'корьбекул' =>
-               'körbekül', 'косме' => 'kosme', 'космик' => 'kosmik', 'костюм' => 'kostüm', 'котельн' =>
-               'koteln', 'котировка' => 'kotirovka', 'котлет' => 'kotlet', 'кочергин' => 'koçergin',
-               'коше' => 'köşe', 'кудрин' => 'kudrin', 'кузнец' => 'kuznets', 'кулинар' => 'kulinar',
-               'кулич' => 'kuliç', 'кульминац' => 'kulminats', 'культив' => 'kultiv',
-               'культура' => 'kultura', 'куркулет' => 'kürkület', 'курсив' => 'kursiv', 'кушку' => 'küşkü',
-               'куюк' => 'küyük', 'къарагоз' => 'qaragöz', 'къолязма' => 'qolyazma', 'къуртумер' =>
-               'qurtümer', 'къуртусеин' => 'qurtüsein', 'марьино' => 'maryino', 'медьюн' => 'medyun',
-               'месули' => 'mesüli', 'месуль' => 'mesül', 'мефкуре' => 'mefküre', 'могедек' => 'mögedek',
-               'муур' => 'müür', 'муче' => 'müçe', 'муюз' => 'müyüz', 'огнево' => 'ognevo',
-               'одеколон' => 'odekolon', 'одеса' => 'odesa', 'одесса' => 'odessa', 'озерки' => 'ozerki',
-               'озерн' => 'ozern', 'озёрн' => 'ozörn', 'океан' => 'okean', 'оленев' => 'olenev',
-               'олимп' => 'olimp', 'ольчер' => 'ölçer', 'онен' => 'onen', 'оннен' => 'onnen',
-               'опера' => 'opera', 'оптим' => 'optim', 'опци' => 'optsi', 'опция' => 'optsiya',
-               'орден' => 'orden', 'ордер' => 'order', 'ореанда' => 'oreanda', 'орех' => 'oreh',
-               'оригинал' => 'original', 'ориент' => 'oriyent', 'оркестр' => 'orkestr', 'орлин' => 'orlin',
-               'офис' => 'ofis', 'офицер' => 'ofitser', 'офсет' => 'ofset', 'оюннен' => 'oyunnen', 'побед' =>
-               'pobed', 'полево' => 'polevo', 'поли' => 'poli', 'полюшко' => 'polüşko',
-               'помидор' => 'pomidor', 'пониз' => 'poniz', 'порфир' => 'porfir', 'потелов' => 'potelov',
-               'почетн' => 'poçetn', 'почётн' => 'poçötn', 'публик' => 'publik', 'публиц' => 'publits',
-               'пушкин' => 'puşkin', 'сеитумер' => 'seitümer', 'сеитусеин' => 'seitüsein', 'сеитягъя' =>
-               'seityağya', 'сеитягья' => 'seityagya', 'сеитяхья' => 'seityahya', 'сеитяя' => 'seityaya',
+               'бутерброд' => 'buterbrod', 'бутилен' => 'butilen', 'бутилир' => 'butilir',
+               'буфер' => 'bufer', 'буфет' => 'bufet', 'гобелен' => 'gobelen', 'гомео' => 'gomeo',
+               'горизонт' => 'gorizont', 'госпитал' => 'gospital', 'готтентот' => 'gottentot',
+               'гофрир' => 'gofrir', 'губерн' => 'gubern', 'гуверн' => 'guvern', 'гугенот' => 'gugenot',
+               'гуливер' => 'guliver', 'гуна' => 'güna', 'гунях' => 'günâh', 'гургуль' => 'gürgül',
+               'гуя' => 'güya', 'дёрткуль' => 'dörtkül', 'джуньджу' => 'cüncü', 'ёлнен' => 'yolnen',
+               'зумбуль' => 'zümbül', 'ильи' => 'ilyi', 'ишунь' => 'işün', 'ковер' => 'kover', 'код' => 'kod',
+               'койлю' => 'köylü', 'кокагъач' => 'kökağaç', 'кокбаштанкъара' => 'kökbaştanqara',
+               'кокгогерджин' => 'kökgögercin', 'кокдогъан' => 'kökdoğan', 'коккозю' => 'kökközü',
+               'коккъузгъун' => 'kökquzğun', 'коклюш' => 'koklüş', 'кокташ' => 'köktaş',
+               'коктогъан' => 'köktoğan', 'коктотай' => 'köktotay', 'коллег' => 'kolleg',
+               'коллект' => 'kollekt', 'коллекц' => 'kollekts', 'колье' => 'kolye', 'кольраби' => 'kolrabi',
+               'кольцов' => 'koltsov', 'комби' => 'kombi', 'комеди' => 'komedi', 'коменда' => 'komenda',
+               'комета' => 'kometa', 'комив' => 'komiv', 'комис' => 'komis', 'комит' => 'komit',
+               'комм' => 'komm', 'коммент' => 'komment', 'коммерс' => 'kommers', 'коммерц' => 'kommerts',
+               'комп' => 'komp', 'конве' => 'konve', 'конгени' => 'kongeni', 'конденс' => 'kondens',
+               'кондил' => 'kondil', 'кондитер' => 'konditer', 'кондиц' => 'kondits', 'коник' => 'konik',
+               'конкис' => 'konkis', 'консерв' => 'konserv', 'конси' => 'konsi', 'контейнер' => 'konteyner',
+               'конти' => 'konti', 'конфе' => 'konfe', 'конфи' => 'konfi', 'конце' => 'kontse',
+               'конъю' => 'konyu', 'коньки' => 'konki', 'коньяк' => 'konyak', 'копирле' => 'kopirle',
+               'копия' => 'kopiya', 'корде' => 'korde', 'кореиз' => 'koreiz', 'коренн' => 'korenn',
+               'корея' => 'koreya', 'кориа' => 'koria', 'коридор' => 'koridor', 'корне' => 'korne',
+               'корнеев' => 'korneyev', 'корни' => 'korni', 'корре' => 'korre', 'косме' => 'kosme',
+               'космик' => 'kosmik', 'костюм' => 'kostüm', 'котельн' => 'koteln', 'котир' => 'kotir',
+               'котлет' => 'kotlet', 'кочерг' => 'koçerg', 'коше' => 'köşe', 'куби' => 'kubi',
+               'кудрин' => 'kudrin', 'кузнец' => 'kuznets', 'кулинар' => 'kulinar', 'кулич' => 'kuliç',
+               'кульмин' => 'kulmin', 'культаш' => 'kültaş', 'культе' => 'külte', 'культ' => 'kult',
+               'куркулет' => 'kürkület', 'курсив' => 'kursiv', 'кушет' => 'kuşet', 'кушку' => 'küşkü',
+               'куюк' => 'küyük', 'къолязма' => 'qolyazma', 'къуртумер' => 'qurtümer',
+               'къуртусеин' => 'qurtüsein', 'медьюн' => 'medyun', 'месули' => 'mesüli',
+               'мефкуре' => 'mefküre', 'могедек' => 'mögedek', 'мумиё' => 'mumiyo', 'мумиф' => 'mumif',
+               'муче' => 'müçe', 'муюз' => 'müyüz', 'нумюне' => 'nümüne', 'обел' => 'obel', 'обер' => 'ober',
+               'обли' => 'obli', 'обсе' => 'obse', 'обт' => 'obt', 'огне' => 'ogne', 'одеколон' => 'odekolon',
+               'одеса' => 'odesa', 'одесса' => 'odessa', 'озерки' => 'ozerki', 'озерн' => 'ozern',
+               'озёрн' => 'ozörn', 'озюя' => 'özüya', 'океан' => 'okean', 'окси' => 'oksi',
+               'октет' => 'oktet', 'олеа' => 'olea', 'олеи' => 'olei', 'оленев' => 'olenev', 'олив' => 'oliv',
+               'олиг' => 'olig', 'олимп' => 'olimp', 'олиф' => 'olif', 'ольчер' => 'ölçer', 'омле' => 'omle',
+               'онен' => 'onen', 'оннен' => 'onnen', 'опера' => 'opera', 'опере' => 'opere',
+               'оптим' => 'optim', 'опци' => 'optsi', 'орби' => 'orbi', 'орден' => 'orden',
+               'ордер' => 'order', 'ордин' => 'ordin', 'ореа' => 'orea', 'орех' => 'oreh',
+               'ориент' => 'oriyent', 'оркестр' => 'orkestr', 'орлин' => 'orlin', 'орни' => 'orni',
+               'орхи' => 'orhi', 'осци' => 'ostsi', 'офис' => 'ofis', 'офиц' => 'ofits', 'офсет' => 'ofset',
+               'очерк' => 'oçerk', 'оюннен' => 'oyunnen', 'побед' => 'pobed', 'полево' => 'polevo',
+               'поли' => 'poli', 'полюшко' => 'polüşko', 'помидор' => 'pomidor', 'пониз' => 'poniz',
+               'порфир' => 'porfir', 'потелов' => 'potelov', 'потюк' => 'pötük', 'почетн' => 'poçetn',
+               'почётн' => 'poçötn', 'пукле' => 'pükle', 'пуркю' => 'pürkü', 'пурумют' => 'purümüt',
+               'пускул' => 'püskül', 'пускур' => 'püskür', 'пусюр' => 'püsür', 'пуфле' => 'püfle',
                'сейитумер' => 'seyitümer', 'сейитусеин' => 'seyitüsein', 'сейитягъя' => 'seyityağya',
                'сейитягья' => 'seyityagya', 'сейитяхья' => 'seyityahya', 'сейитяя' => 'seyityaya',
-               'ультимат' => 'ultimat', 'ультра' => 'ultra', 'ульянов' => 'ulyanov', 'универ' => 'univer',
-               'уника' => 'unika', 'унтер' => 'unter', 'урьян' => 'uryan', 'уткин' => 'utkin', 'учебн' =>
-               'uçebn', 'шовини' => 'şovini', 'шоссе' => 'şosse', 'шубин' => 'şubin', 'шунен' => 'şunen',
-               'шуннен' => 'şunnen', 'щёлкино' => 'şçolkino', 'эмирусеин' => 'emirüsein',
-               'юзбашы' => 'yüzbaşı', 'юзйыл' => 'yüzyıl', 'юртер' => 'yurter', 'ющенко' => 'yuşçenko',
-
-               'кою' => 'köyü', 'кок' => 'kök', 'ком-кок' => 'köm-kök', 'коп' => 'köp', 'ог' => 'ög',
-               'юрип' => 'yürip', 'юз' => 'yüz', 'юк' => 'yük', 'буюп' => 'büyüp', 'буюк' => 'büyük',
-               'джонк' => 'cönk', 'джонкю' => 'cönkü', 'устке' => 'üstke', 'устте' => 'üstte',
-               'усттен' => 'üstten',
-
-               # шофёр needs to come after шофер to override it in the Latin-to-Cyrillic direction
-               'шофер' => 'şoför',
-               'шофёр' => 'şoför',
-
-               #### originally Latin to Cyrillic (deduped from above)
+               'сеитумер' => 'seitümer', 'сеитусеин' => 'seitüsein', 'сеитягъя' => 'seityağya',
+               'сеитягья' => 'seityagya', 'сеитяхья' => 'seityahya', 'сеитяя' => 'seityaya',
+               'сурет' => 'süret', 'увертюра' => 'uvertüra', 'угле' => 'ugle', 'узвий' => 'uzviy',
+               'улица' => 'ulitsa', 'ультимат' => 'ultimat', 'ультра' => 'ultra', 'ульянов' => 'ulyanov',
+               'универ' => 'univer', 'уник' => 'unik', 'унис' => 'unis', 'унит' => 'unit', 'униф' => 'unif',
+               'унтер' => 'unter', 'урьян' => 'uryan', 'утил' => 'util', 'уткин' => 'utkin',
+               'учебн' => 'uçebn', 'шовини' => 'şovini', 'шоссе' => 'şosse', 'шубин' => 'şubin',
+               'шунен' => 'şunen', 'шуннен' => 'şunnen', 'шунчюн' => 'şunçün', 'щёлкино' => 'şçolkino',
+               'эмирусеин' => 'emirüsein', 'юзбашы' => 'yüzbaşı', 'юзйыл' => 'yüzyıl', 'юртер' => 'yurter',
+               'ющенко' => 'yuşçenko',
+
+               ### Carefully ordered many-to-one mappings
+               # these are ordered so L2C is correct (the later Cyrillic one)
+               # see also $ManyToOneC2LMappings above for C2L
+               'шофер' => 'şoför', 'шофёр' => 'şoför',
+               'бугун' => 'bugün', 'бугунь' => 'bugün',
+               'демирёл' => 'demiryol', 'демиръёл' => 'demiryol',
+               'гонъюл' => 'göñül', 'гонъюль' => 'göñül',
+               'коккоз' => 'kökköz', 'коккозь' => 'kökköz',
+               'корбекул' => 'körbekül', 'корьбекул' => 'körbekül', 'корьбекуль' => 'körbekül',
+               'муур' => 'müür', 'муурь' => 'müür',
+               'оригинал' => 'original', 'оригиналь' => 'original',
+               'пускю' => 'püskü', 'пуськю' => 'püskü',
+               'къарагоз' => 'qaragöz', 'къарагозь' => 'qaragöz',
+               'етсин' => 'yetsin', 'етсин' => 'etsin',
+
+               #### Latin to Cyrillic (deduped from above)
 
                # слова на -аль
                # words in -аль
@@ -184,42 +224,39 @@ class CrhExceptions {
                'истикъбаль' => 'istiqbal', 'истикъляль' => 'istiqlâl', 'италия' => 'italiya',
                'италья' => 'italya', 'ишгъаль' => 'işğal', 'кафедраль' => 'kafedral', 'казуаль' => 'kazual',
                'коллегиаль' => 'kollegial', 'колоссаль' => 'kolossal', 'коммуналь' => 'kommunal',
-               'кординаль' => 'kordinal', 'криминаль' => 'kriminal', 'легаль' => 'legal', 'леталь' => 'letal',
-               'либеÑ\80алÑ\8c' => 'liberal', 'локалÑ\8c' => 'lokal', 'магиÑ\81Ñ\82Ñ\80алÑ\8c' => 'magistral',
-               'материаль' => 'material', 'машиналь' => 'maşinal', 'меаль' => 'meal',
-               'медалÑ\8cон' => 'medalyon', 'медалÑ\8c' => 'medal', 'меÑ\80идионалÑ\8c' => 'meridional',
-               'меÑ\88Ñ\8aалÑ\8c' => 'meÅ\9fal', 'минеÑ\80алÑ\8c' => 'mineral', 'минималÑ\8c' => 'minimal', 'миÑ\81алÑ\8c' => 'misal',
-               'модалÑ\8c' => 'modal', 'мÑ\83зÑ\8bкалÑ\8c' => 'muzıkal', 'номиналÑ\8c' => 'nominal', 'ноÑ\80малÑ\8c' => 'normal',
-               'опÑ\82ималÑ\8c' => 'optimal', 'оÑ\80биÑ\82алÑ\8c' => 'orbital', 'оÑ\80игиналÑ\8c' => 'original',
-               'педалÑ\8c' => 'pedal', 'пÑ\80опоÑ\80Ñ\86ионалÑ\8c' => 'proportsional', 'пÑ\80оÑ\84еÑ\81Ñ\81ионалÑ\8c' => 'professional',
-               'радикаль' => 'radikal', 'рациональ' => 'ratsional', 'реаль' => 'real',
-               'региональ' => 'regional', 'суаль' => 'sual', 'шималь' => 'şimal',
+               'кординаль' => 'kordinal', 'криминаль' => 'kriminal', 'легаль' => 'legal',
+               'леÑ\82алÑ\8c' => 'letal', 'либеÑ\80алÑ\8c' => 'liberal', 'локалÑ\8c' => 'lokal',
+               'магистраль' => 'magistral', 'материаль' => 'material', 'машиналь' => 'maşinal',
+               'меалÑ\8c' => 'meal', 'медалÑ\8cон' => 'medalyon', 'медалÑ\8c' => 'medal',
+               'меÑ\80идионалÑ\8c' => 'meridional', 'меÑ\88Ñ\8aалÑ\8c' => 'meÅ\9fal', 'минеÑ\80алÑ\8c' => 'mineral',
+               'минималÑ\8c' => 'minimal', 'миÑ\81алÑ\8c' => 'misal', 'модалÑ\8c' => 'modal', 'мÑ\83зÑ\8bкалÑ\8c' => 'muzıkal',
+               'номиналÑ\8c' => 'nominal', 'ноÑ\80малÑ\8c' => 'normal', 'опÑ\82ималÑ\8c' => 'optimal',
+               'оÑ\80биÑ\82алÑ\8c' => 'orbital', 'педалÑ\8c' => 'pedal', 'пÑ\80опоÑ\80Ñ\86ионалÑ\8c' => 'proportsional',
+               'профессиональ' => 'professional', 'радикаль' => 'radikal', 'рациональ' => 'ratsional',
+               'Ñ\80еалÑ\8c' => 'real', 'Ñ\80егионалÑ\8c' => 'regional', 'Ñ\81Ñ\83алÑ\8c' => 'sual', 'Ñ\88ималÑ\8c' => 'Å\9fimal',
                'территориаль' => 'territorial', 'тимсаль' => 'timsal', 'тоталь' => 'total',
                'уникаль' => 'unikal', 'универсаль' => 'universal', 'вертикаль' => 'vertikal',
                'виртуаль' => 'virtual', 'визуаль' => 'vizual', 'вуаль' => 'vual', 'зональ' => 'zonal',
-               'зуаль' => 'zual',
+               'зуаль' => 'zual', 'италь' => 'ital',
 
                # слова с мягким знаком перед а, о, у, э
                # Words with a soft sign before а, о, у, э
-               'бильакис' => 'bilakis', 'маальэсеф' => 'maalesef',
-               'мельун' => 'melun', 'озьара' => 'özara', 'вельасыл' => 'velasıl',
-               'ельаякъ' => 'yelayaq',
-               # these are ordered so C2L is correct (the later Latin one)
-               'февкъульаде' => 'fevqülade','февкъульаде' => 'fevqulade',
+               'бильакис' => 'bilakis', 'маальэсеф' => 'maalesef', 'мельун' => 'melun', 'озьара' => 'özara',
+               'вельасыл' => 'velasıl', 'ельаякъ' => 'yelayaq',
 
                # другие слова с мягким знаком
                # Other words with a soft sign
                'альбатрос' => 'albatros', 'альбинос' => 'albinos', 'альбом' => 'albom',
                'альбумин' => 'albumin', 'алфавит' => 'alfavit', 'альфа' => 'alfa', 'альманах' => 'almanah',
-               'альпинист' => 'alpinist', 'альтерн' => 'altern', 'альтру' => 'altru', 'альвеола' => 'alveola',
-               'анÑ\81амблÑ\8c' => 'ansambl', 'анÑ\8cане' => 'anane', 'аÑ\81Ñ\84алÑ\8cÑ\82' => 'asfalt', 'балÑ\8cнео' => 'balneo',
-               'бааÑ\80Ñ\8c' => 'baar', 'базалÑ\8cÑ\82' => 'bazalt', 'биноклÑ\8c' => 'binokl', 'джÑ\83Ñ\80Ñ\8cаÑ\82' => 'curat',
-               'джÑ\83Ñ\80Ñ\8cаÑ\82' => 'cürat', 'девалÑ\8cв' => 'devalv', 'Ñ\84акÑ\83лÑ\8cÑ\82' => 'fakult', 'Ñ\84алÑ\8cÑ\81иÑ\84' => 'falsif',
-               'фольклор' => 'folklor', 'гальван' => 'galvan', 'геральд' => 'gerald', 'женьшень' => 'jenşen',
+               'альпинист' => 'alpinist', 'альтерн' => 'altern', 'альтру' => 'altru',
+               'алÑ\8cвеола' => 'alveola', 'анÑ\81амблÑ\8c' => 'ansambl', 'анÑ\8cане' => 'anane', 'аÑ\81Ñ\84алÑ\8cÑ\82' => 'asfalt',
+               'балÑ\8cнео' => 'balneo', 'бааÑ\80Ñ\8c' => 'baar', 'базалÑ\8cÑ\82' => 'bazalt', 'биноклÑ\8c' => 'binokl',
+               'девалÑ\8cв' => 'devalv', 'Ñ\84акÑ\83лÑ\8cÑ\82' => 'fakult', 'Ñ\84алÑ\8cÑ\81иÑ\84' => 'falsif', 'Ñ\84олÑ\8cклоÑ\80' => 'folklor',
+               'гальван' => 'galvan', 'геральд' => 'gerald', 'женьшень' => 'jenşen',
                'инвентарь' => 'inventar', 'кальк' => 'kalk', 'кальмар' => 'kalmar', 'консульт' => 'konsult',
-               'контроль' => 'kontrol', 'кульмин' => 'kulmin', 'культур' => 'kultur', 'лагерь' => 'lager',
-               'макъбуль' => 'maqbul', 'макъуль' => 'maqul', 'мальт' => 'malt', 'мальземе' => 'malzeme',
-               'меджуль' => 'mecul', 'мешгуль' => 'meşgül', 'мешгъуль' => 'meşğul', 'мульти' => 'multi',
+               'контроль' => 'kontrol', 'культур' => 'kultur', 'лагерь' => 'lager', 'макъбуль' => 'maqbul',
+               'макъуль' => 'maqul', 'мальт' => 'malt', 'мальземе' => 'malzeme', 'меджуль' => 'mecul',
+               'мешгуль' => 'meşgül', 'мешгъуль' => 'meşğul', 'мульти' => 'multi',
                'мусульман' => 'musulman', 'нефть' => 'neft', 'пальто' => 'palto', 'пароль' => 'parol',
                'патруль' => 'patrul', 'пенальти' => 'penalti', 'къальби' => 'qalbi', 'къальпке' => 'qalpke',
                'къальплер' => 'qalpler', 'къальпни' => 'qalpni', 'къальпте' => 'qalpte', 'къаарь' => 'qaar',
@@ -233,23 +270,23 @@ class CrhExceptions {
                # слова с твёрдым знаком
                # Words with a solid sign
                'бидъат' => 'bidat', 'бузъюрек' => 'buzyürek', 'атешъюрек' => 'ateşyürek',
-               'алÑ\8aÑ\8fнакÑ\8a' => 'alyanaq', 'демиÑ\80Ñ\8aÑ\91л' => 'demiryol', 'деÑ\80Ñ\8aал' => 'deral', 'инÑ\8aекÑ\86' => 'inyekts',
-               'меÑ\84Ñ\8aÑ\83м' => 'mefum', 'меÑ\88Ñ\8aÑ\83м' => 'meÅ\9fum', 'обÑ\8aекÑ\82' => 'obyekt', 'Ñ\80азÑ\8aезд' => 'razyezd',
-               'Ñ\81Ñ\83бÑ\8aекÑ\82' => 'subyekt', 'Ñ\85авÑ\8aÑ\8fÑ\80' => 'havyar', 'Ñ\8fмÑ\8aÑ\8fм' => 'yamyam',
+               'алÑ\8aÑ\8fнакÑ\8a' => 'alyanaq', 'инÑ\8aекÑ\86' => 'inyekts', 'меÑ\84Ñ\8aÑ\83м' => 'mefum', 'меÑ\88Ñ\8aÑ\83м' => 'meÅ\9fum',
+               'обÑ\8aекÑ\82' => 'obyekt', 'Ñ\80азÑ\8aезд' => 'razyezd', 'Ñ\81Ñ\83бÑ\8aекÑ\82' => 'subyekt', 'Ñ\85авÑ\8aÑ\8fÑ\80' => 'havyar',
+               'ямъям' => 'yamyam',
 
                # слова с буквой щ
                # words with щ
                'ящик' => 'yaşçik', 'мещан' => 'meşçan',
 
-               # слова с буквой ц
+               # слова с ц
                # words with ц
                'акциз' => 'aktsiz', 'ацет' => 'atset', 'блиц' => 'blits', 'бруцеллёз' => 'brutsellöz',
                'доцент' => 'dotsent', 'фармацевт' => 'farmatsevt', 'глицер' => 'glitser',
                'люцерна' => 'lütserna', 'лицей' => 'litsey', 'меццо' => 'metstso', 'наци' => 'natsi',
                'проце' => 'protse', 'рецеп' => 'retsep', 'реценз' => 'retsenz', 'теплица' => 'teplitsa',
-               'виÑ\86е' => 'vitse', 'Ñ\86епÑ\81' => 'tseps', 'Ñ\88вейÑ\86аÑ\80' => 'Å\9fveytsar',
+               'вице' => 'vitse', 'швейцар' => 'şveytsar',
 
-               # слова без буквы тс
+               # слова с тс
                # words with тс
                'агъартс' => 'ağarts', 'агъыртс' => 'ağırts', 'бильдиртс' => 'bildirts', 'битсин' => 'bitsin',
                'буюльтс' => 'büyülts', 'буютс' => 'büyüts', 'гебертс' => 'geberts', 'делиртс' => 'delirts',
@@ -259,253 +296,55 @@ class CrhExceptions {
                'кучертс' => 'küçerts', 'кучюльтс' => 'küçülts', 'пертсин' => 'pertsin', 'къайтс' => 'qayts',
                'къутсуз' => 'qutsuz', 'орьтс' => 'örts', 'отьс' => 'öts', 'тартс' => 'tarts',
                'тутсун' => 'tutsun', 'тюнъюльтс' => 'tüñülts', 'тюртс' => 'türts', 'янъартс' => 'yañarts',
-               'ебеÑ\80Ñ\82Ñ\81' => 'yeberts', 'еÑ\82Ñ\81ин' => 'yetsin', 'еÑ\88еÑ\80Ñ\82Ñ\81' => 'yeÅ\9ferts', 'йиÑ\80иÑ\82Ñ\81' => 'yirits',
+               'ебертс' => 'yeberts', 'ешертс' => 'yeşerts', 'йиритс' => 'yirits',
 
                # разные исключения
                # different exceptions
-               'бейуде' => 'beyude', 'бугунь' => 'bugün', 'бюджет' => 'bücet', 'бюллет' => 'büllet',
-               'бюро' => 'büro', 'бюст' => 'büst', 'джонк' => 'cönk', 'диалог' => 'dialog',
-               'гонъюль' => 'göñül', 'ханымэфенди' => 'hanımefendi', 'каньон' => 'kanyon', 'кирил' => 'kiril',
-               'кирил' => 'kirill', 'кёрджа' => 'körca', 'кой' => 'köy', 'кулеръюзь' => 'küleryüz',
-               'маалле' => 'маальle', 'майор' => 'mayor', 'маниал' => 'manиаль', 'мефкуре' => 'mefküre',
-               'месуль' => 'mesul', 'месуль' => 'mesül', 'муурь' => 'müür',
-               'нормала' => 'нормальa', 'нумюне' => 'nümüne', 'проект' => 'proekt', 'район' => 'rayon',
-               'сойады' => 'soyadı', 'спортсмен' => 'sportsmen', 'услюп' => 'üslüp', 'услюб' => 'üslüb',
-               'вакъиал' => 'vaqиаль', 'юзйыллыкъ' => 'yüzyıllıq',
+               'бюджет' => 'bücet', 'бюллет' => 'büllet', 'бюро' => 'büro', 'бюст' => 'büst',
+               'диалог' => 'dialog', 'ханымэфенди' => 'hanımefendi', 'каньон' => 'kanyon',
+               'кирил' => 'kiril', 'кирилл' => 'kirill', 'кёрджа' => 'körca', 'коy' => 'köy',
+               'кулеръюзь' => 'küleryüz', 'маалле' => 'маальle', 'майор' => 'mayor', 'маниал' => 'manиаль',
+               'нормала' => 'нормальa', 'проект' => 'proekt', 'район' => 'rayon', 'сойады' => 'soyadı',
+               'спортсмен' => 'sportsmen', 'услюп' => 'üslüp', 'услюб' => 'üslüb', 'вакъиал' => 'vaqиаль',
+               'юзйыллыкъ' => 'yüzyıllıq', 'койот' => 'koyot',
 
                # имена собственные
                # proper names
-               'адольф' => 'adolf', 'альберт' => 'albert', 'бешуй' => 'beşüy', 'эмирусеин' => 'emirüsein',
-               'флотск' => 'flotsk', 'гайана' => 'gayana', 'грэсовский' => 'gresovskiy', 'гриц' => 'grits',
-               'гурджи' => 'gürci', 'игорь' => 'igor', 'ильич' => 'ilyiç', 'ильин' => 'ilyin',
-               'исмаил' => 'ismail', 'киттс' => 'kitts', 'комсомольск' => 'komsomolsk',
-               'корьбекулю' => 'körbekülü', 'корьбекуль' => 'körbekül', 'куницын' => 'kunitsın',
-               'львив' => 'lviv', 'львов' => 'lvov', 'марьино' => 'maryino', 'махульдюр' => 'mahuldür',
-               'павел' => 'pavel', 'пантикапейон' => 'pantikapeyon', 'къарагозь' => 'qaragöz',
-               'къуртсейит' => 'qurtseyit', 'къуртсеит' => 'qurtseit', 'къуртумер' => 'qurtümer',
-               'сейитумер' => 'seyitümer', 'сеитумер' => 'seitümer', 'смаил' => 'smail',
-               'советск' => 'sovetsk', 'шемьи-заде' => 'şemi-zade', 'щёлкино' => 'şçolkino',
-               'тсвана' => 'tsvana', 'учьэвли' => 'üçevli', 'йохан' => 'yohan', 'йорк' => 'york',
-               'ющенко' => 'yuşçenko', 'льная' => 'lnaya', 'льное' => 'lnoye', 'льный' => 'lnıy',
-               'льская' => 'lskaya', 'льский' => 'lskiy', 'льское' => 'lskoye', 'ополь' => 'opol',
+               'адольф' => 'adolf', 'альберт' => 'albert', 'бешуй' => 'beşüy', 'флотск' => 'flotsk',
+               'гайана' => 'gayana', 'грэсовский' => 'gresovskiy', 'гриц' => 'grits', 'гурджи' => 'gürci',
+               'игорь' => 'igor', 'ильич' => 'ilyiç', 'ильин' => 'ilyin', 'исмаил' => 'ismail',
+               'киттс' => 'kitts', 'комсомольск' => 'komsomolsk', 'корьбекулю' => 'körbekülü',
+               'куницын' => 'kunitsın', 'львив' => 'lviv', 'львов' => 'lvov', 'марьино' => 'maryino',
+               'махульдюр' => 'mahuldür', 'павел' => 'pavel', 'пантикапейон' => 'pantikapeyon',
+               'къуртсейит' => 'qurtseyit', 'къуртсеит' => 'qurtseit', 'смаил' => 'smail',
+               'советск' => 'sovetsk', 'шемьи-заде' => 'şemi-zade', 'тсвана' => 'tsvana',
+               'учьэвли' => 'üçevli', 'йохан' => 'yohan', 'йорк' => 'york', 'винныця' => 'vinnıtsâ',
+               'винница' => 'vinnitsa', 'хмельницк' => 'hmelnitsk', 'хмельныцк' => 'hmelnıtsk',
+               'зайце' => 'zaytse', 'чистеньк' => 'çistenk', 'кольчуг' => 'kolçug', 'ручьи' => 'ruçyi',
+               'ботсвана' => 'botsvana', 'большой' => 'bolşoy', 'большое' => 'bolşoye',
+               'большая' => 'bolşaya', 'ущелье' => 'uşçelye', 'ущельное' => 'uşçelnoye',
+               'предущельное' => 'preduşçelnoye', 'новенькое' => 'novenkoye', 'новосельц' => 'novoselts',
+               'мелко' => 'melko', 'овощ' => 'ovoşç', 'перепёлк' => 'perepölk', 'рощин' => 'roşçin',
+               'братск' => 'bratsk', 'краснофлотск' => 'krasnoflotsk', 'синицин' => 'sinitsin',
+               'синицын' => 'sinitsın', 'льгов' => 'lgov', 'желто' => 'jelto', 'жёлт' => 'jölt',
+               'пермь' => 'perm', 'солдатск' => 'soldatsk', 'кольцо' => 'koltso', 'шелко' => 'şelko',
+               'охотск' => 'ohotsk', 'марий эл' => 'mariy el', 'мариуполь' => 'mariupol',
+               'белгород' => 'belgorod', 'иркутск' => 'irkutsk', 'Иркутск' => 'İrkutsk', 'орёл' => 'oröl',
+               'рязанск' => 'râzansk', 'рязань' => 'râzan', 'тверск' => 'tversk', 'тверь' => 'tver',
+               'ярославль' => 'yaroslavl', 'благовеще' => 'blagoveşçe', 'мальдив' => 'maldiv',
+               'бальбек' => 'balbek', 'альчик' => 'alçik', 'харьков' => 'harkov', 'волынск' => 'volınsk',
+               'волынь' => 'volın',
 
-               # originally Latin to Cyrillic, deduped from above
-               'ань' => 'an', 'аньге' => 'ange', 'аньде' => 'ande', 'аньки' => 'anki', 'кёр' => 'kör',
-               'мэр' => 'mer', 'этсин' => 'etsin',
-
-               # exceptions added after speaker review
-               # see https://www.mediawiki.org/wiki/User:TJones_(WMF)/T23582
-               'аджизленювинъиз' => 'acizlenüviñiz', 'акъшам' => 'aqşam', 'алчакъгонъюлли' => 'alçaqgöñülli',
-               'аньанелер' => 'ananeler', 'аньанелеримиз' => 'ananelerimiz',
-               'аньанелеримизден' => 'ananelerimizden', 'аньанелеримизни' => 'ananelerimizni',
-               'аньанели' => 'ananeli', 'асфальтке' => 'asfaltke', 'баарьде' => 'baarde', 'бахтсыз' => 'bahtsız',
-               'берилюви' => 'berilüvi', 'берювден' => 'berüvden', 'берювни' => 'berüvni',
-               'большевиклер' => 'bolşevikler', 'большевиклерге' => 'bolşeviklerge', 'болюк' => 'bölük',
-               'болюнген' => 'bölüngen', 'болюнгенини' => 'bölüngenini', 'болюшип' => 'bölüşip',
-               'бугуннинъ' => 'bugünniñ', 'бугуньден' => 'bugünden', 'бугуньки' => 'bugünki',
-               'букюльген' => 'bükülgen', 'букюльди' => 'büküldi', 'буллюр' => 'büllür',
-               'бурюмчик' => 'bürümçik', 'бурюнген' => 'bürüngen', 'бутюн' => 'bütün', 'бутюнлей' => 'bütünley',
-               'буюген' => 'büyügen', 'буюй' => 'büyüy', 'волость' => 'volost', 'волостьларгъа' => 'volostlarğa',
-               'гонъюлини' => 'göñülini', 'гонъюлли' => 'göñülli', 'гонъюллилер' => 'göñülliler',
-               'госпиталинде' => 'gospitalinde', 'госпитальге' => 'gospitalge', 'госпитальде' => 'gospitalde',
-               'гренадёр' => 'grenadör', 'гугюм' => 'gügüm', 'гугюмлер' => 'gügümler',
-               'гугюмлери' => 'gügümleri', 'гугюмлерини' => 'gügümlerini', 'гурьсюльди' => 'gürsüldi',
-               'гурюльдештилер' => 'gürüldeştiler', 'гурюльти' => 'gürülti', 'гурюльтили' => 'gürültili',
-               'гурюльтисидир' => 'gürültisidir', 'дарульмуаллиминде' => 'darülmualliminde',
-               'дарульмуаллимининде' => 'darülmuallimininde', 'дарульмуаллиминнинъ' => 'darülmualliminniñ',
-               'дёгюльген' => 'dögülgen', 'декабрьде' => 'dekabrde', 'дёндюрилип' => 'döndürilip',
-               'дёнермиз' => 'dönermiz', 'дёнмектелер' => 'dönmekteler', 'денъишюв' => 'deñişüv',
-               'дёрдю' => 'dördü', 'дёрдюмиз' => 'dördümiz', 'дёрдюнджи' => 'dördünci', 'дёрт' => 'dört',
-               'дертлешювге' => 'dertleşüvge', 'джесюр' => 'cesür', 'джесюране' => 'cesürane',
-               'джесюрликлерини' => 'cesürliklerini', 'джонегенлерини' => 'cönegenlerini',
-               'джонедим' => 'cönedim', 'джонейлер' => 'cöneyler', 'джурьатсызлыгъына' => 'cüratsızlığına',
-               'дюгюнлер' => 'dügünler', 'дюгюнлерле' => 'dügünlerle', 'дюдюк' => 'düdük', 'дюльбер' => 'dülber',
-               'дюльбери' => 'dülberi', 'дюльберлер' => 'dülberler', 'дюльберлернинъ' => 'dülberlerniñ',
-               'дюльгер' => 'dülger', 'дюльгерге' => 'dülgerge', 'дюльгерлернинъки' => 'dülgerlerniñki',
-               'дюльгерни' => 'dülgerni', 'дюльгернинъ' => 'dülgerniñ', 'дюмбюрдетти' => 'dümbürdetti',
-               'дюмен' => 'dümen', 'дюмени' => 'dümeni', 'дюнья' => 'dünya', 'дюньявий' => 'dünyaviy',
-               'дюньяда' => 'dünyada', 'дюньяларгъа' => 'dünyalarğa', 'дюньяларда' => 'dünyalarda',
-               'дюньяны' => 'dünyanı', 'дюньянынъ' => 'dünyanıñ', 'дюньясы' => 'dünyası',
-               'ельаякълылар' => 'yelayaqlılar', 'елькъуваны' => 'yelquvanı', 'ильич' => 'i̇liç',
-               'ичюн' => 'içün', 'ичюнми' => 'içünmi', 'келюви' => 'kelüvi', 'келювини' => 'kelüvini',
-               'келювинъизде' => 'kelüviñizde', 'келювни' => 'kelüvni', 'кемирювлер' => 'kemirüvler',
-               'кесювде' => 'kesüvde', 'кетюв' => 'ketüv', 'кетювге' => 'ketüvge', 'кетюви' => 'ketüvi',
-               'кетювимни' => 'ketüvimni', 'кетювлер' => 'ketüvler', 'кетювлери' => 'ketüvleri',
-               'кетювлеринънинъ' => 'ketüvleriñniñ', 'кетювнинъ' => 'ketüvniñ', 'кирюв' => 'kirüv',
-               'князь' => 'knâz', 'козькъапакъларыны' => 'közqapaqlarını', 'козьлю' => 'közlü', 'козю' => 'közü',
-               'козюме' => 'közüme', 'козюнде' => 'közünde', 'козюне' => 'közüne', 'козюнен' => 'közünen',
-               'козюнинъ' => 'közüniñ', 'козюнъни' => 'közüñni', 'койлюде' => 'köylüde',
-               'койлюлер' => 'köylüler', 'койлюлерде' => 'köylülerde', 'койлюлерни' => 'köylülerni',
-               'койлюлернинъ' => 'köylülerniñ', 'койлюнинъ' => 'köylüniñ', 'коккозьге' => 'kökközge',
-               'коккозьде' => 'kökközde', 'коккозьдеки' => 'kökközdeki', 'коккозьден' => 'kökközden',
-               'кокюс' => 'köküs', 'кокюси' => 'köküsi', 'кокюсим' => 'köküsim', 'кокюсиме' => 'köküsime',
-               'кокюсинъе' => 'köküsiñe', 'комиссарлар' => 'komissarlar', 'комиссарлары' => 'komissarları',
-               'комитетининъ' => 'komitetiniñ', 'концлагерь' => 'kontslager', 'копьмеди' => 'köpmedi',
-               'копьти' => 'köpti', 'копюр' => 'köpür', 'копюрге' => 'köpürge', 'копюрден' => 'köpürden',
-               'копюри' => 'köpüri', 'копюрнинъ' => 'köpürniñ', 'коридорда' => 'koridorda',
-               'корьсюн' => 'körsün', 'корюв' => 'körüv', 'корюльген' => 'körülgen', 'корюнди' => 'köründi',
-               'корюндинъ' => 'köründiñ', 'корюне' => 'körüne', 'корюнип' => 'körünip',
-               'корюнмеген' => 'körünmegen', 'корюнмеди' => 'körünmedi', 'корюнмедилер' => 'körünmediler',
-               'корюнмей' => 'körünmey', 'корюнмейсинъиз' => 'körünmeysiñiz', 'корюнмекте' => 'körünmekte',
-               'корюнмектелер' => 'körünmekteler', 'корюнъиз' => 'körüñiz', 'корюше' => 'körüşe',
-               'корюшеджекмиз' => 'körüşecekmiz', 'корюшим' => 'körüşim', 'корюшип' => 'körüşip',
-               'корюширмиз' => 'körüşirmiz', 'корюшкен' => 'körüşken', 'корюшкенде' => 'körüşkende',
-               'корюшмеге' => 'körüşmege', 'корюшмегенимиз' => 'körüşmegenimiz', 'корюштик' => 'körüştik',
-               'корюштим' => 'körüştim', 'корюшюв' => 'körüşüv', 'корюшювде' => 'körüşüvde',
-               'корюшювден' => 'körüşüvden', 'корюшюви' => 'körüşüvi', 'корюшювимден' => 'körüşüvimden',
-               'корюшювимизге' => 'körüşüvimizge', 'корюшювимизден' => 'körüşüvimizden',
-               'костюми' => 'kostümi', 'кузю' => 'küzü', 'кулькюден' => 'külküden', 'кулькюнинъ' => 'külküniñ',
-               'кулькюсининъ' => 'külküsiniñ', 'кулю' => 'külü', 'кулюмсиреген' => 'külümsiregen',
-               'кулюмсиреди' => 'külümsiredi', 'кулюмсиредим' => 'külümsiredim', 'кулюмсирей' => 'külümsirey',
-               'кулюмсирейим' => 'külümsireyim', 'кулюмсиреп' => 'külümsirep', 'кулюни' => 'külüni',
-               'кулюнчли' => 'külünçli', 'кулюшинде' => 'külüşinde', 'кулюштилер' => 'külüştiler',
-               'кумюш' => 'kümüş', 'куньдюз' => 'kündüz', 'куньдюзлери' => 'kündüzleri', 'куньлюк' => 'künlük',
-               'куню' => 'künü', 'кунюмде' => 'künümde', 'кунюнде' => 'kününde', 'кунюндеми' => 'künündemi',
-               'кунюнъ' => 'künüñ', 'курькчю' => 'kürkçü', 'курьсю' => 'kürsü', 'курьсюге' => 'kürsüge',
-               'курьсюлер' => 'kürsüler', 'курючтен' => 'kürüçten', 'кутюклерни' => 'kütüklerni',
-               'кутюкли' => 'kütükli', 'кучьлю' => 'küçlü', 'кучьлюклер' => 'küçlükler',
-               'кучьсюнмезсинъ' => 'küçsünmezsiñ', 'кучюджик' => 'küçücik', 'кучюк' => 'küçük',
-               'кучюм' => 'küçüm', 'кучюмле' => 'küçümle', 'кучюнден' => 'küçünden', 'кучюни' => 'küçüni',
-               'къаарьлене' => 'qaarlene', 'къаарьли' => 'qaarli', 'къальбим' => 'qalbim',
-               'къальбимни' => 'qalbimni', 'къальбинде' => 'qalbinde', 'къальпли' => 'qalpli',
-               'къальптен' => 'qalpten', 'къалюбелядан' => 'qalübelâdan', 'къулюбенъде' => 'qulübeñde',
-               'лёман' => 'löman', 'львованынъ' => 'lvovanıñ', 'лютфи' => 'lütfi', 'лютфиге' => 'lütfige',
-               'лютфини' => 'lütfini', 'мазюн' => 'mazün', 'малюм' => 'malüm', 'малюмат' => 'malümat',
-               'махлюкъаттан' => 'mahlüqattan', 'махлюкътан' => 'mahlüqtan', 'махульдюрге' => 'mahuldürge',
-               'махульдюрде' => 'mahuldürde', 'махульдюрдеки' => 'mahuldürdeki',
-               'махульдюрден' => 'mahuldürden', 'махульдюрли' => 'mahuldürli',
-               'махульдюрлилер' => 'mahuldürliler', 'махульдюрлилермиз' => 'mahuldürlilermiz',
-               'махульдюрми' => 'mahuldürmi', 'махульдюрни' => 'mahuldürni', 'мевджут' => 'mevcut',
-               'мезкюр' => 'mezkür', 'мектюп' => 'mektüp', 'мектюпни' => 'mektüpni', 'мектюпте' => 'mektüpte',
-               'мелитопольге' => 'melitopolge', 'мемнюн' => 'memnün', 'мемнюниетле' => 'memnüniyetle',
-               'мемнюним' => 'memnünim', 'мемнюнмиз' => 'memnünmiz', 'менсюп' => 'mensüp',
-               'мешгъульмиз' => 'meşğulmiz', 'мулькюни' => 'mülküni', 'мумкюн' => 'mümkün',
-               'мумкюнми' => 'mümkünmi', 'мусульманлар' => 'musulmanlar', 'мусульманлармы' => 'musulmanlarmı',
-               'мухкемлендирюв' => 'mühkemlendirüv', 'мушкюль' => 'müşkül', 'ничюн' => 'niçün',
-               'ничюндир' => 'niçündir', 'нумюнеси' => 'nümünesi', 'огю' => 'ögü', 'огюз' => 'ögüz',
-               'огюмде' => 'ögümde', 'огюмдеки' => 'ögümdeki', 'огюме' => 'ögüme', 'огюмизге' => 'ögümizge',
-               'огюмизде' => 'ögümizde', 'огюмиздеки' => 'ögümizdeki', 'огюмни' => 'ögümni',
-               'огюнде' => 'ögünde', 'огюндеки' => 'ögündeki', 'огюндекиси' => 'ögündekisi',
-               'огюнден' => 'ögünden', 'огюне' => 'ögüne', 'огюнъизде' => 'ögüñizde', 'огютини' => 'ögütini',
-               'огютлерини' => 'ögütlerini', 'озю' => 'özü', 'озюм' => 'özüm', 'озюмден' => 'özümden',
-               'озюме' => 'özüme', 'озюмизни' => 'özümizni', 'озюмизнинъ' => 'özümizniñ',
-               'озюмизнинъки' => 'özümizniñki', 'озюмнен' => 'özümnen', 'озюмни' => 'özümni',
-               'озюмнинъ' => 'özümniñ', 'озюнде' => 'özünde', 'озюнден' => 'özünden', 'озюне' => 'özüne',
-               'озюнен' => 'özünen', 'озюни' => 'özüni', 'озюнинъ' => 'özüniñ', 'озюнинъкими' => 'özüniñkimi',
-               'озюнъ' => 'özüñ', 'озюнъе' => 'özüñe', 'озюнъиз' => 'özüñiz', 'озюнъиздеки' => 'özüñizdeki',
-               'озюнъни' => 'özüñni', 'оксюз' => 'öksüz', 'окюндим' => 'ökündim', 'ольдюрип' => 'öldürip',
-               'ольдюрмек' => 'öldürmek', 'ольдюрювде' => 'öldürüvde', 'ольчюде' => 'ölçüde', 'олюм' => 'ölüm',
-               'олюмден' => 'ölümden', 'олюмлер' => 'ölümler', 'омюр' => 'ömür', 'омюрге' => 'ömürge',
-               'омюри' => 'ömüri', 'опькеленюв' => 'öpkelenüv', 'орьтилюви' => 'örtilüvi', 'орьтюли' => 'örtüli',
-               'орюли' => 'örüli', 'орюлип' => 'örülip', 'осюв' => 'ösüv', 'осюмлик' => 'ösümlik',
-               'отькерювни' => 'ötkerüvni', 'отькюр' => 'ötkür', 'офицери' => 'ofitseri',
-               'офицерим' => 'ofitserim', 'офицерлер' => 'ofitserler', 'пальтосыны' => 'paltosını',
-               'пальтосынынъ' => 'paltosınıñ', 'пекинюв' => 'pekinüv', 'пекитювнинъ' => 'pekitüvniñ',
-               'пиширюв' => 'pişirüv', 'повидло' => 'povidlo', 'полис' => 'polis', 'полициясы' => 'politsiyası',
-               'помещик' => 'pomeşçik', 'потюк' => 'potük', 'потюклеринен' => 'potüklerinen',
-               'пулемёт' => 'pülemöt', 'пулемётларны' => 'pülemötlarnı', 'режиссёр' => 'rejissör',
-               'ролюнде' => 'rolünde', 'севастопольнинъ' => 'sevastopolniñ', 'сёгди' => 'sögdi', 'сёз' => 'söz',
-               'сёзлер' => 'sözler', 'сёзлери' => 'sözleri', 'сёзлерим' => 'sözlerim',
-               'сёзлеримден' => 'sözlerimden', 'сёзлериме' => 'sözlerime', 'сёзлеримни' => 'sözlerimni',
-               'сёзлеримнинъ' => 'sözlerimniñ', 'сёзлеринде' => 'sözlerinde', 'сёзлерине' => 'sözlerine',
-               'сёзлерини' => 'sözlerini', 'сёзлерининъ' => 'sözleriniñ', 'сёзлеринъиз' => 'sözleriñiz',
-               'сёзлеринъизни' => 'sözleriñizni', 'сёзлернен' => 'sözlernen', 'сёзлерни' => 'sözlerni',
-               'сёзлернинъ' => 'sözlerniñ', 'сёзнен' => 'söznen', 'сёзни' => 'sözni', 'сёзчиклер' => 'sözçikler',
-               'сёзчиклерден' => 'sözçiklerden', 'сёзю' => 'sözü', 'сёзюмен' => 'sözümen',
-               'сёзюмнинъ' => 'sözümniñ', 'сёзюне' => 'sözüne', 'сёзюни' => 'sözüni', 'сёзюнинъ' => 'sözüniñ',
-               'сёйле' => 'söyle', 'сёйлегенде' => 'söylegende', 'сёйлегенлеринден' => 'söylegenlerinden',
-               'сёйледи' => 'söyledi', 'сёйлей' => 'söyley', 'сёйленди' => 'söylendi',
-               'сёйленмеге' => 'söylenmege', 'сёйленмекте' => 'söylenmekte', 'сёйленъиз' => 'söyleñiz',
-               'сёнген' => 'söngen', 'сёнди' => 'söndi', 'сёндюрди' => 'söndürdi',
-               'сёндюрильген' => 'söndürilgen', 'сёндюрип' => 'söndürip', 'сентябрьнинъ' => 'sentâbrniñ',
-               'сергюзешт' => 'sergüzeşt', 'сергюзештлерни' => 'sergüzeştlerni',
-               'ставропольге' => 'stavropolge', 'сулькевич' => 'sulkeviç', 'сурьат' => 'surat',
-               'суфлёр' => 'suflör', 'сюеги' => 'süyegi', 'сюеклерге' => 'süyeklerge',
-               'сюйрекледи' => 'süyrekledi', 'сюйреле' => 'süyrele', 'сюйрен' => 'süyren',
-               'сюйренге' => 'süyrenge', 'сюйренде' => 'süyrende', 'сюйреп' => 'süyrep', 'сюйрю' => 'süyrü',
-               'сюкюнет' => 'sükünet', 'сюкюнети' => 'süküneti', 'сюкюнетте' => 'sükünette', 'сюкют' => 'süküt',
-               'сюляле' => 'sülâle', 'сюрген' => 'sürgen', 'сюрди' => 'sürdi', 'сюрмеди' => 'sürmedi',
-               'сюрюльмеген' => 'sürülmegen', 'сют' => 'süt', 'тебессюм' => 'tebessüm', 'тёкип' => 'tökip',
-               'тёкти' => 'tökti', 'тёкюльген' => 'tökülgen', 'тёкюльди' => 'töküldi',
-               'тёкюндиси' => 'tökündisi', 'тёле' => 'töle', 'тёледим' => 'töledim', 'телюке' => 'telüke',
-               'телюкели' => 'telükeli', 'тенеффюс' => 'teneffüs', 'тенеффюслер' => 'teneffüsler',
-               'тёпеге' => 'töpege', 'тёпелери' => 'töpeleri', 'тёпелерине' => 'töpelerine',
-               'тёпели' => 'töpeli', 'тёпеси' => 'töpesi', 'тёпесинден' => 'töpesinden',
-               'тёпесини' => 'töpesini', 'тёрге' => 'törge', 'тёрде' => 'törde', 'тёрдеки' => 'tördeki',
-               'тёрюне' => 'törüne', 'тешеббюсим' => 'teşebbüsim', 'тёшегинден' => 'töşeginden',
-               'тёшегине' => 'töşegine', 'тёшек' => 'töşek', 'тешеккюр' => 'teşekkür',
-               'тешеккюрлер' => 'teşekkürler', 'тёшекни' => 'töşekni', 'тёшектен' => 'töşekten',
-               'тёшели' => 'töşeli', 'тёшемек' => 'töşemek', 'тёшеп' => 'töşep', 'теэссюф' => 'teessüf',
-               'тюбю' => 'tübü', 'тюбюнде' => 'tübünde', 'тюбюндеки' => 'tübündeki', 'тюз' => 'tüz',
-               'тюзельгенге' => 'tüzelgenge', 'тюзельтмек' => 'tüzeltmek', 'тюземликлер' => 'tüzemlikler',
-               'тюзетип' => 'tüzetip', 'тюзетирим' => 'tüzetirim', 'тюзеткен' => 'tüzetken',
-               'тюзетмеге' => 'tüzetmege', 'тюзетмесенъ' => 'tüzetmeseñ', 'тюзетти' => 'tüzetti',
-               'тюзетюв' => 'tüzetüv', 'тюкенмез' => 'tükenmez', 'тюкюриктен' => 'tükürikten',
-               'тюкян' => 'tükân', 'тюкяны' => 'tükânı', 'тюкянында' => 'tükânında', 'тюм' => 'tüm',
-               'тюневин' => 'tünevin', 'тюневинки' => 'tünevinki', 'тюпсюз' => 'tüpsüz', 'тюрк' => 'türk',
-               'тюрклернинъ' => 'türklerniñ', 'тюркнинъ' => 'türkniñ', 'тюркче' => 'türkçe', 'тюркю' => 'türkü',
-               'тюркюлерини' => 'türkülerini', 'тюркюнинъ' => 'türküniñ', 'тюрлю' => 'türlü',
-               'тюртип' => 'türtip', 'тюрттинъиз' => 'türttiñiz', 'тютемекте' => 'tütemekte', 'тютюн' => 'tütün',
-               'тютюнджи' => 'tütünci', 'тюфеги' => 'tüfegi', 'тюфегини' => 'tüfegini', 'тюфек' => 'tüfek',
-               'тюфеклеринен' => 'tüfeklerinen', 'тюфеклернен' => 'tüfeklernen', 'тюфеклерни' => 'tüfeklerni',
-               'тюфекнен' => 'tüfeknen', 'тюфексиз' => 'tüfeksiz', 'тюш' => 'tüş', 'тюше' => 'tüşe',
-               'тюшеджек' => 'tüşecek', 'тюшеджексинъми' => 'tüşeceksiñmi', 'тюшем' => 'tüşem',
-               'тюшип' => 'tüşip', 'тюшкен' => 'tüşken', 'тюшкенде' => 'tüşkende', 'тюшкенлер' => 'tüşkenler',
-               'тюшмеге' => 'tüşmege', 'тюшмейим' => 'tüşmeyim', 'тюшмейлер' => 'tüşmeyler',
-               'тюшмек' => 'tüşmek', 'тюшмекте' => 'tüşmekte', 'тюшмеси' => 'tüşmesi', 'тюшсе' => 'tüşse',
-               'тюшти' => 'tüşti', 'тюштик' => 'tüştik', 'тюштилер' => 'tüştiler', 'тюштими' => 'tüştimi',
-               'тюштинъиз' => 'tüştiñiz', 'тюшювден' => 'tüşüvden', 'тюшюджек' => 'tüşücek',
-               'тюшюнген' => 'tüşüngen', 'тюшюнгендже' => 'tüşüngence', 'тюшюндже' => 'tüşünce',
-               'тюшюнджеге' => 'tüşüncege', 'тюшюнджелер' => 'tüşünceler', 'тюшюнджелери' => 'tüşünceleri',
-               'тюшюнджелерим' => 'tüşüncelerim', 'тюшюнджели' => 'tüşünceli', 'тюшюнджеси' => 'tüşüncesi',
-               'тюшюнди' => 'tüşündi', 'тюшюндим' => 'tüşündim', 'тюшюне' => 'tüşüne',
-               'тюшюнелер' => 'tüşüneler', 'тюшюнесинъиз' => 'tüşünesiñiz', 'тюшюнип' => 'tüşünip',
-               'тюшюнмеге' => 'tüşünmege', 'тюшюнмезсинъ' => 'tüşünmezsiñ', 'тюшюнмей' => 'tüşünmey',
-               'тюшюнмемек' => 'tüşünmemek', 'тюшюргенлер' => 'tüşürgenler', 'тюшюрди' => 'tüşürdi',
-               'тюшюрдик' => 'tüşürdik', 'тюшюре' => 'tüşüre', 'тюшюрип' => 'tüşürip', 'тюшюрмек' => 'tüşürmek',
-               'уджюм' => 'ücüm', 'удюр' => 'üdür', 'узюле' => 'üzüle', 'узюлип' => 'üzülip',
-               'узюльгенини' => 'üzülgenini', 'узюльди' => 'üzüldi', 'уйрюлип' => 'üyrülip',
-               'укюмет' => 'ükümet', 'укюмети' => 'ükümeti', 'укюметими' => 'ükümetimi',
-               'укюметимиз' => 'ükümetimiz', 'укюметини' => 'ükümetini', 'укюметининъ' => 'ükümetiniñ',
-               'укюметке' => 'ükümetke', 'укюметкеми' => 'ükümetkemi', 'укюметми' => 'ükümetmi',
-               'укюметнинъ' => 'ükümetniñ', 'укюметтен' => 'ükümetten', 'укюмран' => 'ükümran',
-               'улькюн' => 'ülkün', 'умюдим' => 'ümüdim', 'умют' => 'ümüt', 'умютлери' => 'ümütleri',
-               'умютсизден' => 'ümütsizden', 'усть' => 'üst', 'устьке' => 'üstke', 'устьлеринде' => 'üstlerinde',
-               'устьлериндеки' => 'üstlerindeki', 'устьлерине' => 'üstlerine', 'устьлерини' => 'üstlerini',
-               'устюрткъа' => 'üsturtqa', 'усьнюхаткъа' => 'üsnühatqa', 'усьнюхаты' => 'üsnühatı',
-               'усьтю' => 'üstü', 'усьтюмде' => 'üstümde', 'усьтюмдеки' => 'üstümdeki', 'усьтюме' => 'üstüme',
-               'усьтюнде' => 'üstünde', 'усьтюндеки' => 'üstündeki', 'усьтюндемиз' => 'üstündemiz',
-               'усьтюне' => 'üstüne', 'усьтюни' => 'üstüni', 'усьтюнлик' => 'üstünlik',
-               'усьтюнъизге' => 'üstüñizge', 'утёкунь' => 'ütökün', 'уфюрди' => 'üfürdi', 'учю' => 'üçü',
-               'учюмиз' => 'üçümiz', 'учюн' => 'üçün', 'учюнджи' => 'üçünci', 'учюнджисининъ' => 'üçüncisiniñ',
-               'ушюй' => 'üşüy', 'ушюмез' => 'üşümez', 'ушюмезсинъ' => 'üşümezsiñ',
-               'факультетинде' => 'fakultetinde', 'факультетине' => 'fakultetine',
-               'февральнинъ' => 'fevralniñ', 'харьковдаки' => 'harkovdaki', 'харьковдан' => 'harkovdan',
-               'чёкти' => 'çökti', 'чёкюрли' => 'çökürli', 'чёкюч' => 'çöküç', 'чёллюкке' => 'çöllükke',
-               'чёль' => 'çöl', 'чёльде' => 'çölde', 'чёльмек' => 'çölmek', 'чёткю' => 'çötkü',
-               'чёчамийлер' => 'çöçamiyler', 'чюнки' => 'çünki', 'чюрюди' => 'çürüdi', 'чюрюк' => 'çürük',
-               'шукюр' => 'şükür', 'шукюрлер' => 'şükürler', 'этюв' => 'etüv', 'этювден' => 'etüvden',
-               'этюви' => 'etüvi', 'этюдлар' => 'etüdlar', 'юзден' => 'yüzden', 'юзлеп' => 'yüzlep',
-               'юзлерини' => 'yüzlerini', 'юзлернен' => 'yüzlernen', 'юзлюги' => 'yüzlügi',
-               'юзлюкке' => 'yüzlükke', 'юзю' => 'yüzü', 'юзюм' => 'yüzüm', 'юзюме' => 'yüzüme',
-               'юзюмен' => 'yüzümen', 'юзюмни' => 'yüzümni', 'юзюнде' => 'yüzünde', 'юзюни' => 'yüzüni',
-               'юзюнинъ' => 'yüzüniñ', 'юзюнъ' => 'yüzüñ', 'юзюнъизге' => 'yüzüñizge', 'юклю' => 'yüklü',
-               'юксельтюв' => 'yükseltüv', 'юньлю' => 'yünlü', 'юньлюдже' => 'yünlüce',
-               'юртсеверлик' => 'yurtseverlik', 'юртюде' => 'yürtüde', 'юрьтю' => 'yürtü',
-               'юрьтюге' => 'yürtüge', 'юрьтюнинъ' => 'yürtüniñ', 'юрюльсе' => 'yürülse', 'юрюнъиз' => 'yürüñiz',
-               'юрюш' => 'yürüş', 'юрюши' => 'yürüşi', 'юрюшим' => 'yürüşim', 'юрюшини' => 'yürüşini',
-               'юрюшнен' => 'yürüşnen', 'юрюшни' => 'yürüşni',
        ];
 
-       # map Cyrillic to Latin and back, whole word match only
+       # map Cyrillic to Latin and back, simple string match only (no regex)
        # no variants: map exactly as is
-       # items with capture group refs (e.g., $1) are only mapped from the
-       # regex to the reference
        private $exactCaseMappings = [
                # аббревиатуры
                # abbreviations
-               'ОБСЕ' => 'OBSE', 'КъМДж' => 'QMC', 'КъАЭ' => 'QAE', 'ГъСМК' => 'ĞSMK', 'ШСДжБ' => 'ŞSCB',
-               'КъМШСДж' => 'QMŞSC', 'КъДМПУ' => 'QDMPU', 'КъМПУ' => 'QMPU', 'КъЮШ' => 'QYŞ', 'ЮШ' => 'YŞ',
+               'ОБСЕ' => 'OBSE', 'КъМДж' => 'QMC', 'КъДж' => 'QC', 'КъАЭ' => 'QAE', 'ГъСМК' => 'ĞSMK',
+               'ШСДжБ' => 'ŞSCB', 'КъМШСДж' => 'QMŞSC', 'КъАССР' => 'QASSR', 'КъДМПУ' => 'QDMPU',
+               'КъМПУ' => 'QMPU',
        ];
 
        # map Cyrillic to Latin and back, match end of word
@@ -517,10 +356,12 @@ class CrhExceptions {
                # originally C2L
                'иаль' => 'ial', 'нуль' => 'nul', 'кой' => 'köy', 'койнинъ' => 'köyniñ', 'койни' => 'köyni',
                'койге' => 'köyge', 'койде' => 'köyde', 'койдеки' => 'köydeki', 'койден' => 'köyden',
-               'козь' => 'köz',
+               'козь' => 'köz', '-юнджи' => '-ünci', '-юнджиде' => '-üncide', '-юнджиден' => '-ünciden',
 
                # originally L2C, here swapped
-               'етсин' => 'etsin',
+               'етсин' => 'etsin', 'льная' => 'lnaya', 'льное' => 'lnoye', 'льный' => 'lnıy', 'льний' => 'lniy',
+               'льская' => 'lskaya', 'льский' => 'lskiy', 'льское' => 'lskoye', 'ополь' => 'opol',
+               'щее' => 'şçeye', 'щий' => 'şçiy', 'щая' => 'şçaya', 'цепс' => 'tseps',
 
        ];
 
@@ -533,15 +374,18 @@ class CrhExceptions {
                'буюк([^ъ])' => 'büyük$1', 'бую([гдйлмнпрстчшc])(и)' => 'büyü$1$2',
                'буют([^ыа])' => 'büyüt$1', 'джонк([^ъ])' => 'cönk$1', 'коюм' => 'köyüm', 'коюнъ' => 'köyüñ',
                'коюн([ди])' => 'köyün$1', 'куе' => 'küye', 'куркке' => 'kürkke', 'куркни' => 'kürkni',
-               'куркте' => 'kürkte', 'куркчи' => 'kürkçi', 'куркчю' => 'kürkçü',
+               'куркте' => 'kürkte', 'куркчю' => 'kürkçü', 'кою' => 'köyü',
+               'жизнь' => 'jizn',
 
                # арабизмы на муи- муэ- / Arabic муи- муэ-
                'му([иэИЭ])' => 'mü$1',
 
                # originally L2C, here swapped
-               'итъаль' => 'ital',
                'роль$1' => 'rol([^ü])',
-               'усть$1' => 'üst([knt])',
+               'усть$1' => 'üst([^ü])',
+
+               # more prefixes
+               'ком-кок' => 'köm-kök',
 
        ];
 
@@ -555,8 +399,68 @@ class CrhExceptions {
                        # относятся ко всему слову #
                        # whole words              #
                        ############################
-                       '/\b([34])(\-)юнджи\b/u' => '$1$2ünci',
-                       '/\b([34])(\-)ЮНДЖИ\b/u' => '$1$2ÜNCİ',
+
+                       // TODO: refactor upper/lower/first capital whole words without
+                       // regexes into simpler list
+
+                       '/\bКъЮШ\b/u' => 'QYŞ',
+                       '/\bЮШ\b/u' => 'YŞ',
+
+                       '/\bкок\b/u' => 'kök',
+                       '/\bКок\b/u' => 'Kök',
+                       '/\bКОК\b/u' => 'KÖK',
+                       '/\bком-кок\b/u' => 'köm-kök',
+                       '/\bКом-кок\b/u' => 'Köm-kök',
+                       '/\bКОМ-КОК\b/u' => 'KÖM-KÖK',
+
+                       '/\bкоп\b/u' => 'köp',
+                       '/\bКоп\b/u' => 'Köp',
+                       '/\bКОП\b/u' => 'KÖP',
+
+                       '/\bкурк\b/u' => 'kürk',
+                       '/\bКурк\b/u' => 'Kürk',
+                       '/\bКУРК\b/u' => 'KÜRK',
+
+                       '/\bог\b/u' => 'ög',
+                       '/\bОг\b/u' => 'Ög',
+                       '/\bОГ\b/u' => 'ÖG',
+
+                       '/\bюрип\b/u' => 'yürip',
+                       '/\bЮрип\b/u' => 'Yürip',
+                       '/\bЮРИП\b/u' => 'YÜRİP',
+
+                       '/\bюз\b/u' => 'yüz',
+                       '/\bЮз\b/u' => 'Yüz',
+                       '/\bЮЗ\b/u' => 'YÜZ',
+
+                       '/\bюк\b/u' => 'yük',
+                       '/\bЮк\b/u' => 'Yük',
+                       '/\bЮК\b/u' => 'YÜK',
+
+                       '/\bбуюп\b/u' => 'büyüp',
+                       '/\bБуюп\b/u' => 'Büyüp',
+                       '/\bБУЮП\b/u' => 'BÜYÜP',
+
+                       '/\bбуюк\b/u' => 'büyük',
+                       '/\bБуюк\b/u' => 'Büyük',
+                       '/\bБУЮК\b/u' => 'BÜYÜK',
+
+                       '/\bджонк\b/u' => 'cönk',
+                       '/\bДжонк\b/u' => 'Cönk',
+                       '/\bДЖОНК\b/u' => 'CÖNK',
+                       '/\bджонкю\b/u' => 'cönkü',
+                       '/\bДжонкю\b/u' => 'Cönkü',
+                       '/\bДЖОНКЮ\b/u' => 'CÖNKÜ',
+
+                       '/\bустке\b/u' => 'üstke',
+                       '/\bУстке\b/u' => 'Üstke',
+                       '/\bУСТКЕ\b/u' => 'ÜSTKE',
+                       '/\bустте\b/u' => 'üstte',
+                       '/\bУстте\b/u' => 'Üstte',
+                       '/\bУСТТЕ\b/u' => 'ÜSTTE',
+                       '/\bусттен\b/u' => 'üstten',
+                       '/\bУсттен\b/u' => 'Üstten',
+                       '/\bУСТТЕН\b/u' => 'ÜSTTEN',
 
                        # отдельно стоящие Ё и Я
                        # stand-alone Ё and Я
@@ -570,6 +474,16 @@ class CrhExceptions {
                        '/\bКъЮШн/u' => 'QYŞn',
                        '/\bЮШн/u' => 'YŞn',
 
+                       # need to convert digraphs (гъ, къ, нъ, дж) now to match patterns
+                       '/гъ/u' => 'ğ',
+                       '/Г[ъЪ]/u' => 'Ğ',
+                       '/къ/u' => 'q',
+                       '/К[ъЪ]/u' => 'Q',
+                       '/нъ/u' => 'ñ',
+                       '/Н[ъЪ]/u' => 'Ñ',
+                       '/дж/u' => 'c',
+                       '/Д[жЖ]/u' => 'C',
+
                        # о => ö
                        '/\b(['.Crh::C_M_CONS.'])о(['.Crh::C_CONS.'])(['.Crh::C_CONS.'])([еиэюьü])/u' => '$1ö$2$3$4',
                        '/\bо(['.Crh::C_CONS.'])(['.Crh::C_CONS.'])([еиэюьü])/u' => 'ö$1$2$3',
@@ -662,63 +576,101 @@ class CrhExceptions {
                ];
 
                $this->Latn2CyrlRegexes = [
+
+                       // TODO: refactor upper/lower/first capital whole words without
+                       // regexes into simpler list
+
+                       '/\ban\b/u' => 'ань',
+                       '/\bAn\b/u' => 'Ань',
+                       '/\bAN\b/u' => 'АНЬ',
+                       '/\bange\b/u' => 'аньге',
+                       '/\bAnge\b/u' => 'Аньге',
+                       '/\bANGE\b/u' => 'АНЬГЕ',
+                       '/\bande\b/u' => 'аньде',
+                       '/\bAnde\b/u' => 'Аньде',
+                       '/\bANDE\b/u' => 'АНЬДЕ',
+                       '/\banki\b/u' => 'аньки',
+                       '/\bAnki\b/u' => 'Аньки',
+                       '/\bANKİ\b/u' => 'АНЬКИ',
+                       '/\bderal\b/u' => 'деръал',
+                       '/\bDeral\b/u' => 'Деръал',
+                       '/\bDERAL\b/u' => 'ДЕРЪАЛ',
+                       '/\bkör\b/u' => 'кёр',
+                       '/\bKör\b/u' => 'Кёр',
+                       '/\bKÖR\b/u' => 'КЁР',
+                       '/\bmer\b/u' => 'мэр',
+                       '/\bMer\b/u' => 'Мэр',
+                       '/\bMER\b/u' => 'МЭР',
+
+                       '/\bджонк/u' => 'cönk',
+                       '/\bДжонк/u' => 'Cönk',
+                       '/\bДЖОНК/u' => 'CÖNK',
+
+                       '/\bкуркчи/u' => 'kürkçi',
+                       '/\bКуркчи/u' => 'Kürkçi',
+                       '/\bКУРКЧИ/u' => 'KÜRKÇI',
+
                        # буква Ё - первый заход
                        # расставляем Ь после согласных
-                       '/^([yY])ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1ö$2ь$3',
-                       '/^([yY])Ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1Ö$2Ь$3',
-                       '/^AQŞ(['.Crh::WORD_ENDS.'ngd])/u' => 'АКъШ$1',
+                       '/\b([yY])ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1ö$2ь$3',
+                       '/\b([yY])Ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1Ö$2Ь$3',
+                       '/\bAQŞ([^AEI]|\b)/u' => 'АКъШ$1',
 
                        # буква Ю - первый заход
                        # расставляем Ь после согласных
-                       '/^([yY])ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1ü$2ь$3',
-                       '/^([yY])Ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1Ü$2Ь$3',
+                       '/\b([yY])ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1ü$2ь$3',
+                       '/\b([yY])Ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1Ü$2Ь$3',
 
-                       '/^([bcgkpşBCGKPŞ])ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1ö$2ь$3',
-                       '/^([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ö$2Ь$3',
-                       '/^([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ö$2Ь$3',
-                       '/^([bcgkpşBCGKPŞ])ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1ü$2ь$3',
-                       '/^([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ü$2Ь$3',
-                       '/^([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ü$2Ь$3',
+                       '/\b([bcgkpşBCGKPŞ])ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1ö$2ь$3',
+                       '/\b([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ö$2Ь$3',
+                       '/\b([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ö$2Ь$3',
+                       '/\b([bcgkpşBCGKPŞ])ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1ü$2ь$3',
+                       '/\b([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ü$2Ь$3',
+                       '/\b([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ü$2Ь$3',
 
                         # ö и ü в начале слова
                         # случаи, когда нужен Ь
-                       '/^ö(['.Crh::L_N_CONS.'pP])(['.Crh::L_CONS.']|$)/u' => 'ö$1ь$2',
-                       '/^Ö(['.Crh::L_N_CONS_LC.'p])(['.Crh::L_CONS.']|$)/u' => 'Ö$1ь$2',
-                       '/^Ö(['.Crh::L_N_CONS_UC.'P])(['.Crh::L_CONS.']|$)/u' => 'Ö$1Ь$2',
-                       '/^ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => 'ü$1ь$2',
-                       '/^Ü(['.Crh::L_N_CONS_LC.'])(['.Crh::L_CONS.']|$)/u' => 'Ü$1ь$2',
-                       '/^Ü(['.Crh::L_N_CONS_UC.'])(['.Crh::L_CONS.']|$)/u' => 'Ü$1Ь$2',
-
-                       '/ts$/u' => 'ц',
-                       '/şç$/u' => 'щ',
-                       '/Ş[çÇ]$/u' => 'Щ',
-                       '/T[sS]$/u' => 'Ц',
+                       '/\bö(['.Crh::L_N_CONS.'pP])(['.Crh::L_CONS.']|\b)/u' => 'ö$1ь$2',
+                       '/\bÖ(['.Crh::L_N_CONS_LC.'p])(['.Crh::L_CONS.']|\b)/u' => 'Ö$1ь$2',
+                       '/\bÖ(['.Crh::L_N_CONS_UC.'P])(['.Crh::L_CONS.']|\b)/u' => 'Ö$1Ь$2',
+                       '/\bü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => 'ü$1ь$2',
+                       '/\bÜ(['.Crh::L_N_CONS_LC.'])(['.Crh::L_CONS.']|\b)/u' => 'Ü$1ь$2',
+                       '/\bÜ(['.Crh::L_N_CONS_UC.'])(['.Crh::L_CONS.']|\b)/u' => 'Ü$1Ь$2',
+
+                       '/ts\b/u' => 'ц',
+                       '/şç\b/u' => 'щ',
+                       '/Ş[çÇ]\b/u' => 'Щ',
+                       '/T[sS]\b/u' => 'Ц',
 
                        # Ь после Л
                        # add Ь after Л
-                       '/(['.Crh::L_F.'])l(['.Crh::L_CONS_LC.']|$)/u' => '$1ль$2',
-                       '/(['.Crh::L_F_UC.'])L(['.Crh::L_CONS.']|$)/u' => '$1ЛЬ$2',
+                       '/(['.Crh::L_F.'])l(['.Crh::L_CONS_LC.']|\b)/u' => '$1ль$2',
+                       '/(['.Crh::L_F_UC.'])L(['.Crh::L_CONS.']|\b)/u' => '$1ЛЬ$2',
+
+                       '/etsin\b/u' => 'етсин',
+                       '/Etsin\b/u' => 'Етсин',
+                       '/ETSİN\b/u' => 'ЕТСИН',
 
                        # относятся к началу слова
-                       '/^ts/u' => 'ц',
-                       '/^T[sS]/u' => 'Ц',
+                       '/\bts/u' => 'ц',
+                       '/\bT[sS]/u' => 'Ц',
 
-                       '/^şç/u' => 'щ',
-                       '/^Ş[çÇ]/u' => 'Щ',
+                       '/\bşç/u' => 'щ',
+                       '/\bŞ[çÇ]/u' => 'Щ',
 
                        # Э
-                       '/(^|['.Crh::L_VOW.'аеэяАЕЭЯ])e/u' => '$1э',
-                       '/(^|['.Crh::L_VOW_UC.'АЕЭЯ])E/u' => '$1Э',
+                       '/(\b|['.Crh::L_VOW.'аеэяАЕЭЯ])e/u' => '$1э',
+                       '/(\b|['.Crh::L_VOW_UC.'АЕЭЯ])E/u' => '$1Э',
 
-                       '/^(['.Crh::L_M_CONS.'])ö/u' => '$1о',
-                       '/^(['.Crh::L_M_CONS.'])Ö/u' => '$1О',
-                       '/^(['.Crh::L_M_CONS.'])ü/u' => '$1у',
-                       '/^(['.Crh::L_M_CONS.'])Ü/u' => '$1У',
+                       '/\b(['.Crh::L_M_CONS.'])ö/u' => '$1о',
+                       '/\b(['.Crh::L_M_CONS.'])Ö/u' => '$1О',
+                       '/\b(['.Crh::L_M_CONS.'])ü/u' => '$1у',
+                       '/\b(['.Crh::L_M_CONS.'])Ü/u' => '$1У',
 
-                       '/^ö/u' => 'о',
-                       '/^Ö/u' => 'О',
-                       '/^ü/u' => 'у',
-                       '/^Ü/u' => 'У',
+                       '/\bö/u' => 'о',
+                       '/\bÖ/u' => 'О',
+                       '/\bü/u' => 'у',
+                       '/\bÜ/u' => 'У',
 
                        # некоторые исключения
                        # some exceptions
@@ -780,13 +732,18 @@ class CrhExceptions {
                        '/[ьЬ]([aA])/u' => '$1',
 
                        # дж
-                       '/C(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'ДЖ$1',
+                       '/C(['.Crh::L_UC.Crh::C_UC.'АЕЁЙОУЭЮЯ])/u' => 'ДЖ$1',
+                       '/(['.Crh::L_UC.Crh::C_UC.'АЕЁЙОУЭЮЯ])C/u' => '$1ДЖ',
 
                        # гъ, къ, нъ
-                       # гъ, къ, нъ
-                       '/Ğ(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'ГЪ$1',
-                       '/Q(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'КЪ$1',
-                       '/Ñ(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'НЪ$1',
+                       '/Ğ(['.Crh::L_UC.Crh::C_UC.'])/u' => 'ГЪ$1',
+                       '/(['.Crh::L_UC.Crh::C_UC.'Ъ])Ğ/u' => '$1ГЪ',
+
+                       '/Q(['.Crh::L_UC.Crh::C_UC.'])/u' => 'КЪ$1',
+                       '/(['.Crh::L_UC.Crh::C_UC.'Ъ])Q/u' => '$1КЪ',
+
+                       '/Ñ(['.Crh::L_UC.Crh::C_UC.'])/u' => 'НЪ$1',
+                       '/(['.Crh::L_UC.Crh::C_UC.'Ъ])Ñ/u' => '$1НЪ',
 
                ];
        }
index 7a2ac59..b08ae3a 100644 (file)
        "mergelog": "Peugabông log",
        "revertmerge": "Hana jadèh peugabông",
        "history-title": "Riwayat geunantoë nibak \"$1\"",
+       "difference-title": "Bida antara revisi nibak \"$1\"",
        "lineno": "Baréh $1:",
        "compareselectedversions": "Peubandéng curak teupiléh",
        "editundo": "pubateuë",
        "diff-empty": "(Hana bida)",
+       "diff-multi-sameuser": "({{PLURAL:$1|Saboh revisi antara|$1 revisi antara}} lé ureueng ngui nyang saban hana geupeudeuih)",
        "searchresults": "Hasé mita",
        "searchresults-title": "Hasé mita keu \"$1\"",
        "notextmatches": "Hana naseukah laman nyang pah",
        "pager-older-n": "{{PLURAL:$1|1 leubèh awai|$1 leubèh awai}}",
        "booksources": "Nè kitab",
        "booksources-search-legend": "Mita bak nè kitab",
+       "booksources-search": "Mita",
        "specialloguserlabel": "Ureuëng ngui:",
        "speciallogtitlelabel": "Sasaran (judu atawa {{ns:ureueng ngui}}:nan ureueng ngui keu ureueng ngui)",
        "log": "Log",
        "tag-filter-submit": "Saréng",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag}}]]: $2)",
        "logentry-delete-delete": "$1 {{GENDER:$2|geusampôh}} miëng $3",
+       "logentry-move-move": "$1 {{GENDER:$2|geupinah}} mieng $3 u $4",
        "logentry-newusers-create": "$1 {{GENDER:$2|geupeugöt}} akun ureuëng ngui",
        "logentry-upload-upload": "$1 {{GENDER:$2|geupasoe}} $3",
        "searchsuggest-search": "Mita {{SITENAME}}",
index 4f81c3a..1b15090 100644 (file)
        "compareselectedversions": "Seçilən versiyaları müqayisə et",
        "showhideselectedversions": "Seçilən versiyaları göstər/gizlə",
        "editundo": "əvvəlki halına qaytar",
+       "diff-empty": "(Fərqli deyil)",
        "diff-multi-sameuser": "(Eyni istifadəçi tərəfindən edilmiş {{PLURAL:$1|bir dəyişiklik|$1 bir neçə dəyişiklik}} göstərilmir)",
        "diff-multi-manyusers": "({{PLURAL:$2|Bir istifadəçi|$2 istifadəçi}} tərəfindən edilən {{PLURAL:$1|bir ara redaktə|$1 ara redaktə}} göstərilmir)",
        "difference-missing-revision": "Səhifənin  {{PLURAL:$2|bu versiyasının|$2 versiyalarının}} müqayisəsi ($1) tapılmadı.\nBu xəta adətən, köhnəlmiş səhifələrin müqayisə versiyalarından keçid edildikdə baş verir.\nDaha ətraflı məlumat üçün [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} silmə qeydlərinə] baxın.",
        "search-redirect": "($1 səhifəsindən yönləndirmə)",
        "search-section": "(bölmə $1)",
        "search-category": "(kateqoriya $1)",
+       "search-file-match": "(faylın məzmunu ilə oxşardır)",
        "search-suggest": "Bəlkə, bunu nəzərdə tuturdunuz: $1",
        "search-interwiki-caption": "Qonşu layihələrdəki nəticələr",
        "search-interwiki-default": "$1 nəticələri:",
        "tooltip-pt-login": "Daxil olmanız tövsiyə olunur, amma bu məcburi tələb deyil.",
        "tooltip-pt-logout": "Sistemdən çıx",
        "tooltip-ca-talk": "Məqalə haqqındə müzakirə edib, münasibətivi bildir",
-       "tooltip-ca-edit": "Bu səhifəni redaktə edə bilərsiniz. Lütfən əvvəlcə sınaq gostərişi edin.",
+       "tooltip-ca-edit": "Bu səhifəni redaktə et",
        "tooltip-ca-addsection": "Yeni bölmə yarat",
        "tooltip-ca-viewsource": "Bu səhifə dəyişikliklərdən mühafizə olunur. Amma siz onun mətninə baxa və mətnin surətini köçürə bilərsiniz.",
        "tooltip-ca-history": "Bu səhifənin keçmiş nüsxələri.",
        "tooltip-t-recentchangeslinked": "Bu məqaləyə aid başqa səhifələrdə yeni dəyişikliklər",
        "tooltip-feed-rss": "Bu səhifə üçün RSS yayımı",
        "tooltip-feed-atom": "Bu səhifə üçün Atom yayımı",
-       "tooltip-t-contributions": "Bu istifadəçinin redaktə etdiyi səhifələrin siyahısı",
+       "tooltip-t-contributions": "{{GENDER:$1|this user}} adlı istifadəçinin redaktə etdiyi səhifələrin siyahısı",
        "tooltip-t-emailuser": "{{GENDER:$1|Bu istifadəçiyə}} e-məktub göndər",
        "tooltip-t-upload": "Yeni şəkil və ya multimedia faylı yüklə",
        "tooltip-t-specialpages": "Xüsusi səhifələrin siyahısı",
        "pageinfo-visiting-watchers": "Səhifəni izləmədə saxlayanlardan son dəyişiklikləri görənlərin sayı",
        "pageinfo-few-watchers": "$1 {{PLURAL:$1|izləyicidən|izləyicilərdən}} az",
        "pageinfo-redirects-name": "Bu səhifəyə yönləndirmələrin sayı",
+       "pageinfo-subpages-name": "Bu səhifənin alt-səhifələrinin sayı",
        "pageinfo-firstuser": "Səhifəni yaradan",
        "pageinfo-firsttime": "Səhifənin yaranma tarixi",
        "pageinfo-lastuser": "Sonuncu redaktor",
        "version-entrypoints-header-url": "URL",
        "version-libraries-library": "Kitabxana",
        "version-libraries-authors": "Müəlliflər",
+       "redirect-submit": "Keç",
+       "redirect-lookup": "Bax",
        "redirect-user": "İstifadəçi ID-si",
        "redirect-page": "Səhifənin identifikatoru",
+       "redirect-revision": "Səhifənin versiyası",
+       "redirect-file": "Fayl adı",
        "fileduplicatesearch": "Dublikat fayl axtarışı",
        "fileduplicatesearch-filename": "Fayl adı:",
        "fileduplicatesearch-submit": "Axtar",
index ce20657..5f90062 100644 (file)
@@ -44,6 +44,7 @@
        "tog-watchlisthideminor": "धियानसूची से छोट संपादन छिपावल जाय",
        "tog-watchlisthideliu": "खाता में प्रवेश भइल प्रयोगकर्ता लोग के संपादन धियानसूची से छिपावल जाय",
        "tog-watchlistreloadautomatically": "जब कौनों फिल्टर बदलल जाय तब धियानसूची ऑटोमेटिक दोबारा लोड होखे (जावास्क्रिप्ट जरूरी)",
+       "tog-watchlistunwatchlinks": "धियान में राखल जवना पन्ना सभ में बदलाव भइल बा उनहन में बिनाधियान/धियान के चीन्हा सभ ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) के सीधे जोड़ीं (एह टॉगल सुबिधा खातिर जावास्क्रिप्ट के जरूरत पड़ी)",
        "tog-watchlisthideanons": "बेनाम प्रयोगकर्ता लोग के संपादन धियानसूची से छिपावल जाय",
        "tog-watchlisthidepatrolled": "जाँचल गइल संपादन के धियानसूची से छिपावल जाय",
        "tog-watchlisthidecategorization": "पन्ना श्रेणीकरण छिपावल जाय",
        "cascadeprotected": "ए पन्ना के संपादन कइल सुरक्षित क दिहल गइल बा काहें कि ई {{PLURAL:$1|पन्ना में, जौना के|पन्ना सब में, जिन्हन के}} \"कैस्केडिंग\" (बिस्तारित) सुरक्षा चालू क के सुरक्षित कइल गइल बा, में समाइल बाटे:\n$2",
        "namespaceprotected": "रउआ के '''$1''' नामस्थान के पन्नं में सम्पादन करे के अधिकार नइखे दिहल गइल।",
        "customcssprotected": "रउआ के इ CSS पन्ना के संपादित करे के अनुमति नइखे, काहे कि इ में अन्य सदस्यं के व्यक्तिगत सेटिंग्स समाविष्ट बा।",
+       "customjsonprotected": "रउआ के एह JSON पन्ना के संपादित करे के इजाजत नइखे, काहें कि एह में दुसरे प्रयोगकर्ता ब्यक्तिगत सेटिंग सामिल बा।",
        "customjsprotected": "रउआ इ जावास्क्रिप्ट पन्ना के संपादित करे के अनुमति नइखे, काहे कि इ में अन्य सदस्यं के व्यक्तिगत सेटिंग्स समाविष्ट बा।",
        "mycustomcssprotected": "रउआ इ CSS के पन्ना के सम्पादित करे के अधिकार नइखे।",
+       "mycustomjsonprotected": "आपके एह JSON पन्ना में संपादन के इजाजत नइखे।",
        "mycustomjsprotected": "रउआ इ जावास्क्रिप्ट पन्ना के सम्पादित करे के अधिकार नइखे।",
        "myprivateinfoprotected": "रउआ लगे आपन व्यक्तिगत जानकारी बदले के अनुमति नइखे।",
        "mypreferencesprotected": "रउआ लगे आपन वरियतां ‍‍‍‍(पसंद) बदले के अधिकार नइखे।",
        "wrongpasswordempty": "गुप्तशब्द खाली बा। कृपया फिर से कोसिस करीं।",
        "passwordtooshort": "गुप्तशब्द कम से कम {{PLURAL:$1|1 अक्षर|$1 अक्षर}} के होवे के चाहीं।",
        "passwordtoolong": "गुप्तशब्द {{PLURAL:$1|$1 अक्षर}} से लमहर ना चाहीं।",
-       "passwordtoopopular": "à¤\85à¤\95à¥\8dसरहा à¤¬à¥\80à¤\9bल à¤\9cाà¤\8f à¤µà¤¾à¤²à¤¾ à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤¨à¤¾ à¤\87सà¥\8dतà¥\87माल à¤¹à¥\8b à¤¸à¤\95à¥\87 à¤²à¤¾à¥¤ à¤\95à¥\8cनà¥\8bà¤\82 à¤\85à¤\89रà¥\80 à¤\96ास à¤\85लà¤\97 à¤\95िसिम à¤\95à¥\87 à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤\9aà¥\81नà¥\80à¤\82।",
+       "passwordtoopopular": "à¤\85à¤\95à¥\8dसरहा à¤¬à¥\80à¤\9bल à¤\9cाà¤\8f à¤µà¤¾à¤²à¤¾ à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤¨à¤¾ à¤\87सà¥\8dतà¥\87माल à¤\95à¤\87ल à¤\9cा à¤¸à¤\95à¥\87 à¤²à¤¾à¥¤ à¤\85à¤\87सन à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤¬à¥\80à¤\9bà¥\80à¤\82 à¤\9cà¥\87à¤\95र à¤\85à¤\82à¤\9cाद à¤²à¤\97ावल à¤¢à¥\87र à¤\95ठिन à¤¹à¥\8bà¤\96à¥\87।",
        "password-name-match": "राउर गुप्तशब्द राउर प्रयोगकर्तानाँव से अलग होखे के चाहीं।",
        "password-login-forbidden": "इस प्रयोगकर्तानाँव आ गुप्तशब्द के प्रयोग वर्जित बा।",
        "mailmypassword": "गुप्तशब्द रिसेट करीं",
        "passwordremindertitle": "{{SITENAME}} खातिर नया अस्थायी गुप्तशब्द",
-       "passwordremindertext": "केहू (शायद रउए, $1 आइपी पता से) {{SITENAME}} ($4) पर प्रयोग खातिर नया गुप्तशब्द के निवेदन कइले बा। प्रयोगकर्ता \"$2\" खातिर एगो अस्थायी गुप्तशब्द बना दिहल गइल बा, आ ई \"$3\" बा। यदि ई रउवें चाहत रहलीं, त अब रउआँ के खाता में प्रवेश क के एगो नया गुप्तशब्द चुने के पड़ी।\nराउर अस्थायी गुप्तशब्द के अवधि {{PLURAL:$5|एक दिन|$5 दिन}} में खतम हो जाई।\n\nयदि ई निवेदन केहु अउर कइले रहल, या रउआँ के आपन पुरनका गुप्तशब्द इयाद आ गइल बा आ बदलाव नइखीं चाहत, त रउआँ ए सनेसा के अनदेखा कर सकत बानी, आ आपन पुरनका गुप्तशब्द के प्रयोग पहिले नियर कर सकत बानी।",
+       "passwordremindertext": "केहू ($1 आइपी पता से) {{SITENAME}} ($4) पर प्रयोग खातिर नया गुप्तशब्द के निवेदन कइले बा। प्रयोगकर्ता \"$2\" खातिर एगो अस्थायी गुप्तशब्द बना दिहल गइल बा, आ ई \"$3\" बा। यदि ई रउवें चाहत रहलीं, त अब रउआँ के खाता में प्रवेश क के एगो नया गुप्तशब्द चुने के पड़ी।\nराउर अस्थायी गुप्तशब्द के समयसीमा {{PLURAL:$5|एक दिन|$5 दिन}} में खतम हो जाई।\n\nयदि ई निवेदन केहु अउर कइले रहल, या रउआँ के आपन पुरनका गुप्तशब्द इयाद आ गइल बा आ बदलाव नइखीं चाहत, त रउआँ ए सनेसा के अनदेखा कर सकत बानी, आ आपन पुरनका गुप्तशब्द के प्रयोग पहिले नियर कर सकत बानी।",
        "noemail": "\"$1\" प्रयोगकर्ता खातिर कौनों ईमेल पता रिकार्ड में नइखे।",
        "noemailcreate": "रउआँ के एगो जायज ईमेल पता देवे के पड़ी।",
        "passwordsent": "\"$1\" के ईमेल पता पर एगो नया गुप्तशब्द भेज दिहल गइल बा।\nईमेल पावे के बाद कृपया दुबारा खाता में प्रवेश करीं।",
        "expansion-depth-exceeded-warning": "पन्ना अधिकतम बिस्तार गहिराई के पार क गइल",
        "parser-unstrip-loop-warning": "अनस्ट्रिप लूप पकड़ में आइल बा",
        "unstrip-depth-warning": "अनस्ट्रिप रिकर्शन सीमा पार हो गइल ($1)",
+       "unstrip-depth-category": "पन्ना जहाँ अनस्ट्रिप गहिराई सीमा पार क चुकल बाटे",
+       "unstrip-size-warning": "अनस्ट्रिप साइज के सीमा पार हो चुकल बा ($1)",
+       "unstrip-size-category": "पन्ना जहाँ अनस्ट्रिप साइज के सीमा पार हो चुकल बाटे",
        "converter-manual-rule-error": "मैनुअल भाषा परिवर्तन नियम में खराबी पकड़ल गइल",
        "undo-success": "संपादन वापस कइल जा सकत बा।\nनीचे दिहल तुलना के चेक करीं आ पुष्टी करीं की आप इहे कइल चाहत बाड़ीं, ओकरा बाद बदलाव सहेज के संपादन वापसी के पूरा करीं।",
        "undo-failure": "बीच में अउरी संपादन होखला की कारण ई संपादन वापस नइखे लिहल जा सकत।",
        "revdelete-modify-missing": "आइटम ID $1 के बदलाव करे में खराबी: ई डेटाबेस से गायब बा!",
        "revdelete-no-change": "<strong>चेतावनी:</strong> तारीख $2 के $1 बजे के ई आइटम पहिलहीं से ओही देखावे के सेटिंग वाला बाटे जवन माँगल जाता।",
        "revdelete-concurrent-change": "$1 $2 बजे के आइटम के बदले में खराबी आ रहल बा: बुझाता कि आप के कोसिस करे दौरान एकरा स्थिति के दूसर केहू बदल चुकल बा।\nलॉग चेक करीं।",
+       "revdelete-only-restricted": "तारीख $2, $1 के आइटम के लुकवावे में खराबी आवत बा: आप प्रबंधक लोग के नजर में आवे से आइटम के ना दबा सकत बाड़ीं जबले कि कौनों अउरी विजिबिलिटी बिकल्प के भी न सेलेक्ट करीं।",
+       "revdelete-reason-dropdown": "*हटावे के आम कारण\n** कॉपीराइट उलंघन\n** अनुचित कमेंट भा पर्सनल जानकारी\n** अनुचित प्रयोगकर्तानाँव\n** मानहानि-कारक जानकारी",
        "revdelete-otherreason": "अन्य/अतिरिक्त कारण:",
        "revdelete-reasonotherlist": "अन्य कारण",
        "revdelete-edit-reasonlist": "हटावे के कारण बदलीं",
index 897d11b..c12d9bd 100644 (file)
        "rcfilters-clear-all-filters": "Ерриге литтарш цӀанъян",
        "rcfilters-show-new-changes": "ТӀеххьара хийцамаш",
        "rcfilters-search-placeholder": "Литтаран керла хийцамаш лахар",
+       "rcfilters-empty-filter": "Жигара литтарш дац. Дерриге нисдарш гойтуш ю.",
        "rcfilters-filterlist-title": "Литтарш",
        "rcfilters-filterlist-feedbacklink": "Керла (бета) литтарех лаьцна хьайна хеттарг язде",
        "rcfilters-highlightbutton-title": "Билгалде карийнарш",
index 918e4bd..1c372e5 100644 (file)
        "customcssprotected": "Non ten os permisos necesarios para modificar esta páxina de CSS, dado que contén a configuración persoal doutro usuario.",
        "customjsprotected": "Non ten os permisos necesarios para modificar esta páxina de JavaScript, dado que contén a configuración persoal doutro usuario.",
        "mycustomcssprotected": "Non ten os permisos necesarios para editar esta páxina de CSS.",
+       "mycustomjsonprotected": "Non ten permisos para editar esta páxina JSON.",
        "mycustomjsprotected": "Non ten os permisos necesarios para editar esta páxina de JavaScript.",
        "myprivateinfoprotected": "Non ten os permisos necesarios para editar a súa información privada.",
        "mypreferencesprotected": "Non ten os permisos necesarios para editar as súas preferencias.",
        "wrongpasswordempty": "O campo do contrasinal estaba en branco.\nPor favor, inténteo de novo.",
        "passwordtooshort": "Os contrasinais deben conter, como mínimo, {{PLURAL:$1|1 carácter|$1 caracteres}}.",
        "passwordtoolong": "Os contrasinais non poden ser máis longo de {{PLURAL:$1|1 carácter|$1 caracteres}}.",
-       "passwordtoopopular": "Non pode utilizar un contrasinal dos habitualmente elixidos pola xente. Por favor, escolla un contrasinal máis orixinal.",
+       "passwordtoopopular": "Non pode utilizar un contrasinal dos habitualmente elixidos pola xente. Por favor, escolla un contrasinal que sexa máis complicada de adiviñar.",
        "password-name-match": "O seu contrasinal debe ser diferente do seu nome de usuario.",
        "password-login-forbidden": "O uso deste nome de usuario e contrasinal foi prohibido.",
        "mailmypassword": "Restablecer o contrasinal",
        "passwordremindertitle": "Novo contrasinal temporal para {{SITENAME}}",
-       "passwordremindertext": "Alguén (probablemente vostede, desde o enderezo IP $1) solicitou un novo\ncontrasinal para acceder a {{SITENAME}} ($4). Creouse un contrasinal temporal para o usuario\n\"$2\" e quedou establecido como \"$3\". Se esa foi a súa\nintención, terá que acceder ao sistema e escoller un novo contrasinal agora.\nO seu contrasinal temporal caducará {{PLURAL:$5|nun día|en $5 días}}.\n\nSe foi outra persoa a que fixo esta solicitude ou se xa se lembra do seu contrasinal\ne non o quere modificar, pode ignorar esta mensaxe e\ncontinuar a utilizar o seu contrasinal vello.",
+       "passwordremindertext": "Alguén (desde o enderezo IP $1) solicitou un novo\ncontrasinal para acceder a {{SITENAME}} ($4). Creouse un contrasinal temporal para o usuario\n\"$2\" e quedou establecido como \"$3\". Se esa foi a súa\nintención, terá que acceder ao sistema e escoller un novo contrasinal agora.\nO seu contrasinal temporal caducará {{PLURAL:$5|nun día|en $5 días}}.\n\nSe foi outra persoa a que fixo esta solicitude ou se xa se lembra do seu contrasinal\ne non o quere modificar, pode ignorar esta mensaxe e\ncontinuar a utilizar o seu contrasinal vello.",
        "noemail": "O usuario \"$1\" non posúe ningún enderezo de correo electrónico rexistrado.",
        "noemailcreate": "Ten que proporcionar un enderezo de correo electrónico válido",
        "passwordsent": "Enviouse un contrasinal novo ao enderezo de correo electrónico rexistrado de \"$1\".\nPor favor, acceda ao sistema de novo tras recibilo.",
        "sitecsspreview": "'''Lembre que só está vendo a vista previa deste CSS.'''\n'''Este aínda non foi gardado!'''",
        "sitejsonpreview": "<strong>Lembre que tan só está previsualizando esta configuración JSON.\nAínda non foi gardada!</strong>",
        "sitejspreview": "'''Lembre que só está vendo a vista previa deste código JavaScript.'''\n'''Este aínda non foi gardado!'''",
-       "userinvalidconfigtitle": "<strong>Aviso:</strong> Non hai ningunha aparencia chamada \"$1\".\nLembre que as páxinas .css e .js personalizadas utilizan un título en minúsculas, como por exemplo \"{{ns:user}}:Exemplo/vector.css\" no canto de \"{{ns:user}}:Exemplo/Vector.css\".",
+       "userinvalidconfigtitle": "<strong>Aviso:</strong> Non hai ningunha aparencia chamada \"$1\".\nLembre que as páxinas .css, .json e .js personalizadas utilizan un título en minúsculas, como por exemplo \"{{ns:user}}:Exemplo/vector.css\" no canto de \"{{ns:user}}:Exemplo/Vector.css\".",
        "updated": "(Actualizado)",
        "note": "'''Nota:'''",
        "previewnote": "<strong>Lembre que esta é só unha vista previa.</strong>\nAínda non gardou os seus cambios!",
        "longpageerror": "'''Erro: O texto que pretende gardar ocupa {{PLURAL:$1|$1 kilobyte|$1 kilobytes}}, e existe un límite dun máximo de {{PLURAL:$2|$2 kilobyte|$2 kilobytes}}.'''\nPolo tanto, non se pode gardar.",
        "readonlywarning": "<strong>Atención: Pechouse a base de datos para facer mantemento, polo que non vai poder gardar as súas edicións polo de agora.</strong>\nSe cadra, pode cortar e pegar o texto nun ficheiro de texto e gardalo para despois.\n\nO administrador do sistema que a pechou deu esta explicación: $1",
        "protectedpagewarning": "'''Aviso: Esta páxina foi protexida de xeito que só os usuarios con privilexios de administrador a poidan editar.'''\nVelaquí está a última entrada no rexistro, por se quere consultala:",
-       "semiprotectedpagewarning": "'''Nota:''' Esta páxina foi protexida de xeito que só os usuarios rexistrados a poidan editar.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
+       "semiprotectedpagewarning": "<strong>Nota:</strong> Esta páxina foi protexida de xeito que só os usuarios autoconfirmados a poidan editar.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
        "cascadeprotectedwarning": "<strong>Atención:</strong> Protexeuse esta páxina de xeito que só a poden editar os usuarios con [[Special:ListGroupRights|privilexios específicos]] debido a que está transcluída {{PLURAL:$1|na seguinte páxina protexida|nas seguintes páxinas protexidas}} coa opción \"protección en serie\" activada:",
        "titleprotectedwarning": "'''Aviso: Esta páxina foi protexida de xeito que [[Special:ListGroupRights|só algúns usuarios]] a poidan crear.'''\nVelaquí está a última entrada no rexistro, por se quere consultala:",
        "templatesused": "{{PLURAL:$1|Modelo usado|Modelos usados}} nesta páxina:",
        "prefs-dateformat": "Formato da data",
        "prefs-timeoffset": "Desprazamento horario",
        "prefs-advancedediting": "Opcións xerais",
+       "prefs-developertools": "Ferramentas de desenvolvemento",
        "prefs-editor": "Editor",
        "prefs-preview": "Vista previa",
        "prefs-advancedrc": "Opcións avanzadas",
        "rcfilters-filter-humans-description": "Edicións realizadas por editores humanos.",
        "rcfilters-filtergroup-reviewstatus": "Estado de revisión",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "Sen patrullar",
+       "rcfilters-filter-reviewstatus-manual-description": "Edicións marcadas manualmente como vixiadas.",
+       "rcfilters-filter-reviewstatus-manual-label": "Vixiadas manualmente",
+       "rcfilters-filter-reviewstatus-auto-description": "Edicións realizadas por usuarios avanzados cuxo traballo márcase automaticamente como vixiado.",
+       "rcfilters-filter-reviewstatus-auto-label": "Vixiado automaticamente",
        "rcfilters-filtergroup-significance": "Importancia",
        "rcfilters-filter-minor-label": "Edicións menores",
        "rcfilters-filter-minor-description": "Edicións que o autor etiquetou como menores.",
        "rollback-success": "Desfixéronse as edicións de {{GENDER:$3|$1}};\nvolveuse á última edición, feita por {{GENDER:$4|$2}}.",
        "rollback-success-notify": "Revertéronse as edicións de $1;\nrestaurouse a última revisión de $2. [$3 Mostrar os cambios]",
        "sessionfailure-title": "Erro de sesión",
-       "sessionfailure": "Parece que hai un problema co rexistro da súa sesión;\nesta acción cancelouse como precaución fronte ao secuestro de sesións.\nPrema no botón \"atrás\", volva cargar a páxina da que proviña e inténteo de novo.",
+       "sessionfailure": "Parece que hai un problema co rexistro da súa sesión;\nesta acción cancelouse como precaución fronte ao secuestro de sesións.\nPor favor, volva enviar o formulario.",
        "changecontentmodel": "Cambiar o modelo de contido dunha páxina",
        "changecontentmodel-legend": "Cambiar o modelo de contido",
        "changecontentmodel-title-label": "Título da páxina",
        "fix-double-redirects": "Actualizar calquera redirección que apunte cara ao título orixinal",
        "move-leave-redirect": "Deixar unha redirección detrás",
        "protectedpagemovewarning": "'''Aviso:''' Esta páxina foi protexida de xeito que só os usuarios con privilexios de administrador a poidan mover.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
-       "semiprotectedpagemovewarning": "'''Nota:''' Esta páxina foi protexida de xeito que só os usuarios rexistrados a poidan mover.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
+       "semiprotectedpagemovewarning": "<strong>Nota:</strong> Esta páxina foi protexida de xeito que só os usuarios autoconfirmados a poidan mover.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
        "move-over-sharedrepo": "\"[[:$1]]\" xa existe nun repositorio compartido. Ao mover un ficheiro a este título sobrescribirase o ficheiro compartido.",
        "file-exists-sharedrepo": "O nome que elixiu para o ficheiro xa está en uso nun repositorio compartido.\nPor favor, escolla outro nome.",
        "export": "Exportar páxinas",
        "unlinkaccounts-success": "A conta foi desvinculada.",
        "authenticationdatachange-ignored": "Os cambios de datos de autenticación non foron xerados. Está configurado o provedor?",
        "userjsispublic": "Lembre: As subpáxinas JavaScript non deberían conter datos confidenciais porque outros usuarios poden velos.",
+       "userjsonispublic": "Por favor, teña en conta queː as subpáxinas JSON non deben conter datos confidenciais xa que son visibles por outros usuarios.",
        "usercssispublic": "Lembre: As subpáxinas CSS non deberían conter datos confidenciais porque outros usuarios poden velos.",
        "restrictionsfield-badip": "Enderezo IP ou rango de IP non válido: $1",
        "restrictionsfield-label": "Rangos de IP permitidos:",
index 8366db6..c20415e 100644 (file)
        "uploaded-hostile-svg": "נמצא CSS בלתי־מאובטח באלמנט style בקובץ ה־SVG שהועלה.",
        "uploaded-event-handler-on-svg": "אסור להגדיר מאפייני טיפול באירועים <code dir=\"ltr\">$1=\"$2\"</code> בקובצי SVG.",
        "uploaded-href-attribute-svg": "רכיבי <a> יכולים לקשר (href) רק ליעדי data:‎ (קובץ מוטמע), http://‎ או https://‎, או מקטע (עם #, באותו מסמך). ברכיבים אחרים, כגון <image>, מותרים רק יעדי data:‎ ומקטע. באפשרותך לנסות להטמיע תמונות בעת ייצוא קובץ ה־SVG שלך. נמצא <code dir=\"ltr\">&lt;$1 $2=\"$3\"&gt;</code>.",
-       "uploaded-href-unsafe-target-svg": "נמצא href לנתונים לא מאובטחים <code dir=\"ltr\">&lt;$1 $2=\"$3\"&gt;</code> בקובץ ה־SVG שהועלה.",
+       "uploaded-href-unsafe-target-svg": "נמצא href לנתונים לא מאובטחים: יעד URI <code dir=\"ltr\">&lt;$1 $2=\"$3\"&gt;</code> בקובץ ה־SVG שהועלה.",
        "uploaded-animate-svg": "נמצא תג \"animate\" שיכול לשנות href באמצעות מאפיין \"from\"  בצורת <code dir=\"ltr\">&lt;$1 $2=\"$3\"&gt;</code> בקובץ ה־SVG שהועלה.",
        "uploaded-setting-event-handler-svg": "הגדרת מאפייני טיפול באירועים חסומה, נמצא <code dir=\"ltr\">&lt;$1 $2=\"$3\"&gt;</code> בקובץ ה־SVG שהועלה.",
-       "uploaded-setting-href-svg": "השימוש בתג set כדי להוסיף מאפיין href לאלמנט הורה חסום.",
+       "uploaded-setting-href-svg": "השימוש בתג \"set\" כדי להוסיף מאפיין \"href\" לאלמנט הורה חסום.",
        "uploaded-wrong-setting-svg": "השימוש בתג \"set\" כדי להוסיף יעד remote/data/script לכל מאפיין חסום. נמצא <code dir=\"ltr\">&lt;set to=\"$1\"&gt;</code> בקובץ ה־SVG שהועלה.",
        "uploaded-setting-handler-svg": "SVG שמגדיר את המאפיין \"handler\" עם remote/data/script חסום. נמצא <code dir=\"ltr\">$1=\"$2\"</code> בקובץ ה־SVG שהועלה.",
        "uploaded-remote-url-svg": "SVG שמגדיר כל מאפיין style עם URL מרוחק חסום. נמצא <code dir=\"ltr\">$1=\"$2\"</code> בקובץ ה־SVG שהועלה.",
        "uploaded-image-filter-svg": "נמצא מסנן תמונה עם URL‏: <code dir=\"ltr\">&lt;$1 $2=\"$3\"&gt;</code> בקובץ ה־SVG שהועלה.",
-       "uploadscriptednamespace": "ק×\95×\91×¥ ×\94â\80\8fâ\80\8fÖ«Ö¾SVG ×\94×\96×\94 ×\9b×\95×\9c×\9c ×\9eר×\97×\91 ×©×\9d ×\91×\9cת×\99 חוקי \"<nowiki>$1</nowiki>\".",
+       "uploadscriptednamespace": "ק×\95×\91×¥ ×\94â\80\8fâ\80\8fÖ¾SVG ×\94×\96×\94 ×\9b×\95×\9c×\9c ×\9eר×\97×\91 ×©×\9d ×\91×\9cת×\99Ö¾חוקי \"<nowiki>$1</nowiki>\".",
        "uploadinvalidxml": "לא ניתן לפרש את ה־XML בקובץ שהועלה.",
        "uploadvirus": "הקובץ מכיל וירוס!\nפרטים:\n<div dir=\"ltr\">$1</div>",
        "uploadjava": "קובץ זה הוא קובץ ZIP שמכיל קובץ &lrm;.class של Java.\nהעלאת קובצי Java אסורה, כיוון שהם יכולים לגרום לעקיפת מגבלות האבטחה.",
        "upload-description": "תיאור הקובץ",
        "upload-options": "אפשרויות העלאה",
        "watchthisupload": "מעקב אחרי קובץ זה",
-       "filewasdeleted": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ×\94×\95×¢×\9c×\94 ×\91×¢×\91ר, ×\95×\9c×\90×\97ר ×\9e×\9b×\9f × ×\9e×\97ק.\n×\90× ×\90 ×\91Ö´Ö¼×\93ק×\95 ×\90ת $1 ×\9cפנ×\99 ×©×ª×\9eש×\99×\9b×\95 ×\9c×\94×¢×\9c×\95ת את הקובץ שנית.",
+       "filewasdeleted": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ×\94×\95×¢×\9c×\94 ×\91×¢×\91ר, ×\95×\9c×\90×\97ר ×\9e×\9b×\9f × ×\9e×\97ק.\n×\99ש ×\9c×\91×\93×\95ק ×\90ת $1 ×\9cפנ×\99 ×\94×¢×\9cאת הקובץ שנית.",
        "filename-thumb-name": "נראה שכותרת הקובץ היא כותרת של תמונה מוקטנת (ממוזערת). יש להימנע מהעלאת תמונות ממוזערות בחזרה לאותו אתר ויקי. אם זו אינה תמונה ממוזערת, יש לתקן את שם הקובץ כך שיהיה משמעותי יותר ושלא יכלול את הקידומת של תמונה ממוזערת.",
-       "filename-bad-prefix": "ש×\9d ×\94ק×\95×\91×¥ ×©×\90ת×\9d ×\9e×¢×\9c×\99×\9d ×\9eת×\97×\99×\9c ×\91Ö¾<strong>\"$1\"</strong>, ×©×\94×\95×\90 ×©×\9d ×©×\90×\99× ×\95 ×\9eת×\90ר ×\90ת ×\94ק×\95×\91×¥ ×\95×\91×\93ר×\9a כלל מוקצה אוטומטית על־ידי מצלמות דיגיטליות.\nיש לבחור שם מתאים יותר לקובץ, שיתאר את תכניו.",
+       "filename-bad-prefix": "ש×\9d ×\94ק×\95×\91×¥ ×©×\91×\97רת ×\9c×\94×¢×\9c×\95ת ×\9eת×\97×\99×\9c ×\91Ö¾<strong>\"$1\"</strong>, ×©×\94×\95×\90 ×©×\9d ×©×\90×\99× ×\95 ×\9eת×\90ר ×\90ת ×\94ק×\95×\91×¥ ×\95×\91×\93ר×\9aÖ¾כלל מוקצה אוטומטית על־ידי מצלמות דיגיטליות.\nיש לבחור שם מתאים יותר לקובץ, שיתאר את תכניו.",
        "filename-prefix-blacklist": " #<!-- נא להשאיר שורה זו בדיוק כפי שהיא --> <pre>\n# התחביר הוא כדלקמן:\n#   * כל דבר מתו \"#\" לסוף השורה הוא הערה\n#   * כל שורה לא ריקה היא קידומת לשמות קבצים טיפוסיים שמצלמות דיגיטליות נותנות אוטומטית\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # מספר טלפונים סלולריים\nIMG # כללי\nJD # Jenoptik\nMGP # Pentax\nPICT # שונות\n #</pre> <!-- נא להשאיר שורה זו בדיוק כפי שהיא -->",
        "upload-proto-error": "פרוטוקול שגוי",
-       "upload-proto-error-text": "בהעלאה מרוחקת, יש להשתמש בכתובות URL המתחילות עם <code>http://</code> או <code>ftp://</code>.",
+       "upload-proto-error-text": "בהעלאה מרוחקת, יש להשתמש בכתובות URL המתחילות עם <code dir=\"ltr\">http://</code> או עם <code dir=\"ltr\">ftp://</code>.",
        "upload-file-error": "שגיאה פנימית",
        "upload-file-error-text": "שגיאה פנימית התרחשה בעת הניסיון ליצור קובץ זמני על השרת.\nאנא צרו קשר עם [[Special:ListUsers/sysop|מפעיל מערכת]].",
        "upload-misc-error": "שגיאת העלאה בלתי ידועה",
index f5cda9d..fbc3d57 100644 (file)
        "savechanges": "Sačuvaj stranicu",
        "publishpage": "Objavi stranicu",
        "publishchanges": "Sačuvaj uređivanje",
+       "savearticle-start": "Sačuvaj stranicu...",
+       "savechanges-start": "Spremi promjene...",
+       "publishpage-start": "Objavi stranicu...",
        "publishchanges-start": "Sačuvaj uređivanje...",
        "preview": "Pregled kako će stranica izgledati",
        "showpreview": "Prikaži kako će izgledati",
        "accmailtext": "Nova zaporka za [[User talk:$1|$1]] je poslana na $2.\n\nNakon prijave, zaporka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|promijeni zaporku]]'' nakon prijave.",
        "newarticle": "(Novo)",
        "newarticletext": "Došli ste na stranicu koja još ne postoji.\nAko želite stvoriti tu stranicu, počnite tipkati u prozor ispod ovog teksta (pogledajte [$1 stranicu za pomoć]).\nAko ste ovamo dospjeli slučajno, kliknite gumb '''natrag''' (back) u svom pregledniku.",
-       "anontalkpagetext": "----''Ovo je stranica za razgovor s neprijavljenim suradnikom koji još nije otvorio suradnički račun ili se njime ne koristi. Zbog toga se moramo služiti brojčanom IP adresom kako bismo ga identificirali. Takvu adresu često može dijeliti više ljudi. Ako ste neprijavljeni suradnik i smatrate da su Vam upućeni irelevantni komentari, molimo Vas da [[Special:CreateAccount|otvorite suradnički račun]] ili [[Special:UserLogin|se prijavite]] te tako u budućnosti izbjegnete zamjenu s drugim neprijavljenim suradnicima.''",
+       "anontalkpagetext": "----\n<em>Ovo je stranica za razgovor s neprijavljenim suradnikom koji još nije otvorio suradnički račun ili se njime ne koristi.</em>\nZbog toga se moramo služiti brojčanom IP adresom kako bismo ga identificirali. \nTakvu adresu često može dijeliti više ljudi. \nAko ste neprijavljeni suradnik i smatrate da su Vam upućeni irelevantni komentari, molimo Vas da [[Special:CreateAccount|otvorite suradnički račun]] ili [[Special:UserLogin|se prijavite]] te tako u budućnosti izbjegnete zamjenu s drugim neprijavljenim suradnicima.",
        "noarticletext": "Na ovoj stranici trenutačno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane evidencije]\nili [{{fullurl:{{FULLPAGENAME}}|action=edit}} stvoriti ovu stranicu]</span>.",
        "noarticletext-nopermission": "Ova stranica nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane evidencije]</span>, ali ne možete stvoriti ovu stranicu.",
        "missing-revision": "Uređivanje broj $1 na stranici \"{{FULLPAGENAME}}\" ne postoji.\n\nOvo je obično uzrokovano kada kliknete na zastarjelu poveznicu na stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
index 8c6e304..8032223 100644 (file)
        "preview": "Previdar",
        "showpreview": "Previdar",
        "showdiff": "Montrez chanji",
-       "blankarticle": "<strong>Averto:</strong> La pagino vu kreas es vakua.\nSe vu ri-selektos \"$1\", la pagino kreesos sen irga kontenajo.",
+       "blankarticle": "<strong>Averto:</strong> La pagino quon vu kreis es vakua.\nSe vu ri-selektos \"$1\", la pagino kreesos sen irga kontenajo.",
        "anoneditwarning": "<strong>Averto:</strong> Vu ne eniris.\nVua IP-adreso esos videbla publike se vu redaktos. Se vu <strong>[$1 enirus]</strong> od <strong>[$2 kreus konto]</strong>, vua redakti atribuesos a vua uzeronomo, kune kun altra bonaji.",
        "anonpreviewwarning": "<em>Vu ne eniris. Konservar chanji registragos vua IP-adreso en la redakto-historio di ta pagino.</em>",
        "missingcommenttext": "Voluntez skribar komento.",
        "filesource": "Fonto:",
        "ignorewarning": "Ignorar la averto e gardar la arkivo irgakaze.",
        "badfilename": "La imajo-nomo chanjesis a \"$1\".",
+       "empty-file": "L'arkivo sendita da vu esas vakua.",
        "fileexists": "Arkivo kun ta nomo ja existas.\nVolutez kontrolar <strong>[[:$1]]</strong> se {{GENDER:|vu}} ne esas certa pri chanjar olu.\n[[$1|thumb]]",
        "filepageexists": "La pagino kun deskripto pri ica arkivo ja kreesis en <strong>[[:$1]]</strong>, tamen nul arkivo kun ica nomo existas ankore.\nLa rezumo pri ol quon vu skriptis ne aparos en la deskripto-pagino.\nPor ke la rezumo aparos ibe, vu mustos <strong>skribor ol manuale.</strong>\n[[$1|thumb]]",
        "uploadwarning": "Averto pri la adkargo di arkivo",
        "withoutinterwiki": "Pagini sen linguo-ligili",
        "withoutinterwiki-legend": "Prefixo",
        "withoutinterwiki-submit": "Montrar",
+       "fewestrevisions": "Pagini kun poka revizi",
        "nbytes": "$1 {{PLURAL:$1|bicoko|bicoki}}",
        "ncategories": "$1 {{PLURAL:$1|kategorio|kategorii}}",
        "nlinks": "$1 {{PLURAL:$1|ligilo|ligili}}",
        "booksources-search-legend": "Serchez librala fonti",
        "booksources-search": "Serchar",
        "booksources-text": "Infre vu povas vidar listo di ligili ad altra retsitui qui vendas nova ed uzata libri, ed anke povas havar informi pri la libri quin vu serchabas:\nLa {{SITENAME}} ne mantenas komercala relati kun ta vendeyi mencionata, e la listo ne povas konsideresar rekomendo o vend-anunco.",
+       "magiclink-tracking-pmid-desc": "Ica pagino uzas magiala ligili PMID. Videz [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] pri quale migrar.",
        "magiclink-tracking-isbn": "Pagini qui uzas ligili ISBN",
        "specialloguserlabel": "Agero:",
        "speciallogtitlelabel": "Skopo (titulo od {{ns:user}}:uzernomo por uzero):",
        "listgrouprights": "Permisi dil grupo di uzeri",
        "listgrouprights-group": "Grupo",
        "listgrouprights-members": "(listo di membri)",
+       "trackingcategories": "Kategorii por kontrolo",
+       "trackingcategories-name": "Nomo di la mesajo",
+       "trackingcategories-desc": "Kriterii por inkluzar kategorii",
        "restricted-displaytitle-ignored-desc": "La pagino havas nekonocita titulo <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>, pro ol ne esas equivalanta a la nuna titulo di ica pagino.",
        "mailnologin": "Ne sendar adreso",
        "mailnologintext": "Vu mustas [[Special:UserLogin|enirir]] e havar valida e-adreso en vua [[Special:Preferences|preferaji]] por sendar e-posto ad altra uzanti.",
index 3d6f7a8..6831398 100644 (file)
        "rcfilters-liveupdates-button-title-off": "Rādīt jaunās izmaiņas, tiklīdz tās tiek veiktas",
        "rcfilters-watchlist-markseen-button": "Atzīmēt visas izmaiņas kā apskatītas",
        "rcfilters-watchlist-edit-watchlist-button": "Labot manu uzraugāmo lapu sarakstu",
-       "rcfilters-watchlist-showupdated": "Izmaiņas lapās, kuras nav apmeklētas kopš izmaiņu veikšanas ir <strong>trekninātā rakstā</strong>.",
+       "rcfilters-watchlist-showupdated": "Izmaiņas lapās, kuras nav apmeklētas kopš izmaiņu veikšanas, ir <strong>trekninātā rakstā</strong>.",
        "rcfilters-preference-label": "Paslēpt uzlaboto pēdējo izmaiņu versiju",
        "rcnotefrom": "Zemāk {{PLURAL:$5|redzamas izmaiņas|redzama izmaiņa|redzamas izmaiņas}} kopš <strong>$3, $4</strong> (parādītas ne vairāk kā <strong>$1</strong>).",
        "rclistfromreset": "Atiestatīt datuma izvēli",
index adc21c6..b76a4f1 100644 (file)
        "download": "преземи",
        "unwatchedpages": "Ненабљудувани страници",
        "listredirects": "Список на пренасочувања",
-       "listduplicatedfiles": "СпиÑ\81ок Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82еки Ñ\81о Ð´Ñ\83пликаÑ\82и",
+       "listduplicatedfiles": "СпиÑ\81ок Ð½Ð° Ð´Ñ\83плиÑ\80ани Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82еки",
        "listduplicatedfiles-summary": "Ова е список на податотеки чија најнова верзија е дупликат на најнова верзија на некоја друга податотека. Се земаат предвид само месни податотеки.",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] има [[$3|{{PLURAL:$2|дупликат|$2 дупликати}}]].",
        "unusedtemplates": "Неискористени шаблони",
        "version-libraries-license": "Лиценца",
        "version-libraries-description": "Опис",
        "version-libraries-authors": "Автори",
-       "redirect": "Ð\9fÑ\80енаÑ\81оÑ\87Ñ\83ваÑ\9aе Ð¿Ð¾ Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека, Ñ\81Ñ\82Ñ\80аниÑ\86а, Ð¿Ñ\80еÑ\80абоÑ\82ка Ð¸Ð»Ð¸ Ð½Ð°Ð·Ð½Ð°ÐºÐ° Ð²Ð¾ Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÐ¾Ñ\82",
+       "redirect": "Ð\9fÑ\80енаÑ\81оÑ\87Ñ\83ваÑ\9aе Ð¿Ð¾ Ð½Ð°Ð·Ð½Ð°ÐºÐ° Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека, ÐºÐ¾Ñ\80иÑ\81ник, Ñ\81Ñ\82Ñ\80аниÑ\86а, Ð¿Ñ\80еÑ\80абоÑ\82ка Ð¸Ð»Ð¸ Ð´Ð½ÐµÐ²Ð½Ð¸Ðº",
        "redirect-summary": "Оваа службена страница пренасочува кон податотека (се задава името), страница (се задава назнаката на преработката или страницата), корисничка странца (се задава бројчената назнака на корисникот) или дневнички запис (се дава назнака на записот). Употреба: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]],  [[{{#Special:Redirect}}/user/101]] или [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Дај",
        "redirect-lookup": "Пребарај:",
index e7f8ba7..f65f5df 100644 (file)
        "tog-usenewrc": "Molōloāzqueh in tlapatlaliztli in yancuīc tlapatlaliztli āmapan īhuān in tlachiyaliztli tlapōhualāmapan (monequi JavaScript)",
        "tog-showtoolbar": "Motlaīxtlatīz in tlachihchīhualōni pāntli",
        "tog-editondblclick": "Tiquimpatlāz in zāzanilli intlā ōme tiquimpachoa",
-       "tog-watchcreations": "Moaquiāz in āmatl mā niquinyōcoya īhuān in tlahcuilōlli mā niquinquetza īpan notlachiyaliz",
+       "tog-watchcreations": "Niquintlaliz in tlahcuilolamameh in oniquinchiuh ihuan in tlahcuilolpiyaliztin in oniquinquetz ipan notlachiyaliz",
        "tog-watchdefault": "Moaquiāz āmatl īhuān tlahcuilōlli mā niquinpatla in notlachiyaliz",
        "tog-watchmoves": "Moaquiāz āmatl īhuān tlahcuilōlli mā niquinzaca in notlachiyaliz",
-       "tog-watchdeletion": "Moaquiāz āmatl īhuān tlahcuilōlli mā niquimpolo in notlachiyaliz",
+       "tog-watchdeletion": "Niquintlaliz tlahcuilolamameh ihuan tlahcuilolpiyaliztin in oniquimpoloh ipan notlachiyaliz",
        "tog-minordefault": "Ticmachiyōtīz mochīntīn tlapatlalitzintli ic default",
        "tog-previewontop": "Tiquittāz achtochīhualiztli achtopa tlapatlaliztli caxitl",
        "tog-previewonfirst": "Xiquitta achtochīhualiztli inic cē tlapatlalizpan",
@@ -47,7 +47,7 @@
        "tog-diffonly": "Ahmo tiquittāz zāzanilli ītlapiyaliz ahneneuhquilitzīntlan",
        "tog-showhiddencats": "Mà monèxtìkàn in tlatlatìltìn tlaìxmatkàtlàlilòmë",
        "underline-always": "Mochipa",
-       "underline-never": "Aīc",
+       "underline-never": "Aic",
        "editfont-monospace": "Cencoyahualiztli machiyotlahtoliztli",
        "editfont-sansserif": "Sans-serif machiyotlahtoliztli",
        "editfont-serif": "Serif machiyotlahtoliztli",
        "otherlanguages": "Occequintin tlahtlahtolcopa",
        "redirectedfrom": "(Omocuep ihuicpa $1)",
        "redirectpagesub": "Ōmotlacuep zāzanilli",
-       "lastmodifiedat": "Inin tlahcuilolli omopatlac immanin $1, ipan $2.",
+       "lastmodifiedat": "Inin tlahcuilolamatl omopatlac immanin $1, ipan $2.",
        "viewcount": "Inīn zāzanilli quintlapōhua {{PLURAL:$1|cē tlahpololiztli|$1 tlahpololiztli}}.",
        "protectedpage": "Ōmoquīxtix zāzanilli",
        "jumpto": "Ticholoz ihuicpa:",
        "retypenew": "Occeppa xiquihcuiloa yancuīc motlahtōlichtacayo:",
        "resetpass_submit": "Xicpatlāz motlahtōlichtacāyo auh xicalaquīz",
        "changepassword-success": "Moichtacātlahtōl ōmopatlac.",
+       "botpasswords-label-cancel": "Moxitiniz",
        "resetpass_forbidden": "Tlahtōlichtacayōtl ahmo mohuelītih mopatlah",
        "resetpass-submit-loggedin": "Ticpatlāz motlahtōlichtacāyo",
-       "resetpass-submit-cancel": "Xiccahua",
+       "resetpass-submit-cancel": "Moxitiniz",
        "passwordreset-username": "Tequihuihcātōcāitl:",
        "bold_sample": "Tliltic tlahcuiloliztli",
        "bold_tip": "Tliltic tlahcuiloliztli",
        "last": "xocoyoc",
        "page_first": "achto",
        "page_last": "xōcoyōc",
-       "history-fieldset-title": "Xitlatēmo īpan tlahtōllōtl",
+       "history-fieldset-title": "Xitlatemo ihtic tlahtollotl",
        "history-show-deleted": "Zan tlapololtin",
        "histfirst": "in achto",
        "histlast": "in tlatzaucticah",
        "recentchanges-label-newpage": "Inin tlapatlaliztli oquiyocox ce yancuic tlahcuilolamatl",
        "recentchanges-label-minor": " Inin tepiton tlapatlaliztli",
        "recentchanges-label-bot": "Inin tlapaltlaliztli oquichiuh ce robot",
+       "rcfilters-savedqueries-cancel-label": "Moxitiniz",
        "rclistfrom": "Xiquittaz yancuic tlapatlaliztli ixquichca $3 ihuicpa $2",
        "rcshowhideminor": "$1 tlapatlalitzintli",
        "rcshowhideminor-show": "Xicnexti",
        "sourceurl": "Mēyal-URL:",
        "destfilename": "Tōcāhuīc:",
        "watchthisupload": "Tictlachiyaz inin tecpanaliztlapiyaliztli",
+       "upload-dialog-button-cancel": "Moxitiniz",
        "upload-form-label-infoform-name": "Tōcāitl",
        "upload-form-label-usage-filename": "Ihcuilōlli ītōcā",
        "upload_source_file": "(ticpepenaz ce tlahcuilolli mochiuhpohualhuazco)",
        "newpages": "Yancuic tlahcuiloltin",
        "newpages-username": "Tlatequitiltilīltōcāitl:",
        "ancientpages": "Huehcauh tlahcuilolamatl",
-       "move": "Ticzacāz",
+       "move": "Ticzacaz",
        "movethispage": "Ticzacāz inīn zāzanilli",
        "pager-newer-n": "{{PLURAL:$1|1 yancuic|$1 yancuicqueh}}",
        "pager-older-n": "{{PLURAL:$1|1 huehcauh|$1 huehcauhqueh}}",
        "mywatchlist": "Notlachiyaliz",
        "watchnologin": "Ahmo ōtimocalac",
        "removedwatchtext": "Zāzanilli \"[[:$1]]\" ōmopolo [[Special:Watchlist|motlachiyalizco]].",
-       "watch": "Tictlachiyāz",
+       "watch": "Titlachiyaz",
        "watchthispage": "Tictlachiyāz inīn zāzanilli",
        "unwatch": "Ahmo titlachiyaz",
        "watchlist-details": "{{PLURAL:$1|$1 zāzanilli|$1 zāzaniltin}} motlachiyaliz, ahmo mopōhua tēixnāmiquiliztli.",
        "protect-expiry-options": "1 hora:1 hour,1 tonalli:1 day,1 chicueyilhuitl:1 week,2 chicueyilhuitl:2 weeks,1 metztli:1 month,3 metztli:3 months,6 metztli:6 months,1 xihuitl:1 year,mochipa:infinite",
        "restriction-type": "Temacahualiztli:",
        "restriction-edit": "xicpatla",
-       "restriction-move": "Ticzacāz",
+       "restriction-move": "Ticzacaz",
        "restriction-create": "Ticchīhuāz",
        "restriction-upload": "Tlahcuilōlquetza",
        "undelete": "Tiquimittaz tlahcuilolamameh tlen omopohpolohqueh",
        "contributions": "In {{GENDER:$1|tlatequitiltilīlli}} ītlahcuilōl",
        "contributions-title": "Tlatequitiltilīlli $1 ītlahcuilōl",
        "mycontris": "Notlahcuilol",
-       "contribsub2": "$1 ($2)",
+       "contribsub2": "Ihuicpa {{GENDER:$3|$1}} ($2)",
        "uctop": "(axcan tlapatlaliztli)",
-       "month": "Īhuīcpa mētztli (auh achtopa):",
-       "year": "Xiuhhuīcpa (auh achtopa):",
+       "month": "Metzpan (auh yeppa):",
+       "year": "Xiuhpan (auh yeppa):",
        "sp-contributions-newbies": "Tiquinttāz zan yancuīc tlatequitiltilīlli īntlapatlaliz",
        "sp-contributions-newbies-sub": "Ic yancuīc",
        "sp-contributions-newbies-title": "Yancuīc tlatequitiltilīlli ītlahcuilōl",
        "change-blocklink": "Ticpatlaz tlatzacualli",
        "contribslink": "tlapatlaliztli",
        "blocklogpage": "Tlatequitiltilīlli ōmotzacuili",
-       "move-page": "Ticzacāz $1",
+       "move-page": "Ticzacaz $1",
        "move-page-legend": "Tictocapatlaliz inin tlahcuilolamatl",
        "movepagetext": "Nicān mohcuiloa quemeh ticzacāz cē zāzanilli auh mochi in ītlahcuillōloh īhuīc occē yancuīc ītōca.\nHuēhuehtōcāitl yez tlacuepaliztli yancuīc tōcāhuīc.\nTzonhuiliztli huēhuehzāzanilhuīc ahmo mopatlāz.\nXiquitta ic māca xicchīhua [[Special:DoubleRedirects|ōntlacuepaliztli]] ahnozo [[Special:BrokenRedirects|tzomoc]].\nTitzonhuilizpiyāz.\n\nXicmati in zāzanilli ahmo mozacāz intlā ye ia cē zāzanilli tōcātica, zan cah iztāc zāzanilli ahnozo tlacuepaliztli īca ahmo tlahcuilōlloh.\nQuihtōznequi tihuelītīz ticuepāz cē zāzanilli īhuīc ītlācatōca intlā ahcuallōtl ticchīhuāz, tēl ahmo tihuelītīz occeppa tihcuilōz īpan zāzanilli tlein ia.\n\n'''¡XICPŌHUA!'''\nHueliz cah inīn huēyi tlapatlaliztli. Timitztlātlauhtia ticmatīz cuallōtl auh ahcuallōtl achtopa ticzacāz.",
        "movenotallowed": "Ahmo tihuelīti tiquinzaca zāzaniltin.",
        "tooltip-ca-delete": "Ticpolōz inīn zāzanilli",
        "tooltip-ca-undelete": "Ahticpolōz inīn zāzanilli",
        "tooltip-ca-move": "Ticzacaz inin tlahcuilolamatl",
-       "tooltip-ca-watch": "Ticcentiliz inin tlahtolli motecpanaliz",
+       "tooltip-ca-watch": "Tictlaliz inin tlahcuilolamatl motlachiyaliz",
        "tooltip-ca-unwatch": "Ticpohpoloz inin tlahcuilolamatl ipan motlachiyaliz",
        "tooltip-search": "Tlatemoliztli ipan {{SITENAME}}",
        "tooltip-search-go": "Tiyaz ihuicpa tlahcuilolamatl ica inin huel melahuac tocaitl intla oncah",
        "tooltip-summary": "Xiquihcuilo ce tepiton tlahcuiloltontli",
        "anonymous": "Ahtōcāitl {{PLURAL:$1|tlatequitiltilīlli}} īpan {{SITENAME}}",
        "siteuser": "$1 tlatequitiltilīlli īpan {{SITENAME}}",
-       "lastmodifiedatby": "Inin tlahcuilolamatl omopatlac ipan $2, $1 ipal $3.",
+       "lastmodifiedatby": "Inin tlahcuilolamatl omopatlac ipan $2, $1 ipan $3.",
        "others": "occequīntīn",
        "siteusers": "$1 {{PLURAL:$2|{{GENDER:$1|tequitiuhqui}}|tequitiuhqueh}} īpan {{SITENAME}}",
        "spam_reverting": "Mocuepacah īhuīc xōcoyōc tlapatlaliztli ahmo tzonhuilizca īhuīc $1",
        "size-megabytes": "$1 MB",
        "size-gigabytes": "$1 GB",
        "watchlistedit-normal-title": "Ticpatlāz motlachiyaliz",
+       "watchlistedit-raw-titles": "Tlahcuilolamameh",
        "watchlistedit-raw-added": "{{PLURAL:$1|Ōmocentili cē zāzanilli|Ōmocentilih $1 zāzaniltin}}:",
+       "watchlistedit-clear-titles": "Tocaitl",
        "watchlisttools-view": "Tiquinttāz huēyi tlapatlaliztli",
        "watchlisttools-edit": "Tiquittāz auh ticpatlāz motlachiyaliz",
        "version": "Machiyōtzin",
        "blankpage": "Iztāc zāzanilli",
        "htmlform-selectorother-other": "Occe",
        "rightsnone": "ahtlein",
+       "feedback-cancel": "Moxitiniz",
        "searchsuggest-search": "Tlatemoliztli",
        "api-error-stashfailed": "Tlâtek îtlakawilistli: In tlatèmakani awel òkeuh in èwalpanòni.",
        "api-error-unknown-warning": "Âmò ìxmatkàyo tlanawatilistli: \"$1\".",
index 5cda7e8..6fe93cb 100644 (file)
        "pt-login-button": "ⴽⵛⵎ",
        "pt-createaccount": "ⵙⵏⴼⵍⵓⵍ ⴰⵎⵉⴹⴰⵏ",
        "pt-userlogout": "ⴼⴼⵖ",
+       "newpassword": "ⵜⴰⴳⵓⵔⵉ ⵏ ⵓⵣⵔⴰⵢ ⵜⴰⵎⴰⵢⵏⵓⵜ",
        "botpasswords-label-create": "ⵙⵏⵓⵍⴼⵓ",
        "botpasswords-label-delete": "ⴽⴽⵙ",
        "passwordreset": "ⵔⴰⵔ ⴷ ⵜⴰⴳⵓⵔⵉ ⵏ ⵓⵣⵔⴰⵢ",
+       "changeemail-newemail": "ⵉⵎⴰⵢⵍ ⴰⵎⴰⵢⵏⵓ:",
        "bold_sample": "ⴰⴹⵔⵉⵙ ⴰⵣⵓⵔⴰⵔ",
        "bold_tip": "ⴰⴹⵔⵉⵙ ⴰⵣⵓⵔⴰⵔ",
        "italic_sample": "ⴰⴹⵔⵉⵙ ⵓⵣⵍⵉⴳ",
index b9a7ccc..7b779a6 100644 (file)
@@ -6,7 +6,7 @@
     "doc": "jsduck",
     "postdoc": "grunt copy:jsduck",
     "selenium": "./tests/selenium/selenium.sh",
-    "selenium-test": "grunt webdriver:test"
+    "selenium-test": "wdio ./tests/selenium/wdio.conf.js"
   },
   "devDependencies": {
     "bluebird": "3.5.1",
@@ -21,7 +21,6 @@
     "grunt-jsonlint": "1.1.0",
     "grunt-karma": "2.0.0",
     "grunt-stylelint": "0.10.0",
-    "grunt-webdriver": "2.0.3",
     "karma": "1.7.1",
     "karma-chrome-launcher": "2.2.0",
     "karma-firefox-launcher": "1.0.1",
index d3e1b65..12a7bf4 100644 (file)
@@ -113,6 +113,20 @@ return [
                ],
        ],
 
+       'jquery.tablesorter.styles' => [
+               'targets' => [ 'desktop', 'mobile' ],
+               'styles' => [
+                       'resources/src/jquery/jquery.tablesorter.styles.less',
+               ],
+       ],
+       'jquery.makeCollapsible.styles' => [
+               'targets' => [ 'desktop', 'mobile' ],
+               'class' => ResourceLoaderLessVarFileModule::class,
+               'styles' => [
+                       'resources/src/jquery/jquery.makeCollapsible.styles.less',
+               ],
+       ],
+
        'mediawiki.skinning.content.parsoid' => [
                // Style Parsoid HTML+RDFa output consistent with wikitext from PHP parser
                // with the interface.css styles; skinStyles should be used if your
@@ -277,6 +291,7 @@ return [
                'scripts' => 'resources/src/jquery/jquery.localize.js',
        ],
        'jquery.makeCollapsible' => [
+               'dependencies' => [ 'jquery.makeCollapsible.styles' ],
                'scripts' => 'resources/src/jquery/jquery.makeCollapsible.js',
                'styles' => 'resources/src/jquery/jquery.makeCollapsible.css',
                'messages' => [ 'collapsible-expand', 'collapsible-collapse' ],
@@ -317,6 +332,7 @@ return [
                'styles' => 'resources/src/jquery/jquery.tablesorter.less',
                'messages' => [ 'sort-descending', 'sort-ascending' ],
                'dependencies' => [
+                       'jquery.tablesorter.styles',
                        'mediawiki.RegExp',
                        'mediawiki.language.months',
                ],
index 6364c70..fc52d51 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * Please do not add any CSS rules here that impact the positioning of the element
+ *  e.g. padding, margin, position or float.
+ * These instead should live in jquery.makeCollapsible.styles
+*/
+
 /* See also jquery.makeCollapsible.js */
 .mw-collapsible-toggle {
        float: right;
 .mw-collapsible-toggle-default:after {
        content: ']';
 }
-/* Align the toggle based on the direction of the content language */
-/* @noflip */
-.mw-content-ltr .mw-collapsible-toggle,
-.mw-content-rtl .mw-content-ltr .mw-collapsible-toggle {
-       float: right;
-}
-/* @noflip */
-.mw-content-rtl .mw-collapsible-toggle,
-.mw-content-ltr .mw-content-rtl .mw-collapsible-toggle {
-       float: left;
-}
 
 .mw-customtoggle,
 .mw-collapsible-toggle {
@@ -37,17 +32,3 @@ caption .mw-collapsible-toggle,
 .mw-content-ltr .mw-content-rtl caption .mw-collapsible-toggle {
        float: none;
 }
-
-/* list-items go as wide as their parent element, don't float them inside list items */
-li .mw-collapsible-toggle,
-.mw-content-ltr li .mw-collapsible-toggle,
-.mw-content-rtl li .mw-collapsible-toggle,
-.mw-content-rtl .mw-content-ltr li .mw-collapsible-toggle,
-.mw-content-ltr .mw-content-rtl li .mw-collapsible-toggle {
-       float: none;
-}
-
-/* the added list item should have no list-style */
-.mw-collapsible-toggle-li {
-       list-style: none;
-}
index 1f40e0a..503e3a6 100644 (file)
@@ -1,5 +1,8 @@
 /**
  * jQuery makeCollapsible
+ * Note: To avoid performance issues such as reflows, several styles are
+ * shipped in mediawiki.makeCollapsible.styles to reserve space for the toggle control. Please
+ * familiarise yourself with that CSS before making any changes to this code.
  *
  * Dual licensed:
  * - CC BY 3.0 <http://creativecommons.org/licenses/by/3.0>
                        if ( $collapsible.data( 'mw-made-collapsible' ) ) {
                                return;
                        } else {
-                               $collapsible.data( 'mw-made-collapsible', true );
+                               // Let CSS know that it no longer needs to worry about flash of unstyled content.
+                               // This will allow mediawiki.makeCollapsible.styles to disable temporary pseudo elements, that
+                               // are needed to avoid a flash of unstyled content.
+                               $collapsible.addClass( 'mw-made-collapsible' )
+                                       .data( 'mw-made-collapsible', true );
                        }
 
                        // Use custom text or default?
diff --git a/resources/src/jquery/jquery.makeCollapsible.styles.less b/resources/src/jquery/jquery.makeCollapsible.styles.less
new file mode 100644 (file)
index 0000000..f19c3c2
--- /dev/null
@@ -0,0 +1,125 @@
+/**
+ * These rules prevent re-flows relating to collapsible on-wiki elements (T42812).
+ * This is done by temporarily creating a pseudo element in the place that JavaScript will insert
+ * a toggle control. The same CSS rules that control the positioning of the toggle control will apply
+ * to the pseudo element. When the JavaScript has executed
+ * (See corresponding non-render blocking CSS in jquery.makeCollapsible)
+ * all pseudo elements will be removed.
+ *
+ * Currently we support all the examples on [[mw:Manual:Collapsible_elements/Demo/Simple]]
+ * All examples on [[mw:Manual:Collapsible_elements/Demo/Advanced]] are supported with the following
+ * exceptions
+ * - Custom collapsible 4 (table-row)
+ * -- CSS selector would be too complicated
+ * - Collapsible div nested in collapsed div
+ * -- Given it's not easy to identify the collapsed content via CSS, text will be shown until
+ *    JavaScript has loaded
+ * - "Combination example"
+ * -- At a later time, we may want to support the use of of `attr`, but given the code
+ *    complexity we will not for the time being (see https://davidwalsh.name/css-content-attr)
+ */
+
+// This selector is used frequently in the code to indicate that the JavaScript has successfully completed
+// it's execution and pseudo elements can be disabled. For readability and maintainability it is separated
+// as a LESS variable.
+@exclude: ~'.mw-made-collapsible';
+
+.client-js {
+
+       ol.mw-collapsible:before,
+       ul.mw-collapsible:before,
+       .mw-collapsible-toggle-li {
+               /*
+               Rather than inherit any margins from the the general li selector - make sure this is explicit
+               to avoid reflows
+               */
+               display: list-item;
+               list-style: none;
+               margin-bottom: 0.1em;
+       }
+
+       // Reset when mw-collapsible-toggle-li is rendered
+       ol.mw-made-collapsible:before,
+       ul.mw-made-collapsible:before {
+               display: none;
+       }
+
+       ol.mw-collapsible:not( @{exclude} ):before,
+       ul.mw-collapsible:not( @{exclude} ):before,
+       // Where the tbody or thead is the first child of the collapsible table
+       table.mw-collapsible:not( @{exclude} ) :first-child tr:first-child th:last-child:before,
+       table.mw-collapsible:not( @{exclude} ) > caption:first-child:after {
+               content: '[@{msg-collapsible-collapse}]';
+       }
+
+       td.mw-collapsed:not( @{exclude} ):before,
+       table.mw-collapsed:not( @{exclude} ) :first-child tr:first-child th:last-child:before,
+       table.mw-collapsed:not( @{exclude} ) > caption:first-child:after,
+       div.mw-collapsed:not( @{exclude} ):before {
+               content: '[@{msg-collapsible-expand}]';
+       }
+
+       // Any element with id beginning `mw-customcollapsible` will have special treatment
+       .mw-collapsible[ id^='mw-customcollapsible' ] th:before,
+       .mw-collapsible[ id^='mw-customcollapsible' ]:before {
+               content: none !important; // stylelint-disable-line declaration-no-important
+       }
+
+       // Special case for table where first child is caption element
+       table.mw-collapsible:not( @{exclude} ) > caption:first-child:after {
+               float: none;
+               display: block;
+       }
+
+       // Use the exclude selector to ensure animations do not break
+       .mw-collapsed:not( @{exclude} ) {
+               // Avoid FOUC/reflows on collapsed elements by making sure they are opened by default (T42812)
+               > p,
+               > table,
+               // Manual:Collapsible_elements/Demo/Simple#Collapsed_by_default
+               > thead + tbody,
+               tr:not( :first-child ),
+               .mw-collapsible-content {
+                       display: none;
+               }
+       }
+}
+
+/* Align the toggle based on the direction of the content language */
+/* @noflip */
+.mw-content-ltr,
+.mw-content-rtl .mw-content-ltr {
+       .mw-collapsible:not( @{exclude} ) th:before,
+       .mw-collapsible:not( @{exclude} ):before,
+       .mw-collapsible-toggle {
+               float: right;
+       }
+}
+
+/* @noflip */
+.mw-content-rtl,
+.mw-content-ltr .mw-content-rtl {
+       .mw-collapsible:not( @{exclude} ) th:before,
+       .mw-collapsible:not( @{exclude} ):before,
+       .mw-collapsible-toggle {
+               float: left;
+       }
+}
+
+/* list-items go as wide as their parent element, don't float them inside list items */
+li,
+.mw-content-ltr li,
+.mw-content-rtl li,
+.mw-content-ltr .mw-content-rtl li,
+.mw-content-rtl .mw-content-ltr li {
+       .mw-collapsible-toggle {
+               float: none;
+       }
+}
+
+// special treatment for list items to match above
+// !important necessary to override overly-specific float left and right above.
+ol.mw-collapsible:not( @{exclude} ):before,
+ul.mw-collapsible:not( @{exclude} ):before {
+       float: none !important; // stylelint-disable-line declaration-no-important
+}
index ce24b0d..3bea471 100644 (file)
@@ -8,7 +8,10 @@ table.jquery-tablesorter {
                cursor: pointer;
                background-repeat: no-repeat;
                background-position: center right;
-               padding-right: 21px;
+               // Note: To avoid reflows, a padding is set in
+               // the jquery.tableSorter.styles module as a render blocking style.
+               // Please do not add any CSS rules here that impact the positioning of the element
+               // e.g. padding, margin, position or float.
        }
 
        th.headerSortUp {
diff --git a/resources/src/jquery/jquery.tablesorter.styles.less b/resources/src/jquery/jquery.tablesorter.styles.less
new file mode 100644 (file)
index 0000000..bd6b5dd
--- /dev/null
@@ -0,0 +1,6 @@
+.client-js {
+       // Reserve space for table sortable controls
+       table.sortable th {
+               padding-right: 21px;
+       }
+}
index 67d6e2c..d81df65 100644 (file)
        };
 
        /**
-        * Returns a function suitable for use as a global, to construct strings from the message key (and optional replacements).
-        * e.g.
+        * Returns a function suitable for static use, to construct strings from a message key (and optional replacements).
+        *
+        * Example:
         *
-        *       window.gM = mediaWiki.jqueryMsg.getMessageFunction( options );
-        *       $( 'p#headline' ).html( gM( 'hello-user', username ) );
+        *       var format = mediaWiki.jqueryMsg.getMessageFunction( options );
+        *       $( '#example' ).text( format( 'hello-user', username ) );
         *
-        * Like the old gM() function this returns only strings, so it destroys any bindings. If you want to preserve bindings use the
-        * jQuery plugin version instead. This is only included for backwards compatibility with gM().
+        * Tthis returns only strings, so it destroys any bindings. If you want to preserve bindings, use the
+        * jQuery plugin version instead. This was originally created to ease migration from `window.gM()`,
+        * from a time when the parser used by `mw.message` was not extendable.
         *
         * N.B. replacements are variadic arguments or an array in second parameter. In other words:
         *    somefunction( a, b, c, d )
         *    somefunction( a, [b, c, d] )
         *
         * @param {Object} options parser options
-        * @return {Function} Function suitable for assigning to window.gM
+        * @return {Function} Function The message formatter
         * @return {string} return.key Message key.
         * @return {Array|Mixed} return.replacements Optional variable replacements (variadically or an array).
         * @return {string} return.return Rendered HTML.
                }
        };
 
-       // Deprecated! don't rely on gM existing.
-       // The window.gM ought not to be required - or if required, not required here.
-       // But moving it to extensions breaks it (?!)
-       // Need to fix plugin so it could do attributes as well, then will be okay to remove this.
-       // @deprecated since 1.23
-       mw.log.deprecate( window, 'gM', mw.jqueryMsg.getMessageFunction(), 'Use mw.message( ... ).parse() instead.' );
-
        /**
         * @method
         * @member jQuery
index 7c99614..5a554a0 100644 (file)
@@ -57,19 +57,59 @@ class LanguageCrhTest extends LanguageClassesTestCase {
                        ],
                        [ // recent problem words, part 1
                                [
-                                       'crh'      => 'künü куню sürgünligi сюргюнлиги özü озю etti этти',
-                                       'crh-cyrl' => 'куню куню сюргюнлиги сюргюнлиги озю озю этти этти',
-                                       'crh-latn' => 'künü künü sürgünligi sürgünligi özü özü etti etti',
+                                       'crh'      => 'künü куню sürgünligi сюргюнлиги özü озю etti этти esas эсас dört дёрт',
+                                       'crh-cyrl' => 'куню куню сюргюнлиги сюргюнлиги озю озю этти этти эсас эсас дёрт дёрт',
+                                       'crh-latn' => 'künü künü sürgünligi sürgünligi özü özü etti etti esas esas dört dört',
                                ],
-                               'künü куню sürgünligi сюргюнлиги özü озю etti этти'
+                               'künü куню sürgünligi сюргюнлиги özü озю etti этти esas эсас dört дёрт'
                        ],
                        [ // recent problem words, part 2
                                [
-                                       'crh'      => 'esas эсас dört дёрт keldi кельди',
-                                       'crh-cyrl' => 'эсас эсас дёрт дёрт кельди кельди',
-                                       'crh-latn' => 'esas esas dört dört keldi keldi',
+                                       'crh'      => 'keldi кельди km² км² yüz юзь AQŞ АКъШ ŞSCBnen ШСДжБнен iyül июль',
+                                       'crh-cyrl' => 'кельди кельди км² км² юзь юзь АКъШ АКъШ ШСДжБнен ШСДжБнен июль июль',
+                                       'crh-latn' => 'keldi keldi km² km² yüz yüz AQŞ AQŞ ŞSCBnen ŞSCBnen iyül iyül',
                                ],
-                               'esas эсас dört дёрт keldi кельди'
+                               'keldi кельди km² км² yüz юзь AQŞ АКъШ ŞSCBnen ШСДжБнен iyül июль'
+                       ],
+                       [ // recent problem words, part 3
+                               [
+                                       'crh'      => 'işğal ишгъаль işğalcilerine ишгъальджилерине rayon район üst усть',
+                                       'crh-cyrl' => 'ишгъаль ишгъаль ишгъальджилерине ишгъальджилерине район район усть усть',
+                                       'crh-latn' => 'işğal işğal işğalcilerine işğalcilerine rayon rayon üst üst',
+                               ],
+                               'işğal ишгъаль işğalcilerine ишгъальджилерине rayon район üst усть'
+                       ],
+                       [ // recent problem words, part 4
+                               [
+                                       'crh'      => 'rayonınıñ районынынъ Noğay Ногъай Yürtü Юрьтю vatandan ватандан',
+                                       'crh-cyrl' => 'районынынъ районынынъ Ногъай Ногъай Юрьтю Юрьтю ватандан ватандан',
+                                       'crh-latn' => 'rayonınıñ rayonınıñ Noğay Noğay Yürtü Yürtü vatandan vatandan',
+                               ],
+                               'rayonınıñ районынынъ Noğay Ногъай Yürtü Юрьтю vatandan ватандан'
+                       ],
+                       [ // recent problem words, part 5
+                               [
+                                       'crh'      => 'ком-кок köm-kök rol роль AQQI АКЪКЪЫ DAĞĞA ДАГЪГЪА 13-ünci 13-юнджи',
+                                       'crh-cyrl' => 'ком-кок ком-кок роль роль АКЪКЪЫ АКЪКЪЫ ДАГЪГЪА ДАГЪГЪА 13-юнджи 13-юнджи',
+                                       'crh-latn' => 'köm-kök köm-kök rol rol AQQI AQQI DAĞĞA DAĞĞA 13-ünci 13-ünci',
+                               ],
+                               'ком-кок köm-kök rol роль AQQI АКЪКЪЫ DAĞĞA ДАГЪГЪА 13-ünci 13-юнджи'
+                       ],
+                       [ // recent problem words, part 6
+                               [
+                                       'crh'      => 'ДЖУРЬМЕК CÜRMEK кетсин ketsin джумлеси cümlesi ильи ilyi Ильи İlyi',
+                                       'crh-cyrl' => 'ДЖУРЬМЕК ДЖУРЬМЕК кетсин кетсин джумлеси джумлеси ильи ильи Ильи Ильи',
+                                       'crh-latn' => 'CÜRMEK CÜRMEK ketsin ketsin cümlesi cümlesi ilyi ilyi İlyi İlyi',
+                               ],
+                               'ДЖУРЬМЕК CÜRMEK кетсин ketsin джумлеси cümlesi ильи ilyi Ильи İlyi'
+                       ],
+                       [ // regex pattern words
+                               [
+                                       'crh'      => 'köyünden коюнден ange аньге',
+                                       'crh-cyrl' => 'коюнден коюнден аньге аньге',
+                                       'crh-latn' => 'köyünden köyünden ange ange',
+                               ],
+                               'köyünden коюнден ange аньге'
                        ],
                        [ // multi part words
                                [
@@ -79,13 +119,61 @@ class LanguageCrhTest extends LanguageClassesTestCase {
                                ],
                                'эки юз eki yüz'
                        ],
-                       [ // ALL CAPS, made up acronyms (not 100% sure these are correct)
+                       [ // affix patterns
                                [
-                                       'crh'      => 'ÑAB QIC ĞUK COT НЪАБ КЪЫДж ГЪУК ДЖОТ CA ДЖА',
-                                       'crh-cyrl' => 'НЪАБ КЪЫДж ГЪУК ДЖОТ НЪАБ КЪЫДж ГЪУК ДЖОТ ДЖА ДЖА',
+                                       'crh'      => 'köyniñ койнинъ Avcıköyde Авджыкойде ekvatorial экваториаль Canköy Джанкой',
+                                       'crh-cyrl' => 'койнинъ койнинъ Авджыкойде Авджыкойде экваториаль экваториаль Джанкой Джанкой',
+                                       'crh-latn' => 'köyniñ köyniñ Avcıköyde Avcıköyde ekvatorial ekvatorial Canköy Canköy',
+                               ],
+                               'köyniñ койнинъ Avcıköyde Авджыкойде ekvatorial экваториаль Canköy Джанкой'
+                       ],
+                       [ // Roman numerals and quotes, esp. single-letter Roman numerals at the end of a string
+                               [
+                                       'crh'      => 'VI,VII IX “dört” «дёрт» XI XII I V X L C D M',
+                                       'crh-cyrl' => 'VI,VII IX «дёрт» «дёрт» XI XII I V X L C D M',
+                                       'crh-latn' => 'VI,VII IX “dört” "dört" XI XII I V X L C D M',
+                               ],
+                               'VI,VII IX “dört” «дёрт» XI XII I V X L C D M'
+                       ],
+                       [ // Roman numerals vs Initials, part 1 - Roman numeral initials without spaces
+                               [
+                                       'crh'      => 'A.B.C.D.M. Qadırova XII, А.Б.Дж.Д.М. Къадырова XII',
+                                       'crh-cyrl' => 'А.Б.Дж.Д.М. Къадырова XII, А.Б.Дж.Д.М. Къадырова XII',
+                                       'crh-latn' => 'A.B.C.D.M. Qadırova XII, A.B.C.D.M. Qadırova XII',
+                               ],
+                               'A.B.C.D.M. Qadırova XII, А.Б.Дж.Д.М. Къадырова XII'
+                       ],
+                       [ // Roman numerals vs Initials, part 2 - Roman numeral initials with spaces
+                               [
+                                       'crh'      => 'G. H. I. V. X. L. Memetov III, Г. Х. Ы. В. X. Л. Меметов III',
+                                       'crh-cyrl' => 'Г. Х. Ы. В. X. Л. Меметов III, Г. Х. Ы. В. X. Л. Меметов III',
+                                       'crh-latn' => 'G. H. I. V. X. L. Memetov III, G. H. I. V. X. L. Memetov III',
+                               ],
+                               'G. H. I. V. X. L. Memetov III, Г. Х. Ы. В. X. Л. Меметов III'
+                       ],
+                       [ // ALL CAPS, made up acronyms
+                               [
+                                       'crh'      => 'ÑAB QIC ĞUK COT НЪАБ КЪЫДЖ ГЪУК ДЖОТ CA ДЖА',
+                                       'crh-cyrl' => 'НЪАБ КЪЫДЖ ГЪУК ДЖОТ НЪАБ КЪЫДЖ ГЪУК ДЖОТ ДЖА ДЖА',
                                        'crh-latn' => 'ÑAB QIC ĞUK COT ÑAB QIC ĞUK COT CA CA',
                                ],
-                               'ÑAB QIC ĞUK COT НЪАБ КЪЫДж ГЪУК ДЖОТ CA ДЖА'
+                               'ÑAB QIC ĞUK COT НЪАБ КЪЫДЖ ГЪУК ДЖОТ CA ДЖА'
+                       ],
+                       [ // Many-to-one mappings: many Cyrillic to one Latin
+                               [
+                                       'crh'      => 'шофер шофёр şoför корбекул корьбекул корьбекуль körbekül',
+                                       'crh-cyrl' => 'шофер шофёр шофёр корбекул корьбекул корьбекуль корьбекуль',
+                                       'crh-latn' => 'şoför şoför şoför körbekül körbekül körbekül körbekül',
+                               ],
+                               'шофер шофёр şoför корбекул корьбекул корьбекуль körbekül'
+                       ],
+                       [ // Many-to-one mappings: many Latin to one Cyrillic
+                               [
+                                       'crh'      => 'fevqülade fevqulade февкъульаде beyude beyüde бейуде',
+                                       'crh-cyrl' => 'февкъульаде февкъульаде февкъульаде бейуде бейуде бейуде',
+                                       'crh-latn' => 'fevqülade fevqulade fevqulade beyude beyüde beyüde',
+                               ],
+                               'fevqülade fevqulade февкъульаде beyude beyüde бейуде'
                        ],
                ];
        }
index 0653dfd..71362fd 100644 (file)
        } );
 
        QUnit.test( 'Integration', function ( assert ) {
-               var expected, logSpy, msg;
+               var expected, msg;
 
                expected = '<b><a title="Bold" href="/wiki/Bold">Bold</a>!</b>';
                mw.messages.set( 'integration-test', '<b>[[Bold]]!</b>' );
 
-               this.suppressWarnings();
-               logSpy = this.sandbox.spy( mw.log, 'warn' );
-               assert.equal(
-                       window.gM( 'integration-test' ),
-                       expected,
-                       'Global function gM() works correctly'
-               );
-               assert.equal( logSpy.callCount, 1, 'mw.log.warn called' );
-               this.restoreWarnings();
-
                assert.equal(
                        mw.message( 'integration-test' ).parse(),
                        expected,
index 85fc310..e39226c 100644 (file)
@@ -9,6 +9,6 @@
                "browser": false
        },
        "rules":{
-               "no-console":0
+               "no-console": 0
        }
 }
index b15d407..274eb14 100644 (file)
@@ -5,9 +5,8 @@
 - [Chrome](https://www.google.com/chrome/)
 - [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/)
 - [Node.js](https://nodejs.org/en/)
-- [MediaWiki-Vagrant](https://www.mediawiki.org/wiki/MediaWiki-Vagrant)
 
-Set up MediaWiki-Vagrant:
+If using MediaWiki-Vagrant:
 
     cd mediawiki/vagrant
     vagrant up
@@ -24,7 +23,7 @@ Set up MediaWiki-Vagrant:
 By default, Chrome will run in headless mode. If you want to see Chrome, set DISPLAY
 environment variable to any value:
 
-    DISPLAY=:1 npm run selenium
+    DISPLAY=1 npm run selenium
 
 To run only one file (for example page.js), you first need to spawn the chromedriver:
 
index 6b71019..4a5c254 100755 (executable)
@@ -1,5 +1,8 @@
 #!/usr/bin/env bash
 set -euo pipefail
+# Check the command before running in background so
+# that it can actually fail and have a descriptive error
+hash chromedriver
 chromedriver --url-base=/wd/hub --port=4444 &
 # Make sure it is killed to prevent file descriptors leak
 function kill_chromedriver() {