Add i18 support

This commit is contained in:
Linus Groh
2019-12-13 19:45:21 +00:00
parent 4e449235b2
commit 73465268e2
13 changed files with 196 additions and 25 deletions
+14
View File
@@ -98,6 +98,8 @@ See [`docs/config.md`](docs/config.md) for all available options.
- Run `yarn lint` to lint and fix files
- Run `yarn test` to run unit tests
### CORS-Proxy
You can use the [`corsProxy.js`](scripts/corsProxy.js) script to use your production
instance of OwnTracks for development without making changes to its CORS-Headers:
@@ -123,6 +125,18 @@ and `OT_PROXY_PORT` environment variables.
Finally update `api.baseUrl` in your config to `"http://0.0.0.0:8888/https://owntracks.example.com"`.
### I18n
This project uses [Vue I18n](https://kazupon.github.io/vue-i18n/). To see missing and
unused i18n entries, run:
```console
$ yarn i18n:report
```
To add a new locale, copy `en.json` to `<locale>.json` in [`src/locales`](src/locales)
and start translating the individual strings. Make sure to add the new locale to the docs!
## Screenshots
<p align="center">
+8
View File
@@ -26,6 +26,7 @@ window.owntracks.config = {};
- [`baseUrl`](#apibaseurl)
- [`endDate`](#enddate)
- [`ignorePingLocation`](#ignorepinglocation)
- [`locale`](#locale)
- `map`
- [`attribution`](#mapattribution)
- `center`
@@ -120,6 +121,13 @@ Remove the `ping/ping` location from the fetched data. This is useful when using
};
```
### `locale`
The language to use for the user interface. Available: `en` (English).
- Type: [`String`]
- Default: `"en"`
### `map.attribution`
Attribution for map tiles.
+3
View File
@@ -10,6 +10,7 @@
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"cors-proxy": "node scripts/corsProxy.js",
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
"test": "vue-cli-service test:unit"
},
"dependencies": {
@@ -20,6 +21,7 @@
"leaflet.heat": "^0.2.0",
"vue": "^2.6.6",
"vue-feather-icons": "^5.0.0",
"vue-i18n": "^8.0.0",
"vue-js-modal": "^1.3.31",
"vue-outside-events": "^1.1.3",
"vue-router": "^3.1.3",
@@ -45,6 +47,7 @@
"lint-staged": "^9.5.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"vue-cli-plugin-i18n": "^0.6.0",
"vue-template-compiler": "^2.5.21"
},
"license": "MIT",
+17 -15
View File
@@ -4,15 +4,17 @@
<div class="nav-item">
<button
class="button button-outline"
title="Automatically center the map view and zoom in to relevant data"
:title="
$t('Automatically center the map view and zoom in to relevant data')
"
@click="$root.$emit('fitView')"
>
Fit View
{{ $t("Fit view") }}
</button>
</div>
<div class="nav-item">
<LayersIcon size="1x" />
<Dropdown label="Layer Settings" title="Show/hide layers">
<Dropdown :label="$t('Layer settings')" :title="$t('Show/hide layers')">
<label v-for="option in layerSettingsOptions" :key="option.layer">
<input
type="checkbox"
@@ -34,14 +36,14 @@
v-model="startDate"
:use-utc="true"
:disabled-dates="startDateDisabledDates"
title="Select start date"
:title="$t('Select start date')"
/>
to
<Datepicker
v-model="endDate"
:use-utc="true"
:disabled-dates="endDateDisabledDates"
title="Select end date"
:title="$t('Select end date')"
/>
</div>
<div class="nav-item">
@@ -49,10 +51,10 @@
<select
v-model="selectedUser"
class="dropdown-button button"
title="Select user"
:title="$t('Select user')"
>
<option :value="null">
Show All
{{ $t("Show all") }}
</option>
<option v-for="user in users" :value="user" :key="user">
{{ user }}
@@ -64,10 +66,10 @@
<select
v-model="selectedDevice"
class="dropdown-button button"
title="Select device"
:title="$t('Select device')"
>
<option :value="null">
Show All
{{ $t("Show all") }}
</option>
<option
v-for="device in devices[selectedUser]"
@@ -83,7 +85,7 @@
<div class="nav-item">
<button
class="button button-flat button-icon"
title="Download raw data"
:title="$t('Download raw data')"
@click="$modal.show('download')"
>
<DownloadIcon size="1x" />
@@ -92,7 +94,7 @@
<div class="nav-item">
<button
class="button button-flat button-icon"
title="Information"
:title="$t('Information')"
@click="$modal.show('information')"
>
<InfoIcon size="1x" />
@@ -131,10 +133,10 @@ export default {
data() {
return {
layerSettingsOptions: [
{ layer: "last", label: "Show last known locations" },
{ layer: "line", label: "Show location history (line)" },
{ layer: "points", label: "Show location history (points)" },
{ layer: "heatmap", label: "Show location heatmap" },
{ layer: "last", label: this.$t("Show last known locations") },
{ layer: "line", label: this.$t("Show location history (line)") },
{ layer: "points", label: this.$t("Show location history (points)") },
{ layer: "heatmap", label: this.$t("Show location heatmap") },
],
};
},
+3 -3
View File
@@ -8,15 +8,15 @@
id="option-minify-json"
/>
<label for="option-minify-json">
Minify JSON
{{ $t("Minify JSON") }}
</label>
</div>
<div class="buttons">
<button class="button button-outline button-primary" @click="copy">
Copy to Clipboard
{{ $t("Copy to clipboard") }}
</button>
<button class="button button-primary" @click="download">
Download
{{ $t("Download") }}
</button>
</div>
</modal>
+3 -3
View File
@@ -18,19 +18,19 @@
<li>
<GlobeIcon size="1x" />
<a href="https://owntracks.org">
OwnTracks Website
{{ $t("OwnTracks website") }}
</a>
</li>
<li>
<BookIcon size="1x" />
<a href="https://owntracks.org/booklet/">
OwnTracks Documentation
{{ $t("OwnTracks documentation") }}
</a>
</li>
<li>
<TwitterIcon size="1x" />
<a href="https://twitter.com/OwnTracks">
OwnTracks on Twitter
{{ $t("OwnTracks on Twitter") }}
</a>
</li>
</ul>
+1 -1
View File
@@ -1,7 +1,7 @@
<template>
<modal name="loading" :click-to-close="false" adaptive>
<LoaderIcon class="loader" size="1.5x" />
Loading data, please wait...
{{ $t("Loading data, please wait...") }}
</modal>
</template>
+1
View File
@@ -12,6 +12,7 @@ const DEFAULT_CONFIG = {
},
endDate,
ignorePingLocation: true,
locale: "en",
map: {
attribution:
'&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
+23
View File
@@ -0,0 +1,23 @@
import Vue from "vue";
import VueI18n from "vue-i18n";
import config from "@/config";
Vue.use(VueI18n);
const locales = require.context("./locales", true, /[A-Za-z0-9-_,\s]+\.json$/i);
const messages = {};
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i);
if (matched && matched.length > 1) {
const locale = matched[1];
messages[locale] = locales(key);
}
});
export default new VueI18n({
locale: config.locale,
fallbackLocale: "en",
formatFallbackMessages: true,
messages,
});
+24
View File
@@ -0,0 +1,24 @@
{
"Automatically center the map view and zoom in to relevant data": "Automatically center the map view and zoom in to relevant data",
"Fit view": "Fit view",
"Layer settings": "Layer settings",
"Show/hide layers": "Show/hide layers",
"Select start date": "Select start date",
"Select end date": "Select end date",
"Select user": "Select user",
"Show all": "Show all",
"Select device": "Select device",
"Download raw data": "Download raw data",
"Information": "Information",
"Show last known locations": "Show last known locations",
"Show location history (line)": "Show location history (line)",
"Show location history (points)": "Show location history (points)",
"Show location heatmap": "Show location heatmap",
"Minify JSON": "Minify JSON",
"Copy to clipboard": "Copy to clipboard",
"Download": "Download",
"OwnTracks website": "OwnTracks website",
"OwnTracks documentation": "OwnTracks documentation",
"OwnTracks on Twitter": "OwnTracks on Twitter",
"Loading data, please wait...": "Loading data, please wait..."
}
+2
View File
@@ -1,5 +1,6 @@
import Vue from "vue";
import App from "@/App.vue";
import i18n from "@/i18n";
import router from "@/router";
import store from "@/store";
import VModal from "vue-js-modal";
@@ -11,6 +12,7 @@ Vue.use(VOutsideEvents);
Vue.config.productionTip = false;
new Vue({
i18n,
router,
store,
render: h => h(App),
+8
View File
@@ -14,4 +14,12 @@ module.exports = {
}),
],
},
pluginOptions: {
i18n: {
locale: "en",
fallbackLocale: "en",
localeDir: "locales",
},
},
};
+89 -3
View File
@@ -2791,6 +2791,16 @@ cli-spinners@^2.0.0:
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.2.0.tgz#e8b988d9206c692302d8ee834e7a85c0144d8f77"
integrity sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==
cli-table3@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202"
integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==
dependencies:
object-assign "^4.1.0"
string-width "^2.1.1"
optionalDependencies:
colors "^1.1.2"
cli-truncate@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
@@ -2939,6 +2949,11 @@ color@^3.0.0:
color-convert "^1.9.1"
color-string "^1.5.2"
colors@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -3498,7 +3513,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
dependencies:
ms "2.0.0"
debug@^3.0.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
@@ -3554,6 +3569,11 @@ deepmerge@^1.5.2:
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"
integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
deepmerge@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
deepmerge@^4.0.0, deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
@@ -3800,6 +3820,14 @@ domutils@^1.5.1, domutils@^1.7.0:
dom-serializer "0"
domelementtype "1"
dot-object@^1.7.1:
version "1.9.0"
resolved "https://registry.yarnpkg.com/dot-object/-/dot-object-1.9.0.tgz#6e3d6d8379f794c5174599ddf05528f5990f076e"
integrity sha512-7MPN6y7XhAO4vM4eguj5+5HNKLjJYfkVG1ZR1Aput4Q4TR6SYeSjhpVQ77IzJHoSHffKbDxBC+48aCiiRurDPw==
dependencies:
commander "^2.20.0"
glob "^7.1.4"
dot-prop@^4.1.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@@ -3812,6 +3840,11 @@ dotenv-expand@^5.1.0:
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
dotenv@^6.0.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
dotenv@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
@@ -4110,6 +4143,11 @@ eslint@^6.7.2:
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
esm@^3.2.13:
version "3.2.25"
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
espree@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a"
@@ -4614,6 +4652,13 @@ flat-cache@^2.0.1:
rimraf "2.6.3"
write "1.0.3"
flat@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
dependencies:
is-buffer "~2.0.3"
flatted@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
@@ -5529,6 +5574,11 @@ is-buffer@^1.1.5:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-buffer@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
@@ -5778,6 +5828,11 @@ is-utf8@^0.2.0:
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
is-valid-glob@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa"
integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=
is-whitespace@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/is-whitespace/-/is-whitespace-0.3.0.tgz#1639ecb1be036aec69a54cbb401cfbed7114ab7f"
@@ -10573,6 +10628,20 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
vue-cli-plugin-i18n@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/vue-cli-plugin-i18n/-/vue-cli-plugin-i18n-0.6.0.tgz#8b15a5e817b6f55a05e411a565f7f3c5bb86c16b"
integrity sha512-tNF35Xjq5SnwN8VwbwIZaVKjYTRKU/Hg8tnx6ZrznI5OcFeYNXkmmazAyKTOFrxPHXxqspDOUqx/ougVLU04Lg==
dependencies:
debug "^3.1.0"
deepmerge "^2.1.1"
dotenv "^6.0.0"
flat "^4.0.0"
rimraf "^2.6.3"
vue "^2.5.16"
vue-i18n "^8.0.0"
vue-i18n-extract "^0.4.13"
vue-eslint-parser@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-6.0.5.tgz#c1c067c2755748e28f3872cd42e8c1c4c1a8059f"
@@ -10597,6 +10666,23 @@ vue-hot-reload-api@^2.3.0:
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
vue-i18n-extract@^0.4.13:
version "0.4.14"
resolved "https://registry.yarnpkg.com/vue-i18n-extract/-/vue-i18n-extract-0.4.14.tgz#ed48137944b562fec67bca41a9dcaaee93909738"
integrity sha512-gfbhyOU+zo8/dg1kHudBGHTJx9cvS7bsO2G/3mvSjzb3jCIu/HSbBT/EFaJMbo3y82zODq9+ehZZyVj5UH2qNA==
dependencies:
cli-table3 "^0.5.1"
dot-object "^1.7.1"
esm "^3.2.13"
glob "^7.1.3"
is-valid-glob "^1.0.0"
yargs "^13.2.2"
vue-i18n@^8.0.0:
version "8.15.1"
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.15.1.tgz#90097a08a1e932f645c6b9c404c780d24f6d6224"
integrity sha512-GBbz8qYCu0U2LNu4IcuFLZiuyninG4k26knvhL7GZG5Ncp4RR2VKDEH6g8gQ6I+UUBCvH2MBQVPSdxWe4DBkPw==
vue-jest@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/vue-jest/-/vue-jest-3.0.5.tgz#d6f124b542dcbff207bf9296c19413f4c40b70c9"
@@ -10665,7 +10751,7 @@ vue2-leaflet@^2.2.1:
resolved "https://registry.yarnpkg.com/vue2-leaflet/-/vue2-leaflet-2.2.1.tgz#cd67274951751a33df147481fce2b956ba174c7e"
integrity sha512-yBB3Ilv9LTszNn/uxUATq8+Ahw/1FqIasdQehb9m1tJ5T9qeEk8Fr9a6uLzvR+zuz88rnEQVo7/iGUd96E7iLg==
vue@^2.6.6:
vue@^2.5.16, vue@^2.6.6:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
@@ -11134,7 +11220,7 @@ yargs@12.0.5:
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^11.1.1"
yargs@^13.3.0:
yargs@^13.2.2, yargs@^13.3.0:
version "13.3.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==