From b12c30461b3d78084f37ccacdf209cc6e8921eba Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 21 Feb 2020 12:24:08 -0500 Subject: [PATCH] Don't bundle the locales anymore, load first in context init (re: #4994) --- modules/core/context.js | 25 +++++++++--------- modules/index.js | 5 ++-- modules/ui/init.js | 10 +++++--- modules/util/detect.js | 5 ++-- modules/util/locale.js | 53 +++++++++++++++++++-------------------- test/spec/spec_helpers.js | 3 ++- 6 files changed, 52 insertions(+), 49 deletions(-) diff --git a/modules/core/context.js b/modules/core/context.js index f091652b7..a465bc62f 100644 --- a/modules/core/context.js +++ b/modules/core/context.js @@ -4,13 +4,12 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; import { json as d3_json } from 'd3-fetch'; import { select as d3_select } from 'd3-selection'; -import { t, localeStrings, setLocale } from '../util/locale'; +import { t, setLocale, localeStrings, localeData } from '../util/locale'; import { coreData } from './data'; import { coreHistory } from './history'; import { coreValidator } from './validator'; import { coreUploader } from './uploader'; -import { dataLocales } from '../../data'; import { geoRawMercator } from '../geo/raw_mercator'; import { modeSelect } from '../modes/select'; import { osmSetAreaKeys, osmSetPointTags, osmSetVertexTags } from '../osm/tags'; @@ -51,9 +50,6 @@ export function coreContext() { // forOwn(tkeys, traverser); // addLocale('_tkeys_', tkeys); - // addLocale('en', dataEn); - // setLocale('en'); - // https://github.com/openstreetmap/iD/issues/772 // http://mathiasbynens.be/notes/localstorage-pattern#comment-9 @@ -432,17 +428,17 @@ export function coreContext() { /* Locales */ - // Returns a Promise to load the strings for the given locale + // Returns a Promise to load the strings for the requested locale context.loadLocale = (requested) => { let locale = requested; if (!_data) { return Promise.reject('loadLocale called before init'); } - if (!dataLocales.hasOwnProperty(locale)) { // Not supported, e.g. 'es-FAKE' - locale = locale.split('-')[0]; // Fallback to the first part 'es' + if (!localeData[locale]) { // Locale not supported, e.g. 'es-FAKE' + locale = locale.split('-')[0]; // Fallback to the first part 'es' } - if (!dataLocales.hasOwnProperty(locale)) { + if (!localeData[locale]) { return Promise.reject(`Unsupported locale: ${requested}`); } @@ -452,7 +448,7 @@ export function coreContext() { let fileMap = _data.fileMap(); const key = `locale_${locale}`; - fileMap[key] = `locales/${locale}.json`; // .min.json? + fileMap[key] = `locales/${locale}.json`; return _data.get(key) .then(d => { @@ -500,9 +496,14 @@ export function coreContext() { _data = coreData(context); - // always load the English locale, then load preferred locale. + // Start loading data: + // 1. the list of supported locales + // 2. the English locale strings (used as fallbacks) + // 3. the preferred locale strings (detected by utilDetect) const requested = utilDetect().locale; - context.loadLocale('en') + _data.get('locales') + .then(d => Object.assign(localeData, d)) + .then(() => context.loadLocale('en')) .then(() => context.loadLocale(requested)) .then(received => { // `received` may not match `requested`. setLocale(received); // (e.g. 'es-FAKE' will return 'es') diff --git a/modules/index.js b/modules/index.js index efca40c50..1d3c98bab 100644 --- a/modules/index.js +++ b/modules/index.js @@ -1,9 +1,9 @@ -import * as d3 from 'd3'; // TODO: remove (needed for tests?) +import * as d3 from 'd3'; // remove someday, see #4379 +export { d3 }; export * from './actions/index'; export * from './behavior/index'; export * from './core/index'; -export * from '../data/index'; export * from './geo/index'; export * from './modes/index'; export * from './operations/index'; @@ -48,4 +48,3 @@ export { uiPresetEditor as uiPreset } from './ui/preset_editor'; export var debug = false; -export { d3 }; diff --git a/modules/ui/init.js b/modules/ui/init.js index e3ece81e0..17f5d9f63 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -340,8 +340,8 @@ export function uiInit(context) { // `ui()` renders the iD interface into the given node, assigning - // that node as the `container`. We need to delay rendering until - // the locale has been loaded (i.e. promise settled), because the + // that node as the `container`. We need to delay rendering until the + // locale data has been loaded (i.e. promises all settled), because the // UI code expects localized strings to be available. function ui(node, callback) { _initCallback = callback; @@ -349,7 +349,11 @@ export function uiInit(context) { context.container(container); const current = utilDetect().locale; - context.loadLocale(current) + + context.data().get('locales') + .then(function () { + return context.loadLocale(current); + }) .then(function() { render(container); if (callback) callback(); diff --git a/modules/util/detect.js b/modules/util/detect.js index 8a08dcb8e..859a845fc 100644 --- a/modules/util/detect.js +++ b/modules/util/detect.js @@ -1,5 +1,4 @@ -import { currentLocale, setTextDirection, setLanguageNames, setScriptNames } from './locale'; -import { dataLocales } from '../../data/index'; +import { currentLocale, localeData, setTextDirection, setLanguageNames, setScriptNames } from './locale'; import { utilStringQs } from './util'; let _detected; @@ -126,7 +125,7 @@ export function utilDetect(force) { } // detect text direction - const lang = dataLocales[_detected.locale] || dataLocales[_detected.language]; + const lang = localeData[_detected.locale] || localeData[_detected.language]; if ((lang && lang.rtl) || (hash.rtl === 'true')) { _detected.textDirection = 'rtl'; } else { diff --git a/modules/util/locale.js b/modules/util/locale.js index 7bf18832d..444c62ab5 100644 --- a/modules/util/locale.js +++ b/modules/util/locale.js @@ -1,27 +1,42 @@ let _dataLanguages = {}; -// `localeStrings` is an object containing all loaded locale codes -> string data +// `localeData` is an object containing all _supported_ locale codes -> language info +// `context.init()` will load this before anything else. // { -// en: {icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, …}, -// de: {icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, …}, +// en: { rtl: false, languageNames: {…}, scriptNames: {…} }, +// de: { rtl: false, languageNames: {…}, scriptNames: {…} }, // … // } -export let localeStrings = Object.create(null); +export let localeData = {}; + +// `localeStrings` is an object containing all _loaded_ locale codes -> string data +// `context.init()` will load the 'en' strings. +// { +// en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … }, +// de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … }, +// … +// } +export let localeStrings = {}; export let currentLocale; export let textDirection = 'ltr'; export let languageNames = {}; export let scriptNames = {}; -export function setLocale(locale) { - currentLocale = locale; - // if (localeStrings[locale] !== undefined) { - // currentLocale = locale; - // } else if (localeStrings[locale.split('-')[0]]) { - // currentLocale = locale.split('-')[0]; - // } +export function setLocale(val) { + currentLocale = val; } +export function setTextDirection(val) { + textDirection = val; +} +export function setLanguageNames(val) { + languageNames = val; +} +export function setScriptNames(val) { + scriptNames = val; +} + /** * Given a string identifier, try to find that string in the current @@ -72,22 +87,6 @@ export function t(s, replacements, locale) { return missing; } -/** - * Given string 'ltr' or 'rtl', save that setting - * - * @param {string} dir ltr or rtl - */ -export function setTextDirection(dir) { - textDirection = dir; -} - -export function setLanguageNames(obj) { - languageNames = obj; -} - -export function setScriptNames(obj) { - scriptNames = obj; -} export function languageName(context, code, options) { // Data access is async now, which makes this complicated. diff --git a/test/spec/spec_helpers.js b/test/spec/spec_helpers.js index 0dfeebe5e..359f21919 100644 --- a/test/spec/spec_helpers.js +++ b/test/spec/spec_helpers.js @@ -7,7 +7,8 @@ for (var k in iD.services) { delete iD.services[k]; } // Run without data for speed (tests which need data can set it up themselves) -// Initializing `coreContext` will try loading the English locale strings: +// Initializing `coreContext` will try loading the locale data and English locale strings: +iD.data.locales = { en: { rtl: false, languageNames: {}, scriptNames: {} }}; iD.data.locale_en = { en: {} }; // Initializing `coreContext` initializes `_background`, which tries loading: iD.data.imagery = [];