Skip to content

Commit

Permalink
Improve locale detection
Browse files Browse the repository at this point in the history
Zbib will now normalize browser-reported languages and attempt to find a
matching a supported locale. This fixes an issue where citeproc-rs would
use a fallback locale if lang didn't match exactly (e.g. Chrome reports
"pl" but locale name is "pl-PL"). Also Zbib will now attempt to match
all browser-reported languages in order of preference (previously if
first lang didn't match locale, fallback would be used).
  • Loading branch information
tnajdek committed Jul 30, 2021
1 parent 32f34bc commit 6672605
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 4 deletions.
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -14,10 +14,11 @@
"prebuild": "npm run clean -s && mkdir -p build/static/",
"clean": "rimraf build",
"clean:data": "rimraf data",
"build": "npm run build:styles-json && run-p 'build:js -s' 'build:scss -s' 'build:html -s' 'build:static -s' && npm run build:postprocess",
"build": "run-p \"build:collect-locale\" \"build:styles-json\" && run-p 'build:js -s' 'build:scss -s' 'build:html -s' 'build:static -s' && npm run build:postprocess",
"build:js": "mkdir -p build/static && NODE_ENV=production rollup -c",
"build:scss": "for f in src/scss/*.scss; do sass --no-source-map $f build/static/`basename $f .scss`.css; done;",
"build:html": "node scripts/build-html.cjs",
"build:collect-locale": "node scripts/collect-locale.js",
"build:styles-json": "node scripts/build-styles-json.cjs --stylesCacheTime $npm_package_config_styles_cache_time",
"build:static": "mkdir -p build/static && rsync -vazL src/static/* build/static/",
"build:postprocess": "postcss build/static/bib.css --use autoprefixer --use cssnano --no-map -r",
Expand All @@ -26,7 +27,7 @@
"devel:scss": "for f in src/scss/*.scss; do sass --embed-source-map --watch $f build/static/`basename $f .scss`.css; done;",
"devel:html": "nodemon -q -w src/html -w config --ext '.' --exec 'npm run build:html'",
"devel:static": "nodemon -q -w src/static --ext '.' --exec 'npm run build:static'",
"start": "mkdir -p build/static && run-p \"build:styles-json\" \"serve -s {@}\" \"devel -s {@}\"",
"start": "mkdir -p build/static && run-p \"build:collect-locale\" \"build:styles-json\" \"serve -s {@}\" \"devel -s {@}\"",
"stylelint": "stylelint src/scss/**/*.scss || true",
"eslint": "eslint \"src/js/**/*.+(js|jsx)\" || true",
"lint": "run-p stylelint eslint",
Expand Down
25 changes: 25 additions & 0 deletions scripts/collect-locale.js
@@ -0,0 +1,25 @@
import * as fs from 'fs/promises';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';

const collectLocale = async (pathToLocales, outputPath) => {
const files = await fs.readdir(pathToLocales);
const localeXmls = files.filter(fname => fname.startsWith('locales') && fname.endsWith('.xml'));
const locales = localeXmls.map(xml => xml.slice(8, -4)).map(locale => {
const localeSplit = locale.split('-');
return localeSplit.length > 1 ?
`${localeSplit[0].toLowerCase()}-${localeSplit[1].toUpperCase()}` :
localeSplit[0].toLowerCase();
});

await fs.mkdir(resolve(dirname(outputPath)), { recursive: true });
await fs.writeFile(outputPath, JSON.stringify(locales));
};

if (process.argv[1] === fileURLToPath(import.meta.url)) {
const pathToLocales = `${dirname(fileURLToPath(import.meta.url))}/../third-party/locales`;
const outputPath = `${dirname(fileURLToPath(import.meta.url))}/../data/supported-locales.json`;
collectLocale(pathToLocales, outputPath);
}

export default collectLocale;
5 changes: 4 additions & 1 deletion src/js/citeproc-wrapper.js
@@ -1,5 +1,7 @@
import load from 'load-script';
import { getStyleProperties } from './common/citation-style';
import supportedLocales from '../../data/supported-locales.json';
import { pickBestLocale } from './utils';

const isWasmSupported = typeof WebAssembly === 'object' && typeof WebAssembly.instantiate === 'function';
var Driver = null;
Expand Down Expand Up @@ -359,7 +361,8 @@ const getCiteprocRSLoader = async () => {
}

CiteprocWrapper.new = async ({ style, format = 'html', lang = null, wrap_url_and_doi = false }, useLegacy = null, DriverORCSL = null) => {
lang = lang ? lang : window ? window.navigator.userLanguage || window.navigator.language : null;
const userLocales = lang ? lang : window ? (window.navigator.languages || window.navigator.userLanguage || window.navigator.language) : null;
lang = pickBestLocale(userLocales, supportedLocales);
useLegacy = useLegacy === null ? !isWasmSupported : useLegacy;

try {
Expand Down
25 changes: 24 additions & 1 deletion src/js/utils.js
Expand Up @@ -366,10 +366,33 @@ const enumerateObjects = (objects, key = 'id', start = 0) => {
return objects.map((o, i) => ({ ...o, [key]: i + start }));
}

const normalizeLocaleName = locale => {
const localeSplit = locale.split('-');
return locale = localeSplit.length > 1 ?
`${localeSplit[0].toLowerCase()}-${localeSplit[1].toUpperCase()}` :
localeSplit[0].toLowerCase();
}

const pickBestLocale = (userLocales, supportedLocales, fallback = 'en-US') => {
if(!Array.isArray(userLocales)) {
userLocales = [userLocales];
}

for(let i = 0; i < userLocales.length; i++) {
let locale = normalizeLocaleName(userLocales[i]);
const matchingLocale = supportedLocales.find(supportedLocale => supportedLocale.startsWith(locale));
if(matchingLocale) {
return matchingLocale;
}
}
return fallback;
}

export {
calcOffset,
dedupMultipleChoiceItems,
ensureNoBlankItems,
enumerateObjects,
fetchFromPermalink,
fetchWithCachedFallback,
getExpandedCitationStyles,
Expand All @@ -379,6 +402,7 @@ export {
isLikeUrl,
noop,
parseIdentifier,
pickBestLocale,
processMultipleChoiceItems,
processSentenceCaseAPAField,
processSentenceCaseAPAItems,
Expand All @@ -389,5 +413,4 @@ export {
splice,
validateItem,
validateUrl,
enumerateObjects,
};

0 comments on commit 6672605

Please sign in to comment.