diff --git a/README.md b/README.md index 99ea2e2b..138864db 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,16 @@ npm run lint-css npm run sort-styles ``` +Update the translation files (run this whenever touching user-facing strings). +After running, check your working copy for files and add/correct as needed. + +``` +npm run i18n:refresh +``` + +You can test the UI in different languages using the dropdown in the top menu +(Maputnik does not automatically localize based on browser language settings +at the moment). ## Tests For E2E testing we use [Cypress](https://www.cypress.io/) diff --git a/cypress/e2e/modals.cy.ts b/cypress/e2e/modals.cy.ts index ec3e4d77..02cb244f 100644 --- a/cypress/e2e/modals.cy.ts +++ b/cypress/e2e/modals.cy.ts @@ -160,6 +160,18 @@ describe("modals", () => { ).shouldInclude({ "maputnik:thunderforest_access_token": apiKey }); }); + it("stadia access token", () => { + let apiKey = "testing123"; + when.setValue( + "modal:settings.maputnik:stadia_access_token", + apiKey + ); + when.click("modal:settings.name"); + then( + get.styleFromLocalStorage().then((style) => style.metadata) + ).shouldInclude({ "maputnik:stadia_access_token": apiKey }); + }); + it("style renderer", () => { cy.on("uncaught:exception", () => false); // this is due to the fact that this is an invalid style for openlayers when.select("modal:settings.maputnik:renderer", "ol"); diff --git a/src/components/Doc.tsx b/src/components/Doc.tsx index c0fa40fe..6a5949b9 100644 --- a/src/components/Doc.tsx +++ b/src/components/Doc.tsx @@ -18,14 +18,15 @@ type DocProps = { 'sdk-support'?: { [key: string]: typeof headers } + docUrl?: string } -}; +}; // & WithTranslation? export default class Doc extends React.Component { render () { const {fieldSpec} = this.props; - const {doc, values} = fieldSpec; + const {doc, values, docUrl} = fieldSpec; const sdkSupport = fieldSpec['sdk-support']; const renderValues = ( @@ -85,7 +86,12 @@ export default class Doc extends React.Component { } + {docUrl && +
+ console.log('Link clicked')}>Learn More (TODO i18n) +
+ } ); } -} \ No newline at end of file +} diff --git a/src/components/ModalExport.tsx b/src/components/ModalExport.tsx index 56bb0d1a..1fa6b32b 100644 --- a/src/components/ModalExport.tsx +++ b/src/components/ModalExport.tsx @@ -130,6 +130,12 @@ class ModalExportInternal extends React.Component { value={(this.props.mapStyle.metadata || {} as any)['maputnik:thunderforest_access_token']} onChange={this.changeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")} /> +
diff --git a/src/components/ModalSettings.tsx b/src/components/ModalSettings.tsx index 1989c4c8..991e8804 100644 --- a/src/components/ModalSettings.tsx +++ b/src/components/ModalSettings.tsx @@ -156,6 +156,14 @@ class ModalSettingsInternal extends React.Component onChange={onChangeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")} /> + + ({ maputnik: { maptiler_access_token: { label: t("MapTiler Access Token"), - doc: t("Public access token for MapTiler Cloud.") + doc: t("Public access token for MapTiler Cloud."), + docUrl: "https://docs.maptiler.com/cloud/api/authentication-key/" }, thunderforest_access_token: { label: t("Thunderforest Access Token"), - doc: t("Public access token for Thunderforest services.") + doc: t("Public access token for Thunderforest services."), + docUrl: "https://www.thunderforest.com/docs/apikeys/", + }, + stadia_access_token: { + label: t("Stadia Maps API Key"), + doc: t("API key for Stadia Maps."), + docUrl: "https://docs.stadiamaps.com/authentication/", }, style_renderer: { label: t("Style Renderer"), - doc: t("Choose the default Maputnik renderer for this style."), + doc: t("Choose the default Maputnik renderer for this style.") }, } }) diff --git a/src/libs/style.ts b/src/libs/style.ts index 1c71ae93..750f488b 100644 --- a/src/libs/style.ts +++ b/src/libs/style.ts @@ -55,10 +55,6 @@ function indexOfLayer(layers: LayerSpecification[], layerId: string) { } function getAccessToken(sourceName: string, mapStyle: StyleSpecification, opts: {allowFallback?: boolean}) { - if(sourceName === "thunderforest_transport" || sourceName === "thunderforest_outdoors") { - sourceName = "thunderforest" - } - const metadata = mapStyle.metadata || {} as any; let accessToken = metadata[`maputnik:${sourceName}_access_token`] @@ -74,18 +70,38 @@ function replaceSourceAccessToken(mapStyle: StyleSpecification, sourceName: stri if(!source) return mapStyle if(!("url" in source) || !source.url) return mapStyle - const accessToken = getAccessToken(sourceName, mapStyle, opts) + let authSourceName = sourceName + if(sourceName === "thunderforest_transport" || sourceName === "thunderforest_outdoors") { + authSourceName = "thunderforest" + } + else if (("url" in source) && source.url?.match(/\.stadiamaps\.com/)) { + // The code currently usually assumes openmaptiles == MapTiler, + // so we need to check the source URL. + authSourceName = "stadia" + } + + const accessToken = getAccessToken(authSourceName, mapStyle, opts) if(!accessToken) { // Early exit. return mapStyle; } + let sourceUrl: string + if (authSourceName == "stadia") { + // Stadia Maps does not always require an API key, + // so there is no placeholder in our styles. + // We append it at the end of the URL when exporting if necessary. + sourceUrl = `${source.url}?api_key=${accessToken}` + } else { + sourceUrl = source.url.replace('{key}', accessToken) + } + const changedSources = { ...mapStyle.sources, [sourceName]: { ...source, - url: source.url.replace('{key}', accessToken) + url: sourceUrl } } const changedStyle = { @@ -120,6 +136,8 @@ function stripAccessTokens(mapStyle: StyleSpecification) { ...mapStyle.metadata as any }; delete changedMetadata['maputnik:openmaptiles_access_token']; + delete changedMetadata['maputnik:thunderforest_access_token']; + delete changedMetadata['maputnik:stadia_access_token']; return { ...mapStyle, metadata: changedMetadata diff --git a/src/locales/he/translation.json b/src/locales/he/translation.json index b11f26cd..3ac5fb5f 100644 --- a/src/locales/he/translation.json +++ b/src/locales/he/translation.json @@ -82,7 +82,7 @@ "Close modal": "סגירת חלונית", "Debug": "דיבאג", "Options": "אפשרויות", - "<0>Open in OSM — Opens the current view on openstreetmap.org": "<0>פתיחה ב-OSM - פתיחה של התצוגה הנוכחית ב- openstreetmap.org", + "<0>Open in OSM — Opens the current view on openstreetmap.org": "<0>פתיחה ב-OSM - פתיחה של התצוגה הנוכחית ב- openstreetmap.org", "Export Style": "ייצוא של הסטייל", "Download Style": "הורדה של הסטייל", "Download a JSON style to your computer.": "הורדה של הסטייל למחשב", @@ -179,6 +179,8 @@ "Public access token for MapTiler Cloud.": "Public access token for MapTiler Cloud.", "Thunderforest Access Token": "Thunderforest Access Token", "Public access token for Thunderforest services.": "Public access token for Thunderforest services.", + "Stadia Maps API Key": "Stadia Maps API Key", + "API key for Stadia Maps.": "API key for Stadia Maps", "Style Renderer": "צייר הסטייל", "Choose the default Maputnik renderer for this style.": "בחירת צייר ברירת המחדל של מפוטניק עבור הסטייל הזה" } diff --git a/src/locales/ja/translation.json b/src/locales/ja/translation.json index 31751a81..6f9f1b50 100644 --- a/src/locales/ja/translation.json +++ b/src/locales/ja/translation.json @@ -82,7 +82,7 @@ "Close modal": "モーダルを閉じる", "Debug": "デバッグ", "Options": "設定", - "<0>Open in OSM — Opens the current view on openstreetmap.org": "現在のビューを <0>openstreetmap.org で開く", + "<0>Open in OSM — Opens the current view on openstreetmap.org": "現在のビューを <0>openstreetmap.org で開く", "Export Style": "スタイルをエクスポート", "Download Style": "スタイルをダウンロード", "Download a JSON style to your computer.": "パソコンにJSONスタイルをダウンロードします。", @@ -179,6 +179,8 @@ "Public access token for MapTiler Cloud.": "MapTiler Cloud の公開用アクセストークン", "Thunderforest Access Token": "Thunderforest アクセストークン", "Public access token for Thunderforest services.": "Thunderforest サービスの公開用アクセストークン", + "Stadia Maps API Key": "Stadia Maps API キー", + "API key for Stadia Maps.": "Stadia Maps の API キー", "Style Renderer": "スタイルレンダラ", "Choose the default Maputnik renderer for this style.": "このスタイルのデフォルトの Maputnik レンダラを選択してください", "Layer options": "レイヤー設定", diff --git a/src/locales/zh/translation.json b/src/locales/zh/translation.json index dd26994b..aaf9e225 100644 --- a/src/locales/zh/translation.json +++ b/src/locales/zh/translation.json @@ -82,7 +82,6 @@ "Close modal": "关闭模态框", "Debug": "调试", "Options": "选项", - "<0>Open in OSM — Opens the current view on openstreetmap.org": "在 openstreetmap.org 打开当前视图", "Export Style": "导出样式", "Download Style": "下载样式", "Download a JSON style to your computer.": "将JSON样式下载到您的电脑。", @@ -179,8 +178,11 @@ "Public access token for MapTiler Cloud.": "MapTiler Cloud 的公共访问令牌。", "Thunderforest Access Token": "Thunderforest 访问令牌", "Public access token for Thunderforest services.": "Thunderforest 服务的公共访问令牌。", + "Stadia Maps API Key": "Stadia Maps API 密钥", + "API key for Stadia Maps.": "Stadia Maps 的 API 密钥", "Style Renderer": "样式渲染器", "Choose the default Maputnik renderer for this style.": "为这种样式选择默认的Maputnik渲染器。", + "<0>Open in OSM — Opens the current view on openstreetmap.org": "在 openstreetmap.org 打开当前视图", "Layer options": "图层选项", "Paint properties": "绘制属性", "Layout properties": "布局属性",