Skip to content

Commit 6993186

Browse files
committed
[demoController] enable more internationalization of typeSpec config, so far especially of columnConfig.
1 parent fcc5ff6 commit 6993186

File tree

4 files changed

+283
-57
lines changed

4 files changed

+283
-57
lines changed

Emsquare/Volume-01/js/main.mjs

+3-11
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,11 @@ function reduceColumnConfig (columnConfig) {
99
return result;
1010
}
1111

12-
const typeSpec_ = {};
13-
for(let [k,v] of Object.entries(typeSpec)) {
14-
if(k === 'columnConfig') {
15-
let columnConfig_ = {};
16-
for(let [lang, columnConfig] of Object.entries(v))
17-
columnConfig_[lang] = reduceColumnConfig(columnConfig);
18-
typeSpec_[k] = columnConfig_;
19-
continue;
20-
}
21-
typeSpec_[k] = typeSpec[k];
12+
const massageConfigurations = {
13+
columnConfig: reduceColumnConfig
2214
}
2315

2416
const inject = {};
2517
window.onload = ()=>{
26-
main(window, inject, typeSpec_);
18+
main(window, inject, typeSpec, massageConfigurations);
2719
};

explorations/wikipedia/js/main.mjs

+5-3
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ function applyWikiPage({document}, {subDomain, data}) {
191191
// TODO: changing the "dir" attribute and changing the layout
192192
// to rtl direction is not supported yet. However, we don't have
193193
// fonts for those cases yet as well.
194+
195+
// FIXME: the newly fetched content should rather be spared by this.
194196
for(let elem of document.querySelectorAll(
195197
// Some elements have a different language as their content
196198
// and hence set lang, e.g. a word in an <em> in Greek also,
@@ -200,7 +202,7 @@ function applyWikiPage({document}, {subDomain, data}) {
200202
elem.setAttribute('lang', fetchedLang);
201203
}
202204
}
203-
return true;
205+
return {contentLanguage: fetchedLang};
204206
}
205207

206208
const ARTICLE_URL_TEMPLATE = `
@@ -294,11 +296,11 @@ class WikipediaArticleURLWidget {
294296
.then(
295297
fetched=> {
296298
// success
297-
applyWikiPage(window, fetched);
299+
const {contentLanguage} = applyWikiPage(window, fetched);
298300
// -> set this._input value!
299301
this._input.value = `https://${fetched.subDomain}.wikipedia.org/wiki/${fetched.page}`;
300302
this.setLoadingStatus(null);
301-
this._updateAfterChangedContent();
303+
this._updateAfterChangedContent(contentLanguage);
302304
},
303305
err=>this.setLoadingStatus(`[${err.name}] ${err.message}`)
304306
);

lib/js/demoController.mjs

+139-16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {getElementSizesInPx, getComputedStyle, getComputedPropertyValues
33
} from './domTool.mjs';
44
import WidgetsContainerWidget, {ID} from './WidgetsContainerWidget.mjs';
55
import {JustificationController, parseFontVariationSettings} from './justification.mjs';
6+
import { getFromI18NConfig } from './typeSpec.mjs';
67

78
class _ContainerWidget {
89
constructor(domTool, baseElement) {
@@ -874,6 +875,7 @@ class InspectorWidget extends _ContainerWidget {
874875
, reason = '(not set)'
875876
, beacon = this._targetElement.ownerDocument.querySelector(
876877
`:not(.${JUSTIFICATION_CONTEXT_BLOCK_CLASS}) .${INSPECTION_MODE_BEACON_CLASS}`)
878+
, debug = false
877879
;
878880
RECORDS:
879881
for( let rec of mutationRecords) {
@@ -949,7 +951,7 @@ class InspectorWidget extends _ContainerWidget {
949951
}
950952
if(!reportNeedsUpdate)
951953
return;
952-
// console.warn('>>>> REPORT NEEDS UPDATE', reason);
954+
debug && console.warn('>>>> REPORT NEEDS UPDATE', reason);
953955
this._updateReport();
954956
}
955957
createtReport(elem) {
@@ -1224,8 +1226,8 @@ class InspectorWidget extends _ContainerWidget {
12241226
, report=(type, element, shared)=>reports.push([
12251227
mkelem('li',[
12261228
mkfrac(`<strong class="${this._class}-report_heading">${key2label[type] || type}</strong>`)
1227-
, reporters.get(reporters.has(type) ? type : undefined)
1228-
(element, shared, type)
1229+
, reporters.get(reporters.has(type)
1230+
? type : undefined)(element, shared, type)
12291231
])
12301232
])
12311233
;
@@ -1465,7 +1467,7 @@ function _runion_01_columns(columnConfig, availableWidthEn) {
14651467
}
14661468
// With a proper config this should not be possible (1 column min-width = 0),
14671469
// thus, if this happens we must look at the case and figure out what to do.
1468-
throw new Error(`Can\'t compose column setup for availableWidthEn: ${availableWidthEn}!`);
1470+
throw new Error(`Can't compose column setup for availableWidthEn: ${availableWidthEn}!`);
14691471
}
14701472

14711473
function _runion_01_lineHeight ({minLineHeight, maxLineHeight,
@@ -1725,6 +1727,115 @@ function fixCSSKeyframes(document, cssKeyframeFixes) {
17251727
}
17261728
}
17271729

1730+
function ucFirst(str) {
1731+
return str.split('')
1732+
.map((chr, i)=>i === 0
1733+
? chr.toUpperCase()
1734+
: chr.toLowerCase()
1735+
)
1736+
.join('');
1737+
}
1738+
1739+
1740+
/**
1741+
* As input expect a string with the locale order "{language}-{script}-{territory}"
1742+
* but returns an array of [script, language, territory] as the order better
1743+
* fits our internal logic. Also, each particle may be null if not found in the
1744+
* string. There's no check if the particles actually exist (in CLDR) just
1745+
* a formal length check and respective uppercase/lowercase treatments.
1746+
* We also allow locales that don't bring a language and we try to produce
1747+
* a script for languages that don't specify it.
1748+
*/
1749+
function parseLocale(locale) {
1750+
const parts = locale.split('-');
1751+
let language = null
1752+
, script = null
1753+
, territory = null
1754+
;
1755+
// A full locale looks like 'de-Latn-AT'
1756+
// or fr-Latn-CA
1757+
if(parts.length && parts[0].length === 2)
1758+
language = parts.pop().toLowerCase();
1759+
// Here we accept also locales if they don't specify a language,
1760+
// e.g. just 'Arab' or 'Latn-UK', as we can just use the default
1761+
// setup for the script later.
1762+
if(parts.length && parts[0].length === 4)
1763+
script = ucFirst(parts[0].pop());
1764+
// This can be at second position if there's no script specified
1765+
// e.g. 'de-DE'
1766+
// We don't use the territory so far!
1767+
if(parts.length && parts[0].length === 2)
1768+
territory = parts.pop().toUpperCase();
1769+
1770+
// Ideally locale would contain {language}-{script}-{region}
1771+
// as in ISO e.g. en-Latn-us, so we could make very elaborate decisions.
1772+
// In this application, however, {scrip}` is more generic than {language}
1773+
// I.e. we will fallback to the more general typography settings of a
1774+
// {script} if specific {language} (similar {region}) are not available.
1775+
// The hierarchy should be {script} > {language} > {region}.
1776+
// It is however very possible that we get a {language} without the
1777+
// {script}. There are defaullt scripts for languages in the Unicode
1778+
// Common Locale Data Repository (CLDR) which we can use to determine
1779+
// the default script when we only get a language.
1780+
//
1781+
// https://github.com/unicode-org/cldr-json/
1782+
//
1783+
// Here's an example of existing locale variants for az (Azerbaijani):
1784+
// "az", "az-Arab", "az-Arab-IQ", "az-Arab-TR", "az-Cyrl","az-Latn"
1785+
// from cldr-json/cldr-json/cldr-core/availableLocales.json
1786+
// it has Arab, Cyrl and Latn as possible scripts!
1787+
//
1788+
// We can find in cldr-json/cldr-json/cldr-core/supplemental/languageData.json:
1789+
// (see also https://www.unicode.org/reports/tr35/tr35-info.html#Supplemental_Language_Data)
1790+
// [...], "az": {
1791+
// "_territories": ["AZ"],
1792+
// "_scripts": ["Arab", "Cyrl", "Latn"]
1793+
// },
1794+
// So, if we don't get an explicit script for a language, we pick
1795+
// the first of "_scripts" in there as the default script for that
1796+
// language.
1797+
//
1798+
// Since we start with en-Latn and that is all we have right now,
1799+
// that typeSpec will be elevated to be the default of everything.
1800+
1801+
// For now only using a small excerpt from the CLDR mentioned above.
1802+
const languageToScript = {
1803+
'en': 'Latn'
1804+
, 'de': 'Latn'
1805+
, 'az': 'Arab' // as per the example above
1806+
};
1807+
if (!script && (language in languageToScript))
1808+
script = languageToScript[language];
1809+
1810+
return [script, language, territory];
1811+
}
1812+
1813+
function selectTypeSpecByLanguage(typeSpecI18N, localeStr) {
1814+
// this is a stub
1815+
// next, .de will be added
1816+
// other scripts like cyrillic, greek, all the other
1817+
//
1818+
// initially we'll only have a different config for "de" (German)
1819+
// but that will change!
1820+
// We'll also have differences for the scripts (Latn, Arab, Cyrl. Grek)
1821+
// likeley a go-to for the default script of the lang then the specific
1822+
// settings for the lanf writtten in that script. Our current English
1823+
// setting would become the default for all of Latn. German will, so
1824+
// far. have only less minimal column width than english, because it
1825+
// has longer words.
1826+
1827+
1828+
// So far only columnConfig is internationalized, hence it makes sense
1829+
// to return it's configLanguageCode. Later, probably the most specific
1830+
// code of the different typeSpec sections should be returned.
1831+
const [configLocale, columnConfig] = getFromI18NConfig(typeSpecI18N.columnConfigI18N, parseLocale(localeStr))
1832+
return [configLocale, {
1833+
columnConfig
1834+
, cssKeyframeFixes: typeSpecI18N.cssKeyframeFixes
1835+
, justificationSpecs: typeSpecI18N.justificationSpecs
1836+
, wdthJustificationSpecs: typeSpecI18N.wdthJustificationSpecs
1837+
}];
1838+
}
17281839

17291840
// TODO: I think this should eventually become a Controller class where
17301841
// state is managed more explicitly, I'm not sure yet, however of the full
@@ -1739,12 +1850,8 @@ export function main(
17391850
, WikipediaArticleURLWidget=null
17401851
, defaults={}
17411852
},
1742-
{ /* typeSpec */
1743-
columnConfig: columnConfigI18N
1744-
, cssKeyframeFixes
1745-
, justificationSpecs
1746-
, wdthJustificationSpecs
1747-
}
1853+
typeSpecI18N,
1854+
massageConfigurations = {}
17481855
) {
17491856

17501857
let contentDocument = contentWindow.document
@@ -1753,8 +1860,6 @@ export function main(
17531860
: contentWindow
17541861
, widgetHostDocument = widgetHostWindow.document
17551862
, widgetInParent = contentWindow !== widgetHostWindow
1756-
// i18n is a stub
1757-
, columnConfig = columnConfigI18N.en
17581863
;
17591864

17601865
if(widgetInParent) {
@@ -1780,11 +1885,28 @@ export function main(
17801885
]
17811886
, toggleUserSettingsWidget = null
17821887
, runion01Elem = null
1888+
, columnConfig = null
1889+
, cssKeyframeFixes = null
1890+
, justificationSpecs = null
1891+
, wdthJustificationSpecs = null
1892+
// not used so far
1893+
, configLocale = null
17831894
;
17841895

1896+
let initContent = (contentLanguageCode) => {
1897+
let rawColumnConfig = null;
1898+
[configLocale, {
1899+
columnConfig: rawColumnConfig
1900+
, cssKeyframeFixes
1901+
, justificationSpecs
1902+
, wdthJustificationSpecs
1903+
}] = selectTypeSpecByLanguage(typeSpecI18N, contentLanguageCode);
17851904

1905+
columnConfig = massageConfigurations?.columnConfig
1906+
? massageConfigurations.columnConfig(rawColumnConfig)
1907+
: rawColumnConfig
17861908

1787-
let initContent = () => {
1909+
console.log('contentLanguageCode:', contentLanguageCode, 'configLocale;', configLocale.map(e=>e.toString()).join('-'));
17881910
let userSettingsWidgetContainer = widgetHostDocument.querySelector(userSettingsWidgetSelector);
17891911
if(!userSettingsWidgetContainer) {
17901912
console.log('Demo is disabled: no userSettingsWidgetContainer.');
@@ -1970,15 +2092,16 @@ export function main(
19702092
.checked)
19712093
justificationController.run();
19722094
}
1973-
, updateAfterChangedContent = ()=>{
1974-
initContent();
2095+
, updateAfterChangedContent = (contentLanguage)=>{
2096+
initContent(contentLanguage);
19752097
// This will most likely be executed by the USER_SETTINGS_EVENT handler
19762098
// so here's a way to cancel this fail-safe initial call.
19772099
scheduleUpdateViewport();
19782100
}
19792101
;
19802102

1981-
updateAfterChangedContent();
2103+
// FIXME: remove hard coded default, should be done differently.
2104+
updateAfterChangedContent('en');
19822105
// FIXME: resize is currently only interesting when the width of
19832106
// the page changes, height can change more often (open the debugger,
19842107
// OSsses may change height to make room for the main toolbar when in

0 commit comments

Comments
 (0)