src/transformer.js
function _replaceLanguageTags( doc, survey ) {
    const map = {};

    const languageElements = doc.find( '/root/form/select[@id="form-languages"]/option' );

    // List of parsed language objects
    const languages = languageElements.map( el => {
        const lang = el.text();
        return language.parse( lang, _getLanguageSampleText( doc, lang ) );
    } );

    // forms without itext and only one language, still need directionality info
    if ( languages.length === 0 ) {
        languages.push( language.parse( '', _getLanguageSampleText( doc, '' ) ) );
    }

    // add or correct dir and value attributes, and amend textcontent of options in language selector
    languageElements.forEach( ( el, index ) => {
        const val = el.attr( 'value' ).value();
        if ( val && val !== languages[ index ].tag ) {
            map[ val ] = languages[ index ].tag;
        }
        el.attr( {
            'data-dir': languages[ index ].dir,
            'value': languages[ index ].tag
        } ).text( languages[ index ].desc );
    } );

    // correct lang attributes
    languages.forEach( lang => {
        if ( lang.src === lang.tag ) {
            return;
        }
        doc.find( `/root/form//*[@lang="${lang.src}"]` ).forEach( el => {
            el.attr( {
                lang: lang.tag
            } );
        } );
    } );

    // correct default lang attribute
    const langSelectorElement = doc.get( '/root/form/*[@data-default-lang]' );
    if ( langSelectorElement ) {
        const defaultLang = langSelectorElement.attr( 'data-default-lang' ).value();
        languages.some( lang => {
            if ( lang.src === defaultLang ) {
                langSelectorElement.attr( {
                    'data-default-lang': lang.tag
                } );
                return true;
            }
            return false;
        } );
    }

    survey.languageMap = map;
    return doc;
}
function _replaceLanguageTags( doc, survey ) {
    const map = {};

    const languageElements = doc.find( '/root/form/select[@id="form-languages"]/option' );

    // List of parsed language objects
    const languages = languageElements.map( el => {
        const lang = el.text();
        return language.parse( lang, _getLanguageSampleText( doc, lang ) );
    } );

    // forms without itext and only one language, still need directionality info
    if ( languages.length === 0 ) {
        languages.push( language.parse( '', _getLanguageSampleText( doc, '' ) ) );
    }

    // add or correct dir and value attributes, and amend textcontent of options in language selector
    languageElements.forEach( ( el, index ) => {
        const val = el.attr( 'value' ).value();
        if ( val && val !== languages[ index ].tag ) {
            map[ val ] = languages[ index ].tag;
        }
        el.attr( {
            'data-dir': languages[ index ].dir,
            'value': languages[ index ].tag
        } ).text( languages[ index ].desc );
    } );

    // correct lang attributes
    languages.forEach( lang => {
        if ( lang.src === lang.tag ) {
            return;
        }
        doc.find( `/root/form//*[@lang="${lang.src}"]` ).forEach( el => {
            el.attr( {
                lang: lang.tag
            } );
        } );
    } );

    // correct default lang attribute
    const langSelectorElement = doc.get( '/root/form/*[@data-default-lang]' );
    if ( langSelectorElement ) {
        const defaultLang = langSelectorElement.attr( 'data-default-lang' ).value();
        languages.some( lang => {
            if ( lang.src === defaultLang ) {
                langSelectorElement.attr( {
                    'data-default-lang': lang.tag
                } );
                return true;
            }
            return false;
        } );
    }

    survey.languageMap = map;
    return doc;
}
function _replaceLanguageTags ( doc , survey ) { const map = { } ; const languageElements = doc . find ( '/root/form/select[@id="form-languages"]/option' ) ; // List of parsed language objects const languages = languageElements . map ( el => { const lang = el . text ( ) ; return language . parse ( lang , _getLanguageSampleText ( doc , lang ) ) ; } ) ; // forms without itext and only one language, still need directionality info if ( languages . length === 0 ) { languages . push ( language . parse ( '' , _getLanguageSampleText ( doc , '' ) ) ) ; } // add or correct dir and value attributes, and amend textcontent of options in language selector languageElements . forEach ( ( el , index ) => { const val = el . attr ( 'value' ) . value ( ) ; if ( val && val !== languages [ index ] . tag ) { map [ val ] = languages [ index ] . tag ; } el . attr ( { 'data-dir' : languages [ index ] . dir , 'value' : languages [ index ] . tag } ) . text ( languages [ index ] . desc ) ; } ) ; // correct lang attributes languages . forEach ( lang => { if ( lang . src === lang . tag ) { return ; } doc . find ( ` ${ lang . src } ` ) . forEach ( el => { el . attr ( { lang : lang . tag } ) ; } ) ; } ) ; // correct default lang attribute const langSelectorElement = doc . get ( '/root/form/*[@data-default-lang]' ) ; if ( langSelectorElement ) { const defaultLang = langSelectorElement . attr ( 'data-default-lang' ) . value ( ) ; languages . some ( lang => { if ( lang . src === defaultLang ) { langSelectorElement . attr ( { 'data-default-lang' : lang . tag } ) ; return true ; } return false ; } ) ; } survey . languageMap = map ; return doc ; }
Replaces all lang attributes to the valid IANA tag if found.
Also add the dir attribute to the languages in the language selector.

@see  http://www.w3.org/International/questions/qa-choosing-language-tags

@param  {[type]} doc libxmljs object
@return {[type]}     libxmljs object
Replaces all lang attributes to the valid IANA tag if found . Also add the dir attribute to the languages in the language selector .