mirror of
https://github.com/maputnik/editor.git
synced 2026-08-24 22:17:25 +00:00
feat: use FileSystemFileHandle to modify a file on the local filesystem (#965)
## Launch Checklist <!-- Thanks for the PR! Feel free to add or remove items from the checklist. --> - [x] Briefly describe the changes in this PR. - [x] Link to related issues. - [x] Include before/after visuals or gifs if this PR includes visual changes. - [ ] Write tests for all new functionality. - [x] Add an entry to `CHANGELOG.md` under the `## main` section. ## Changes - This pull request makes use of the FileSystemFileHandle API to modify a local file. No need to download it - just click save. - I don't know how to cover this functionality by tests so I need directions in case test coverage is required. - The pull request adds [@types/wicg-file-system-access](https://www.npmjs.com/package/@types/wicg-file-system-access) as a new dev dependency which I am not really pleased about but can't think of a way around it. ## Known Limitations - The used File API is only available in when accessed from https or on localhost. - There is no visual indicator that the file has been saved. Previously the browser showed it as a new download. ## Issue - https://github.com/maplibre/maputnik/issues/964 ## Screenshots ### Menu <img src="https://github.com/user-attachments/assets/dfcfc5c2-0019-4857-ba26-224b5598fc11" /> ### Open modal <img src="https://github.com/user-attachments/assets/4e1293e8-16b6-4b86-925b-3bebb49d8ca6" height="200px" /> ### Save modal <img src="https://github.com/user-attachments/assets/4f10e2c0-2dd3-4726-a613-30e0406619b0" height="200px" /> --------- Co-authored-by: Harel M <harel.mazor@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
- Add scheme type options for vector/raster tile
|
- Add scheme type options for vector/raster tile
|
||||||
- Add `tileSize` field for raster and raster-dem tile sources
|
- Add `tileSize` field for raster and raster-dem tile sources
|
||||||
- Update Protomaps Light gallery style to v4
|
- Update Protomaps Light gallery style to v4
|
||||||
|
- Add support to edit local files on the file system
|
||||||
- _...Add new stuff here..._
|
- _...Add new stuff here..._
|
||||||
|
|
||||||
### 🐞 Bug fixes
|
### 🐞 Bug fixes
|
||||||
|
|||||||
Generated
+8
@@ -94,6 +94,7 @@
|
|||||||
"@types/react-icon-base": "^2.1.6",
|
"@types/react-icon-base": "^2.1.6",
|
||||||
"@types/string-hash": "^1.1.3",
|
"@types/string-hash": "^1.1.3",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
|
"@types/wicg-file-system-access": "^2023.10.5",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cypress": "^13.13.0",
|
"cypress": "^13.13.0",
|
||||||
@@ -2395,6 +2396,13 @@
|
|||||||
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
|
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/wicg-file-system-access": {
|
||||||
|
"version": "2023.10.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2023.10.5.tgz",
|
||||||
|
"integrity": "sha512-e9kZO9kCdLqT2h9Tw38oGv9UNzBBWaR1MzuAavxPcsV/7FJ3tWbU6RI3uB+yKIDPGLkGVbplS52ub0AcRLvrhA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/yauzl": {
|
"node_modules/@types/yauzl": {
|
||||||
"version": "2.10.3",
|
"version": "2.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||||
|
|||||||
@@ -125,6 +125,7 @@
|
|||||||
"@types/react-icon-base": "^2.1.6",
|
"@types/react-icon-base": "^2.1.6",
|
||||||
"@types/string-hash": "^1.1.3",
|
"@types/string-hash": "^1.1.3",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
|
"@types/wicg-file-system-access": "^2023.10.5",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cypress": "^13.13.0",
|
"cypress": "^13.13.0",
|
||||||
|
|||||||
+11
-1
@@ -129,6 +129,7 @@ type AppState = {
|
|||||||
export: boolean
|
export: boolean
|
||||||
debug: boolean
|
debug: boolean
|
||||||
}
|
}
|
||||||
|
fileHandle: FileSystemFileHandle | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class App extends React.Component<any, AppState> {
|
export default class App extends React.Component<any, AppState> {
|
||||||
@@ -284,6 +285,7 @@ export default class App extends React.Component<any, AppState> {
|
|||||||
openlayersDebugOptions: {
|
openlayersDebugOptions: {
|
||||||
debugToolbox: false,
|
debugToolbox: false,
|
||||||
},
|
},
|
||||||
|
fileHandle: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.layerWatcher = new LayerWatcher({
|
this.layerWatcher = new LayerWatcher({
|
||||||
@@ -611,7 +613,8 @@ export default class App extends React.Component<any, AppState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openStyle = (styleObj: StyleSpecification & {id: string}) => {
|
openStyle = (styleObj: StyleSpecification & {id: string}, fileHandle: FileSystemFileHandle | null) => {
|
||||||
|
this.setState({fileHandle: fileHandle});
|
||||||
styleObj = this.setDefaultValues(styleObj)
|
styleObj = this.setDefaultValues(styleObj)
|
||||||
this.onStyleChanged(styleObj)
|
this.onStyleChanged(styleObj)
|
||||||
}
|
}
|
||||||
@@ -847,6 +850,10 @@ export default class App extends React.Component<any, AppState> {
|
|||||||
this.setModal(modalName, !this.state.isOpen[modalName]);
|
this.setModal(modalName, !this.state.isOpen[modalName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSetFileHandle(fileHandle: FileSystemFileHandle | null) {
|
||||||
|
this.setState({fileHandle: fileHandle});
|
||||||
|
}
|
||||||
|
|
||||||
onChangeOpenlayersDebug = (key: keyof AppState["openlayersDebugOptions"], value: boolean) => {
|
onChangeOpenlayersDebug = (key: keyof AppState["openlayersDebugOptions"], value: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
openlayersDebugOptions: {
|
openlayersDebugOptions: {
|
||||||
@@ -949,11 +956,14 @@ export default class App extends React.Component<any, AppState> {
|
|||||||
onStyleChanged={this.onStyleChanged}
|
onStyleChanged={this.onStyleChanged}
|
||||||
isOpen={this.state.isOpen.export}
|
isOpen={this.state.isOpen.export}
|
||||||
onOpenToggle={this.toggleModal.bind(this, 'export')}
|
onOpenToggle={this.toggleModal.bind(this, 'export')}
|
||||||
|
fileHandle={this.state.fileHandle}
|
||||||
|
onSetFileHandle={this.onSetFileHandle}
|
||||||
/>
|
/>
|
||||||
<ModalOpen
|
<ModalOpen
|
||||||
isOpen={this.state.isOpen.open}
|
isOpen={this.state.isOpen.open}
|
||||||
onStyleOpen={this.openStyle}
|
onStyleOpen={this.openStyle}
|
||||||
onOpenToggle={this.toggleModal.bind(this, 'open')}
|
onOpenToggle={this.toggleModal.bind(this, 'open')}
|
||||||
|
fileHandle={this.state.fileHandle}
|
||||||
/>
|
/>
|
||||||
<ModalSources
|
<ModalSources
|
||||||
mapStyle={this.state.mapStyle}
|
mapStyle={this.state.mapStyle}
|
||||||
|
|||||||
@@ -2,7 +2,15 @@ import React from 'react'
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import {detect} from 'detect-browser';
|
import {detect} from 'detect-browser';
|
||||||
|
|
||||||
import {MdFileDownload, MdOpenInBrowser, MdSettings, MdLayers, MdHelpOutline, MdFindInPage, MdLanguage} from 'react-icons/md'
|
import {
|
||||||
|
MdOpenInBrowser,
|
||||||
|
MdSettings,
|
||||||
|
MdLayers,
|
||||||
|
MdHelpOutline,
|
||||||
|
MdFindInPage,
|
||||||
|
MdLanguage,
|
||||||
|
MdSave
|
||||||
|
} from 'react-icons/md'
|
||||||
import pkgJson from '../../package.json'
|
import pkgJson from '../../package.json'
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import maputnikLogo from 'maputnik-design/logos/logo-color.svg?inline'
|
import maputnikLogo from 'maputnik-design/logos/logo-color.svg?inline'
|
||||||
@@ -216,8 +224,8 @@ class AppToolbarInternal extends React.Component<AppToolbarInternalProps> {
|
|||||||
<IconText>{t("Open")}</IconText>
|
<IconText>{t("Open")}</IconText>
|
||||||
</ToolbarAction>
|
</ToolbarAction>
|
||||||
<ToolbarAction wdKey="nav:export" onClick={this.props.onToggleModal.bind(this, 'export')}>
|
<ToolbarAction wdKey="nav:export" onClick={this.props.onToggleModal.bind(this, 'export')}>
|
||||||
<MdFileDownload />
|
<MdSave />
|
||||||
<IconText>{t("Export")}</IconText>
|
<IconText>{t("Save")}</IconText>
|
||||||
</ToolbarAction>
|
</ToolbarAction>
|
||||||
<ToolbarAction wdKey="nav:sources" onClick={this.props.onToggleModal.bind(this, 'sources')}>
|
<ToolbarAction wdKey="nav:sources" onClick={this.props.onToggleModal.bind(this, 'sources')}>
|
||||||
<MdLayers />
|
<MdLayers />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {saveAs} from 'file-saver'
|
|||||||
import {version} from 'maplibre-gl/package.json'
|
import {version} from 'maplibre-gl/package.json'
|
||||||
import {format} from '@maplibre/maplibre-gl-style-spec'
|
import {format} from '@maplibre/maplibre-gl-style-spec'
|
||||||
import type {StyleSpecification} from 'maplibre-gl'
|
import type {StyleSpecification} from 'maplibre-gl'
|
||||||
import {MdFileDownload} from 'react-icons/md'
|
import {MdMap, MdSave} from 'react-icons/md'
|
||||||
import { WithTranslation, withTranslation } from 'react-i18next';
|
import { WithTranslation, withTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import FieldString from './FieldString'
|
import FieldString from './FieldString'
|
||||||
@@ -22,6 +22,8 @@ type ModalExportInternalProps = {
|
|||||||
onStyleChanged(...args: unknown[]): unknown
|
onStyleChanged(...args: unknown[]): unknown
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onOpenToggle(...args: unknown[]): unknown
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
|
onSetFileHandle(fileHandle: FileSystemFileHandle | null): unknown
|
||||||
|
fileHandle: FileSystemFileHandle | null
|
||||||
} & WithTranslation;
|
} & WithTranslation;
|
||||||
|
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadHtml() {
|
createHtml() {
|
||||||
const tokenStyle = this.tokenizedStyle();
|
const tokenStyle = this.tokenizedStyle();
|
||||||
const htmlTitle = this.props.mapStyle.name || this.props.t("Map");
|
const htmlTitle = this.props.mapStyle.name || this.props.t("Map");
|
||||||
const html = `<!DOCTYPE html>
|
const html = `<!DOCTYPE html>
|
||||||
@@ -81,11 +83,49 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
|||||||
saveAs(blob, exportName + ".html");
|
saveAs(blob, exportName + ".html");
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadStyle() {
|
async saveStyle() {
|
||||||
const tokenStyle = this.tokenizedStyle();
|
const tokenStyle = this.tokenizedStyle();
|
||||||
const blob = new Blob([tokenStyle], {type: "application/json;charset=utf-8"});
|
|
||||||
const exportName = this.exportName();
|
let fileHandle = this.props.fileHandle;
|
||||||
saveAs(blob, exportName + ".json");
|
if (fileHandle == null) {
|
||||||
|
fileHandle = await this.createFileHandle();
|
||||||
|
this.props.onSetFileHandle(fileHandle)
|
||||||
|
if (fileHandle == null) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const writable = await fileHandle.createWritable();
|
||||||
|
await writable.write(tokenStyle);
|
||||||
|
await writable.close();
|
||||||
|
this.props.onOpenToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveStyleAs() {
|
||||||
|
const tokenStyle = this.tokenizedStyle();
|
||||||
|
|
||||||
|
const fileHandle = await this.createFileHandle();
|
||||||
|
this.props.onSetFileHandle(fileHandle)
|
||||||
|
if (fileHandle == null) return;
|
||||||
|
|
||||||
|
const writable = await fileHandle.createWritable();
|
||||||
|
await writable.write(tokenStyle);
|
||||||
|
await writable.close();
|
||||||
|
this.props.onOpenToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
async createFileHandle() : Promise<FileSystemFileHandle | null> {
|
||||||
|
const pickerOpts: SaveFilePickerOptions = {
|
||||||
|
types: [
|
||||||
|
{
|
||||||
|
description: "json",
|
||||||
|
accept: { "application/json": [".json"] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
suggestedName: this.exportName(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileHandle = await window.showSaveFilePicker(pickerOpts) as FileSystemFileHandle;
|
||||||
|
this.props.onSetFileHandle(fileHandle)
|
||||||
|
return fileHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeMetadataProperty(property: string, value: any) {
|
changeMetadataProperty(property: string, value: any) {
|
||||||
@@ -107,14 +147,14 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
|||||||
data-wd-key="modal:export"
|
data-wd-key="modal:export"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={t('Export Style')}
|
title={t('Save Style')}
|
||||||
className="maputnik-export-modal"
|
className="maputnik-export-modal"
|
||||||
>
|
>
|
||||||
|
|
||||||
<section className="maputnik-modal-section">
|
<section className="maputnik-modal-section">
|
||||||
<h1>{t("Download Style")}</h1>
|
<h1>{t("Save Style")}</h1>
|
||||||
<p>
|
<p>
|
||||||
{t("Download a JSON style to your computer.")}
|
{t("Save the JSON style to your computer.")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -140,17 +180,23 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
|||||||
|
|
||||||
<div className="maputnik-modal-export-buttons">
|
<div className="maputnik-modal-export-buttons">
|
||||||
<InputButton
|
<InputButton
|
||||||
onClick={this.downloadStyle.bind(this)}
|
onClick={this.saveStyle.bind(this)}
|
||||||
>
|
>
|
||||||
<MdFileDownload />
|
<MdSave />
|
||||||
{t("Download Style")}
|
{t("Save")}
|
||||||
|
</InputButton>
|
||||||
|
<InputButton
|
||||||
|
onClick={this.saveStyleAs.bind(this)}
|
||||||
|
>
|
||||||
|
<MdSave />
|
||||||
|
{t("Save as")}
|
||||||
</InputButton>
|
</InputButton>
|
||||||
|
|
||||||
<InputButton
|
<InputButton
|
||||||
onClick={this.downloadHtml.bind(this)}
|
onClick={this.createHtml.bind(this)}
|
||||||
>
|
>
|
||||||
<MdFileDownload />
|
<MdMap />
|
||||||
{t("Download HTML")}
|
{t("Create HTML")}
|
||||||
</InputButton>
|
</InputButton>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { FormEvent } from 'react'
|
import React, { FormEvent } from 'react'
|
||||||
import {MdFileUpload} from 'react-icons/md'
|
import {MdFileUpload} from 'react-icons/md'
|
||||||
import {MdAddCircleOutline} from 'react-icons/md'
|
import {MdAddCircleOutline} from 'react-icons/md'
|
||||||
import FileReaderInput, { Result } from 'react-file-reader-input'
|
|
||||||
import { Trans, WithTranslation, withTranslation } from 'react-i18next';
|
import { Trans, WithTranslation, withTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import ModalLoading from './ModalLoading'
|
import ModalLoading from './ModalLoading'
|
||||||
@@ -47,6 +46,7 @@ type ModalOpenInternalProps = {
|
|||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onOpenToggle(...args: unknown[]): unknown
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
onStyleOpen(...args: unknown[]): unknown
|
onStyleOpen(...args: unknown[]): unknown
|
||||||
|
fileHandle: FileSystemFileHandle | null
|
||||||
} & WithTranslation;
|
} & WithTranslation;
|
||||||
|
|
||||||
type ModalOpenState = {
|
type ModalOpenState = {
|
||||||
@@ -135,29 +135,37 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
this.onStyleSelect(this.state.styleUrl);
|
this.onStyleSelect(this.state.styleUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpload = (_: any, files: Result[]) => {
|
onOpenFile = async () => {
|
||||||
const [, file] = files[0];
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
this.clearError();
|
this.clearError();
|
||||||
|
|
||||||
reader.readAsText(file, "UTF-8");
|
const pickerOpts: OpenFilePickerOptions = {
|
||||||
reader.onload = e => {
|
types: [
|
||||||
let mapStyle;
|
{
|
||||||
try {
|
description: "json",
|
||||||
mapStyle = JSON.parse(e.target?.result as string)
|
accept: { "application/json": [".json"] },
|
||||||
}
|
},
|
||||||
catch(err) {
|
],
|
||||||
this.setState({
|
multiple: false,
|
||||||
error: (err as Error).toString()
|
};
|
||||||
});
|
|
||||||
return;
|
const [fileHandle] = await window.showOpenFilePicker(pickerOpts) as Array<FileSystemFileHandle>;
|
||||||
}
|
const file = await fileHandle.getFile();
|
||||||
mapStyle = style.ensureStyleValidity(mapStyle)
|
const content = await file.text();
|
||||||
this.props.onStyleOpen(mapStyle);
|
|
||||||
this.onOpenToggle();
|
let mapStyle;
|
||||||
|
try {
|
||||||
|
mapStyle = JSON.parse(content)
|
||||||
|
} catch (err) {
|
||||||
|
this.setState({
|
||||||
|
error: (err as Error).toString()
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
reader.onerror = e => console.log(e.target);
|
mapStyle = style.ensureStyleValidity(mapStyle)
|
||||||
|
|
||||||
|
this.props.onStyleOpen(mapStyle, fileHandle);
|
||||||
|
this.onOpenToggle();
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpenToggle() {
|
onOpenToggle() {
|
||||||
@@ -196,7 +204,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Modal
|
<Modal
|
||||||
data-wd-key="modal:open"
|
data-wd-key="modal:open"
|
||||||
@@ -206,11 +214,14 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
>
|
>
|
||||||
{errorElement}
|
{errorElement}
|
||||||
<section className="maputnik-modal-section">
|
<section className="maputnik-modal-section">
|
||||||
<h1>{t("Upload Style")}</h1>
|
<h1>{t("Open local Style")}</h1>
|
||||||
<p>{t("Upload a JSON style from your computer.")}</p>
|
<p>{t("Open a local JSON style from your computer.")}</p>
|
||||||
<FileReaderInput onChange={this.onUpload} tabIndex={-1} aria-label={t("Style file")}>
|
<div>
|
||||||
<InputButton className="maputnik-upload-button"><MdFileUpload /> {t("Upload")}</InputButton>
|
<InputButton
|
||||||
</FileReaderInput>
|
className="maputnik-big-button"
|
||||||
|
onClick={this.onOpenFile}><MdFileUpload/> {t("Open Style")}
|
||||||
|
</InputButton>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="maputnik-modal-section">
|
<section className="maputnik-modal-section">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
## Internationalization
|
## Internationalization
|
||||||
|
|
||||||
The process of internationlization is pretty straight forward for Maputnik.
|
The process of internationalization is pretty straight forward for Maputnik.
|
||||||
|
|
||||||
## Add a new language
|
## Add a new language
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"Map view": "Kartenansicht",
|
"Map view": "Kartenansicht",
|
||||||
"Maputnik on GitHub": "Maputnik auf GitHub",
|
"Maputnik on GitHub": "Maputnik auf GitHub",
|
||||||
"Open": "Öffnen",
|
"Open": "Öffnen",
|
||||||
"Export": "Exportieren",
|
"Save": "Speichern",
|
||||||
"Data Sources": "Datenquellen",
|
"Data Sources": "Datenquellen",
|
||||||
"Style Settings": "Stileinstellungen",
|
"Style Settings": "Stileinstellungen",
|
||||||
"View": "Ansicht",
|
"View": "Ansicht",
|
||||||
@@ -81,17 +81,14 @@
|
|||||||
"Close modal": "Modale Fenster schließen",
|
"Close modal": "Modale Fenster schließen",
|
||||||
"Debug": "Debug",
|
"Debug": "Debug",
|
||||||
"Options": "Optionen",
|
"Options": "Optionen",
|
||||||
"<0>Open in OSM</0> — Opens the current view on openstreetmap.org": "<0>In OSM öffnen</0> — Öffnet die aktuelle Ansicht auf openstreetmap.org",
|
"Save Style": "Stil Speichern",
|
||||||
"Export Style": "Stil exportieren",
|
"Save the JSON style to your computer.": "Speichere den JSON Stil auf deinem Computer.",
|
||||||
"Download Style": "Stil herunterladen",
|
"Save as": "Speichern unter",
|
||||||
"Download a JSON style to your computer.": "Lade einen JSON-Stil auf deinen Computer herunter.",
|
"Create HTML": "HTML erstellen",
|
||||||
"Download HTML": "HTML herunterladen",
|
|
||||||
"Cancel": "Abbrechen",
|
"Cancel": "Abbrechen",
|
||||||
"Open Style": "Stil öffnen",
|
"Open Style": "Stil öffnen",
|
||||||
"Upload Style": "Stil hochladen",
|
"Open local Style": "Lokalen Stil öffnen",
|
||||||
"Upload a JSON style from your computer.": "Lade einen JSON-Stil von deinem Computer hoch.",
|
"Open a local JSON style from your computer.": "Öffne einen lokalen JSON Stil von deinem Computer.",
|
||||||
"Style file": "Stildatei",
|
|
||||||
"Upload": "Hochladen",
|
|
||||||
"Load from URL": "Von URL laden",
|
"Load from URL": "Von URL laden",
|
||||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "Von einer URL laden. Beachte, dass die URL <1>CORS aktiviert</1> haben muss.",
|
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "Von einer URL laden. Beachte, dass die URL <1>CORS aktiviert</1> haben muss.",
|
||||||
"Style URL": "Stil-URL",
|
"Style URL": "Stil-URL",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"Map view": "Vue de la carte",
|
"Map view": "Vue de la carte",
|
||||||
"Maputnik on GitHub": "Maputnik sur GitHub",
|
"Maputnik on GitHub": "Maputnik sur GitHub",
|
||||||
"Open": "Ouvrir",
|
"Open": "Ouvrir",
|
||||||
"Export": "Exporter",
|
"Save": "Enregistrer",
|
||||||
"Data Sources": "Sources de données",
|
"Data Sources": "Sources de données",
|
||||||
"Style Settings": "Paramètres du style",
|
"Style Settings": "Paramètres du style",
|
||||||
"View": "Vue",
|
"View": "Vue",
|
||||||
@@ -81,17 +81,14 @@
|
|||||||
"Close modal": "Fermer la fenêtre modale",
|
"Close modal": "Fermer la fenêtre modale",
|
||||||
"Debug": "Déboguer",
|
"Debug": "Déboguer",
|
||||||
"Options": "Options",
|
"Options": "Options",
|
||||||
"<0>Open in OSM</0> — Opens the current view on openstreetmap.org": "<0>Ouvrir dans OSM</0> — Ouvre la vue actuelle sur openstreetmap.org",
|
"Save Style": "Enregistrer le style",
|
||||||
"Export Style": "Exporter le style",
|
"Save the JSON style to your computer.": "Enregistrer le style JSON sur votre ordinateur.",
|
||||||
"Download Style": "Télécharger le style",
|
"Save as": "Enregistrer sous",
|
||||||
"Download a JSON style to your computer.": "Téléchargez un style JSON sur votre ordinateur.",
|
"Create HTML": "Créer le HTML",
|
||||||
"Download HTML": "Télécharger HTML",
|
|
||||||
"Cancel": "Annuler",
|
"Cancel": "Annuler",
|
||||||
"Open Style": "Ouvrir le style",
|
"Open Style": "Ouvrir le style",
|
||||||
"Upload Style": "Transférer un style",
|
"Open local Style": "Ouvrir un style local",
|
||||||
"Upload a JSON style from your computer.": "Transférer un style JSON depuis votre ordinateur.",
|
"Open a local JSON style from your computer.": "Ouvrir un style JSON local depuis votre ordinateur.",
|
||||||
"Style file": "Fichier de style",
|
|
||||||
"Upload": "Transférer",
|
|
||||||
"Load from URL": "Charger depuis une URL",
|
"Load from URL": "Charger depuis une URL",
|
||||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "Charger depuis une URL. Notez que l'URL doit avoir les <1>CORS activés</1>.",
|
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "Charger depuis une URL. Notez que l'URL doit avoir les <1>CORS activés</1>.",
|
||||||
"Style URL": "URL du style",
|
"Style URL": "URL du style",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"Map view": "תצוגת מפה",
|
"Map view": "תצוגת מפה",
|
||||||
"Maputnik on GitHub": "מפוטניק בגיטהב",
|
"Maputnik on GitHub": "מפוטניק בגיטהב",
|
||||||
"Open": "פתיחה",
|
"Open": "פתיחה",
|
||||||
"Export": "ייצוא",
|
"Save": "שמור",
|
||||||
"Data Sources": "מקורות מידע",
|
"Data Sources": "מקורות מידע",
|
||||||
"Style Settings": "הגדרות הסטייל",
|
"Style Settings": "הגדרות הסטייל",
|
||||||
"View": "תצוגה",
|
"View": "תצוגה",
|
||||||
@@ -81,16 +81,14 @@
|
|||||||
"Close modal": "סגירת חלונית",
|
"Close modal": "סגירת חלונית",
|
||||||
"Debug": "דיבאג",
|
"Debug": "דיבאג",
|
||||||
"Options": "אפשרויות",
|
"Options": "אפשרויות",
|
||||||
"Export Style": "ייצוא של הסטייל",
|
"Save Style": "שמירת הסטייל",
|
||||||
"Download Style": "הורדה של הסטייל",
|
"Save the JSON style to your computer.": "שמירת הסטייל JSON במחשב שלך.",
|
||||||
"Download a JSON style to your computer.": "הורדה של הסטייל למחשב",
|
"Save as": "שמירה בשם",
|
||||||
"Download HTML": "הורדה כ-HTML",
|
"Create HTML": "צור HTML",
|
||||||
"Cancel": "ביטול",
|
"Cancel": "ביטול",
|
||||||
"Open Style": "פתיחת סטייל",
|
"Open Style": "פתיחת סטייל",
|
||||||
"Upload Style": "העלאה של סטייל",
|
"Open local Style": "פתיחת סטייל מקומי",
|
||||||
"Upload a JSON style from your computer.": "העלאה של סטייל מהמחשב",
|
"Open a local JSON style from your computer.": "פתיחת סטייל JSON מקומי מהמחשב שלך.",
|
||||||
"Style file": "קובץ סטייל",
|
|
||||||
"Upload": "העלאה",
|
|
||||||
"Load from URL": "פתיחה מתוך כתובת",
|
"Load from URL": "פתיחה מתוך כתובת",
|
||||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "פתיחה מכתובת, שימו לב: הכתובת צריכה לתמוך ב- CORS",
|
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "פתיחה מכתובת, שימו לב: הכתובת צריכה לתמוך ב- CORS",
|
||||||
"Style URL": "כתוסת סטייל",
|
"Style URL": "כתוסת סטייל",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"Map view": "地図画面",
|
"Map view": "地図画面",
|
||||||
"Maputnik on GitHub": "GitHubのMaputnik",
|
"Maputnik on GitHub": "GitHubのMaputnik",
|
||||||
"Open": "開く",
|
"Open": "開く",
|
||||||
"Export": "エクスポート",
|
"Save": "保存",
|
||||||
"Data Sources": "データソース",
|
"Data Sources": "データソース",
|
||||||
"Style Settings": "スタイル設定",
|
"Style Settings": "スタイル設定",
|
||||||
"View": "表示",
|
"View": "表示",
|
||||||
@@ -81,16 +81,14 @@
|
|||||||
"Close modal": "モーダルを閉じる",
|
"Close modal": "モーダルを閉じる",
|
||||||
"Debug": "デバッグ",
|
"Debug": "デバッグ",
|
||||||
"Options": "設定",
|
"Options": "設定",
|
||||||
"Export Style": "スタイルをエクスポート",
|
"Save Style": "スタイルを保存",
|
||||||
"Download Style": "スタイルをダウンロード",
|
"Save the JSON style to your computer.": "JSONスタイルをコンピュータに保存します。",
|
||||||
"Download a JSON style to your computer.": "パソコンにJSONスタイルをダウンロードします。",
|
"Save as": "名前を付けて保存",
|
||||||
"Download HTML": "HTMLをダウンロード",
|
"Create HTML": "HTMLを作成",
|
||||||
"Cancel": "キャンセル",
|
"Cancel": "キャンセル",
|
||||||
"Open Style": "スタイルを開く",
|
"Open Style": "スタイルを開く",
|
||||||
"Upload Style": "スタイルをアップロードする",
|
"Open local Style": "ローカルスタイルを開く",
|
||||||
"Upload a JSON style from your computer.": "JSONスタイルをパソコンからアップロードする",
|
"Open a local JSON style from your computer.": "コンピュータからローカルJSONスタイルを開きます。",
|
||||||
"Style file": "スタイルファイル",
|
|
||||||
"Upload": "アップロード",
|
|
||||||
"Load from URL": "URLから読み込む",
|
"Load from URL": "URLから読み込む",
|
||||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "URLから読み込む。注意: URLは <1>CORSを有効にする</1> 必要があります。",
|
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "URLから読み込む。注意: URLは <1>CORSを有効にする</1> 必要があります。",
|
||||||
"Style URL": "スタイルURL",
|
"Style URL": "スタイルURL",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"Map view": "地图视图",
|
"Map view": "地图视图",
|
||||||
"Maputnik on GitHub": "GitHub上的Maputnik",
|
"Maputnik on GitHub": "GitHub上的Maputnik",
|
||||||
"Open": "打开",
|
"Open": "打开",
|
||||||
"Export": "导出",
|
"Save": "保存",
|
||||||
"Data Sources": "数据源",
|
"Data Sources": "数据源",
|
||||||
"Style Settings": "样式设置",
|
"Style Settings": "样式设置",
|
||||||
"View": "视图",
|
"View": "视图",
|
||||||
@@ -81,16 +81,14 @@
|
|||||||
"Close modal": "关闭模态框",
|
"Close modal": "关闭模态框",
|
||||||
"Debug": "调试",
|
"Debug": "调试",
|
||||||
"Options": "选项",
|
"Options": "选项",
|
||||||
"Export Style": "导出样式",
|
"Save Style": "保存样式",
|
||||||
"Download Style": "下载样式",
|
"Save the JSON style to your computer.": "将JSON样式保存到您的计算机。",
|
||||||
"Download a JSON style to your computer.": "将JSON样式下载到您的电脑。",
|
"Save as": "另存为",
|
||||||
"Download HTML": "下载HTML",
|
"Create HTML": "创建HTML",
|
||||||
"Cancel": "取消",
|
"Cancel": "取消",
|
||||||
"Open Style": "打开样式",
|
"Open Style": "打开样式",
|
||||||
"Upload Style": "上传样式",
|
"Open local Style": "打开本地样式",
|
||||||
"Upload a JSON style from your computer.": "从您的电脑上传JSON样式。",
|
"Open a local JSON style from your computer.": "从您的计算机打开本地JSON样式。",
|
||||||
"Style file": "样式文件",
|
|
||||||
"Upload": "上传",
|
|
||||||
"Load from URL": "从URL加载",
|
"Load from URL": "从URL加载",
|
||||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "从URL加载。注意:URL必须启用 <1>CORS</1>。",
|
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "从URL加载。注意:URL必须启用 <1>CORS</1>。",
|
||||||
"Style URL": "样式URL",
|
"Style URL": "样式URL",
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@
|
|||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"types": ["geojson"],
|
"types": ["geojson", "@types/wicg-file-system-access"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"ts-node": {
|
"ts-node": {
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Node"
|
"moduleResolution": "Node",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user