(function(){ var jqScreen = $('#screen_problem'), languageCache = {}, // keyed by language identifier: processed data about languages translationCache = [], // keys are autogenerated in ta(), a value is a dictionary of translations of a translation key for every language problemCache = {}, // problem data cache, 3-level, keyed by: language, problem group, and problem identifier langs, Nlangs, // constants, set on init // ================================================================================ // Hint processing: extract hints from the translations and return them in the // processed form, hint key -> translation language -> value // ================================================================================ processHints = function (rawTranslations) { var defaultHint = {}, // here we put all the hints with their default translations allHints = {}, // the result allHintKeys = [], tr, key, i, lang, hint, h, j; // find the default hint translations, they will form the basis of default hints tr = chooseDefaultTranslation(rawTranslations, 'hint') || {}; for (key in tr) { // copy the hints if (!tr.hasOwnProperty(key)) continue; defaultHint[key] = tr[key]; allHintKeys.push(key); } // copy any hints not in the default hints to the default hints for (i = langs.length - 1; i >= 0; i--) { lang = langs[i]; tr = rawTranslations[lang]; if (!tr || !tr.hint) continue; // skip unavailable translations or translations with no hints hint = tr.hint; for (key in hint) { if (!hint.hasOwnProperty(key) || !hint[key]) continue; if (!key in defaultHint) { defaultHint[key] = hint[key]; allHintKeys.push(key); } } } // create all translations for hints for (i = langs.length - 1; i >= 0; i--) { lang = langs[i]; tr = rawTranslations[lang]; // set up hints if (!tr || !tr.hint) { // there's no hint in the current language, copy the default in its entirety allHints[lang] = defaultHint; } else { // make a copy of all hints, using the default hint value where a hint value is missing hint = {}; allHints[lang] = hint; h = tr.hint; for (j = allHintKeys.length; j >= 0; j--) { key = allHintKeys[j]; hint[key] = h[key] || defaultHint[key]; } } } return allHints; }, // ================================================================================ // Plan processing: extract plans from the translations and return them in the // processed form, hint key -> translation language -> value // ================================================================================ processPlans = function (rawTranslations) { // find the default plan translation var defaultPlan = chooseDefaultTranslation(rawTranslations, 'plan') || [], allPlans = {}, // the result i, lang, tr; // create all translations for plan for (i = langs.length - 1; i >= 0; i--) { lang = langs[i]; tr = rawTranslations[lang]; // set up plan if (!tr || !tr.plan) { // there's no plan in the current language, copy the default plan allPlans[lang] = defaultPlan; } else { allPlans[lang] = tr.plan; } } return allPlans; }, // ================================================================================ // Group + problems directory processing // ================================================================================ chooseTranslation = function (keyword, lang, currentDict, enDict, translations) { var tr = currentDict[keyword], otherLang; if (tr) return tr; // if there is a translation in the current dictionary: return it tr = enDict[keyword]; if (tr) { // if there is a translation in the english dictionary: return it codeq.log.info('Translation for ' + keyword + ' not set for language ' + lang + ', using translation from en'); return tr; } for (otherLang in translations) { if (!translations.hasOwnProperty(otherLang)) continue; tr = (translations[otherLang] || {})[keyword]; if (tr) { // otherwise: return the first available translation in any language codeq.log.info('Translation for ' + keyword + ' not set for language ' + lang + ', using translation from ' + otherLang); return tr; } } return keyword + ' not set for language ' + lang; }, /** * convert the input translations (arg0) for given keys (arg1..argN) * so each keys holds all its translations for ever language */ convertTranslations = function () { var translations = arguments[0] || {}, result = {}, enDict = translations['en'] || {}, lang, dict, i, keyword, l; // initialize result: one lang-dict per keyword for (i = arguments.length - 1; i > 0; i--) result[arguments[i]] = {}; // convert translations: one keyword-dict per lang -> one lang-dict per keyword for (l = Nlangs - 1; l >= 0; l--) { lang = langs[l]; dict = translations[lang] || {}; for (i = arguments.length - 1; i > 0; i--) { keyword = arguments[i]; // result[keyword][lang] = dict[keyword] || keyword + ' not set for language ' + lang; result[keyword][lang] = chooseTranslation(keyword, lang, dict, enDict, translations); } } return result; }, /** * Connect the given translations of a key with the DOM, returning * the string of arguments to use with a HTML tag which will contain * a translation chosen from the given dictionary. */ ta = function (trObj) { // an object of the form: {'en': 'english content', 'sl': 'slovenska vsebina'} var result = ['data-dict="directory" data-tkey="', translationCache.length, '"'].join(''); translationCache.push(trObj); return result; }, /** * Assemble the display structure and translations from the server's * language.json for the given language identifier. */ createLanguageData = function (data, languageIdentifier) { // data is the content of language.json var li = languageIdentifier, // a shorthand rawTranslations = data.translations || {}, groups = data.groups || [], Ngroups = groups.length, html = [], problemReferences = [], group, problems, Nproblems, problem, i, j; var langDict = convertTranslations(rawTranslations, 'name', 'description'), // this will be the resulting dictionary: multi-level keys that lead up to the lang-dict groupDict, problemDict; // title: HTML structure for "name" and "desc" html.push('