Skip to content

Commit

Permalink
First draft for i18n support #123
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr committed Dec 21, 2022
1 parent e855873 commit 204fbe1
Show file tree
Hide file tree
Showing 17 changed files with 170 additions and 25 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ This allows or disallows loading and browsing external STAC data.
External STAC data is any data that is not a children of the given `catalogUrl`.
Must be set to `true` if a `catalogUrl` is not given as otherwise you won't be able to browse anything.

### locale

The default language to use for STAC Browser, defaults to `en` (English).
The language given here must be present in `supportedLocales`.

### fallbackLocale

The language to use if individual phrases are not available in the default language, defaults to `en` (English).
The language given here must be present in `supportedLocales`.

### supportedLocales

A list of languages to show in the STAC Browser UI.
The languages given here must have a corresponding JSON file in the `src/locales` folder, e.g.
`src/locales/en.json` for English.

In CLI, please provide the languages separated by a space, e.g. `--supportedLocales en de fr it`

### stacLint

***experimental***
Expand Down
6 changes: 6 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ module.exports = {
catalogUrl: null, // Must have a slash at the end for folders/APIs
catalogTitle: "STAC Browser",
allowExternalAccess: true, // Must be true if catalogUrl is not given
locale: "en",
fallbackLocale: "en",
supportedLocales: [
"en",
"de"
],
useTileLayerAsFallback: true,
tileSourceTemplate: null,
displayGeoTiffByDefault: false,
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"start": "vue-cli-service serve",
"build": "vue-cli-service build --report",
"lint": "vue-cli-service lint"
"lint": "vue-cli-service lint",
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\""
},
"bugs": {
"url": "https://github.com/radiantearth/stac-browser/issues"
Expand Down Expand Up @@ -44,6 +45,7 @@
"urijs": "^1.19.11",
"v-clipboard": "^2.2.3",
"vue": "^2.6.12",
"vue-i18n": "^8.28.2",
"vue-read-more-smooth": "^0.1.8",
"vue-router": "^3.2.0",
"vue2-datepicker": "^3.9.2",
Expand All @@ -63,6 +65,7 @@
"eslint-plugin-vue": "^8.7.1",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"vue-cli-plugin-i18n": "~2.3.1",
"vue-template-compiler": "^2.6.12"
},
"browserslist": [
Expand Down
16 changes: 6 additions & 10 deletions src/StacBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import Vue from "vue";
import VueRouter from "vue-router";
import Vuex, { mapGetters, mapState } from 'vuex';
import CONFIG from './config';
import getRoutes from "./router";
import getStore from "./store";
Expand Down Expand Up @@ -61,14 +62,6 @@ Vue.directive('b-toggle', VBToggle);
// Used to detect when a catalog/item becomes visible so that further data can be loaded
Vue.directive('b-visible', VBVisible);
let CONFIG;
if (typeof CONFIG_PATH === 'undefined' && typeof CONFIG_CLI === 'undefined') {
CONFIG = require('../config');
}
else {
CONFIG = Object.assign(require(CONFIG_PATH), CONFIG_CLI);
}
// Setup store
Vue.use(Vuex);
const store = getStore(CONFIG);
Expand Down Expand Up @@ -117,8 +110,8 @@ export default {
};
},
computed: {
...mapState(['title', 'doAuth', 'globalError', 'stateQueryParameters']),
...mapState({catalogUrlFromVueX: 'catalogUrl'}),
...mapState(['doAuth', 'globalError', 'stateQueryParameters', 'title']),
...mapState({catalogUrlFromVueX: 'catalogUrl', localeFromVueX: 'locale'}),
...mapGetters(['displayCatalogTitle']),
browserVersion() {
if (typeof STAC_BROWSER_VERSION !== 'undefined') {
Expand All @@ -134,6 +127,9 @@ export default {
title(title) {
document.title = title;
},
localeFromVueX(locale) {
this.$root.$i18n.locale = locale;
},
catalogUrlFromVueX(url) {
if (url) {
// Load the root catalog data if not available (e.g. after page refresh or external access)
Expand Down
19 changes: 16 additions & 3 deletions src/components/Map.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="map-container">
<l-map class="map" v-if="show" :class="stac.type" @ready="init" :options="mapOptions">
<LControlFullscreen />
<LControlFullscreen :key="fullscreenKey" :options="fullscreenOptions" />
<template v-if="baseMaps.length > 0">
<component v-for="baseMap in baseMaps" :key="baseMap.name" :is="baseMap.component" v-bind="baseMap" :layers="baseMap.name" layer-type="base" />
</template>
Expand Down Expand Up @@ -112,12 +112,21 @@ export default {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors.'
},
dblClickState: null,
selectedItem: null
selectedItem: null,
fullscreenKey: 1
};
},
computed: {
...mapState(['buildTileUrlTemplate', 'crossOriginMedia', 'displayGeoTiffByDefault', 'geoTiffResolution', 'maxPreviewsOnMap', 'tileSourceTemplate', 'useTileLayerAsFallback']),
...mapState(['buildTileUrlTemplate', 'crossOriginMedia', 'displayGeoTiffByDefault', 'geoTiffResolution', 'locale', 'maxPreviewsOnMap', 'tileSourceTemplate', 'useTileLayerAsFallback']),
...mapGetters(['getStac', 'supportsExtension']),
fullscreenOptions() {
return {
title: {
'false': this.$t('leaflet.fullscreen.false'),
'true': this.$t('leaflet.fullscreen.true'),
}
};
},
baseMaps() {
let targets = [];
if (this.stac instanceof STAC) {
Expand Down Expand Up @@ -146,6 +155,10 @@ export default {
}
},
watch: {
locale() {
// This recreates the component so that it picks up the new translations
this.fullscreenKey++;
},
async stacLayerData() {
await this.showStacLayer();
},
Expand Down
40 changes: 35 additions & 5 deletions src/components/Share.vue → src/components/Source.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
<template>
<div class="share mt-1">
<b-button-group>
<b-button v-if="stacUrl" size="sm" variant="outline-primary" id="popover-link" title="Details about the STAC source"><b-icon-link /> <span class="button-label">Source</span></b-button>
<b-button size="sm" variant="outline-primary" id="popover-share" title="Share this page with others"><b-icon-share /> <span class="button-label">Share</span></b-button>
<b-button size="sm" variant="outline-primary" id="popover-link" title="Details about the STAC source">
<b-icon-link /> <span class="button-label">Source</span>
</b-button>
<b-button v-if="stacUrl" size="sm" variant="outline-primary" id="popover-link" title="Details about the STAC source">
<b-icon-link /> <span class="button-label">Source</span>
</b-button>
<b-button size="sm" variant="outline-primary" id="popover-share" title="Share this page with others">
<b-icon-share /> <span class="button-label">Share</span>
</b-button>
<b-dropdown size="sm" variant="outline-primary" right>
<template #button-content>
<b-icon-flag /> <span class="button-label">Language ({{ currentLanguage }})</span>
</template>
<b-dropdown-item v-for="l of supportedLocales" :key="l" @click="switchLanguage(l)">
<b-icon-check v-if="locale === l" />
<b-icon-blank v-else />
{{ $t(`languages.${l}.native`) }} / {{ $t(`languages.${l}.global`) }}
</b-dropdown-item>
</b-dropdown>
</b-button-group>
<b-popover
v-if="stacUrl" target="popover-link" triggers="click blur" placement="bottom"
Expand Down Expand Up @@ -37,7 +54,9 @@
</template>

<script>
import { BIconEnvelope, BIconLink, BIconShare, BIconTwitter, BPopover } from 'bootstrap-vue';
import {
BIconBlank, BIconCheck, BIconEnvelope, BIconFlag, BIconLink, BIconShare, BIconTwitter,
BDropdown, BDropdownItem, BPopover } from 'bootstrap-vue';
import { mapState } from 'vuex';
import Url from './Url.vue';
Expand All @@ -46,9 +65,14 @@ import URI from 'urijs';
import Utils from '../utils';
export default {
name: "Share",
name: "Source",
components: {
BDropdown,
BDropdownItem,
BIconBlank,
BIconCheck,
BIconEnvelope,
BIconFlag,
BIconLink,
BIconShare,
BIconTwitter,
Expand All @@ -70,7 +94,10 @@ export default {
}
},
computed: {
...mapState(['privateQueryParameters', 'stacLint', 'stacProxyUrl', 'valid']),
...mapState(['locale', 'privateQueryParameters', 'supportedLocales', 'stacLint', 'stacProxyUrl', 'valid']),
currentLanguage() {
return this.$t(`languages.${this.locale}.native`);
},
canValidate() {
if (!this.stacLint || typeof this.stacUrl !== 'string') {
return false;
Expand Down Expand Up @@ -110,6 +137,9 @@ export default {
},
browserUrl() {
return window.location.toString();
},
switchLanguage(locale) {
this.$store.commit('config', {locale});
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/StacHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default {
BIconLock,
BIconUnlock,
StacLink,
Share: () => import('../components/Share.vue')
Share: () => import('./Source.vue')
},
computed: {
...mapState(['allowSelectCatalog', 'authConfig', 'authData', 'catalogUrl', 'data', 'url', 'title']),
Expand Down
9 changes: 9 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let config;
if (typeof CONFIG_PATH === 'undefined' && typeof CONFIG_CLI === 'undefined') {
config = require('../config');
}
else {
config = Object.assign(require(CONFIG_PATH), CONFIG_CLI);
}

export default config;
28 changes: 28 additions & 0 deletions src/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import CONFIG from './config';

Vue.use(VueI18n);

function loadLocaleMessages () {
const messages = {};
const languages = {};
for(let locale of CONFIG.supportedLocales) {
languages[locale] = require(`./locales/${locale}/config.json`);
// ToDo: Load not yet required languages async
// https://kazupon.github.io/vue-i18n/guide/lazy-loading.html
messages[locale] = require(`./locales/${locale}/texts.json`);
}
for(let locale in messages) {
messages[locale].languages = languages;
}
return messages;
}

const i18n = new VueI18n({
locale: CONFIG.locale,
fallbackLocale: CONFIG.fallbackLocale,
messages: loadLocaleMessages()
});

export default i18n;
4 changes: 4 additions & 0 deletions src/locales/de/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"native": "Deutsch",
"global": "German"
}
11 changes: 11 additions & 0 deletions src/locales/de/texts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"specifyCatalog": "Bitte gib einen STAC Catalog oder eine STAC API an...",
"selectStacIndex": "... oder wähle einen von STAC Index",
"load": "Laden",
"leaflet": {
"fullscreen": {
"false": "Zeige im Vollbild-Modus",
"true": "Verlasse den Vollbild-Modus"
}
}
}
4 changes: 4 additions & 0 deletions src/locales/en/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"native": "English",
"global": "English"
}
11 changes: 11 additions & 0 deletions src/locales/en/texts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"specifyCatalog": "Please specify a STAC Catalog or API...",
"selectStacIndex": "... or select one from STAC Index",
"load": "Load",
"leaflet": {
"fullscreen": {
"false": "View Fullscreen",
"true": "Exit Fullscreen"
}
}
}
4 changes: 3 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Vue from "vue";
import StacBrowser from "./StacBrowser.vue";
import i18n from './i18n';

Vue.config.productionTip = false;

new Vue({
render: (h) => h(StacBrowser),
i18n,
render: (h) => h(StacBrowser)
}).$mount("#stac-browser");
2 changes: 1 addition & 1 deletion src/views/Catalog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<h2>Description</h2>
<DeprecationNotice v-if="data.deprecated" :data="data" />
<AnonymizedNotice v-if="data['anon:warning']" :warning="data['anon:warning']" />
<ReadMore v-if="data.description" :lines="10">
<ReadMore v-if="data.description" :lines="10" text="Read more" text-less="Read less">
<Description :description="data.description" />
</ReadMore>
<Keywords v-if="Array.isArray(data.keywords) && data.keywords.length > 0" :keywords="data.keywords" />
Expand Down
6 changes: 3 additions & 3 deletions src/views/SelectDataSource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
<b-col>
<b-form @submit="go">
<b-form-group
id="select" label="Please specify a STAC Catalog or API..." label-for="url"
id="select" :label="$t('specifyCatalog')" label-for="url"
:invalid-feedback="error" :state="valid"
>
<b-form-input id="url" type="url" :value="url" @input="setUrl" placeholder="https://..." />
</b-form-group>
<b-button type="submit" variant="primary">Load</b-button>
<b-button type="submit" variant="primary">{{ $t('load') }}</b-button>
</b-form>
<hr>
<b-form-group v-if="stacIndex.length > 0" id="stacIndex" label="... or select one from STAC Index">
<b-form-group v-if="stacIndex.length > 0" id="stacIndex" :label="$t('selectStacIndex')">
<b-list-group class="stacIndex">
<template v-for="catalog in stacIndex">
<b-list-group-item
Expand Down
10 changes: 10 additions & 0 deletions vue.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const argv = yargs(hideBin(process.argv))
'itemsPerPage',
'maxPreviewsOnMap'
])
.array([
'supportedLocales'
])
.argv;
// Clean-up arguments
delete argv._;
Expand Down Expand Up @@ -48,5 +51,12 @@ module.exports = {
includeAliases: ['Buffer', 'console', 'http', 'https', 'process', 'url']
})
]
},
pluginOptions: {
i18n: {
locale: mergedConfig.locale,
fallbackLocale: mergedConfig.fallbackLocale,
enableInSFC: false
}
}
};

0 comments on commit 204fbe1

Please sign in to comment.