Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UHF-8727: Added transliterating for multiple languages. #571

Merged
merged 5 commits into from
Sep 12, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 115 additions & 21 deletions modules/helfi_toc/assets/js/tableOfContents.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
'use strict';

(function (Drupal, once) {
(function (Drupal, once, drupalSettings) {
Drupal.behaviors.table_of_contents = {
attach: function attach() {

function findAvailableId(name, reserved, anchors, count) {
let newName = name;
if (count > 0) { // Only when headings are not unique on page we want to add counter
newName += '-' + count;
newName += `-${count}`;
}
if (reserved.includes(newName)) {
return findAvailableId(name, reserved, anchors, ++count);
} else if (anchors.includes(newName)) {
return findAvailableId(name, reserved, anchors, count + 1);
}

if (anchors.includes(newName)) {
if (count === 0) {
count++; // When reserved heading is visible on page, lets start counting from 2 instead of 1
count += 1; // When reserved heading is visible on page, lets start counting from 2 instead of 1
}
return findAvailableId(name, reserved, anchors, ++count);
return findAvailableId(name, reserved, anchors, count + 1);
}
return newName;
}
Expand All @@ -32,33 +34,125 @@

// Exclude elements from TOC that are not content:
// e.g. TOC, sidebar, cookie compliency-banner etc.
const exclusions = '' +
const exclusions =
'' +
':not(.layout-sidebar-first *)' +
':not(.layout-sidebar-second *)' +
':not(.tools__container *)' +
':not(.breadcrumb__container *)' +
':not(#helfi-toc-table-of-contents *)' +
':not(.embedded-content-cookie-compliance *)' +
':not(.react-and-share-cookie-compliance *)'
':not(.react-and-share-cookie-compliance *)';

const titleComponents = [
'h2'+exclusions,
'h3'+exclusions,
'h4'+exclusions,
'h5'+exclusions,
'h6'+exclusions,
`h2${exclusions}`,
`h3${exclusions}`,
`h4${exclusions}`,
`h5${exclusions}`,
`h6${exclusions}`,
];

const mainLanguages = [
'en',
'fi',
'sv',
];

const swaps = {
'0': '[°₀۰0]',
'1': '[¹₁۱1]',
'2': '[²₂۲2]',
'3': '[³₃۳3]',
'4': '[⁴₄۴٤4]',
'5': '[⁵₅۵٥5]',
'6': '[⁶₆۶٦6]',
'7': '[⁷₇۷7]',
'8': '[⁸₈۸8]',
'9': '[⁹₉۹9]',
'a': '[àáảãạăắằẳẵặâấầẩẫậāąåαάἀἁἂἃἄἅἆἇᾀᾁᾂᾃᾄᾅᾆᾇὰᾰᾱᾲᾳᾴᾶᾷаأအာါǻǎªაअاaä]',
'b': '[бβبဗბbब]',
'c': '[çćčĉċc©]',
'd': '[ďðđƌȡɖɗᵭᶁᶑдδدضဍဒდdᴅᴆ]',
'e': '[éèẻẽẹêếềểễệëēęěĕėεέἐἑἒἓἔἕὲеёэєəဧေဲეएإئe]',
'f': '[фφفƒფf]',
'g': '[ĝğġģгґγဂგگg]',
'h': '[ĥħηήحهဟှჰh]',
'i': '[íìỉĩịîïīĭįıιίϊΐἰἱἲἳἴἵἶἷὶῐῑῒῖῗіїиဣိီည်ǐიइیii̇ϒ]',
'j': '[ĵјჯجj]',
'k': '[ķĸкκقكကკქکk]',
'l': '[łľĺļŀлλلလლlल]',
'm': '[мμمမმm]',
'n': '[ñńňņʼnŋνнنနნn]',
'o': '[óòỏõọôốồổỗộơớờởỡợøōőŏοὀὁὂὃὄὅὸόоوθိုǒǿºოओoöө]',
'p': '[пπပპپp]',
'q': '[ყq]',
'r': '[ŕřŗрρرრr]',
's': '[śšşсσșςسصစſსsŝ]',
't': '[ťţтτțتطဋတŧთტt]',
'u': '[úùủũụưứừửữựûūůűŭųµуဉုူǔǖǘǚǜუउuўü]',
'v': '[вვϐv]',
'w': '[ŵωώဝွw]',
'x': '[χξx]',
'y': '[ýỳỷỹỵÿŷйыυϋύΰيယyῠῡὺ]',
'z': '[źžżзζزဇზz]',
'aa': '[عआآ]',
'ae': '[æǽ]',
'ai': '[ऐ]',
'ch': '[чჩჭچ]',
'dj': '[ђđ]',
'dz': '[џძ]',
'ei': '[ऍ]',
'gh': '[غღ]',
'ii': '[ई]',
'ij': '[ij]',
'kh': '[хخხ]',
'lj': '[љ]',
'nj': '[њ]',
'oe': '[öœؤ]',
'oi': '[ऑ]',
'oii': '[ऒ]',
'ps': '[ψ]',
'sh': '[шშش]',
'shch': '[щ]',
'ss': '[ß]',
'sx': '[ŝ]',
'th': '[þϑثذظ]',
'ts': '[цცწ]',
'ue': '[ü]',
'uu': '[ऊ]',
'ya': '[я]',
'yu': '[ю]',
'zh': '[жჟژ]',
'gx': '[ĝ]',
'hx': '[ĥ]',
'jx': '[ĵ]',
};

// Craft table of contents.
once('table-of-contents', titleComponents.join(','), mainContent)
.forEach(function (content) {
const name = content.textContent
let name = content.textContent
.toLowerCase()
.trim()
.replace(/ä/gi, 'a')
.replace(/ö/gi, 'o')
.replace(/å/gi, 'a')
.trim();

// To ensure backwards compatibility, this is done only to "other" languages.
if (!mainLanguages.includes(drupalSettings.path.currentLanguage)) {
Object.keys(swaps).forEach((swap) => {
name = name.replace(new RegExp(swaps[swap], 'g'), swap);
});
}
else {
name = name
.replace(/ä/gi, 'a')
.replace(/ö/gi, 'o')
.replace(/å/gi, 'a');
}

name = name
// Replace any remaining non-word character including whitespace with '-'.
// This leaves only characters matching [A-Za-z0-9-_] to the name.
.replace(/\W/g, '-')
// Use underscore at the end of the string: 'example-1' -> 'example_1'.
.replace(/-(\d+)$/g, '_$1');

let nodeName = content.nodeName.toLowerCase();
Expand All @@ -73,13 +167,13 @@
anchors.push(anchorName);

// Create table of contents if component is enabled.
if (tableOfContentsList && nodeName === "h2") {
if (tableOfContentsList && nodeName === 'h2') {
let listItem = document.createElement('li');
listItem.classList.add('table-of-contents__item');

let link = document.createElement('a');
link.classList.add('table-of-contents__link');
link.href = '#' + anchorName;
link.href = `#${anchorName}`;
link.textContent = content.textContent.trim();

listItem.appendChild(link);
Expand All @@ -98,4 +192,4 @@
}
},
};
})(Drupal, once);
})(Drupal, once, drupalSettings);