User:Jon Harald Søby/ordbøkenetools
These are the main tools I use to help me create lexemes in Norwegian Bokmål (nb
) and Norwegian Nynorsk (nn
) using Ordbøkene.no as a source. The main tool, of course, is Wikidata Lexeme Forms, but I have written some scripts to help me pre-fill the forms in Lexeme Forms, which – while pretty specific for Norwegian – may serve as inspiration for those who wish to do something similar for other languages.
User scripts
[edit]Nikki scripts
[edit]I use Nikki's excellent scripts LexemeEntitySuggester.js, LexemeAddIPA.js and LexemeInterwikiLinks.js, in addition to the improved KeyShortcuts.js. My settings for these in my common.js are as follows:
// [[User:Nikki/KeyShortcuts.js]]
mw.loader.load( "//www.wikidata.org/w/index.php?title=User:Nikki/KeyShortcuts.js&action=raw&ctype=text/javascript" );
// [[User:Nikki/LexemeEntitySuggester.js]]
mw.loader.load( "//www.wikidata.org/w/index.php?title=User:Nikki/LexemeEntitySuggester.js&action=raw&ctype=text/javascript" );
// [[User:Nikki/LexemeAddIPA.js]]
addipa_p5237 = { "Q25167": "Q6457972" };
addipa_alwaysshown = true;
mw.loader.load("//www.wikidata.org/w/index.php?title=User:Nikki/LexemeAddIPA.js&action=raw&ctype=text/javascript");
// [[User:Nikki/LexemeInterwikiLinks.js]]
mw.loader.load("//www.wikidata.org/w/index.php?title=User:Nikki/LexemeInterwikiLinks.js&action=raw&ctype=text/javascript");
In addition, I made my own "extension" to the Add IPA script which validates and simplifies input for IPA:
function JHSipa() {
var $ipas = $(".addipa-ipa-input input"),
$firstIpa = $ipas.first(),
allchanged = false;
setTimeout( function() { $firstIpa.focus(); }, 100 );
$firstIpa.change( function() {
if ( !allchanged ) {
$(".addipa-ipa-input input:not(:first)").val($firstIpa.val().split("¦")[0].replace(/\/$/, "") );
allchanged = true;
}
}).blur( function() {
$( this ).val( $( this ).val().replace("¦", "") );
});
$(".addipa-ipa-input input:not(:first)").focus( function() {
var that = this;
var strlen = $( this ).val().length;
setTimeout( function() {
that.setSelectionRange( strlen, strlen );
}, 0);
}).blur( function() {
$( this ).val( $( this ).val().replace( /[ˈ²]?(.*)([ˈ²])$/, "$2$1" ) );
if ( !( $( this ).val().includes(".") ) ) {
$( this ).val( $( this ).val().replace(/[ˈ²]/, "") );
}
});
$ipas.blur( function() {
if ( /([:\'agrv]|[eioyø][\u0300\u0302][^ː]|[əɛɪɔʏœ]ː|^(?=.*\.)(?!.*[ˈ²]).*$|^(?!.*\.)(?=.*[ˈ²]).*$)/.test( $( this ).val() ) ) {
$( this ).css( { "background": "pink", "transition": "all 0.5s" } );
} else {
$( this ).css( "background", "#fff" );
}
var valsplit = $( this ).val().split( "¦" );
if ( valsplit.length > 2 ) {
var ret = [];
for ( var i = 1; i < valsplit.length; i++ ) {
ret.push( valsplit[ 0 ] + valsplit[ i ] );
}
$( this ).val( ret.join( "|" ) );
}
});
$ipas.last().blur( function() {
$ipas.each( function() {
var val = $( this ).val(),
altreg = /\[(.)(.)\]/;
if ( altreg.test( val ) ) {
val = val.replace( altreg, '$1' ) + '|' + val.replace( altreg, '$2' );
}
val = val.replace( /(^(?!\/)|(?<!\/)$)/g, "/" ).replaceAll( "|", "/|/" ).replaceAll( "//", "/" ).replace( /^\/$/, "" );
// exchange ˈ and ² with proper IPA
let oldvals = val.split( '|' ),
newvals = [];
for ( let vall of oldvals ) {
if ( ( vall.includes( 'ˈ' ) || vall.includes( '²' ) ) && !vall.includes( '̀' ) && !vall.includes( '̂' ) ) {
const vowel = /([eiouyæøɑɛəɪɔʉʏœ])/,
toneme1 = '̀', // U+0300
toneme2 = '̂'; // U+0302
let split = vall.split( /[ˈ²]/ ),
change = split[ 1 ],
joiner = '';
if ( vall.includes( 'ˈ' ) && !vall.includes( toneme1 ) && !vall.includes( toneme2 ) ) {
change = change.replace( vowel, '$1' + toneme1 );
joiner = 'ˈ';
} else if ( vall.includes( '²' ) ) {
change = change.replace( vowel, '$1' + toneme2 );
joiner = 'ˈ';
}
vall = split[ 0 ] + joiner + change;
}
newvals.push( vall );
}
val = newvals.join( '|' );
$( this ).val( val );
$( this ).change();
});
});
}
mw.hook("addipa-dialog-opened").add(JHSipa);
My own scripts
[edit]copySenses.js lets you copy senses from one lexeme to another. You can either copy all senses, by using just a lexeme ID (like L12345), or copy a single sense by using a sense ID (like L12345-S6). Include it with:
// [[User:Jon Harald Søby/ordbokIframe.js]]
// Remove the two slashes from the next line to make the script not add translation (P5972) statements when copying senses:
// mw.config.set( 'userjs-copysenses-excludetranslations', true );
mw.loader.load( '//www.wikidata.org/w/index.php?title=User:Jon_Harald_Søby/ordbokIframe.js&action=raw&ctype=text/javascript' );
ordbokIframe.js adds an iframe with the contents of Ordbøkene's entry/entries for the current lemma on the right-hand side of lexeme pages. Include it with:
// [[User:Jon Harald Søby/ordbokIframe.js]]
mw.loader.load( '//www.wikidata.org/w/index.php?title=User:Jon_Harald_Søby/ordbokIframe.js&action=raw&ctype=text/javascript' );
bøyningsklasse.js (based on Nikki's LexemeP31Menu.js) adds convenient links for statements I add often, especially paradigm class (P5911)). Include it with:
// [[User:Jon Harald Søby/bøyningsklasse.js]]
mw.loader.load( '//www.wikidata.org/w/index.php?title=User:Jon_Harald_Søby/bøyningsklasse.js&action=raw&ctype=text/javascript' );
hashStatements.js will add statements automatically when they are specified with hashes in the URL, separated with pipes. This can efficiently be used with Lexeme Forms' "target_hash" URL parameter. This script works for all item types, not only lexemes, though my main use for it is for lexemes. If you enable this script and visit https://www.wikidata.org/wiki/Q4115189#P31:Q5|P10042:50077
, it will automatically add instance of (P31)human (Q5) and Bokmålsordboka-ID (P10042)50077 to Wikidata Sandbox (Q4115189).
Include it with:
// [[User:Jon Harald Søby/hashStatements.js]]
mw.loader.load( '//www.wikidata.org/w/index.php?title=User:Jon_Harald_Søby/hashStatements.js&action=raw&ctype=text/javascript' );
Violentmonkey scripts
[edit]I use Violentmonkey in Firefox, which is a Greasemonkey fork. These scripts will probably work in Greasemonkey too, but may need some small adjustments, though I haven't tested that.
Add Lexeme Forms links to Ordbøkene.no
[edit]This script adds pre-filled links for the lemmas directly in Ordbøkene.no. So if you search for a word there, all you have to do is click the lemma to create a lexeme for it (and Lexeme Forms itself will tell you if it already exists or not).
// ==UserScript==
// @name Ordbøkene + Lexeme-Forms
// @namespace Violentmonkey Scripts
// @include https://ordbokene.no/*
// @grant unsafeWindow
// @version 2.4 (2024-08-20)
// @author Jon Harald Søby
// @description 22.12.2021, 15:25:31
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.js
// ==/UserScript==
// jshint esversion: 8
$( 'html' ).css( 'font-size', '12px' );
const inflectionclasses = {
'm1': 'Q97097665',
'm2': 'Q97097666',
'm3': 'Q97097667',
'f1': 'Q97097668',
'f2': 'Q97097669',
'f3': 'Q97097670',
'n1': 'Q97097671',
'n2': 'Q97097672',
'n3': 'Q97097673',
'a1': 'Q97097692',
'a2': 'Q97097693',
'a3': 'Q97097694',
'a4': 'Q97097695',
'a5': 'Q97097697',
'v1': 'Q97097688',
'v2': 'Q97097689',
'v3': 'Q97097690',
'v4': 'Q97097691'
};
const lexemeforms = {
'bm': {
'noun-m': 'https://lexeme-forms.toolforge.org/template/bokmål-noun-masculine/',
'noun-f': 'https://lexeme-forms.toolforge.org/template/bokmål-noun-feminine/',
'noun-n': 'https://lexeme-forms.toolforge.org/template/bokmål-noun-neuter/',
'noun-mn': 'https://lexeme-forms.toolforge.org/template/bokmål-noun-masculine-neuter/',
'adj': 'https://lexeme-forms.toolforge.org/template/bokmål-adjective/',
'verb': 'https://lexeme-forms.toolforge.org/template/bokmål-verb/',
'verb-s': 'https://lexeme-forms.toolforge.org/template/bokmål-verb-passive/',
'interj': 'https://lexeme-forms.toolforge.org/template/bokmål-interjection/',
'adv': 'https://lexeme-forms.toolforge.org/template/bokmål-adverb/',
'DEFAULT': 'https://www.wikidata.org/wiki/Special:NewLexeme?lexeme-language=Q25167'
},
'nn': {
'noun-m': 'https://lexeme-forms.toolforge.org/template/nynorsk-noun-masculine/',
'noun-f': 'https://lexeme-forms.toolforge.org/template/nynorsk-noun-feminine/',
'noun-n': 'https://lexeme-forms.toolforge.org/template/nynorsk-noun-neuter/',
'noun-fm': 'https://lexeme-forms.toolforge.org/template/nynorsk-noun-feminine-masculine/',
'noun-fn': 'https://lexeme-forms.toolforge.org/template/nynorsk-noun-feminine-neuter/',
'noun-mn': 'https://lexeme-forms.toolforge.org/template/nynorsk-noun-masculine-neuter/',
'adj': 'https://lexeme-forms.toolforge.org/template/nynorsk-adjective/',
'verb': 'https://lexeme-forms.toolforge.org/template/nynorsk-verb/',
'verb-s': 'https://lexeme-forms.toolforge.org/template/nynorsk-verb-passive/',
'interj': 'https://lexeme-forms.toolforge.org/template/nynorsk-interjection/',
'adv': 'https://lexeme-forms.toolforge.org/template/nynorsk-adverb/',
'DEFAULT': 'https://www.wikidata.org/wiki/Special:NewLexeme?lexeme-language=Q25164'
}
};
const nonLexemeformsCategories = {
'ADP': 'Q4833830',
'CCONJ': 'Q36484',
'DET': 'Q576271',
'EXPR': 'Q187931',
'NOUN_uninfl': 'Q1084',
'PFX': 'Q134830',
'PRON': 'Q36224',
'SCONJ': 'Q11655558'
}
async function fetchOda( lang, oid ) {
const oda = await fetch( 'https://oda.uib.no/opal/prod/' + lang + '/article/' + oid + '.json')
.then( ( response ) => response.json() )
.then( ( data ) => data );
return oda;
}
async function processOda( lang, oid ) {
let oda = await fetchOda( lang, oid ),
lemmas = {},
idprop = 'bm' === lang ? 'P10042' : 'P10041',
copylemmas = {};
for ( let l of oda.lemmas ) {
let lemma = l.lemma;
lemmas[ lemma ] = {
'id': oda.article_id,
'statements': [],
'forms': [],
'lexemeform': 'DEFAULT',
'urlsuffix': '?generated_via=[[User:Jon Harald Søby/ordbøkenetools|ordbøkenetools]]'
};
lemmas[ lemma ].statements.push( idprop + ':' + oda.article_id );
let inflectionclass = ( l.hasOwnProperty( 'inflection_class' ) && l.inflection_class ) ? l.inflection_class.split( ',' ) : [];
inflectionclass.map( x => x.trim() );
let iclassstatement = [];
for ( let iclass of inflectionclass ) {
if ( inflectionclasses.hasOwnProperty( iclass ) ) {
iclassstatement.push( 'P5911:' + inflectionclasses[ iclass ] );
} else if ( inflectionclass.includes( 'verb' ) ) {
iclassstatement = [ 'P31:Q70235' ];
break;
} else {
iclassstatement = null;
break;
}
}
if ( iclassstatement ) {
lemmas[ lemma ].statements = lemmas[ lemma ].statements.concat( iclassstatement );
}
let inflection_group = new Set(),
paradigmtags = new Set(),
maintag;
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
for ( let tag of paradigm.tags ) {
paradigmtags.add( tag );
if ( /^[A-Z]+$/.test( tag ) ) {
maintag = tag;
}
}
inflection_group.add( paradigm.inflection_group );
if ( paradigm.inflection_group === 'NOUN_uninfl' ) {
maintag = 'NOUN_uninfl';
}
}
paradigmtags.delete( '<Ord>' );
inflection_group = [...inflection_group];
paradigmtags = [...paradigmtags];
let cont = true;
if ( paradigmtags.length > 3 ) {
lemmas[ lemma ].forms = [ lemma ];
cont = false;
}
if ( cont && paradigmtags.length === 3 ) {
if (
lang === 'bm' &&
maintag === 'NOUN' &&
paradigmtags.includes( 'Masc' ) &&
paradigmtags.includes( 'Fem' )
) {
lemmas[ lemma ].lexemeform = 'noun-f';
let mascforms = [ ...new Array( 4 ) ].map( () => new Set() );
let femforms = [ ...new Array( 4 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
if ( paradigm.tags.includes( 'Masc' ) ) {
for ( let form in paradigm.inflection ) {
mascforms[ form ].add( paradigm.inflection[ form ].word_form );
}
} else if ( paradigm.tags.includes( 'Fem' ) ) {
for ( let form in paradigm.inflection ) {
femforms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
}
mascforms = mascforms.map( x => [ ...x ].join( '/' ) );
femforms = femforms.map( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = [ mascforms[ 0 ], femforms[ 1 ], mascforms[ 1 ], mascforms[ 2 ], mascforms[ 3 ] ];
} else if (
lang === 'bm' &&
maintag === 'NOUN' &&
paradigmtags.includes( 'Masc' ) &&
paradigmtags.includes( 'Neuter' )
) {
lemmas[ lemma ].lexemeform = 'noun-mn';
let mascforms = [ ...new Array( 4 ) ].map( () => new Set() );
let neutforms = [ ...new Array( 4 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
if ( paradigm.tags.includes( 'Masc' ) ) {
for ( let form in paradigm.inflection ) {
mascforms[ form ].add( paradigm.inflection[ form ].word_form );
}
} else if ( paradigm.tags.includes( 'Neuter' ) ) {
for ( let form in paradigm.inflection ) {
neutforms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
}
mascforms = mascforms.map( x => [ ...x ].join( '/' ) );
neutforms = neutforms.map ( x => [ ...x ].join( '/' ) );
let forms = [];
forms.push( mascforms[ 0 ], mascforms[ 1 ] );
forms.push( neutforms[ 1 ] );
forms.push( mascforms[ 2 ] );
if ( neutforms[ 2 ] === mascforms[ 2 ] ) {
forms.push( '' );
} else {
forms.push( neutforms[ 2 ] );
}
forms.push( mascforms[ 3 ] );
let defneutpl = neutforms[ 3 ].split( '/' );
for ( let f of defneutpl ) {
if ( f !== mascforms[ 3 ] ) {
forms.push( f );
}
}
lemmas[ lemma ].forms = forms;
} else if (
lang === 'nn' &&
maintag === 'NOUN' &&
paradigmtags.includes( 'Fem' ) &&
paradigmtags.includes( 'Masc' )
) {
lemmas[ lemma ].lexemeform = 'noun-fm';
let femforms = [ ...new Array( 4 ) ].map( () => new Set() );
let mascforms = [ ...new Array( 4 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
if ( paradigm.tags.includes( 'Masc' ) ) {
for ( let form in paradigm.inflection ) {
mascforms[ form ].add( paradigm.inflection[ form ].word_form );
}
} else if ( paradigm.tags.includes( 'Fem' ) ) {
for ( let form in paradigm.inflection ) {
femforms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
}
femforms = femforms.map( x => [ ...x ].join( '/' ) );
mascforms = mascforms.map ( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = [ femforms[ 0 ], femforms[ 1 ], mascforms[ 1 ], femforms[ 2 ], mascforms[ 2 ], femforms[ 3 ], mascforms[ 3 ] ];
} else if (
lang === 'nn' &&
maintag === 'NOUN' &&
paradigmtags.includes( 'Fem' ) &&
paradigmtags.includes( 'Neuter' )
) {
lemmas[ lemma ].lexemeform = 'noun-fn';
let femforms = [ ...new Array( 4 ) ].map( () => new Set() );
let neutforms = [ ...new Array( 4 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
if ( paradigm.tags.includes( 'Fem' ) ) {
for ( let form in paradigm.inflection ) {
femforms[ form ].add( paradigm.inflection[ form ].word_form );
}
} else if ( paradigm.tags.includes( 'Neuter' ) ) {
for ( let form in paradigm.inflection ) {
neutforms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
}
femforms = femforms.map( x => [ ...x ].join( '/' ) );
neutforms = neutforms.map ( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = [ femforms[ 0 ], femforms[ 1 ], neutforms[ 1 ], femforms[ 2 ], neutforms[ 2 ], femforms[ 3 ], neutforms[ 3 ] ];
} else if (
lang === 'nn' &&
maintag === 'NOUN' &&
paradigmtags.includes( 'Masc' ) &&
paradigmtags.includes( 'Neuter' )
) {
lemmas[ lemma ].lexemeform = 'noun-mn';
let mascforms = [ ...new Array( 4 ) ].map( () => new Set() );
let neutforms = [ ...new Array( 4 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
if ( paradigm.tags.includes( 'Masc' ) ) {
for ( let form in paradigm.inflection ) {
mascforms[ form ].add( paradigm.inflection[ form ].word_form );
}
} else if ( paradigm.tags.includes( 'Neuter' ) ) {
for ( let form in paradigm.inflection ) {
neutforms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
}
mascforms = mascforms.map( x => [ ...x ].join( '/' ) );
neutforms = neutforms.map ( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = [ mascforms[ 0 ], mascforms[ 1 ], neutforms[ 1 ], mascforms[ 2 ], neutforms[ 2 ], mascforms[ 3 ], neutforms[ 3 ] ];
}
} else if ( cont && paradigmtags.length === 2 ) {
if ( maintag === 'NOUN' ) {
let lexemeform;
if ( paradigmtags.includes( 'Masc' ) ) {
lexemeform = 'noun-m';
} else if ( paradigmtags.includes( 'Neuter' ) ) {
lexemeform = 'noun-n';
} else if ( paradigmtags.includes( 'Fem' ) ) {
lexemeform = 'noun-f';
}
lemmas[ lemma ].lexemeform = lexemeform;
let forms = [ ...new Array( 4 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
for ( let form in paradigm.inflection ) {
forms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
forms = forms.map( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = forms;
} else {
lemmas[ lemma ].urlsuffix = '&lemma=' + lemma + '&lexicalcategory=' + nonLexemeformsCategories[ maintag ];
}
} else if ( cont && maintag === 'VERB' ) {
if ( inflection_group[ 0 ] === 'VERB_sPass' ) {
lemmas[ lemma ].lexemeform = 'verb-s';
let forms = [ ...new Array( 5 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
for ( let form in paradigm.inflection ) {
forms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
forms = forms.map( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = forms;
} else {
lemmas[ lemma ].lexemeform = 'verb';
let forms = [ ...new Array( 16 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
for ( let form in paradigm.inflection ) {
forms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
let imperative = [ ...new Set( [ ...forms[ 13 ], ...forms[ 14 ], ...forms[ 15 ] ] ) ].filter( x => !!x ).join( '/' );
forms = forms.map( x => [ ...x ].join( '/' ) );
if ( lang === 'bm' ) {
lemmas[ lemma ].forms = [
forms[ 0 ],
forms[ 2 ],
forms[ 5 ],
forms[ 6 ],
imperative,
forms[ 8 ],
forms[ 7 ],
forms[ 10 ],
forms[ 11 ],
forms[ 12 ],
forms[ 3 ],
forms[ 4 ]
];
} else {
lemmas[ lemma ].forms = [
forms[ 1 ],
forms[ 0 ],
forms[ 2 ],
forms[ 5 ],
forms[ 6 ],
imperative,
forms[ 8 ],
forms[ 7 ],
forms[ 10 ],
forms[ 11 ],
forms[ 12 ],
forms[ 3 ],
forms[ 4 ]
];
if ( !lemmas[ lemma ].forms[ 0 ] && lemmas[ lemma ].forms[ 1 ] ) {
lemmas[ lemma ].forms[ 0 ] = lemmas[ lemma ].forms[ 1 ];
lemmas[ lemma ].forms[ 1 ] = '';
} else {
copylemmas[ lemma ] = lemmas[ lemma ].forms[ 0 ];
}
}
}
} else if ( cont && paradigmtags.length === 1 ) {
let forms;
switch ( maintag ) {
case 'ADJ':
forms = [ ...new Array( 7 ) ].map( () => new Set() );
for ( let paradigm of l.paradigm_info ) {
if ( paradigm.to ) continue;
for ( let form in paradigm.inflection ) {
forms[ form ].add( paradigm.inflection[ form ].word_form );
}
}
lemmas[ lemma ].lexemeform = 'adj';
forms = forms.map( x => [ ...x ].join( '/' ) );
lemmas[ lemma ].forms = [
forms[ 0 ],
forms[ 3 ],
forms[ 1 ],
forms[ 2 ],
forms[ 4 ],
forms[ 5 ],
forms[ 6 ]
];
break;
case 'ADV':
lemmas[ lemma ].lexemeform = 'adv';
lemmas[ lemma ].forms = [ lemma ];
break;
case 'INTJ':
lemmas[ lemma ].lexemeform = 'interj';
lemmas[ lemma ].forms = [ lemma ];
break;
default:
lemmas[ lemma ].urlsuffix = '&lemma=' + lemma + '&lexicalcategory=' + nonLexemeformsCategories[ maintag ];
}
}
if (
[ 'NOUN', 'VERB' ].includes( maintag ) &&
lemmas[ lemma ].forms.includes( '' )
) {
lemmas[ lemma ].urlsuffix = 'advanced/' + lemmas[ lemma ].urlsuffix;
}
}
for ( let lemma in copylemmas ) {
lemmas[ copylemmas[ lemma ] ] = lemmas[ lemma ];
}
return lemmas;
}
async function fetchQuery( lang, oids ) {
let prop = lang === 'bm' ? 'P10042' : 'P10041';
oids = '"' + oids.join( '" "' ) + '"';
let query = `SELECT ?oid ?l ?lemma WHERE {
VALUES ?oid { ${oids} } .
?l wdt:${prop} ?oid .
?l wikibase:lemma ?lemma
}`;
const res = await fetch( 'https://query.wikidata.org/sparql?format=json&query=' + encodeURIComponent( query ) )
.then( ( response ) => response.json() );
if ( res.results.bindings.length === 0 ) {
return false;
} else {
let bindings = {};
for ( let binding of res.results.bindings ) {
if ( !bindings.hasOwnProperty( binding.oid.value ) ) {
bindings[ binding.oid.value ] = {};
}
bindings[ binding.oid.value ][ binding.lemma.value ] = binding.l.value;
}
return bindings;
}
}
/*
async function dummy( lang, oid ) {
let process = await processOda( lang, oid );
let query = await fetchQuery( lang, oid );
console.log( process );
}
dummy( 'nn', 76670 );
*/
function alphabetnext( qstring ) {
let newstring = '';
const alphabet = 'abcdefghijklmnopqrstuvwxyzæøå';
if ( !/\*$/.test( qstring ) ) return false;
let lastletter = qstring[ qstring.length - 2 ];
if ( lastletter === 'å' ) {
newstring = qstring.substring( 0, qstring.length - 2 ) + '*';
newstring = alphabetnext( newstring );
} else {
let lastpos = alphabet.indexOf( lastletter );
newstring = qstring.substring( 0, qstring.length - 2 ) + alphabet[ lastpos + 1 ] + '*';
}
return newstring;
}
setTimeout( async function() {
$( document ).ready( async function() {
let bm_oids = [],
nn_oids = [];
$( '.article a.whitespace-nowrap' ).each( async function() {
let id = $( this ).attr( 'href' ).split( '/' ),
lang = id[ 2 ],
oid = id[ 3 ];
if ( lang === 'bm' ) {
bm_oids.push( oid );
} else {
nn_oids.push( oid );
}
});
let bm_query = await fetchQuery( 'bm', bm_oids ),
nn_query = await fetchQuery( 'nn', nn_oids );
$( '.article' ).each( async function() {
let id = $( this ).find( 'a.whitespace-nowrap[href^="/nob/"]' ).attr( 'href' ).split( '/' ),
lang = id[ 2 ],
oid = id[ 3 ],
$h3 = $( this ).find( 'h3' );
let oda = await processOda( lang, oid ),
query = lang === 'bm' ? bm_query : nn_query,
$a = $( '<a>' );
$h3.each( function() {
let theselemmas = $( this ).find( 'span > span:not([class], [aria-hidden])' );
theselemmas.each( function() {
$( this ).addClass( 'lexlemma' );
});
if ( theselemmas.length === 0 ) {
$( this ).html( '<span class="lexlemma">' + $( this ).text() + '</span>' );
}
} );
let $lemmas = $( this ).find( 'span.lexlemma' );
$lemmas.each( async function() {
let lemma = $( this ).text().trim();
let href = lexemeforms[ lang ][ oda[ lemma ].lexemeform ];
href = href + oda[ lemma ].urlsuffix;
if ( oda[ lemma ].lexemeform !== 'DEFAULT' ) {
href = href + [ '' ].concat( oda[ lemma ].forms ).join( '&form_representation=' );
href = href + '&target_hash=' + oda[ lemma ].statements.join( '|' );
}
if ( query && query.hasOwnProperty( oid ) && query[ oid ].hasOwnProperty( lemma ) ) {
let lid = query[ oid ][ lemma ].split( '/' )[ 4 ];
$( this ).wrapInner( $a.attr( 'href', query[ oid ][ lemma ] ).attr( 'style', 'color: green !important;' ) );
$( this ).after( $( '<sup><a href="' + href.replace( /(advanced\/)?\?/, 'edit/' + lid + '?' ) + '">rediger</a></sup>') );
} else {
$( this ).wrapInner( $a.attr( 'href', href ) ).attr( 'style', 'color: orange !important;' );
}
} );
let $copyid = $( '<p>' ).css( { color: 'red', cursor: 'copy', border: 'none', 'text-align': 'right' } ).text( 'OID: ' + oid ).on( 'click', async function() {
await navigator.clipboard.writeText( oid );
$( this ).css( 'color', 'green' );
} );
$( this ).prepend( $copyid );
} );
} );
}, 1000);
Add Ordbøkene.no to Lexeme Forms
[edit]This is the Lexeme Forms version of the ordbokIframe.js script – it adds an iframe with the results from Ordbøkene.no for the current lexeme. Handy to have access to all the right forms in case the word is irregular.
// ==UserScript==
// @name Ordbøkene i Lexeme Forms
// @namespace Violentmonkey Scripts
// @match https://lexeme-forms.toolforge.org/template/*
// @grant unsafeWindow
// @version 2.0
// @author Jon Harald Søby
// @description 17.5.2021, 14:29:32
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.js
// ==/UserScript==
$(document).ready(function() {
var lang = $( 'main' ).attr( 'lang' ),
firstform = $( 'input[name=form_representation]:first' ).val();
if ( lang === 'nb' || lang === 'nn' ) {
var src = 'https://ordbokene.no/bm/search?q=';
if ( lang === 'nn' ) src = 'https://ordbokene.no/nn/search?q=';
$( "main" ).css( "max-width", "1400px" );
$( "main form" ).wrap( '<div class="cols" />' );
$( ".cols" ).css( { 'display': 'grid', 'grid-template-columns': '50% calc(50% - 2em)', 'grid-gap': '2em' } );
$( ".cols" ).append(
$( '<iframe />' )
.css( { 'width': '100%', 'height': '70vh', 'border': 0, 'box-shadow': '0 3px 5px #ccc', 'position': 'sticky', 'top': 0 } )
.attr( 'src', src + firstform ) );
setTimeout( function() {
$( 'input[name=form_representation]:first' ).focus();
}, 1500 );
}
});