Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Updated Keycloak to 26.3.2
- Added Latvian, Portuguese (Brazil), Russian, Ukrainian and Chinese (Taiwan) translation

## [1.4.3](https://github.com/cryptomator/hub/compare/1.4.2...1.4.3)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ALTER TABLE "user_details" ALTER COLUMN "language" TYPE VARCHAR;

UPDATE "user_details" SET "language" = 'de-DE' WHERE "language" = 'de';
UPDATE "user_details" SET "language" = 'en-US' WHERE "language" = 'en';
UPDATE "user_details" SET "language" = 'fr-FR' WHERE "language" = 'fr';
UPDATE "user_details" SET "language" = 'it-IT' WHERE "language" = 'it';
UPDATE "user_details" SET "language" = 'nl-NL' WHERE "language" = 'nl';
UPDATE "user_details" SET "language" = 'pt-PT' WHERE "language" = 'pt';
UPDATE "user_details" SET "language" = 'tr-TR' WHERE "language" = 'tr';
6 changes: 1 addition & 5 deletions frontend/src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,6 @@ import backend, { BillingDto, VersionDto } from '../common/backend';
import config, { absFrontendBaseURL } from '../common/config';
import { FetchUpdateError, LatestVersionDto, updateChecker } from '../common/updatecheck';
import { debounce } from '../common/util';
import { Locale } from '../i18n/index';
import FetchError from './FetchError.vue';

const { t, d, locale, fallbackLocale } = useI18n({ useScope: 'global' });
Expand Down Expand Up @@ -389,10 +388,7 @@ async function fetchData() {

function manageSubscription() {
const returnUrl = `${absFrontendBaseURL}admin`;
const supportedLanguages = [Locale.EN, Locale.DE];
const supportedLanguagePathComponents = Object.fromEntries(supportedLanguages.map(lang => [lang, lang == Locale.EN ? '' : `${lang}/`]));
const languagePathComponent = supportedLanguagePathComponents[(locale.value as string).split('-')[0]] ?? supportedLanguagePathComponents[fallbackLocale.value as string] ?? '';
window.open(`https://cryptomator.org/${languagePathComponent}hub/billing/?hub_id=${admin.value?.hubId}&return_url=${encodeURIComponent(returnUrl)}`, '_self');
window.open(`https://cryptomator.org/hub/billing/?hub_id=${admin.value?.hubId}&return_url=${encodeURIComponent(returnUrl)}`, '_self');
}

async function saveWebOfTrust() {
Expand Down
21 changes: 13 additions & 8 deletions frontend/src/i18n/en-US.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
{
"locale.en": "English",
"locale.de": "German",
"locale.fr": "French",
"locale.it": "Italian",
"locale.ko": "Korean",
"locale.nl": "Dutch",
"locale.pt": "Portuguese",
"locale.tr": "Turkish",
"locale.en-US": "English",
"locale.de-DE": "German",
"locale.fr-FR": "French",
"locale.it-IT": "Italian",
"locale.ko-KR": "Korean",
"locale.lv-LV": "Latvian",
"locale.nl-NL": "Dutch",
"locale.pt-BR": "Portuguese (Brazil)",
"locale.pt-PT": "Portuguese",
"locale.ru-RU": "Russian",
"locale.tr-TR": "Turkish",
"locale.uk-UA": "Ukrainian",
"locale.zh-TW": "Chinese (Taiwan)",

"common.add": "Add",
"common.apply": "Apply",
Expand Down
110 changes: 67 additions & 43 deletions frontend/src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
import { I18nOptions } from 'vue-i18n';
import de from './de-DE.json';
import en from './en-US.json';
import fr from './fr-FR.json';
import it from './it-IT.json';
import ko from './ko-KR.json';
import nl from './nl-NL.json';
import pt from './pt-PT.json';
import tr from './tr-TR.json';
import deDe from './de-DE.json';
import enUs from './en-US.json';
import frFr from './fr-FR.json';
import itIt from './it-IT.json';
import koKr from './ko-KR.json';
import lvLv from './lv-LV.json';
import nlNl from './nl-NL.json';
import ptBr from './pt-BR.json';
import ptPt from './pt-PT.json';
import ruRu from './ru-RU.json';
import trTr from './tr-TR.json';
import uaUa from './uk-UA.json';
import zhTw from './zh-TW.json';

import { createI18n } from 'vue-i18n';

// ISO 639‑1 two letter code
export enum Locale {
EN = 'en',
DE = 'de',
FR = 'fr',
IT = 'it',
KO = 'ko',
NL = 'nl',
PT = 'pt',
TR = 'tr'
EN_US = 'en-US',
DE_DE = 'de-DE',
FR_FR = 'fr-FR',
IT_IT = 'it-IT',
KO_KR = 'ko-KR',
LV_LV = 'lv-LV',
NL_NL = 'nl-NL',
PT_BR = 'pt-BR',
PT_PT = 'pt-PT',
RU_RU = 'ru-RU',
TR_TR = 'tr-TR',
UK_UA = 'uk-UA',
ZH_TW = 'zh-TW',
}

export const messages = {
[Locale.EN]: en,
[Locale.DE]: de,
[Locale.FR]: fr,
[Locale.IT]: it,
[Locale.KO]: ko,
[Locale.NL]: nl,
[Locale.PT]: pt,
[Locale.TR]: tr
[Locale.EN_US]: enUs,
[Locale.DE_DE]: deDe,
[Locale.FR_FR]: frFr,
[Locale.IT_IT]: itIt,
[Locale.KO_KR]: koKr,
[Locale.LV_LV]: lvLv,
[Locale.NL_NL]: nlNl,
[Locale.PT_BR]: ptBr,
[Locale.PT_PT]: ptPt,
[Locale.RU_RU]: ruRu,
[Locale.TR_TR]: trTr,
[Locale.UK_UA]: uaUa,
[Locale.ZH_TW]: zhTw
};

const defaultShortDatetimeFormat = {
Expand All @@ -50,14 +64,19 @@ const defaultShortDatetimeFormat = {
} as const;

export const datetimeFormats: I18nOptions['datetimeFormats'] = {
[Locale.EN]: defaultShortDatetimeFormat,
[Locale.DE]: defaultShortDatetimeFormat,
[Locale.FR]: defaultShortDatetimeFormat,
[Locale.IT]: defaultShortDatetimeFormat,
[Locale.KO]: defaultShortDatetimeFormat,
[Locale.NL]: defaultShortDatetimeFormat,
[Locale.PT]: defaultShortDatetimeFormat,
[Locale.TR]: defaultShortDatetimeFormat
[Locale.EN_US]: defaultShortDatetimeFormat,
[Locale.DE_DE]: defaultShortDatetimeFormat,
[Locale.FR_FR]: defaultShortDatetimeFormat,
[Locale.IT_IT]: defaultShortDatetimeFormat,
[Locale.KO_KR]: defaultShortDatetimeFormat,
[Locale.LV_LV]: defaultShortDatetimeFormat,
[Locale.NL_NL]: defaultShortDatetimeFormat,
[Locale.PT_BR]: defaultShortDatetimeFormat,
[Locale.PT_PT]: defaultShortDatetimeFormat,
[Locale.RU_RU]: defaultShortDatetimeFormat,
[Locale.TR_TR]: defaultShortDatetimeFormat,
[Locale.UK_UA]: defaultShortDatetimeFormat,
[Locale.ZH_TW]: defaultShortDatetimeFormat,
};

const defaultNumberFormat = {
Expand All @@ -68,24 +87,29 @@ const defaultNumberFormat = {
} as const;

export const numberFormats: I18nOptions['numberFormats'] = {
[Locale.EN]: defaultNumberFormat,
[Locale.DE]: defaultNumberFormat,
[Locale.FR]: defaultNumberFormat,
[Locale.IT]: defaultNumberFormat,
[Locale.KO]: defaultNumberFormat,
[Locale.NL]: defaultNumberFormat,
[Locale.PT]: defaultNumberFormat,
[Locale.TR]: defaultNumberFormat
[Locale.EN_US]: defaultNumberFormat,
[Locale.DE_DE]: defaultNumberFormat,
[Locale.FR_FR]: defaultNumberFormat,
[Locale.IT_IT]: defaultNumberFormat,
[Locale.KO_KR]: defaultNumberFormat,
[Locale.LV_LV]: defaultNumberFormat,
[Locale.NL_NL]: defaultNumberFormat,
[Locale.PT_BR]: defaultNumberFormat,
[Locale.PT_PT]: defaultNumberFormat,
[Locale.RU_RU]: defaultNumberFormat,
[Locale.TR_TR]: defaultNumberFormat,
[Locale.UK_UA]: defaultNumberFormat,
[Locale.ZH_TW]: defaultNumberFormat
};

export const mapToLocale = (local: string): Locale =>
(Object.values(Locale) as string[]).includes(local)
? (local as Locale)
: Locale.EN;
: Locale.EN_US;

const i18n = createI18n({
locale: navigator.language,
fallbackLocale: Locale.EN,
fallbackLocale: Locale.EN_US,
messages,
datetimeFormats,
numberFormats,
Expand Down