refactor idp

Signed-off-by: Christian Richter <crichter@owncloud.com>
This commit is contained in:
Christian Richter
2022-04-13 17:04:37 +02:00
parent 4404b9741d
commit bfc8db848c
131 changed files with 43 additions and 18176 deletions
+2
View File
@@ -0,0 +1,2 @@
*
!bin/
+5
View File
@@ -0,0 +1,5 @@
PORT=3001
HOST=127.0.0.1
BROWSER=none
INLINE_RUNTIME_CHUNK=false
EXTEND_ESLINT=true
+3
View File
@@ -0,0 +1,3 @@
build/*
node_modules/*
+30
View File
@@ -0,0 +1,30 @@
{
"plugins": ["react-intl-format"],
"extends": ["plugin:react/recommended", "plugin:jest/recommended"],
"settings": {
"react": {
"version": "detect"
}
},
"parser": "babel-eslint",
"rules": {
"react-intl-format/missing-formatted-message": [
"error",
{
"noTrailingWhitespace": false,
"ignoreLinks": false
}
],
"react-intl-format/missing-attribute": [
"error",
{
"noTrailingWhitespace": false,
"noSpreadOperator": true
}
],
"react-intl-format/missing-values": [
"error"
],
"react/display-name": "off"
}
}
+17
View File
@@ -0,0 +1,17 @@
# yarn2 with Zero-Installs: https://yarnpkg.com/features/zero-installs
#.yarn/*
#!.yarn/cache
#!.yarn/patches
#!.yarn/plugins
#!.yarn/releases
#!.yarn/sdks
#!.yarn/versions
# yarn2 not using Zero-Installs: https://yarnpkg.com/features/zero-installs
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
.pnp.*
+768
View File
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-3.1.0.cjs
enableScripts: false
enableTelemetry: false
+71
View File
@@ -0,0 +1,71 @@
SHELL := bash
NAME := idp
include ../../.make/recursion.mk
############ tooling ############
ifneq (, $(shell which go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include ../../.bingo/Variables.mk
endif
############ go tooling ############
include ../../.make/go.mk
############ release ############
include ../../.make/release.mk
############ docs generate ############
include ../../.make/docs.mk
.PHONY: docs-generate
docs-generate: config-docs-generate
############ generate ############
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate: assets
.PHONY: assets
assets: yarn-build \
assets/identifier/static \
assets/identifier/static/logo.svg \
assets/identifier/static/favicon.ico
assets/identifier/static:
mkdir -p assets/identifier/static
LOGO_URL = https://raw.githubusercontent.com/owncloud/assets/main/logo.svg
.PHONY: assets/identifier/static/logo.svg # force overwrite
assets/identifier/static/logo.svg:
curl --fail -o assets/identifier/static/logo.svg ${LOGO_URL}
FAVICON_URL = https://raw.githubusercontent.com/owncloud/assets/main/favicon.ico
.PHONY: assets/identifier/static/favicon.ico # force overwrite
assets/identifier/static/favicon.ico:
curl --fail -o assets/identifier/static/favicon.ico ${FAVICON_URL}
.PHONY: yarn-build
yarn-build: node_modules
#yarn lint #TODO: activate
#yarn test #TODO: activate
yarn build
.PHONY: node_modules
node_modules:
@yarn install --immutable 2>&1 >/dev/null
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses: node_modules
yarn licenses:check
.PHONY: ci-node-save-licenses
ci-node-save-licenses: node_modules
yarn licenses:csv
yarn licenses:save
@@ -0,0 +1,44 @@
---
# OpenID Connect client registry.
clients:
- id: web
name: ownCloud web app
trusted: yes
redirect_uris:
- {{OCIS_URL}}/
- {{OCIS_URL}}/oidc-callback.html
- {{OCIS_URL}}/oidc-silent-redirect.html
origins:
- {{OCIS_URL}}
- id: ocis-explorer.js
name: oCIS Graph Explorer
trusted: yes
redirect_uris:
- {{OCIS_URL}}/graph-explorer/
origins:
- {{OCIS_URL}}
- id: xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69
secret: UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh
name: ownCloud desktop app
application_type: native
redirect_uris:
- http://127.0.0.1
- http://localhost
- id: e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD
secret: dInFYGV33xKzhbRmpqQltYNdfLdJIfJ9L5ISoKhNoT9qZftpdWSP71VrpGR9pmoD
name: ownCloud Android app
application_type: native
redirect_uris:
- oc://android.owncloud.com
- id: mxd5OQDk6es5LzOzRvidJNfXLUZS2oN3oUFeXPP8LpPrhx3UroJFduGEYIBOxkY1
secret: KFeFWWEZO9TkisIQzR3fo7hfiMXlOpaqP8CFuTbSHzV1TUuGECglPxpiVKJfOXIx
name: ownCloud iOS app
application_type: native
redirect_uris:
- oc://ios.owncloud.com
- oc.ios://ios.owncloud.com
+14
View File
@@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/owncloud/ocis/extensions/idp/pkg/command"
"github.com/owncloud/ocis/extensions/idp/pkg/config/defaults"
)
func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}
@@ -0,0 +1,19 @@
FROM amd64/alpine:latest
RUN apk update && \
apk upgrade && \
apk add ca-certificates mailcap && \
rm -rf /var/cache/apk/* && \
echo 'hosts: files dns' >| /etc/nsswitch.conf
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
org.label-schema.name="oCIS LibreGraph Connect" \
org.label-schema.vendor="ownCloud GmbH" \
org.label-schema.schema-version="1.0"
EXPOSE 9130 9134
ENTRYPOINT ["/usr/bin/ocis-idp"]
CMD ["server"]
COPY bin/ocis-idp /usr/bin/ocis-idp
@@ -0,0 +1,19 @@
FROM arm32v6/alpine:latest
RUN apk update && \
apk upgrade && \
apk add ca-certificates mailcap && \
rm -rf /var/cache/apk/* && \
echo 'hosts: files dns' >| /etc/nsswitch.conf
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
org.label-schema.name="oCIS LibreGraph Connect" \
org.label-schema.vendor="ownCloud GmbH" \
org.label-schema.schema-version="1.0"
EXPOSE 9130 9134
ENTRYPOINT ["/usr/bin/ocis-idp"]
CMD ["server"]
COPY bin/ocis-idp /usr/bin/ocis-idp
@@ -0,0 +1,19 @@
FROM arm64v8/alpine:latest
RUN apk update && \
apk upgrade && \
apk add ca-certificates mailcap && \
rm -rf /var/cache/apk/* && \
echo 'hosts: files dns' >| /etc/nsswitch.conf
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
org.label-schema.name="oCIS LibreGraph Connect" \
org.label-schema.vendor="ownCloud GmbH" \
org.label-schema.schema-version="1.0"
EXPOSE 9130 9134
ENTRYPOINT ["/usr/bin/ocis-idp"]
CMD ["server"]
COPY bin/ocis-idp /usr/bin/ocis-idp
+22
View File
@@ -0,0 +1,22 @@
image: owncloud/ocis-idp:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
- image: owncloud/ocis-idp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
- image: owncloud/ocis-idp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
variant: v8
os: linux
- image: owncloud/ocis-idp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
platform:
architecture: arm
variant: v6
os: linux
+9
View File
@@ -0,0 +1,9 @@
package idp
import (
"embed"
)
//go:generate make generate
//go:embed assets/*
var Assets embed.FS
+156
View File
@@ -0,0 +1,156 @@
{
"name": "identifier",
"version": "1.0.0",
"private": true,
"homepage": ".",
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
"build": "node scripts/build.js && rm -f build/service-worker.js",
"start": "node scripts/start.js",
"test": "node scripts/test.js --env=jsdom",
"licenses:check": "license-checker-rseidelsohn --summary --relativeLicensePath --onlyAllow 'Python-2.0;Apache*;Apache License, Version 2.0;Apache-2.0;Apache 2.0;Artistic-2.0;BSD;BSD-3-Clause;CC-BY-3.0;CC-BY-4.0;CC0-1.0;ISC;MIT;MPL-2.0;Public Domain;Unicode-TOU;Unlicense;WTFPL' --excludePackages 'identifier;kpop;po2json;unicoderegexp'",
"licenses:csv": "license-checker-rseidelsohn --relativeLicensePath --csv --out ../third-party-licenses/node/idp/third-party-licenses.csv",
"licenses:save": "license-checker-rseidelsohn --relativeLicensePath --out /dev/null --files ../third-party-licenses/node/idp/third-party-licenses"
},
"babel": {
"presets": [
"react-app"
]
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"jest": {
"collectCoverageFrom": [
"src/**/*.js"
],
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"modulePaths": [],
"roots": [
"<rootDir>/src"
],
"setupFiles": [
"react-app-polyfill/jsdom"
],
"setupFilesAfterEnv": [],
"testEnvironment": "jest-environment-jsdom-fourteen",
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"node_modules/?!(kpop)"
],
"watchPlugins": [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
]
},
"dependencies": {
"@babel/core": "^7.15.5",
"@material-ui/core": "^4.8.0",
"@material-ui/icons": "^4.5.0",
"axios": "^0.21.1",
"classnames": "^2.3.1",
"dotenv": "10.0.0",
"dotenv-expand": "5.1.0",
"file-loader": "6.2.0",
"fs-extra": "^9.1.0",
"identity-obj-proxy": "3.0.0",
"kpop": "https://download.kopano.io/community/kapp:/kpop-2.2.0.tgz",
"query-string": "^6.14.1",
"react": "^17.0.1",
"react-app-polyfill": "^2.0.0",
"react-dom": "17.0.1",
"react-intl": "^5.20.6",
"react-loadable": "^5.3.1",
"react-redux": "^7.2.4",
"react-router": "^5.0.0",
"react-router-dom": "^5.2.0",
"redux": "^4.0.5",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
"render-if": "^0.1.1",
"semver": "7.3.4",
"typeface-roboto": "^1.1.13"
},
"devDependencies": {
"@babel/runtime": "7.13.10",
"@svgr/webpack": "5.5.0",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.32.0",
"babel-eslint": "10.1.0",
"babel-jest": "^26.6.3",
"babel-loader": "8.2.2",
"babel-plugin-named-asset-import": "^0.3.6",
"babel-preset-react-app": "^10.0.0",
"camelcase": "^6.2.0",
"case-sensitive-paths-webpack-plugin": "2.4.0",
"css-loader": "5.2.6",
"eslint": "^7.21.0",
"eslint-config-react-app": "^6.0.0",
"eslint-loader": "4.0.2",
"eslint-plugin-flowtype": "5.7.2",
"eslint-plugin-i18n-text": "^1.0.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jest": "^24.2.1",
"eslint-plugin-react": "7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-react-intl-format": "^1.1.6",
"html-webpack-plugin": "4.5.2",
"jest": "26.6.3",
"jest-environment-jsdom-fourteen": "1.0.1",
"jest-resolve": "27.2.2",
"jest-watch-typeahead": "0.6.1",
"license-checker-rseidelsohn": "^3.1.0",
"mini-css-extract-plugin": "1.3.9",
"optimize-css-assets-webpack-plugin": "5.0.4",
"pnp-webpack-plugin": "1.6.4",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-normalize": "9.0.0",
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "5.0.2",
"prop-types": "^15.6.2",
"react-dev-utils": "11.0.4",
"react-intl-cra": "^0.3.3",
"react-intl-po": "^2.2.2",
"resolve": "1.20.0",
"resolve-url-loader": "^3.1.2",
"sass-loader": "11.0.1",
"source-map-explorer": "^2.5.2",
"style-loader": "2.0.0",
"terser-webpack-plugin": "4.2.3",
"ts-pnp": "1.2.0",
"url-loader": "4.1.1",
"webpack": "4.46.0",
"webpack-dev-server": "^3.11.2",
"webpack-manifest-plugin": "3.1.0",
"workbox-webpack-plugin": "4.3.1",
"yarn-deduplicate": "^3.1.0"
},
"packageManager": "yarn@3.1.0"
}
+50
View File
@@ -0,0 +1,50 @@
package assets
import (
"net/http"
"github.com/owncloud/ocis/extensions/idp"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/assetsfs"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// New returns a new http filesystem to serve assets.
func New(opts ...Option) http.FileSystem {
options := newOptions(opts...)
return assetsfs.New(idp.Assets, options.Config.Asset.Path, options.Logger)
}
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
+53
View File
@@ -0,0 +1,53 @@
package command
import (
"fmt"
"net/http"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/extensions/idp/pkg/config/parser"
"github.com/owncloud/ocis/extensions/idp/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)
if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}
logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")
return nil
},
}
}
+64
View File
@@ -0,0 +1,64 @@
package command
import (
"context"
"os"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-idp command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "ocis-idp",
Usage: "Serve IDP API for oCIS",
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
return app.Run(os.Args)
}
// SutureService allows for the idp command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new idp.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.IDP.Commons = cfg.Commons
return SutureService{
cfg: cfg.IDP,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}
+98
View File
@@ -0,0 +1,98 @@
package command
import (
"context"
"fmt"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/extensions/idp/pkg/config/parser"
"github.com/owncloud/ocis/extensions/idp/pkg/logging"
"github.com/owncloud/ocis/extensions/idp/pkg/metrics"
"github.com/owncloud/ocis/extensions/idp/pkg/server/debug"
"github.com/owncloud/ocis/extensions/idp/pkg/server/http"
"github.com/owncloud/ocis/extensions/idp/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg)
if err != nil {
return err
}
var (
gr = run.Group{}
ctx, cancel = func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
metrics = metrics.New()
)
defer cancel()
metrics.BuildInfo.WithLabelValues(version.String).Set(1)
{
server, err := http.Server(
http.Logger(logger),
http.Context(ctx),
http.Config(cfg),
http.Metrics(metrics),
)
if err != nil {
logger.Info().
Err(err).
Str("transport", "http").
Msg("Failed to initialize server")
return err
}
gr.Add(func() error {
return server.Run()
}, func(_ error) {
logger.Info().
Str("transport", "http").
Msg("Shutting down server")
cancel()
})
}
{
server, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(server.ListenAndServe, func(_ error) {
_ = server.Shutdown(ctx)
cancel()
})
}
return gr.Run()
},
}
}
+50
View File
@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}
+102
View File
@@ -0,0 +1,102 @@
package config
import (
"context"
"github.com/owncloud/ocis/ocis-pkg/shared"
)
// Config combines all available configuration parts.
type Config struct {
*shared.Commons `yaml:"-"`
Service Service `yaml:"-"`
Tracing *Tracing `yaml:"tracing"`
Log *Log `yaml:"log"`
Debug Debug `yaml:"debug"`
HTTP HTTP `yaml:"http"`
Asset Asset `yaml:"asset"`
IDP Settings `yaml:"idp"`
Ldap Ldap `yaml:"ldap"`
Context context.Context `yaml:"-"`
}
// Ldap defines the available LDAP configuration.
type Ldap struct {
URI string `yaml:"uri" env:"LDAP_URI;IDP_LDAP_URI"`
BindDN string `yaml:"bind_dn" env:"LDAP_BIND_DN;IDP_LDAP_BIND_DN"`
BindPassword string `yaml:"bind_password" env:"LDAP_BIND_PASSWORD;IDP_LDAP_BIND_PASSWORD"`
BaseDN string `yaml:"base_dn" env:"LDAP_USER_BASE_DN,IDP_LDAP_BASE_DN"`
Scope string `yaml:"scope" env:"LDAP_USER_SCOPE;IDP_LDAP_SCOPE"`
LoginAttribute string `yaml:"login_attribute" env:"IDP_LDAP_LOGIN_ATTRIBUTE"`
EmailAttribute string `yaml:"email_attribute" env:"LDAP_USER_SCHEMA_MAIL;IDP_LDAP_EMAIL_ATTRIBUTE"`
NameAttribute string `yaml:"name_attribute" env:"LDAP_USER_SCHEMA_USERNAME;IDP_LDAP_NAME_ATTRIBUTE"`
UUIDAttribute string `yaml:"uuid_attribute" env:"LDAP_USER_SCHEMA_ID;IDP_LDAP_UUID_ATTRIBUTE"`
UUIDAttributeType string `yaml:"uuid_attribute_type" env:"IDP_LDAP_UUID_ATTRIBUTE_TYPE"`
Filter string `yaml:"filter" env:"LDAP_USER_FILTER;IDP_LDAP_FILTER"`
ObjectClass string `yaml:"objectclass" env:"LDAP_USER_OBJECTCLASS;IDP_LDAP_OBJECTCLASS"`
}
// Asset defines the available asset configuration.
type Asset struct {
Path string `yaml:"asset" env:"IDP_ASSET_PATH"`
}
type Settings struct {
// don't change the order of elements in this struct
// it needs to match github.com/libregraph/lico/bootstrap.Settings
Iss string `yaml:"iss" env:"OCIS_URL;IDP_ISS"`
IdentityManager string `yaml:"identity_manager" env:"IDP_IDENTITY_MANAGER"`
URIBasePath string `yaml:"uri_base_path" env:"IDP_URI_BASE_PATH"`
SignInURI string `yaml:"sign_in_uri" env:"IDP_SIGN_IN_URI"`
SignedOutURI string `yaml:"signed_out_uri" env:"IDP_SIGN_OUT_URI"`
AuthorizationEndpointURI string `yaml:"authorization_endpoint_uri" env:"IDP_ENDPOINT_URI"`
EndsessionEndpointURI string `yaml:"end_session_endpoint_uri" env:"IDP_ENDSESSION_ENDPOINT_URI"`
Insecure bool `yaml:"insecure" env:"IDP_INSECURE"`
TrustedProxy []string `yaml:"trusted_proxy"` //TODO: how to configure this via env?
AllowScope []string `yaml:"allow_scope"` // TODO: is this even needed?
AllowClientGuests bool `yaml:"allow_client_guests" env:"IDP_ALLOW_CLIENT_GUESTS"`
AllowDynamicClientRegistration bool `yaml:"allow_dynamic_client_registration" env:"IDP_ALLOW_DYNAMIC_CLIENT_REGISTRATION"`
EncryptionSecretFile string `yaml:"encrypt_secret_file" env:"IDP_ENCRYPTION_SECRET"`
Listen string
IdentifierClientDisabled bool `yaml:"identifier_client_disabled" env:"IDP_DISABLE_IDENTIFIER_WEBAPP"`
IdentifierClientPath string `yaml:"identifier_client_path" env:"IDP_IDENTIFIER_CLIENT_PATH"`
IdentifierRegistrationConf string `yaml:"identifier_registration_conf" env:"IDP_IDENTIFIER_REGISTRATION_CONF"`
IdentifierScopesConf string `yaml:"identifier_scopes_conf" env:"IDP_IDENTIFIER_SCOPES_CONF"`
IdentifierDefaultBannerLogo string
IdentifierDefaultSignInPageText string
IdentifierDefaultUsernameHintText string
IdentifierUILocales []string
SigningKid string `yaml:"signing_kid" env:"IDP_SIGNING_KID"`
SigningMethod string `yaml:"signing_method" env:"IDP_SIGNING_METHOD"`
SigningPrivateKeyFiles []string `yaml:"signing_private_key_files"` // TODO: is this even needed?
ValidationKeysPath string `yaml:"validation_keys_path" env:"IDP_VALIDATION_KEYS_PATH"`
CookieBackendURI string
CookieNames []string
AccessTokenDurationSeconds uint64 `yaml:"access_token_duration_seconds" env:"IDP_ACCESS_TOKEN_EXPIRATION"`
IDTokenDurationSeconds uint64 `yaml:"id_token_duration_seconds" env:"IDP_ID_TOKEN_EXPIRATION"`
RefreshTokenDurationSeconds uint64 `yaml:"refresh_token_duration_seconds" env:"IDP_REFRESH_TOKEN_EXPIRATION"`
DyamicClientSecretDurationSeconds uint64 `yaml:"dynamic_client_secret_duration_seconds" env:""`
}
+9
View File
@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `yaml:"addr" env:"IDP_DEBUG_ADDR"`
Token string `yaml:"token" env:"IDP_DEBUG_TOKEN"`
Pprof bool `yaml:"pprof" env:"IDP_DEBUG_PPROF"`
Zpages bool `yaml:"zpages" env:"IDP_DEBUG_ZPAGES"`
}
@@ -0,0 +1,117 @@
package defaults
import (
"path"
"strings"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
func FullDefaultConfig() *config.Config {
cfg := DefaultConfig()
EnsureDefaults(cfg)
Sanitize(cfg)
return cfg
}
func DefaultConfig() *config.Config {
return &config.Config{
Debug: config.Debug{
Addr: "127.0.0.1:9134",
},
HTTP: config.HTTP{
Addr: "127.0.0.1:9130",
Root: "/",
Namespace: "com.owncloud.web",
TLSCert: path.Join(defaults.BaseDataPath(), "idp", "server.crt"),
TLSKey: path.Join(defaults.BaseDataPath(), "idp", "server.key"),
TLS: false,
},
Service: config.Service{
Name: "idp",
},
Asset: config.Asset{},
IDP: config.Settings{
Iss: "https://localhost:9200",
IdentityManager: "ldap",
URIBasePath: "",
SignInURI: "",
SignedOutURI: "",
AuthorizationEndpointURI: "",
EndsessionEndpointURI: "",
Insecure: false,
TrustedProxy: nil,
AllowScope: nil,
AllowClientGuests: false,
AllowDynamicClientRegistration: false,
EncryptionSecretFile: "",
Listen: "",
IdentifierClientDisabled: true,
IdentifierClientPath: path.Join(defaults.BaseDataPath(), "idp"),
IdentifierRegistrationConf: path.Join(defaults.BaseDataPath(), "idp", "identifier-registration.yaml"),
IdentifierScopesConf: "",
IdentifierDefaultBannerLogo: "",
IdentifierDefaultSignInPageText: "",
IdentifierDefaultUsernameHintText: "",
SigningKid: "",
SigningMethod: "PS256",
SigningPrivateKeyFiles: nil,
ValidationKeysPath: "",
CookieBackendURI: "",
CookieNames: nil,
AccessTokenDurationSeconds: 60 * 10, // 10 minutes
IDTokenDurationSeconds: 60 * 60, // 1 hour
RefreshTokenDurationSeconds: 60 * 60 * 24 * 365 * 3, // 1 year
DyamicClientSecretDurationSeconds: 0,
},
Ldap: config.Ldap{
URI: "ldap://localhost:9125",
BindDN: "cn=idp,ou=sysusers,dc=ocis,dc=test",
BindPassword: "idp",
BaseDN: "ou=users,dc=ocis,dc=test",
Scope: "sub",
LoginAttribute: "cn",
EmailAttribute: "mail",
NameAttribute: "displayName",
UUIDAttribute: "uid",
UUIDAttributeType: "text",
Filter: "",
ObjectClass: "posixAccount",
},
}
}
func EnsureDefaults(cfg *config.Config) {
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil {
cfg.Log = &config.Log{}
}
// provide with defaults for shared tracing, since we need a valid destination address for BindEnv.
if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {
cfg.Tracing = &config.Tracing{
Enabled: cfg.Commons.Tracing.Enabled,
Type: cfg.Commons.Tracing.Type,
Endpoint: cfg.Commons.Tracing.Endpoint,
Collector: cfg.Commons.Tracing.Collector,
}
} else if cfg.Tracing == nil {
cfg.Tracing = &config.Tracing{}
}
}
func Sanitize(cfg *config.Config) {
// sanitize config
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
}
+11
View File
@@ -0,0 +1,11 @@
package config
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `yaml:"addr" env:"IDP_HTTP_ADDR"`
Root string `yaml:"root" env:"IDP_HTTP_ROOT"`
Namespace string `yaml:"-"`
TLSCert string `yaml:"tls_cert" env:"IDP_TRANSPORT_TLS_CERT"`
TLSKey string `yaml:"tls_key" env:"IDP_TRANSPORT_TLS_KEY"`
TLS bool `yaml:"tls" env:"IDP_TLS"`
}
+9
View File
@@ -0,0 +1,9 @@
package config
// Log defines the available log configuration.
type Log struct {
Level string `yaml:"level" env:"OCIS_LOG_LEVEL;IDP_LOG_LEVEL"`
Pretty bool `yaml:"pretty" env:"OCIS_LOG_PRETTY;IDP_LOG_PRETTY"`
Color bool `yaml:"color" env:"OCIS_LOG_COLOR;IDP_LOG_COLOR"`
File string `yaml:"file" env:"OCIS_LOG_FILE;IDP_LOG_FILE"`
}
+33
View File
@@ -0,0 +1,33 @@
package parser
import (
"errors"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/extensions/idp/pkg/config/defaults"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
)
// ParseConfig loads accounts configuration from known paths.
func ParseConfig(cfg *config.Config) error {
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
if err != nil {
return err
}
defaults.EnsureDefaults(cfg)
// load all env variables relevant to the config in the current context.
if err := envdecode.Decode(cfg); err != nil {
// no environment variable set for this config is an expected "error"
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
return err
}
}
defaults.Sanitize(cfg)
return nil
}
+7
View File
@@ -0,0 +1,7 @@
package config
// Service defines the available service configuration.
type Service struct {
Name string `yaml:"-"`
PasswordResetURI string `yaml:"password_reset_uri" env:"IDP_PASSWORD_RESET_URI" desc:"The URI where a user can reset their password."`
}
+9
View File
@@ -0,0 +1,9 @@
package config
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;IDP_TRACING_ENABLED"`
Type string `yaml:"type" env:"OCIS_TRACING_TYPE;IDP_TRACING_TYPE"`
Endpoint string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;IDP_TRACING_ENDPOINT"`
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;IDP_TRACING_COLLECTOR"`
}
+17
View File
@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}
+45
View File
@@ -0,0 +1,45 @@
package metrics
import "github.com/prometheus/client_golang/prometheus"
var (
// Namespace defines the namespace for the defines metrics.
Namespace = "ocis"
// Subsystem defines the subsystem for the defines metrics.
Subsystem = "idp"
)
// Metrics defines the available metrics of this service.
type Metrics struct {
// Counter *prometheus.CounterVec
BuildInfo *prometheus.GaugeVec
}
// New initializes the available metrics.
func New() *Metrics {
m := &Metrics{
// Counter: prometheus.NewCounterVec(prometheus.CounterOpts{
// Namespace: Namespace,
// Subsystem: Subsystem,
// Name: "greet_total",
// Help: "How many greeting requests processed",
// }, []string{}),
BuildInfo: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: Subsystem,
Name: "build_info",
Help: "Build Information",
}, []string{"version"}),
}
// prometheus.Register(
// m.Counter,
// )
_ = prometheus.Register(
m.BuildInfo,
)
return m
}
+51
View File
@@ -0,0 +1,51 @@
package middleware
import (
"net/http"
"strings"
idpTracing "github.com/owncloud/ocis/extensions/idp/pkg/tracing"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
)
// Static is a middleware that serves static assets.
func Static(root string, fs http.FileSystem) func(http.Handler) http.Handler {
if !strings.HasSuffix(root, "/") {
root = root + "/"
}
static := http.StripPrefix(
root,
http.FileServer(
fs,
),
)
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, span := idpTracing.TraceProvider.Tracer("idp").Start(r.Context(), "serve static asset")
defer span.End()
r = r.WithContext(ctx)
// serve the static assets for the identifier web app
if strings.HasPrefix(r.URL.Path, "/signin/v1/static/") {
if strings.HasSuffix(r.URL.Path, "/") {
// but no listing of folders
span.SetAttributes(attribute.KeyValue{Key: "path", Value: attribute.StringValue(r.URL.Path)})
span.SetStatus(codes.Error, "asset not found")
http.NotFound(w, r)
} else {
r.URL.Path = strings.Replace(r.URL.Path, "/signin/v1/static/", "/signin/v1/identifier/static/", 1)
span.SetAttributes(attribute.KeyValue{Key: "server", Value: attribute.StringValue(r.URL.Path)})
static.ServeHTTP(w, r)
}
return
}
span.SetAttributes(attribute.KeyValue{Key: "path", Value: attribute.StringValue(r.URL.Path)})
span.SetStatus(codes.Ok, "ok")
next.ServeHTTP(w, r)
})
}
}
+50
View File
@@ -0,0 +1,50 @@
package debug
import (
"context"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Context context.Context
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
+70
View File
@@ -0,0 +1,70 @@
package debug
import (
"io"
"net/http"
"net/url"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/service/debug"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/version"
)
// Server initializes the debug service and server.
func Server(opts ...Option) (*http.Server, error) {
options := newOptions(opts...)
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
debug.Pprof(options.Config.Debug.Pprof),
debug.Zpages(options.Config.Debug.Zpages),
debug.Health(health(options.Config, options.Logger)),
debug.Ready(ready(options.Config)),
), nil
}
// health implements the health check.
func health(cfg *config.Config, l log.Logger) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
targetHost, err := url.Parse(cfg.Ldap.URI)
if err != nil {
l.Fatal().Err(err).Str("uri", cfg.Ldap.URI).Msg("invalid LDAP URI")
}
err = shared.RunChecklist(shared.TCPConnect(targetHost.Host))
retVal := http.StatusOK
if err != nil {
l.Error().Err(err).Msg("Healtcheck failed")
retVal = http.StatusInternalServerError
}
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(retVal)
_, err = io.WriteString(w, http.StatusText(retVal))
if err != nil {
l.Fatal().Err(err).Msg("Could not write health check body")
}
}
}
// ready implements the ready check.
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// if we can call this function, a http(200) is a valid response as
// there is nothing we can check at this point for IDP
// if there is a mishap when initializing, there is a minimal (talking ms or ns window)
// timeframe where this code is callable
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}
+76
View File
@@ -0,0 +1,76 @@
package http
import (
"context"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/extensions/idp/pkg/metrics"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/urfave/cli/v2"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Namespace string
Logger log.Logger
Context context.Context
Config *config.Config
Metrics *metrics.Metrics
Flags []cli.Flag
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
// Metrics provides a function to set the metrics option.
func Metrics(val *metrics.Metrics) Option {
return func(o *Options) {
o.Metrics = val
}
}
// Flags provides a function to set the flags option.
func Flags(val []cli.Flag) Option {
return func(o *Options) {
o.Flags = append(o.Flags, val...)
}
}
// Namespace provides a function to set the namespace option.
func Namespace(val string) Option {
return func(o *Options) {
o.Namespace = val
}
}
+82
View File
@@ -0,0 +1,82 @@
package http
import (
"crypto/tls"
"os"
chimiddleware "github.com/go-chi/chi/v5/middleware"
svc "github.com/owncloud/ocis/extensions/idp/pkg/service/v0"
pkgcrypto "github.com/owncloud/ocis/ocis-pkg/crypto"
"github.com/owncloud/ocis/ocis-pkg/middleware"
"github.com/owncloud/ocis/ocis-pkg/service/http"
"github.com/owncloud/ocis/ocis-pkg/version"
"go-micro.dev/v4"
)
// Server initializes the http service and server.
func Server(opts ...Option) (http.Service, error) {
options := newOptions(opts...)
var tlsConfig *tls.Config
if options.Config.HTTP.TLS {
_, certErr := os.Stat(options.Config.HTTP.TLSCert)
_, keyErr := os.Stat(options.Config.HTTP.TLSKey)
if os.IsNotExist(certErr) || os.IsNotExist(keyErr) {
options.Logger.Info().Msgf("Generating certs")
if err := pkgcrypto.GenCert(options.Config.HTTP.TLSCert, options.Config.HTTP.TLSKey, options.Logger); err != nil {
options.Logger.Fatal().Err(err).Msg("Could not setup TLS")
os.Exit(1)
}
}
cer, err := tls.LoadX509KeyPair(options.Config.HTTP.TLSCert, options.Config.HTTP.TLSKey)
if err != nil {
options.Logger.Fatal().Err(err).Msg("Could not setup TLS")
os.Exit(1)
}
tlsConfig = &tls.Config{MinVersion: tls.VersionTLS12, Certificates: []tls.Certificate{cer}}
}
service := http.NewService(
http.Logger(options.Logger),
http.Namespace(options.Config.HTTP.Namespace),
http.Name(options.Config.Service.Name),
http.Version(version.String),
http.Address(options.Config.HTTP.Addr),
http.Context(options.Context),
http.Flags(options.Flags...),
http.TLSConfig(tlsConfig),
)
handle := svc.NewService(
svc.Logger(options.Logger),
svc.Config(options.Config),
svc.Middleware(
chimiddleware.RealIP,
chimiddleware.RequestID,
middleware.TraceContext,
middleware.NoCache,
middleware.Secure,
middleware.Version(
options.Config.Service.Name,
version.String,
),
middleware.Logger(
options.Logger,
),
),
)
{
handle = svc.NewInstrument(handle, options.Metrics)
handle = svc.NewLoggingHandler(handle, options.Logger)
}
if err := micro.RegisterHandler(service.Server(), handle); err != nil {
return http.Service{}, err
}
return service, nil
}
@@ -0,0 +1,25 @@
package svc
import (
"net/http"
"github.com/owncloud/ocis/extensions/idp/pkg/metrics"
)
// NewInstrument returns a service that instruments metrics.
func NewInstrument(next Service, metrics *metrics.Metrics) Service {
return instrument{
next: next,
metrics: metrics,
}
}
type instrument struct {
next Service
metrics *metrics.Metrics
}
// ServeHTTP implements the Service interface.
func (i instrument) ServeHTTP(w http.ResponseWriter, r *http.Request) {
i.next.ServeHTTP(w, r)
}
+25
View File
@@ -0,0 +1,25 @@
package svc
import (
"net/http"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// NewLogging returns a service that logs messages.
func NewLoggingHandler(next Service, logger log.Logger) Service {
return loggingHandler{
next: next,
logger: logger,
}
}
type loggingHandler struct {
next Service
logger log.Logger
}
// ServeHTTP implements the Service interface.
func (l loggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
l.next.ServeHTTP(w, r)
}
+50
View File
@@ -0,0 +1,50 @@
package svc
import (
"net/http"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Config *config.Config
Middleware []func(http.Handler) http.Handler
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
// Middleware provides a function to set the middleware option.
func Middleware(val ...func(http.Handler) http.Handler) Option {
return func(o *Options) {
o.Middleware = val
}
}
+229
View File
@@ -0,0 +1,229 @@
package svc
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
"strings"
"github.com/go-chi/chi/v5"
"github.com/gorilla/mux"
"github.com/libregraph/lico/bootstrap"
dummyBackendSupport "github.com/libregraph/lico/bootstrap/backends/dummy"
guestBackendSupport "github.com/libregraph/lico/bootstrap/backends/guest"
kcBackendSupport "github.com/libregraph/lico/bootstrap/backends/kc"
ldapBackendSupport "github.com/libregraph/lico/bootstrap/backends/ldap"
licoconfig "github.com/libregraph/lico/config"
"github.com/libregraph/lico/server"
"github.com/owncloud/ocis/extensions/idp/pkg/assets"
"github.com/owncloud/ocis/extensions/idp/pkg/config"
"github.com/owncloud/ocis/extensions/idp/pkg/middleware"
"github.com/owncloud/ocis/ocis-pkg/log"
"stash.kopano.io/kgol/rndm"
)
// Service defines the extension handlers.
type Service interface {
ServeHTTP(http.ResponseWriter, *http.Request)
}
// NewService returns a service implementation for Service.
func NewService(opts ...Option) Service {
ctx := context.Background()
options := newOptions(opts...)
logger := options.Logger.Logger
assetVFS := assets.New(
assets.Logger(options.Logger),
assets.Config(options.Config),
)
if err := initLicoInternalEnvVars(&options.Config.Ldap); err != nil {
logger.Fatal().Err(err).Msg("could not initialize env vars")
}
if err := createConfigsIfNotExist(assetVFS, options.Config.IDP.IdentifierRegistrationConf, options.Config.IDP.Iss); err != nil {
logger.Fatal().Err(err).Msg("could not create default config")
}
guestBackendSupport.MustRegister()
ldapBackendSupport.MustRegister()
dummyBackendSupport.MustRegister()
kcBackendSupport.MustRegister()
// https://play.golang.org/p/Mh8AVJCd593
idpSettings := bootstrap.Settings(options.Config.IDP)
bs, err := bootstrap.Boot(ctx, &idpSettings, &licoconfig.Config{
Logger: log.LogrusWrap(logger),
})
if err != nil {
logger.Fatal().Err(err).Msg("could not bootstrap idp")
}
managers := bs.Managers()
routes := []server.WithRoutes{managers.Must("identity").(server.WithRoutes)}
handlers := managers.Must("handler").(http.Handler)
svc := IDP{
logger: options.Logger,
config: options.Config,
assets: assetVFS,
}
svc.initMux(ctx, routes, handlers, options)
return svc
}
func createConfigsIfNotExist(assets http.FileSystem, filePath, ocisURL string) error {
folder := path.Dir(filePath)
if _, err := os.Stat(folder); os.IsNotExist(err) {
if err := os.MkdirAll(folder, 0700); err != nil {
return err
}
}
if _, err := os.Stat(filePath); os.IsNotExist(err) {
defaultConf, err := assets.Open("/identifier-registration.yaml")
if err != nil {
return err
}
defer defaultConf.Close()
confOnDisk, err := os.Create(filePath)
if err != nil {
return err
}
defer confOnDisk.Close()
conf, err := ioutil.ReadAll(defaultConf)
if err != nil {
return err
}
// replace placeholder {{OCIS_URL}} with https://localhost:9200 / correct host
conf = []byte(strings.ReplaceAll(string(conf), "{{OCIS_URL}}", strings.TrimRight(ocisURL, "/")))
err = ioutil.WriteFile(filePath, conf, 0600)
if err != nil {
return err
}
}
return nil
}
// Init vars which are currently not accessible via idp api
func initLicoInternalEnvVars(ldap *config.Ldap) error {
filter := fmt.Sprintf("(objectclass=%s)", ldap.ObjectClass)
if ldap.Filter != "" {
filter = fmt.Sprintf("(&%s%s)", ldap.Filter, filter)
}
var defaults = map[string]string{
"LDAP_URI": ldap.URI,
"LDAP_BINDDN": ldap.BindDN,
"LDAP_BINDPW": ldap.BindPassword,
"LDAP_BASEDN": ldap.BaseDN,
"LDAP_SCOPE": ldap.Scope,
"LDAP_LOGIN_ATTRIBUTE": ldap.LoginAttribute,
"LDAP_EMAIL_ATTRIBUTE": ldap.EmailAttribute,
"LDAP_NAME_ATTRIBUTE": ldap.NameAttribute,
"LDAP_UUID_ATTRIBUTE": ldap.UUIDAttribute,
"LDAP_UUID_ATTRIBUTE_TYPE": ldap.UUIDAttributeType,
"LDAP_FILTER": filter,
}
for k, v := range defaults {
if err := os.Setenv(k, v); err != nil {
return fmt.Errorf("could not set env var %s=%s", k, v)
}
}
return nil
}
// IDP defines implements the business logic for Service.
type IDP struct {
logger log.Logger
config *config.Config
mux *chi.Mux
assets http.FileSystem
}
// initMux initializes the internal idp gorilla mux and mounts it in to a ocis chi-router
func (idp *IDP) initMux(ctx context.Context, r []server.WithRoutes, h http.Handler, options Options) {
gm := mux.NewRouter()
for _, route := range r {
route.AddRoutes(ctx, gm)
}
// Delegate rest to provider which is also a handler.
if h != nil {
gm.NotFoundHandler = h
}
idp.mux = chi.NewMux()
idp.mux.Use(options.Middleware...)
idp.mux.Use(middleware.Static(
"/signin/v1/",
assets.New(
assets.Logger(options.Logger),
assets.Config(options.Config),
),
))
// handle / | index.html with a template that needs to have the BASE_PREFIX replaced
idp.mux.Get("/signin/v1/identifier", idp.Index())
idp.mux.Get("/signin/v1/identifier/", idp.Index())
idp.mux.Get("/signin/v1/identifier/index.html", idp.Index())
idp.mux.Mount("/", gm)
}
// ServeHTTP implements the Service interface.
func (idp IDP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
idp.mux.ServeHTTP(w, r)
}
// Index renders the static html with the
func (idp IDP) Index() http.HandlerFunc {
f, err := idp.assets.Open("/identifier/index.html")
if err != nil {
idp.logger.Fatal().Err(err).Msg("Could not open index template")
}
template, err := ioutil.ReadAll(f)
if err != nil {
idp.logger.Fatal().Err(err).Msg("Could not read index template")
}
if err = f.Close(); err != nil {
idp.logger.Fatal().Err(err).Msg("Could not close body")
}
// TODO add environment variable to make the path prefix configurable
pp := "/signin/v1"
indexHTML := bytes.Replace(template, []byte("__PATH_PREFIX__"), []byte(pp), 1)
nonce := rndm.GenerateRandomString(32)
indexHTML = bytes.Replace(indexHTML, []byte("__CSP_NONCE__"), []byte(nonce), 1)
indexHTML = bytes.Replace(indexHTML, []byte("__PASSWORD_RESET_LINK__"), []byte(idp.config.Service.PasswordResetURI), 1)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if _, err := w.Write(indexHTML); err != nil {
idp.logger.Error().Err(err).Msg("could not write to response writer")
}
})
}
+23
View File
@@ -0,0 +1,23 @@
package svc
import (
"net/http"
"github.com/owncloud/ocis/ocis-pkg/middleware"
)
// NewTracing returns a service that instruments traces.
func NewTracing(next Service) Service {
return tracing{
next: next,
}
}
type tracing struct {
next Service
}
// ServeHTTP implements the Service interface.
func (t tracing) ServeHTTP(w http.ResponseWriter, r *http.Request) {
middleware.TraceContext(t.next).ServeHTTP(w, r)
}
+23
View File
@@ -0,0 +1,23 @@
package tracing
import (
"github.com/owncloud/ocis/extensions/idp/pkg/config"
pkgtrace "github.com/owncloud/ocis/ocis-pkg/tracing"
"go.opentelemetry.io/otel/trace"
)
var (
// TraceProvider is the global trace provider for the idp service.
TraceProvider = trace.NewNoopTracerProvider()
)
func Configure(cfg *config.Config) error {
var err error
if cfg.Tracing.Enabled {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, cfg.Service.Name, cfg.Tracing.Type); err != nil {
return err
}
}
return nil
}
+2
View File
@@ -0,0 +1,2 @@
# backend
-r '^(cmd|pkg)/.*\.go$' -R '^node_modules/' -s -- sh -c 'make bin/ocis-idp-debug && bin/ocis-idp-debug --log-level debug server --debug-pprof --debug-zpages'
+211
View File
@@ -0,0 +1,211 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../ui_config/env');
const path = require('path');
const chalk = require('react-dev-utils/chalk');
const fs = require('fs-extra');
const webpack = require('webpack');
const configFactory = require('../ui_config/webpack.config');
const paths = require('../ui_config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Generate configuration
const config = configFactory('production');
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
return measureFileSizesBeforeBuild(paths.appBuild);
})
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({ stats, previousFileSizes, warnings }) => {
if (warnings.length) {
console.log(chalk.yellow('Compiled with warnings.\n'));
console.log(warnings.join('\n\n'));
console.log(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
);
console.log(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
);
} else {
console.log(chalk.green('Compiled successfully.\n'));
}
console.log('File sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
);
console.log();
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrl;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
publicUrl,
publicPath,
buildFolder,
useYarn
);
},
err => {
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
if (tscCompileOnError) {
console.log(
chalk.yellow(
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
)
);
printBuildError(err);
} else {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
}
)
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
// We used to support resolving modules according to `NODE_PATH`.
// This now has been deprecated in favor of jsconfig/tsconfig.json
// This lets you use absolute paths in imports inside large monorepos:
if (process.env.NODE_PATH) {
console.log(
chalk.yellow(
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
)
);
console.log();
}
console.log('Creating an optimized production build...');
const compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
let messages;
if (err) {
if (!err.message) {
return reject(err);
}
let errMessage = err.message;
// Add additional information for postcss errors
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
errMessage +=
'\nCompileError: Begins at CSS selector ' +
err['postcssNode'].selector;
}
messages = formatWebpackMessages({
errors: [errMessage],
warnings: [],
});
} else {
messages = formatWebpackMessages(
stats.toJson({ all: false, warnings: true, errors: true })
);
}
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(messages.warnings.join('\n\n')));
}
return resolve({
stats,
previousFileSizes,
warnings: messages.warnings,
});
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}
+147
View File
@@ -0,0 +1,147 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../ui_config/env');
const fs = require('fs');
const chalk = require('react-dev-utils/chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../ui_config/paths');
const configFactory = require('../ui_config/webpack.config');
const createDevServerConfig = require('../ui_config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(
`Learn more here: ${chalk.yellow('https://bit.ly/CRA-advanced-config')}`
);
console.log();
}
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
return choosePort(HOST, DEFAULT_PORT);
})
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const config = configFactory('development');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const useTypeScript = fs.existsSync(paths.appTsConfig);
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
const urls = prepareUrls(protocol, HOST, port);
const devSocket = {
warnings: warnings =>
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
errors: errors =>
devServer.sockWrite(devServer.sockets, 'errors', errors),
};
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler({
appName,
config,
devSocket,
urls,
useYarn,
useTypeScript,
tscCompileOnError,
webpack,
});
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web server.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
// We used to support resolving modules according to `NODE_PATH`.
// This now has been deprecated in favor of jsconfig/tsconfig.json
// This lets you use absolute paths in imports inside large monorepos:
if (process.env.NODE_PATH) {
console.log(
chalk.yellow(
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
)
);
console.log();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
+53
View File
@@ -0,0 +1,53 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../ui_config/env');
const jest = require('jest');
const execSync = require('child_process').execSync;
let argv = process.argv.slice(2);
function isInGitRepository() {
try {
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
function isInMercurialRepository() {
try {
execSync('hg --cwd . root', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
// Watch unless on CI or explicitly running all tests
if (
!process.env.CI &&
argv.indexOf('--watchAll') === -1 &&
argv.indexOf('--watchAll=false') === -1
) {
// https://github.com/facebook/create-react-app/issues/5210
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
argv.push(hasSourceControl ? '--watch' : '--watchAll');
}
jest.run(argv);
+52
View File
@@ -0,0 +1,52 @@
# Tools
YARN ?= yarn
MSGMERGE ?= msgmerge
MSGFMT ?= msgfmt
# Variables
POT = konnect-identifier.pot
POS = $(wildcard *.po)
# Translations
.PHONY: build
build: json
.PHONY: extract
extract: pot
.PHONY: i18n/src/messages.json
i18n/src/messages.json:
$(YARN) react-intl-cra './src/**/*.{js,jsx}' -o $@
.PHONY: pot
pot: i18n/src/messages.json
$(YARN) rip json2pot './i18n/src/**/*.json' \
-o ./i18n/$(POT) \
-c 'id'
.PHONY: json
json: i18n/src/messages.json
$(YARN) rip po2json './i18n/*.po' \
-m './i18n/src/**/*.json' \
-o './src/locales/' \
-c 'id' \
--indentation=2
.PHONY: merge
merge: $(POS)
.PHONY: stats
stats:
$(foreach po, $(POS), $(shell $(MSGFMT) -v --statistics $(po)))
@- true
$(POS): FORCE $(POT)
$(MSGMERGE) -U \
--backup=none \
--no-wrap \
$@ $(POT)
FORCE:
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-05-08 18:23+0200\n"
"Last-Translator: Simon Eisenmann <simon@longsleep.org>\n"
"Language-Team: German <http://translate.kopano.io/projects/kopano/konnect/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Poedit 1.8.7.1\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Zugriff auf Ihre grundlegenden Benutzerinformationen"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Einverstanden"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "{clientDisplayName} den Zugriff gestatten?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "Wenn Sie Einverstanden klicken, erhält die App Zugriff auf Ihre Informationen."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Abbrechen"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Konto auswählen"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "Wenn Sie \"Einverstanden\" klicken werden Sie zu {redirectURI} weitergeleitet"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Geben Sie ein Passwort ein"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Geben Sie einen Benutzername ein"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "Verbindung zum Server fehlgeschlagen"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "Bis bald"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Hallo {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Hi {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "Dauerhaften Zugriff (läuft nicht ab)"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Anmeldung fehlgeschlagen. Bitte überprüfen Sie Ihre Eingabe und versuchen Sie es noch einmal."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Netzwerkfehler. Bitte prüfen Sie Ihre Verbindung und versuchen Sie es noch einmal."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Weiter"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Passwort"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Klicken Sie auf die Schaltfläche unten um sich aus Ihrem Kopano Konto abzumelden."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Wiederholen"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Geltungsbereich: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Anmelden"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Abmelden"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Abmelden"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Unerwartete HTTP-Antwort: {status}. Bitte prüfen Sie Ihre Verbindung und versuchen Sie es noch einmal."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Unerwarteter Antwort-Status: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Anderes Konto"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Benutzername"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Willkommen {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Sie sind angemeldet - super!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Sie können dieses Fenster jetzt schließen."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "Bitte bestätigen Sie, dass Sie sich abmelden möchten"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "um sich bei Kopano anzumelden"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "mit Ihrem Kopano Konto"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "sie sind jetzt von Ihrem Kopano Konto abgemeldet"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} möchte"
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2018-10-30T16:08:29.860Z\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: react-intl-po\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-08-26 15:43+0000\n"
"Last-Translator: Dominique <dperessoni@alternatiq.com>\n"
"Language-Team: French <http://translate.kopano.io/projects/kopano/konnect/fr/>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Consulter les informations de base de votre compte"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Autoriser"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "Autoriser {clientDisplayName} à faire cela ?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "En cliquant, vous autoriser l'app à accéder à vos informations."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Annuler"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Choisir un compte"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "En cliquant \"Autoriser\" vous serez redirigé vers : {redirectURI}"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Saisir un mot de passe"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Saisir un identifiant"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "La connexion au serveur a échoué"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "Au revoir"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Bonjour {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Bonjour {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "Conserver les autorisations d'accès à l'avenir"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Echec de connexion. Vérifier vos identifiants et essayer à nouveau."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Erreur réseau. Vérifier votre connexion, et réessayer."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Suivant"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Mot de passe"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Cliquer le bouton ci-dessous, pour quitter Kopano."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Réessayer"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Portée : {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Identification"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Quitter"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Quitter"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Erreur HTTP inattendue : {status}. Vérifier votre connexion et réessayer."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Erreur d'état inattendue : {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Utiliser un autre compte"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Utilisateur"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Bienvenue {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Magnifique - Vous êtes connecté !"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Vous pouvez fermer cette fenêtre à présent."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "Confirmer votre déconnexion"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "pour vous authentifier dans Kopano"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "avec vos identifiants Kopano"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "vous avez été déconnecté de Kopano"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} souhaite"
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-09-04 09:55+0000\n"
"Last-Translator: Mayank <m.dabhi@kopano.com>\n"
"Language-Team: Hindi <http://translate.kopano.io/projects/kopano/konnect/hi/>\n"
"Language: hi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "अपनी मूल खाता जानकारी देखे"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "अनुमति दीजिये"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "क्या {clientDisplayName} को ये करने की अनुमति देना चाहते है?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "अनुमति पर क्लिक करके, आप इस एप्लिकेशन को आपकी जानकारी का उपयोग करने की अनुमति देते हैं."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "रद्द करें"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "खाता चुनें"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "\"अनुमति\" पर क्लिक करने से आपको {redirecturI} पे पुनर्निर्देशित किया जायेगा"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "पासवर्ड डालिए"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "उपयोगकर्ता नाम डालिये"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "सर्वर से कनेक्ट करने में विफल"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "अलविदा"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "नमस्ते {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "नमस्ते {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "अनुमत पहुंच को लगातार और हमेशा बनाए रखें"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "लोगऑन नाकाम रहा. कृपया अपने क्रेडेंशियल्स जांचे और पुनः प्रयास करें."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "नेटवर्क त्रुटि। कृपया अपने संपर्क की जांच करे और फिर से प्रयास करें."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "अगला"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "पासवर्ड"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "अपने Kopano खाते से साइन आउट करने के लिए नीचे दिए गए बटन को दबाएं."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "पुन: प्रयास करें"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "क्षेत्र: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "साइन इन"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "साइन आउट"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "साइन आउट"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "अनपेक्षित HTTP प्रतिक्रिया: {status}. कृपया अपने संपर्क की जांच करे और फिर से प्रयास करें."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "अनपेक्षित प्रतिक्रिया अवस्था: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "दूसरे खाते का उपयोग करें"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "उपयोगकर्ता नाम"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "स्वागत हे {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "आप साइंड इन हैं - अद्भुत!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "अब आप इस विंडो को बंद कर सकते हैं."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "कृपया साइन आउट की पुष्टि करें"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "Kopano में साइन इन करने के लिए"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "अपने Kopano खाते के साथ"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "आपको अपने Kopano खाते से साइन आउट कर दिया गया है"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} चाहते है की"
+310
View File
@@ -0,0 +1,310 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"MIME-Version: 1.0\n"
"X-Generator: react-intl-po\n"
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2019-08-30 11:41+0200\n"
"Last-Translator: root <translations@kopano.io>\n"
"Language-Team: Croatian\n"
"Language: hr\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2018-10-30T16:08:29.860Z\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: react-intl-po\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-09-02 15:40+0000\n"
"Last-Translator: Tryggvi Björgvinsson <ME@TRICKVI.IS>\n"
"Language-Team: Icelandic <http://translate.kopano.io/projects/kopano/konnect/is/>\n"
"Language: is\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Komast í grunnupplýsingar um þig"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Leyfa"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "Leyfa {clientDisplayName} að gera þetta?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "Með því að smella á \"Leyfa\", leyfir þú þessu forriti að nota upplýsingarnar um þig."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Hætta við"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Veldu aðgang"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "Þegar þú smellir á \"Leyfa\" áframsendist þú á: {redirectURI}"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Sláðu inn lykilorð"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Sláðu inn notandanafn"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "Mistókst að tengjast netþjóni"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "Bless"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Halló {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Hæ {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "Viðhalda heimildunum alltaf og að eilífu (mundu mig)"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Innskráning mistókst. Vinsamlegast staðfestu notandaupplýsingarnar og reyndu aftur."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Netvilla. Vinsamlegast athugaðu tenginguna þína og reyndu aftur."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Næsta"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Lykilorð"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Smelltu á takkann fyrir neðan til að skrá þig út af Kopano aðganginum núna."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Reyna aftur"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Gildissvið: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Innskrá"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Útskrá"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Útskrá"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Ófyrirsjáanlegt HTTP svar: {status}. Vinsamlegast athugaðu tenginguna þína og reyndu aftur."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Ófyrirsjáanleg svarstaða: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Nota annan aðgang"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Notandanafn"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Halló {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Innskráningin tókst - frábært!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Þú getur lokað þessum glugga núna."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "vinsamlegast staðfestu útskráningu"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "til að skrá þig inn í Kopano"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "með Kopano-aðganginum þínum"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "útskráning Kopano-aðgangsins þíns tókst"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} vill"
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2018-10-30T16:08:29.860Z\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: react-intl-po\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2018-10-30T16:08:29.860Z\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: react-intl-po\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
@@ -0,0 +1,304 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"MIME-Version: 1.0\n"
"X-Generator: react-intl-po\n"
#: ./i18n/src/messages.json
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#: ./i18n/src/messages.json
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#: ./i18n/src/messages.json
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-08-26 16:21+0000\n"
"Last-Translator: Klaus <klaus@linuxavdelingen.no>\n"
"Language-Team: Norwegian Bokmål <http://translate.kopano.io/projects/kopano/konnect/nb/>\n"
"Language: nb\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Tilgang til informasjon om basiskonto"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Tillat"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "Tillatt {clientDisplayName} å gjøre dette?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "Ved å klikke på Aksepter, så tillater du at appen bruker din informasjon."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Avbryt"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Velg en konto"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "Ved å klikke på \"Tillatt\" så vil du bli ledet til: {redirectURI}"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Skriv inn et passord"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Skriv inn et brukernavn"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "Klarte ikke å forbinde med server"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "Farvel"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Hallo {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Hei {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "Behold den tillate tilgangen for alltid"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Logg inn feilet. Vennligst sjekk brukernavn/passord, og forsøk igjen."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Nettverksfeil. Sjekk din forbindelse, og forsøk igjen."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Neste"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Passord"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Trykk på knappen under, for å logge ut av din Kopano konto."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Prøv igjen"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Omfang: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Logg inn"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Logg ut"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Logg ut"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Uventet HTTP respons: {status}. Sjekk tilkoblingen din og prøv igjen."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Uventet svar-status: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Bruk en annen konto"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Brukernavn"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Velkommen {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Du er logget på!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Du kan lukke dette vinduet nå."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "vennligst bekreft utlogging"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "for å logge inn i Kopano"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "med din Kopano konto"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "du har blitt logget ut fra din Kopano konto"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} ønsker"
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-05-09 13:19+0000\n"
"Last-Translator: Bob <b.huisman@kopano.com>\n"
"Language-Team: Dutch <http://translate.kopano.io/projects/kopano/konnect/nl/>\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Basis accountgegevens weergeven"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Toestaan"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "{clientDisplayName} toestaan dit te doen?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "Door op Toestaan te klikken, krijgt deze app toestemming je informatie te gebruiken."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Annuleren"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Account kiezen"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "Door op \"Toestaan\" te klikken word je doorverwezen naar: {redirectURI}"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Voer een wachtwoord in"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Voer een gebruikersnaam in"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "Kon niet met server verbinden"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "Tot ziens"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Hallo {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Hoi {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "De toestemming voor altijd onthouden"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Inloggen mislukt. Controleer logingegevens en probeer opnieuw."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Netwerk probleem. Controleer je verbinding en probeer opnieuw."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Volgende"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Wachtwoord"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Klik op onderstaande knop om af te melden van je Kopano account."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Opnieuw"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Scope: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Aanmelden"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Afmelden"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Afmelden"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Onverwachte HTTP respons: {status}. Controleer je verbinding en probeer opnieuw."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Onverwachte respons status: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Gebruik een ander account"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Gebruikersnaam"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Welkom {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Je bent aangemeld - fantastisch!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Dit venster kan nu worden gesloten."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "bevestig afmelden"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "om aan te melden bij Kopano"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "met je Kopano account"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "je bent afgemeld van je Kopano account"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} wil"
+308
View File
@@ -0,0 +1,308 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"MIME-Version: 1.0\n"
"X-Generator: react-intl-po\n"
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2019-08-30 11:45+0200\n"
"Last-Translator: root <root@podo.kopano.io>\n"
"Language-Team: Language po\n"
"Language: po\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-05-31 09:39+0000\n"
"Last-Translator: Nuno Jerónimo <nuno.jeronimo@valsousa.pt>\n"
"Language-Team: Portuguese (Portugal) <http://translate.kopano.io/projects/kopano/konnect/pt_PT/>\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Aceder à sua informação básica da conta"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Permitir"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "Permitir que {clientDisplayName} faça isto?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "Ao carregar em Permitir, está a permitir que esta app use os seus dados."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Cancelar"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Escolher uma conta"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "Ao carregar em \"Permitir\" será redirecionado para: {redirectURI}"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Insira uma palavra-passe"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Insira um utilizador"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "Falhou a ligar ao servidor"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "Adeus"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Olá {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Olá {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "Manter o acesso permitido de forma persistente e para sempre"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Falhou início de sessão. Por favor verifique as suas credenciais e tente novamente."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Erro de rede. Por favor verifique as ligações e tente novamente."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Seguinte"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Palavra-passe"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Carregue no botão abaixo para terminar sessão na sua conta Kopano agora."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Tentar novamente"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Contexto: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Iniciar sessão"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Terminar sessão"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Terminar sessão"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Resposta HTTP inesperada: {status}. Por favor verifique a sua ligação e tente novamente."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Resposta de estado inesperada: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Use outra conta"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Utilizador"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Bem vindo {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Iniciou sessão - fantástico!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Pode fechar esta janela agora."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "por favor confirme o fim de sessão"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "para iniciar sessão no Kopano"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "com a sua conta Kopano"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "a sessão da sua conta Kopano foi terminada"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} quer"
+309
View File
@@ -0,0 +1,309 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"PO-Revision-Date: 2019-08-27 08:46+0000\n"
"Last-Translator: Sotneo <kerovsot@gmail.com>\n"
"Language-Team: Russian <http://translate.kopano.io/projects/kopano/konnect/ru/>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 2.4\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr "?"
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr "Доступ к вашей основной учетной записи"
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr "Разрешить"
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr "Разрешить {clientDisplayName} сделать это?"
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr "Нажимая Разрешить, ты даёте разрешение этому приложению использовать вашу информацию."
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr "Отмена"
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr "Выберите учётную запись"
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr "После нажатия \"Разрешить\" вы будете перенаправлена на: {redirectURI}"
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr "Введите пароль"
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr "Введите имя пользователя"
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr "Не удалось подключиться к серверу"
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr "До свидания"
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr "Здравствуйте, {displayName}"
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr "Привет, {displayName}"
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr "Сохраните разрешение на доступ как постоянное"
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr "Не удалось войти. Пожалуйста, проверьте ваши учетные данные и попробуйте снова."
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr "Сетевая ошибка. Пожалуйста, проверьте ваше соединение и попробуйте снова."
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr "Далее"
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr "Пароль"
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr "Нажмите кнопку ниже, чтобы выйти из вашей учетной записи Kopano."
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr "Повторить"
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr "Охват: {scope}"
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr "Вход"
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr "Выход"
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr "Выход"
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr "Неожиданный ответ HTTP: {status}. Проверьте подключение и повторите попытку."
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr "Неожиданный ответ: {state}"
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr "Другой пользователь"
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr "Имя пользователя"
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr "Добро пожаловать, {displayName}"
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr "Вы вошли - круто!"
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr "Теперь вы можете закрыть окно."
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr "пожалуйста, подтвердите выход"
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr "для входа в Kopano"
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr "с вашей учётной записью Kopano"
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr "вы вышли из вашей учетной записи Kopano"
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr "{clientDisplayName} хочет"
+310
View File
@@ -0,0 +1,310 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2019-05-09T14:09:27.715Z\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"MIME-Version: 1.0\n"
"X-Generator: react-intl-po\n"
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2019-08-30 11:46+0200\n"
"Last-Translator: root <root@transdoc.kopano.io>\n"
"Language-Team: Slovenian\n"
"Language: sl\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n"
"%100==4 ? 2 : 3);\n"
#. [konnect.chooseaccount.useOther.persona.label]
#. defaultMessage is:
#. ?
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.persona.label"
msgid "?"
msgstr ""
#. [konnect.scopeDescription.aliasBasic]
#. defaultMessage is:
#. Access your basic account information
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.aliasBasic"
msgid "Access your basic account information"
msgstr ""
#. [konnect.consent.allowButton.label]
#. defaultMessage is:
#. Allow
#: i18n/src/messages.json
msgctxt "konnect.consent.allowButton.label"
msgid "Allow"
msgstr ""
#. [konnect.consent.question]
#. defaultMessage is:
#. Allow {clientDisplayName} to do this?
#: i18n/src/messages.json
msgctxt "konnect.consent.question"
msgid "Allow {clientDisplayName} to do this?"
msgstr ""
#. [konnect.consent.consequence]
#. defaultMessage is:
#. By clicking Allow, you allow this app to use your information.
#: i18n/src/messages.json
msgctxt "konnect.consent.consequence"
msgid "By clicking Allow, you allow this app to use your information."
msgstr ""
#. [konnect.consent.cancelButton.label]
#. defaultMessage is:
#. Cancel
#: i18n/src/messages.json
msgctxt "konnect.consent.cancelButton.label"
msgid "Cancel"
msgstr ""
#. [konnect.chooseaccount.headline]
#. defaultMessage is:
#. Choose an account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.headline"
msgid "Choose an account"
msgstr ""
#. [konnect.consent.tooltip.client]
#. defaultMessage is:
#. Clicking "Allow" will redirect you to: {redirectURI}
#: i18n/src/messages.json
msgctxt "konnect.consent.tooltip.client"
msgid "Clicking \"Allow\" will redirect you to: {redirectURI}"
msgstr ""
#. [konnect.error.login.validate.missingPassword]
#. defaultMessage is:
#. Enter a password
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingPassword"
msgid "Enter a password"
msgstr ""
#. [konnect.error.login.validate.missingUsername]
#. defaultMessage is:
#. Enter an username
#: i18n/src/messages.json
msgctxt "konnect.error.login.validate.missingUsername"
msgid "Enter an username"
msgstr ""
#. [konnect.loading.error.headline]
#. defaultMessage is:
#. Failed to connect to server
#: i18n/src/messages.json
msgctxt "konnect.loading.error.headline"
msgid "Failed to connect to server"
msgstr ""
#. [konnect.goodbye.headline]
#. defaultMessage is:
#. Goodbye
#: i18n/src/messages.json
msgctxt "konnect.goodbye.headline"
msgid "Goodbye"
msgstr ""
#. [konnect.goodbye.confirm.headline]
#. defaultMessage is:
#. Hello {displayName}
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.headline"
msgid "Hello {displayName}"
msgstr ""
#. [konnect.consent.headline]
#. defaultMessage is:
#. Hi {displayName}
#: i18n/src/messages.json
msgctxt "konnect.consent.headline"
msgid "Hi {displayName}"
msgstr ""
#. [konnect.scopeDescription.offlineAccess]
#. defaultMessage is:
#. Keep the allowed access persistently and forever
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.offlineAccess"
msgid "Keep the allowed access persistently and forever"
msgstr ""
#. [konnect.error.login.failed]
#. defaultMessage is:
#. Logon failed. Please verify your credentials and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.login.failed"
msgid "Logon failed. Please verify your credentials and try again."
msgstr ""
#. [konnet.error.http.networkError]
#. defaultMessage is:
#. Network error. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnet.error.http.networkError"
msgid "Network error. Please check your connection and try again."
msgstr ""
#. [konnect.login.nextButton.label]
#. defaultMessage is:
#. Next
#: i18n/src/messages.json
msgctxt "konnect.login.nextButton.label"
msgid "Next"
msgstr ""
#. [konnect.login.passwordField.label]
#. defaultMessage is:
#. Password
#: i18n/src/messages.json
msgctxt "konnect.login.passwordField.label"
msgid "Password"
msgstr ""
#. [konnect.goodbye.message.confirm]
#. defaultMessage is:
#. Press the button below, to sign out from your Kopano account now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.confirm"
msgid "Press the button below, to sign out from your Kopano account now."
msgstr ""
#. [konnect.login.retryButton.label]
#. defaultMessage is:
#. Retry
#: i18n/src/messages.json
msgctxt "konnect.login.retryButton.label"
msgid "Retry"
msgstr ""
#. [konnect.scopeDescription.scope]
#. defaultMessage is:
#. Scope: {scope}
#: i18n/src/messages.json
msgctxt "konnect.scopeDescription.scope"
msgid "Scope: {scope}"
msgstr ""
#. [konnect.login.headline]
#. defaultMessage is:
#. Sign in
#: i18n/src/messages.json
msgctxt "konnect.login.headline"
msgid "Sign in"
msgstr ""
#. [konnect.goodbye.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.welcome.signoutButton.label]
#. defaultMessage is:
#. Sign out
#: i18n/src/messages.json
msgctxt "konnect.welcome.signoutButton.label"
msgid "Sign out"
msgstr ""
#. [konnect.error.http.unexpectedResponseStatus]
#. defaultMessage is:
#. Unexpected HTTP response: {status}. Please check your connection and try again.
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseStatus"
msgid "Unexpected HTTP response: {status}. Please check your connection and try again."
msgstr ""
#. [konnect.error.http.unexpectedResponseState]
#. defaultMessage is:
#. Unexpected response state: {state}
#: i18n/src/messages.json
msgctxt "konnect.error.http.unexpectedResponseState"
msgid "Unexpected response state: {state}"
msgstr ""
#. [konnect.chooseaccount.useOther.label]
#. defaultMessage is:
#. Use another account
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.useOther.label"
msgid "Use another account"
msgstr ""
#. [konnect.login.usernameField.label]
#. defaultMessage is:
#. Username
#: i18n/src/messages.json
msgctxt "konnect.login.usernameField.label"
msgid "Username"
msgstr ""
#. [konnect.welcome.headline]
#. defaultMessage is:
#. Welcome {displayName}
#: i18n/src/messages.json
msgctxt "konnect.welcome.headline"
msgid "Welcome {displayName}"
msgstr ""
#. [konnect.welcome.message]
#. defaultMessage is:
#. You are signed in - awesome!
#: i18n/src/messages.json
msgctxt "konnect.welcome.message"
msgid "You are signed in - awesome!"
msgstr ""
#. [konnect.goodbye.message.close]
#. defaultMessage is:
#. You can close this window now.
#: i18n/src/messages.json
msgctxt "konnect.goodbye.message.close"
msgid "You can close this window now."
msgstr ""
#. [konnect.goodbye.confirm.subHeader]
#. defaultMessage is:
#. please confirm sign out
#: i18n/src/messages.json
msgctxt "konnect.goodbye.confirm.subHeader"
msgid "please confirm sign out"
msgstr ""
#. [konnect.chooseaccount.subHeader]
#. defaultMessage is:
#. to sign in to Kopano
#: i18n/src/messages.json
msgctxt "konnect.chooseaccount.subHeader"
msgid "to sign in to Kopano"
msgstr ""
#. [konnect.login.subHeader]
#. defaultMessage is:
#. with your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.login.subHeader"
msgid "with your Kopano account"
msgstr ""
#. [konnect.goodbye.subHeader]
#. defaultMessage is:
#. you have been signed out from your Kopano account
#: i18n/src/messages.json
msgctxt "konnect.goodbye.subHeader"
msgid "you have been signed out from your Kopano account"
msgstr ""
#. [konnect.consent.message]
#. defaultMessage is:
#. {clientDisplayName} wants to
#: i18n/src/messages.json
msgctxt "konnect.consent.message"
msgid "{clientDisplayName} wants to"
msgstr ""
+187
View File
@@ -0,0 +1,187 @@
[
{
"id": "konnect.loading.error.headline",
"defaultMessage": "Failed to connect to server",
"filepath": "./src/components/Loading.js"
},
{
"id": "konnect.login.retryButton.label",
"defaultMessage": "Retry",
"filepath": "./src/components/Loading.js"
},
{
"id": "konnect.scopeDescription.aliasBasic",
"defaultMessage": "Access your basic account information",
"filepath": "./src/components/ScopesList.js"
},
{
"id": "konnect.scopeDescription.offlineAccess",
"defaultMessage": "Keep the allowed access persistently and forever",
"filepath": "./src/components/ScopesList.js"
},
{
"id": "konnect.scopeDescription.scope",
"defaultMessage": "Scope: {scope}",
"filepath": "./src/components/ScopesList.js"
},
{
"id": "konnect.goodbye.headline",
"defaultMessage": "Goodbye",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.goodbye.subHeader",
"defaultMessage": "you have been signed out from your Kopano account",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.goodbye.message.close",
"defaultMessage": "You can close this window now.",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.goodbye.confirm.headline",
"defaultMessage": "Hello {displayName}",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.goodbye.confirm.subHeader",
"defaultMessage": "please confirm sign out",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.goodbye.message.confirm",
"defaultMessage": "Press the button below, to sign out from your Kopano account now.",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.goodbye.signoutButton.label",
"defaultMessage": "Sign out",
"filepath": "./src/containers/Goodbye/Goodbyescreen.js"
},
{
"id": "konnect.chooseaccount.headline",
"defaultMessage": "Choose an account",
"filepath": "./src/containers/Login/Chooseaccount.js"
},
{
"id": "konnect.chooseaccount.subHeader",
"defaultMessage": "to sign in to Kopano",
"filepath": "./src/containers/Login/Chooseaccount.js"
},
{
"id": "konnect.chooseaccount.useOther.persona.label",
"defaultMessage": "?",
"filepath": "./src/containers/Login/Chooseaccount.js"
},
{
"id": "konnect.chooseaccount.useOther.label",
"defaultMessage": "Use another account",
"filepath": "./src/containers/Login/Chooseaccount.js"
},
{
"id": "konnect.consent.headline",
"defaultMessage": "Hi {displayName}",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.consent.message",
"defaultMessage": "{clientDisplayName} wants to",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.consent.tooltip.client",
"defaultMessage": "Clicking \"Allow\" will redirect you to: {redirectURI}",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.consent.question",
"defaultMessage": "Allow {clientDisplayName} to do this?",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.consent.consequence",
"defaultMessage": "By clicking Allow, you allow this app to use your information.",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.consent.cancelButton.label",
"defaultMessage": "Cancel",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.consent.allowButton.label",
"defaultMessage": "Allow",
"filepath": "./src/containers/Login/Consent.js"
},
{
"id": "konnect.login.headline",
"defaultMessage": "Sign in",
"filepath": "./src/containers/Login/Login.js"
},
{
"id": "konnect.login.subHeader",
"defaultMessage": "with your Kopano account",
"filepath": "./src/containers/Login/Login.js"
},
{
"id": "konnect.login.usernameField.label",
"defaultMessage": "Username",
"filepath": "./src/containers/Login/Login.js"
},
{
"id": "konnect.login.passwordField.label",
"defaultMessage": "Password",
"filepath": "./src/containers/Login/Login.js"
},
{
"id": "konnect.login.nextButton.label",
"defaultMessage": "Next",
"filepath": "./src/containers/Login/Login.js"
},
{
"id": "konnect.welcome.headline",
"defaultMessage": "Welcome {displayName}",
"filepath": "./src/containers/Welcome/Welcomescreen.js"
},
{
"id": "konnect.welcome.message",
"defaultMessage": "You are signed in - awesome!",
"filepath": "./src/containers/Welcome/Welcomescreen.js"
},
{
"id": "konnect.welcome.signoutButton.label",
"defaultMessage": "Sign out",
"filepath": "./src/containers/Welcome/Welcomescreen.js"
},
{
"id": "konnect.error.login.validate.missingUsername",
"defaultMessage": "Enter an username",
"filepath": "./src/errors/index.js"
},
{
"id": "konnect.error.login.validate.missingPassword",
"defaultMessage": "Enter a password",
"filepath": "./src/errors/index.js"
},
{
"id": "konnect.error.login.failed",
"defaultMessage": "Logon failed. Please verify your credentials and try again.",
"filepath": "./src/errors/index.js"
},
{
"id": "konnet.error.http.networkError",
"defaultMessage": "Network error. Please check your connection and try again.",
"filepath": "./src/errors/index.js"
},
{
"id": "konnect.error.http.unexpectedResponseStatus",
"defaultMessage": "Unexpected HTTP response: {status}. Please check your connection and try again.",
"filepath": "./src/errors/index.js"
},
{
"id": "konnect.error.http.unexpectedResponseState",
"defaultMessage": "Unexpected response state: {state}",
"filepath": "./src/errors/index.js"
}
]
+18
View File
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#1b223d">
<link rel="shortcut icon" href="%PUBLIC_URL%/static/favicon.ico" type="image/x-icon">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600&display=swap" rel="stylesheet">
<meta property="csp-nonce" content="__CSP_NONCE__">
<title>Sign in - ownCloud</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<main id="root" class="oc-login-bg" data-path-prefix="__PATH_PREFIX__" passwort-reset-link="__PASSWORD_RESET_LINK__"></main>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="cloud" class="svg-inline--fa fa-cloud fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="#ffffff" d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"></path></svg>

After

Width:  |  Height:  |  Size: 479 B

+45
View File
@@ -0,0 +1,45 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import Routes from './Routes';
class App extends PureComponent {
render() {
const { classes, hello, pathPrefix } = this.props;
return (
<BrowserRouter basename={pathPrefix}>
<Routes hello={hello}/>
</BrowserRouter>
);
}
reload(event) {
event.preventDefault();
window.location.reload();
}
}
App.propTypes = {
classes: PropTypes.object.isRequired,
hello: PropTypes.object,
updateAvailable: PropTypes.bool.isRequired,
pathPrefix: PropTypes.string.isRequired
};
const mapStateToProps = (state) => {
const { hello, updateAvailable, pathPrefix } = state.common;
return {
hello,
updateAvailable,
pathPrefix
};
};
export default connect(mapStateToProps)(App);
+12
View File
@@ -0,0 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './Main';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Provider store={store}><App/></Provider>, div);
});
+40
View File
@@ -0,0 +1,40 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Route, Switch } from 'react-router-dom';
import AsyncComponent from 'kpop/es/AsyncComponent';
import PrivateRoute from './components/PrivateRoute';
const AsyncLogin = AsyncComponent(() =>
import(/* webpackChunkName: "containers-login" */ './containers/Login'));
const AsyncWelcome = AsyncComponent(() =>
import(/* webpackChunkName: "containers-welcome" */ './containers/Welcome'));
const AsyncGoodbye = AsyncComponent(() =>
import(/* webpackChunkName: "containers-goodbye" */ './containers/Goodbye'));
const Routes = ({ hello }) => (
<Switch>
<PrivateRoute
path="/welcome"
exact
component={AsyncWelcome}
hello={hello}
/>
<Route
path="/goodbye"
exact
component={AsyncGoodbye}
/>
<Route
path="/"
component={AsyncLogin}
/>
</Switch>
);
Routes.propTypes = {
hello: PropTypes.object
};
export default Routes;
+133
View File
@@ -0,0 +1,133 @@
import axios from 'axios';
import { newHelloRequest } from '../models/hello';
import { withClientRequestState } from '../utils';
import {
ExtendedError,
ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS,
ERROR_HTTP_UNEXPECTED_RESPONSE_STATE
} from '../errors';
import { handleAxiosError } from './utils';
import * as types from './types';
export function receiveError(error) {
return {
type: types.RECEIVE_ERROR,
error
};
}
export function resetHello() {
return {
type: types.RESET_HELLO
};
}
export function receiveHello(hello) {
const { success, username, displayName } = hello;
return {
type: types.RECEIVE_HELLO,
state: success === true,
username,
displayName,
hello
};
}
export function executeHello() {
return function(dispatch, getState) {
dispatch(resetHello());
const { flow, query } = getState().common;
const r = withClientRequestState(newHelloRequest(flow, query));
return axios.post('./identifier/_/hello', r, {
headers: {
'Kopano-Konnect-XSRF': '1'
}
}).then(response => {
switch (response.status) {
case 200:
// success.
return response.data;
case 204:
// not signed-in.
return {
success: false,
state: response.headers['kopano-konnect-state']
};
default:
// error.
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
}
}).then(response => {
if (response.state !== r.state) {
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
}
dispatch(receiveHello(response));
return Promise.resolve(response);
}).catch(error => {
error = handleAxiosError(error);
dispatch(receiveError(error));
});
};
}
export function retryHello() {
return function(dispatch) {
dispatch(receiveError(null));
return dispatch(executeHello());
};
}
export function requestLogoff() {
return {
type: types.REQUEST_LOGOFF
};
}
export function receiveLogoff(state) {
return {
type: types.RECEIVE_LOGOFF,
state
};
}
export function executeLogoff() {
return function(dispatch) {
dispatch(resetHello());
dispatch(requestLogoff());
const r = withClientRequestState({});
return axios.post('./identifier/_/logoff', r, {
headers: {
'Kopano-Konnect-XSRF': '1'
}
}).then(response => {
switch (response.status) {
case 200:
// success.
return response.data;
default:
// error.
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
}
}).then(response => {
if (response.state !== r.state) {
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
}
dispatch(receiveLogoff(response.success === true));
return Promise.resolve(response);
}).catch(error => {
error = handleAxiosError(error);
dispatch(receiveError(error));
});
};
}
+291
View File
@@ -0,0 +1,291 @@
import axios from 'axios';
import queryString from 'query-string';
import { newHelloRequest } from '../models/hello';
import { withClientRequestState } from '../utils';
import {
ExtendedError,
ERROR_LOGIN_VALIDATE_MISSINGUSERNAME,
ERROR_LOGIN_VALIDATE_MISSINGPASSWORD,
ERROR_LOGIN_FAILED,
ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS,
ERROR_HTTP_UNEXPECTED_RESPONSE_STATE
} from '../errors';
import * as types from './types';
import { receiveHello } from './common';
import { handleAxiosError } from './utils';
// Modes for logon.
export const ModeLogonUsernameEmptyPasswordCookie = '0';
export const ModeLogonUsernamePassword = '1';
export function updateInput(name, value) {
return {
type: types.UPDATE_INPUT,
name,
value
};
}
export function receiveValidateLogon(errors) {
return {
type: types.RECEIVE_VALIDATE_LOGON,
errors
};
}
export function requestLogon(username, password) {
return {
type: types.REQUEST_LOGON,
username,
password
};
}
export function receiveLogon(logon) {
const { success, errors } = logon;
return {
type: types.RECEIVE_LOGON,
success,
errors
};
}
export function requestConsent(allow=false) {
return {
type: allow ? types.REQUEST_CONSENT_ALLOW : types.REQUEST_CONSENT_CANCEL
};
}
export function receiveConsent(logon) {
const { success, errors } = logon;
return {
type: types.RECEIVE_CONSENT,
success,
errors
};
}
export function executeLogon(username, password, mode=ModeLogonUsernamePassword) {
return function(dispatch, getState) {
dispatch(requestLogon(username, password));
dispatch(receiveHello({
username
})); // Reset any hello state on logon.
const { flow, query } = getState().common;
// Prepare params based on mode.
const params = [];
switch (mode) {
case ModeLogonUsernamePassword:
// Username with password.
params.push(username, password, mode);
break;
case ModeLogonUsernameEmptyPasswordCookie:
// Username with empty password - this only works when the user is already signed in.
params.push(username, '', mode);
break;
}
const r = withClientRequestState({
params: params,
hello: newHelloRequest(flow, query)
});
return axios.post('./identifier/_/logon', r, {
headers: {
'Kopano-Konnect-XSRF': '1'
}
}).then(response => {
switch (response.status) {
case 200:
// success.
return response.data;
case 204:
// login failed.
return {
success: false,
state: response.headers['kopano-konnect-state'],
errors: {
http: new Error(ERROR_LOGIN_FAILED)
}
};
default:
// error.
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
}
}).then(response => {
if (response.state !== r.state) {
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
}
let { hello } = response;
if (!hello) {
hello = {
success: response.success,
username
};
}
dispatch(receiveHello(hello));
dispatch(receiveLogon(response));
return Promise.resolve(response);
}).catch(error => {
error = handleAxiosError(error);
const errors = {
http: error
};
dispatch(receiveValidateLogon(errors));
return {
success: false,
errors: errors
};
});
};
}
export function executeConsent(allow=false, scope='') {
return function(dispatch, getState) {
dispatch(requestConsent(allow));
const { query } = getState().common;
const r = withClientRequestState({
allow,
scope,
client_id: query.client_id || '', // eslint-disable-line camelcase
redirect_uri: query.redirect_uri || '', // eslint-disable-line camelcase
ref: query.state || '',
flow_nonce: query.nonce || '' // eslint-disable-line camelcase
});
return axios.post('./identifier/_/consent', r, {
headers: {
'Kopano-Konnect-XSRF': '1'
}
}).then(response => {
switch (response.status) {
case 200:
// success.
return response.data;
case 204:
// cancel reply.
return {
success: true,
state: response.headers['kopano-konnect-state']
};
default:
// error.
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
}
}).then(response => {
if (response.state !== r.state) {
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
}
dispatch(receiveConsent(response));
return Promise.resolve(response);
}).catch(error => {
error = handleAxiosError(error);
const errors = {
http: error
};
dispatch(receiveValidateLogon(errors));
return {
success: false,
errors: errors
};
});
};
}
export function validateUsernamePassword(username, password, isSignedIn) {
return function(dispatch) {
return new Promise((resolve, reject) => {
const errors = {};
if (!username) {
errors.username = new Error(ERROR_LOGIN_VALIDATE_MISSINGUSERNAME);
}
if (!password && !isSignedIn) {
errors.password = new Error(ERROR_LOGIN_VALIDATE_MISSINGPASSWORD);
}
dispatch(receiveValidateLogon(errors));
if (Object.keys(errors).length === 0) {
resolve(errors);
} else {
reject(errors);
}
});
};
}
export function executeLogonIfFormValid(username, password, isSignedIn) {
return (dispatch) => {
return dispatch(
validateUsernamePassword(username, password, isSignedIn)
).then(() => {
const mode = isSignedIn ? ModeLogonUsernameEmptyPasswordCookie : ModeLogonUsernamePassword;
return dispatch(executeLogon(username, password, mode));
}).catch((errors) => {
return {
success: false,
errors: errors
};
});
};
}
export function advanceLogonFlow(success, history, done=false, extraQuery={}) {
return (dispatch, getState) => {
if (!success) {
return;
}
const { flow, query, hello } = getState().common;
const q = Object.assign({}, query, extraQuery);
switch (flow) {
case 'oauth':
case 'consent':
case 'oidc':
if (hello.details.flow !== flow) {
// Ignore requested flow if hello flow does not match.
break;
}
if (!done && hello.details.next === 'consent') {
history.replace(`/consent${history.location.search}${history.location.hash}`);
return;
}
if (hello.details.continue_uri) {
q.prompt = 'none';
window.location.replace(hello.details.continue_uri + '?' + queryString.stringify(q));
return;
}
break;
default:
// Legacy stupid modes.
if (q.continue && q.continue.indexOf(document.location.origin) === 0) {
window.location.replace(q.continue);
return;
}
}
// Default action.
let target = '/welcome';
if (history.action === 'REPLACE') {
target = target + history.location.search + history.location.hash;
}
dispatch(receiveValidateLogon({})); // XXX(longsleep): hack to reset loading and errors.
history.push(target);
};
}
+25
View File
@@ -0,0 +1,25 @@
export const RECEIVE_ERROR = 'RECEIVE_ERROR';
export const RESET_HELLO = 'RESET_HELLO';
export const EXECUTE_HELLO = 'EXECUTE_HELLO';
export const RECEIVE_HELLO = 'RECEIVE_HELLO';
export const RECEIVE_VALIDATE_LOGON = 'RECEIVE_VALIDATE_LOGON';
export const REQUEST_LOGON = 'REQUEST_LOGON';
export const EXECUTE_LOGON = 'EXECUTE_LOGON';
export const RECEIVE_LOGON = 'RECEIVE_LOGON';
export const UPDATE_INPUT = 'UPDATE_INPUT';
export const REQUEST_CONSENT_ALLOW = 'REQUEST_CONSENT_ALLOW';
export const REQUEST_CONSENT_CANCEL = 'REQUEST_CONSENT_CANCEL';
export const EXECUTE_CONSENT = 'EXECUTE_CONSENT';
export const RECEIVE_CONSENT = 'RECEIVE_CONSENT';
export const REQUEST_LOGOFF = 'REQUEST_LOGOFF';
export const EXECUTE_LOGOFF = 'EXECUTE_LOGOFF';
export const RECEIVE_LOGOFF = 'RECEIVE_LOGOFF';
export const SERVICE_WORKER_NEW_CONTENT = 'SERVICE_WORKER_NEW_CONTENT';
export const SERVICE_WORKER_READY = 'SERVICE_WORKER_READY';
export const SERVICE_WORKER_ERROR = 'SERVICE_WORKER_ERROR';
export const SERVICE_WORKER_OFFLINE = 'SERVICE_WORKER_OFFLINE';
+18
View File
@@ -0,0 +1,18 @@
import {
ExtendedError,
ERROR_HTTP_NETWORK_ERROR,
ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS
} from '../errors';
export function handleAxiosError(error) {
if (error.request) {
// Axios errors.
if (error.response) {
error = new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, error.response);
} else {
error = new ExtendedError(ERROR_HTTP_NETWORK_ERROR);
}
}
return error;
}
+157
View File
@@ -0,0 +1,157 @@
/* additional css on top of kpop */
html {
font-family: 'Open Sans', sans-serif;
}
strong {
font-weight: 600;
}
.oc-login-bg {
background-image: url(./images/background.jpg);
background-size: cover;
background-repeat: no-repeat;
background-position: center;
z-index: 0;
}
#loader {
/* NOTE(longsleep): White here needed because of the background image */
color: white;
text-shadow: #000 0 0 1px;
}
.oc-logo {
position: absolute;
top: -130px;
left: 50%;
height: 80px;
transform: translateX(-50%);
}
.oc-progress {
/* Needs to be important to overwrite material-ui */
background-color: rgba(78, 133, 200, 0.8) !important;
height: 4px;
width: 100px;
}
.oc-progress > div {
/* Needs to be important to overwrite material-ui */
background-color: #4a76ac !important;
}
.oc-input {
background-color: #042047;
border: 1px solid rgba(78, 133, 200, 0.8);
border-radius: 3px;
color: rgba(255, 255, 255, 0.8);
height: 40px;
width: 300px;
padding: 16px;
box-sizing: border-box;
font-size: 1rem;
}
.oc-label {
color: #fff;
display: inline-block;
margin-bottom: 5px;
}
.oc-input.error {
outline: none;
border: 1px solid #fe4600;
}
.MuiTypography-colorError {
color: #fe4600 !important;
}
.oc-input:focus {
outline: none;
border: 1px solid #fff;
}
.oc-input::placeholder {
color: rgba(78, 133, 200, 0.8);
}
.oc-input + .oc-input {
margin-top: 15px;
}
.MuiTouchRipple-root {
display: none !important;
}
.oc-button {
/* Needs to be important to overwrite material-ui */
font-size: 1.0625rem !important;
}
.oc-button-primary {
/* Needs to be important to overwrite material-ui */
background-color: #4a76ac !important;
border: 1px solid transparent !important;
}
.oc-button-primary:hover,
.oc-button-primary:focus {
/* Needs to be important to overwrite material-ui */
background-color: #4a76ac !important;
border: 1px solid white !important;
}
.oc-checkbox-dark svg {
/* Needs to be important to overwrite material-ui */
fill: white !important;
}
.oc-footer-message {
color: white;
padding: 10px;
font-size: 0.8rem;
}
@media only screen and (max-width: 768px) {
.oc-logo {
height: 60px;
top: -90px;
}
}
/* Helpers */
.oc-mt-l {
margin-top: 30px !important;
}
.oc-mb-m {
margin-bottom: 20px !important;
}
.oc-light {
color: #fff !important;
}
.oc-login-form div:not(:last-of-type) {
margin-bottom: 15px;
}
/*
* Special SR classes
* Used to hide an element visually, but keeping it accessible for accessibility tools.
*/
.oc-invisible-sr {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
height: 1px !important;
overflow: hidden !important;
padding: 0 !important;
/* Need to make sure we override any existing styles. */
position: absolute !important;
top: 0;
white-space: nowrap;
width: 1px !important;
}
+34
View File
@@ -0,0 +1,34 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Loadable from 'react-loadable';
import { Provider } from 'react-redux';
import { MuiThemeProvider } from '@material-ui/core/styles';
import { defaultTheme as theme } from 'kpop/es/theme';
import { IntlProvider } from 'react-intl';
import Loading from 'kpop/es/Loading';
import { unregister } from 'kpop/es/serviceWorker';
import store from './store';
import translations from './locales';
// NOTE(longsleep): Load async with loader, this enables code splitting via Webpack.
const LoadableApp = Loadable({
loader: () => import(/* webpackChunkName: "identifier-main" */ './Main'),
loading: Loading,
timeout: 20000
});
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider theme={theme}>
<IntlProvider messages={translations} locale="en" defaultLocale="en">
<LoadableApp />
</IntlProvider>
</MuiThemeProvider>
</Provider>,
document.getElementById('root')
);
unregister();
@@ -0,0 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
const ClientDisplayName = ({ client, ...rest }) => (
<span {...rest}>{client.display_name ? client.display_name : client.id}</span>
);
ClientDisplayName.propTypes = {
client: PropTypes.object.isRequired
};
export default ClientDisplayName;
@@ -0,0 +1,63 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import LinearProgress from '@material-ui/core/LinearProgress';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import renderIf from 'render-if';
import { retryHello } from '../actions/common';
import { ErrorMessage } from '../errors';
function Loading({ error, dispatch }) {
const retry = (event) => {
event.preventDefault();
dispatch(retryHello());
}
return (
<Grid item align="center">
{renderIf(error === null)(() => (
<LinearProgress className="oc-progress" />
))}
{renderIf(error !== null)(() => (
<div>
<Typography className="oc-light" variant="h5" gutterBottom align="center">
<FormattedMessage id="konnect.loading.error.headline" defaultMessage="Failed to connect to server" />
</Typography>
<Typography align="center" color="error">
<ErrorMessage error={error} />
</Typography>
<Button
autoFocus
color="primary"
variant="contained"
className="oc-button-primary oc-mt-l"
onClick={(event) => retry(event)}
>
<FormattedMessage id="konnect.login.retryButton.label" defaultMessage="Retry" />
</Button>
</div>
))}
</Grid>
);
}
Loading.propTypes = {
error: PropTypes.object,
dispatch: PropTypes.func.isRequired
};
const mapStateToProps = (state) => {
const { error } = state.common;
return {
error
};
};
export default connect(mapStateToProps)(Loading);
@@ -0,0 +1,22 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Route } from 'react-router-dom';
import RedirectWithQuery from './RedirectWithQuery';
const PrivateRoute = ({ component: Target, hello, ...rest }) => (
<Route {...rest} render={props => (
hello ? (
<Target {...props}/>
) : (
<RedirectWithQuery target='/identifier' />
)
)}/>
);
PrivateRoute.propTypes = {
component: PropTypes.func.isRequired,
hello: PropTypes.object
};
export default PrivateRoute;
@@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import { Redirect } from 'react-router-dom';
const RedirectWithQuery = ({target, location, ...rest}) => {
const to = {
pathname: target,
search: location.search,
hash: location.hash
};
return (
<Redirect to={to} {...rest}></Redirect>
);
};
RedirectWithQuery.propTypes = {
target: PropTypes.string.isRequired,
location: PropTypes.object.isRequired
};
export default withRouter(RedirectWithQuery);
@@ -0,0 +1,95 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';
import { withStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import DialogContent from '@material-ui/core/DialogContent';
import Loading from './Loading';
const styles = theme => ({
root: {
display: 'flex',
flex: 1
},
content: {
position: 'relative',
width: '100%'
},
actions: {
marginTop: -40,
justifyContent: 'flex-start',
paddingLeft: theme.spacing(3),
paddingRight: theme.spacing(3)
},
wrapper: {
width: '100%',
maxWidth: 300,
display: 'flex',
flex: 1,
alignItems: 'center'
}
});
const footerProductName = name => <strong>{name}</strong>;
const ResponsiveScreen = (props) => {
const {
classes,
withoutLogo,
withoutPadding,
loading,
children,
className,
DialogProps,
PaperProps,
...other
} = props;
const logo = withoutLogo ? null :
<img src={process.env.PUBLIC_URL + '/static/logo.svg'} className="oc-logo" alt="ownCloud Logo"/>;
const content = loading ? <Loading/> : (withoutPadding ? children : <DialogContent>{children}</DialogContent>);
return (
<Grid container justify="center" alignItems="center" direction="column" spacing={0}
className={classNames(classes.root, className)} {...other}>
<div className={classes.wrapper}>
<div className={classes.content}>
{logo}
{content}
</div>
</div>
<footer className="oc-footer-message">
<FormattedMessage
id="konnect.footer.slogan"
defaultMessage="<name>ownCloud</name> - a safe home for all your data"
values={{
name: chunks => footerProductName(chunks)
}}
/>
</footer>
</Grid>
);
};
ResponsiveScreen.defaultProps = {
withoutLogo: false,
withoutPadding: false,
loading: false
};
ResponsiveScreen.propTypes = {
classes: PropTypes.object.isRequired,
withoutLogo: PropTypes.bool,
withoutPadding: PropTypes.bool,
loading: PropTypes.bool,
children: PropTypes.node.isRequired,
className: PropTypes.string,
PaperProps: PropTypes.object,
DialogProps: PropTypes.object
};
export default withStyles(styles)(ResponsiveScreen);
@@ -0,0 +1,102 @@
import React from 'react';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import { withStyles } from '@material-ui/core/styles';
import PropTypes from 'prop-types';
import Checkbox from '@material-ui/core/Checkbox';
import { injectIntl, useIntl, defineMessages, FormattedMessage } from 'react-intl';
const styles = () => ({
row: {
paddingTop: 0,
paddingBottom: 0
}
});
const scopeIDTranslations = defineMessages({
'scope_alias_basic': {
id: 'konnect.scopeDescription.aliasBasic',
defaultMessage: 'Access your basic account information'
},
'scope_offline_access': {
id: 'konnect.scopeDescription.offlineAccess',
defaultMessage: 'Keep the allowed access persistently and forever'
}
});
const ScopesList = ({scopes, meta, classes, ...rest}) => {
const { mapping, definitions } = meta;
const intl = useIntl()
const rows = [];
const known = {};
// TODO(longsleep): Sort scopes according to priority.
for (let scope in scopes) {
if (!scopes[scope]) {
continue;
}
let id = mapping[scope];
if (id) {
if (known[id]) {
continue;
}
known[id] = true;
} else {
id = scope;
}
let definition = definitions[id];
let label ;
if (definition) {
if (definition.id) {
const translation = scopeIDTranslations[definition.id];
if (translation) {
label = intl.formatMessage(translation);
}
}
if (!label) {
label = definition.description;
}
}
if (!label) {
label = <FormattedMessage
id="konnect.scopeDescription.scope"
defaultMessage="Scope: {scope}"
values={{scope}}
/>;
}
rows.push(
<ListItem
disableGutters
dense
key={id}
className={classes.row}
><Checkbox
checked
disableRipple
disabled
className="oc-checkbox-dark"
/>
<ListItemText primary={label} className="oc-light" />
</ListItem>
);
}
return (
<List {...rest}>
{rows}
</List>
);
};
ScopesList.propTypes = {
classes: PropTypes.object.isRequired,
scopes: PropTypes.object.isRequired,
meta: PropTypes.object.isRequired
};
export default withStyles(styles)(injectIntl(ScopesList));
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import {useIntl} from 'react-intl';
const TextInput = (props) => {
const intl = useIntl();
const label = props.label;
const extraClassName = props.extraClassName;
delete props.label;
delete props.extraClassName;
return (
<div>
<label className="oc-label"
htmlFor={props.id}>{intl.formatMessage(label)}</label>
<input className={`oc-input ${extraClassName ? extraClassName : ''}`} {...props}
placeholder={props.placeholder ? intl.formatMessage(props.placeholder) : null}/>
</div>);
};
TextInput.propTypes = {
placeholder: PropTypes.object,
label: PropTypes.object,
id: PropTypes.string,
extraClassName: props.string,
}
export default TextInput;
@@ -0,0 +1,125 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import renderIf from 'render-if';
import { FormattedMessage } from 'react-intl';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import DialogActions from '@material-ui/core/DialogActions';
import ResponsiveScreen from '../../components/ResponsiveScreen';
import { executeHello, executeLogoff } from '../../actions/common';
const styles = theme => ({
subHeader: {
marginBottom: theme.spacing(5)
},
wrapper: {
marginTop: theme.spacing(5),
position: 'relative',
display: 'inline-block'
}
});
class Goodbyescreen extends React.PureComponent {
componentDidMount() {
this.props.dispatch(executeHello());
}
render() {
const { classes, hello } = this.props;
const loading = hello === null;
return (
<ResponsiveScreen loading={loading}>
{renderIf(hello !== null && !hello.state)(() => (
<div>
<Typography variant="h5" component="h3">
<FormattedMessage id="konnect.goodbye.headline" defaultMessage="Goodbye"></FormattedMessage>
</Typography>
<Typography variant="subtitle1" className={classes.subHeader}>
<FormattedMessage id="konnect.goodbye.subHeader"
defaultMessage="you have been signed out from your Kopano account">
</FormattedMessage>
</Typography>
<Typography gutterBottom>
<FormattedMessage id="konnect.goodbye.message.close"
defaultMessage="You can close this window now.">
</FormattedMessage>
</Typography>
</div>
))}
{renderIf(hello !== null && hello.state === true)(() => (
<div>
<Typography variant="h5" component="h3">
<FormattedMessage
id="konnect.goodbye.confirm.headline"
defaultMessage="Hello {displayName}"
values={{displayName: hello.displayName}}>
</FormattedMessage>
</Typography>
<Typography variant="subtitle1" className={classes.subHeader}>
<FormattedMessage id="konnect.goodbye.confirm.subHeader"
defaultMessage="please confirm sign out">
</FormattedMessage>
</Typography>
<Typography gutterBottom>
<FormattedMessage id="konnect.goodbye.message.confirm"
defaultMessage="Press the button below, to sign out from your Kopano account now.">
</FormattedMessage>
</Typography>
<DialogActions>
<div className={classes.wrapper}>
<Button
color="secondary"
className={classes.button}
onClick={(event) => this.logoff(event)}
>
<FormattedMessage id="konnect.goodbye.signoutButton.label"
defaultMessage="Sign out"></FormattedMessage>
</Button>
</div>
</DialogActions>
</div>
))}
</ResponsiveScreen>
);
}
logoff(event) {
event.preventDefault();
this.props.dispatch(executeLogoff()).then((response) => {
const { history } = this.props;
if (response.success) {
this.props.dispatch(executeHello());
history.push('/goodbye');
}
});
}
}
Goodbyescreen.propTypes = {
classes: PropTypes.object.isRequired,
hello: PropTypes.object,
dispatch: PropTypes.func.isRequired,
history: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { hello } = state.common;
return {
hello
};
};
export default connect(mapStateToProps)(withStyles(styles)(Goodbyescreen));
@@ -0,0 +1 @@
export { default } from './Goodbyescreen';
@@ -0,0 +1,144 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { withStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import Avatar from '@material-ui/core/Avatar';
import Typography from '@material-ui/core/Typography';
import { executeLogonIfFormValid, advanceLogonFlow } from '../../actions/login';
import { ErrorMessage } from '../../errors';
const styles = theme => ({
subHeader: {
marginBottom: theme.spacing(2)
},
message: {
marginTop: theme.spacing(2)
},
accountList: {
marginLeft: theme.spacing(-3),
marginRight: theme.spacing(-3)
},
accountListItem: {
paddingLeft: theme.spacing(3),
paddingRight: theme.spacing(3)
}
});
function Chooseaccount({ loading, errors, classes, hello, history, dispatch }) {
useEffect(() => {
if ((!hello || !hello.state) && history.action !== 'PUSH') {
history.replace(`/identifier${history.location.search}${history.location.hash}`);
}
});
let errorMessage = null;
if (errors.http) {
errorMessage = <Typography color="error" className={classes.message}>
<ErrorMessage error={errors.http}></ErrorMessage>
</Typography>;
}
let username = '';
if (hello && hello.state) {
username = hello.username;
}
const logon = (event) => {
event.preventDefault();
dispatch(executeLogonIfFormValid(hello.username, '', true)).then((response) => {
if (response.success) {
dispatch(advanceLogonFlow(response.success, history));
}
});
}
const logoff = (event) => {
event.preventDefault();
history.push(`/identifier${history.location.search}${history.location.hash}`);
}
return (
<div>
<Typography variant="h5" component="h3" className="oc-light">
<FormattedMessage id="konnect.chooseaccount.headline" defaultMessage="Choose an account"></FormattedMessage>
</Typography>
<Typography variant="subtitle1" className={classes.subHeader + " oc-light"}>
<FormattedMessage id="konnect.chooseaccount.subHeader" defaultMessage="to sign in to Kopano">
</FormattedMessage>
</Typography>
<form action="" onSubmit={(event) => logon(event)}>
<List disablePadding className={classes.accountList}>
<ListItem
button
disableGutters
className={classes.accountListItem}
disabled={!!loading}
onClick={(event) => logon(event)}
><ListItemAvatar><Avatar>{username.slice(0, 1)}</Avatar></ListItemAvatar>
<ListItemText className="oc-light" primary={username} />
</ListItem>
<ListItem
button
disableGutters
className={classes.accountListItem}
disabled={!!loading}
onClick={(event) => logoff(event)}
>
<ListItemAvatar>
<Avatar>
<FormattedMessage id="konnect.chooseaccount.useOther.persona.label" defaultMessage="?">
</FormattedMessage>
</Avatar>
</ListItemAvatar>
<ListItemText
className="oc-light"
primary={
<FormattedMessage
id="konnect.chooseaccount.useOther.label"
defaultMessage="Use another account">
</FormattedMessage>
}
/>
</ListItem>
</List>
{errorMessage}
</form>
</div>
);
}
Chooseaccount.propTypes = {
classes: PropTypes.object.isRequired,
loading: PropTypes.string.isRequired,
errors: PropTypes.object.isRequired,
hello: PropTypes.object,
dispatch: PropTypes.func.isRequired,
history: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { loading, errors } = state.login;
const { hello } = state.common;
return {
loading,
errors,
hello
};
};
export default connect(mapStateToProps)(withStyles(styles)(Chooseaccount));
@@ -0,0 +1,187 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import renderIf from 'render-if';
import { FormattedMessage } from 'react-intl';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Tooltip from '@material-ui/core/Tooltip';
import CircularProgress from '@material-ui/core/CircularProgress';
import green from '@material-ui/core/colors/green';
import Typography from '@material-ui/core/Typography';
import DialogActions from '@material-ui/core/DialogActions';
import { executeConsent, advanceLogonFlow, receiveValidateLogon } from '../../actions/login';
import { ErrorMessage } from '../../errors';
import { REQUEST_CONSENT_ALLOW } from '../../actions/types';
import ClientDisplayName from '../../components/ClientDisplayName';
import ScopesList from '../../components/ScopesList';
const styles = theme => ({
buttonProgress: {
color: green[500],
position: 'absolute',
top: '50%',
left: '50%',
marginTop: -12,
marginLeft: -12
},
scopesList: {
marginBottom: theme.spacing(2)
},
wrapper: {
marginTop: theme.spacing(2),
position: 'relative',
display: 'inline-block'
},
message: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2)
}
});
class Consent extends React.PureComponent {
componentDidMount() {
const { dispatch, hello, history, client } = this.props;
if ((!hello || !hello.state || !client) && history.action !== 'PUSH') {
history.replace(`/identifier${history.location.search}${history.location.hash}`);
}
dispatch(receiveValidateLogon({})); // XXX(longsleep): hack to reset loading and errors.
}
action = (allow=false, scopes={}) => (event) => {
event.preventDefault();
if (allow === undefined) {
return;
}
// Convert all scopes which are true to a scope value.
const scope = Object.keys(scopes).filter(scope => {
return !!scopes[scope];
}).join(' ');
const { dispatch, history } = this.props;
dispatch(executeConsent(allow, scope)).then((response) => {
if (response.success) {
dispatch(advanceLogonFlow(response.success, history, true, {konnect: response.state}));
}
});
}
render() {
const { classes, loading, hello, errors, client } = this.props;
const scopes = hello.details.scopes || {};
const meta = hello.details.meta || {};
return (
<div>
<Typography variant="h5" component="h3" className="oc-light">
<FormattedMessage
id="konnect.consent.headline"
defaultMessage="Hi {displayName}"
values={{displayName: hello.displayName}}
/>
</Typography>
<Typography variant="subtitle1" className="oc-light oc-mb-m">
{hello.username}
</Typography>
<Typography variant="subtitle1" gutterBottom className="oc-light">
<FormattedMessage
id="konnect.consent.message"
defaultMessage="{clientDisplayName} wants to"
values={{clientDisplayName:
<Tooltip
placement="bottom"
title={<FormattedMessage
id="konnect.consent.tooltip.client"
defaultMessage='Clicking "Allow" will redirect you to: {redirectURI}'
values={{
redirectURI: client.redirect_uri
}}
></FormattedMessage>}
>
<em><ClientDisplayName client={client}/></em>
</Tooltip>
}}
></FormattedMessage>
</Typography>
<ScopesList dense disablePadding className={classes.scopesList} scopes={scopes} meta={meta.scopes}></ScopesList>
<Typography className="oc-light">
<FormattedMessage
id="konnect.consent.consequence"
defaultMessage="By clicking Allow, you allow this app to use your information.">
</FormattedMessage>
</Typography>
<form action="" onSubmit={this.action(undefined, scopes)}>
<DialogActions>
<div className={classes.wrapper}>
<Button
color="secondary"
className={classes.button}
disabled={!!loading}
onClick={this.action(false, scopes)}
>
<FormattedMessage id="konnect.consent.cancelButton.label" defaultMessage="Cancel"></FormattedMessage>
</Button>
{(loading && loading !== REQUEST_CONSENT_ALLOW) &&
<CircularProgress size={24} className={classes.buttonProgress} />}
</div>
<div className={classes.wrapper}>
<Button
type="submit"
color="primary"
variant="contained"
className="oc-button-primary"
disabled={!!loading}
onClick={this.action(true, scopes)}
>
<FormattedMessage id="konnect.consent.allowButton.label" defaultMessage="Allow"></FormattedMessage>
</Button>
{loading === REQUEST_CONSENT_ALLOW && <CircularProgress size={24} className={classes.buttonProgress} />}
</div>
</DialogActions>
{renderIf(errors.http)(() => (
<Typography variant="subtitle2" color="error" className={classes.message}>
<ErrorMessage error={errors.http}></ErrorMessage>
</Typography>
))}
</form>
</div>
);
}
}
Consent.propTypes = {
classes: PropTypes.object.isRequired,
loading: PropTypes.string.isRequired,
errors: PropTypes.object.isRequired,
hello: PropTypes.object,
client: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
history: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { hello } = state.common;
const { loading, errors } = state.login;
return {
loading: loading,
errors,
hello,
client: hello.details.client || {}
};
};
export default connect(mapStateToProps)(withStyles(styles)(Consent));
@@ -0,0 +1,181 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import CircularProgress from '@material-ui/core/CircularProgress';
import green from '@material-ui/core/colors/green';
import Typography from '@material-ui/core/Typography';
import Link from '@material-ui/core/Link';
import TextInput from '../../components/TextInput'
import { updateInput, executeLogonIfFormValid, advanceLogonFlow } from '../../actions/login';
import { ErrorMessage } from '../../errors';
const styles = theme => ({
buttonProgress: {
color: green[500],
position: 'absolute',
top: '50%',
left: '50%',
marginTop: -12,
marginLeft: -12
},
subHeader: {
marginBottom: theme.spacing(3)
},
wrapper: {
position: 'relative',
width: '100%',
textAlign: 'center'
},
message: {
marginTop: 5,
marginBottom: 5
}
});
class Login extends React.PureComponent {
state = {};
componentDidMount() {
const { hello, query, dispatch, history } = this.props;
if (hello && hello.state && history.action !== 'PUSH') {
if (!query.prompt || query.prompt.indexOf('select_account') == -1) {
dispatch(advanceLogonFlow(true, history));
return;
}
history.replace(`/chooseaccount${history.location.search}${history.location.hash}`);
return;
}
}
render() {
const { loading, errors, classes, username, passwordResetLink } = this.props;
const loginFailed = errors.http;
const hasError = errors.http || errors.username || errors.password;
const errorMessage = errors.http
? <ErrorMessage error={errors.http}></ErrorMessage>
: (errors.username
? <ErrorMessage error={errors.username}></ErrorMessage>
: <ErrorMessage error={errors.password}></ErrorMessage>);
const extraPropsUsername = {
"aria-invalid" : (errors.username || errors.http) ? 'true' : 'false'
};
const extraPropsPassword = {
"aria-invalid" : (errors.password || errors.http) ? 'true' : 'false',
};
if(errors.username || errors.http){
extraPropsUsername['extraClassName'] = 'error';
extraPropsUsername['aria-describedby'] = 'oc-login-error-message';
}
if(errors.password || errors.http){
extraPropsPassword['extraClassName'] = 'error';
extraPropsPassword['aria-describedby'] = 'oc-login-error-message';
}
return (
<div>
{/* eslint-disable-next-line react-intl-format/missing-formatted-message */}
<h1 className="oc-invisible-sr"> Login </h1>
<form action="" className="oc-login-form" onSubmit={(event) => this.logon(event)}>
<TextInput
autoFocus
autoCapitalize="off"
spellCheck="false"
value={username}
onChange={this.handleChange('username')}
autoComplete="kopano-account username"
placeholder={({id: "konnect.login.usernameField.label", defaultMessage: "Username"})}
label={({id: "konnect.login.usernameField.label", defaultMessage: "Username"})}
id="oc-login-username"
{...extraPropsUsername}
/>
<TextInput
type="password"
margin="normal"
onChange={this.handleChange('password')}
autoComplete="kopano-account current-password"
placeholder={({id: "konnect.login.usernameField.label", defaultMessage: "Password"})}
label={({id: "konnect.login.usernameField.label", defaultMessage: "Password"})}
id="oc-login-password"
{...extraPropsPassword}
/>
{hasError && <Typography id="oc-login-error-message" variant="subtitle2" component="span" color="error"
className={classes.message}>{errorMessage}</Typography>}
<div className={classes.wrapper}>
{loginFailed && passwordResetLink && <Link id="oc-login-password-reset" href={passwordResetLink} variant="subtitle2">{"Reset password?"}</Link>}
<br />
<Button
type="submit"
color="primary"
variant="contained"
className="oc-button-primary oc-mt-l"
disabled={!!loading}
onClick={(event) => this.logon(event)}
>
<FormattedMessage id="konnect.login.nextButton.label" defaultMessage="Log in"></FormattedMessage>
</Button>
{loading && <CircularProgress size={24} className={classes.buttonProgress}/>}
</div>
</form>
</div>
);
}
handleChange(name) {
return event => {
this.props.dispatch(updateInput(name, event.target.value));
};
}
logon(event) {
event.preventDefault();
const { username, password, dispatch, history } = this.props;
dispatch(executeLogonIfFormValid(username, password, false)).then((response) => {
if (response.success) {
dispatch(advanceLogonFlow(response.success, history));
}
});
}
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
loading: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
password: PropTypes.string.isRequired,
passwordResetLink: PropTypes.string.isRequired,
errors: PropTypes.object.isRequired,
hello: PropTypes.object,
query: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
history: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { loading, username, password, errors} = state.login;
const { hello, query, passwordResetLink } = state.common;
return {
loading,
username,
password,
errors,
hello,
query,
passwordResetLink
};
};
export default connect(mapStateToProps)(withStyles(styles)(Login));
@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import { withStyles } from '@material-ui/core/styles';
import ResponsiveScreen from '../../components/ResponsiveScreen';
import RedirectWithQuery from '../../components/RedirectWithQuery';
import { executeHello } from '../../actions/common';
import Login from './Login';
import Chooseaccount from './Chooseaccount';
import Consent from './Consent';
const styles = () => ({
});
class Loginscreen extends React.PureComponent {
componentDidMount() {
this.props.dispatch(executeHello());
}
render() {
const { hello } = this.props;
const loading = hello === null;
return (
<ResponsiveScreen loading={loading} withoutPadding={true} >
<Switch>
<Route path="/identifier" exact component={Login}></Route>
<Route path="/chooseaccount" exact component={Chooseaccount}></Route>
<Route path="/consent" exact component={Consent}></Route>
<RedirectWithQuery target="/identifier"/>
</Switch>
</ResponsiveScreen>
);
}
}
Loginscreen.propTypes = {
classes: PropTypes.object.isRequired,
hello: PropTypes.object,
dispatch: PropTypes.func.isRequired
};
const mapStateToProps = (state) => {
const { hello } = state.common;
return {
hello
};
};
export default connect(mapStateToProps)(withStyles(styles)(Loginscreen));
@@ -0,0 +1 @@
export { default } from './Loginscreen';
@@ -0,0 +1,92 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import DialogActions from '@material-ui/core/DialogActions';
import ResponsiveScreen from '../../components/ResponsiveScreen';
import { executeLogoff } from '../../actions/common';
const styles = theme => ({
button: {
margin: theme.spacing(1),
minWidth: 100
},
subHeader: {
marginBottom: theme.spacing(5)
}
});
class Welcomescreen extends React.PureComponent {
render() {
const { classes, hello } = this.props;
const loading = hello === null;
return (
<ResponsiveScreen loading={loading}>
<Typography variant="h5" component="h3" className="oc-light">
<FormattedMessage
id="konnect.welcome.headline"
defaultMessage="Welcome {displayName}"
values={{displayName: hello.displayName}}>
</FormattedMessage>
</Typography>
<Typography variant="subtitle1" className={classes.subHeader + " oc-light"}>
{hello.username}
</Typography>
<Typography gutterBottom className="oc-light">
<FormattedMessage id="konnect.welcome.message"
defaultMessage="You are signed in - awesome!"></FormattedMessage>
</Typography>
<DialogActions>
<Button
color="secondary"
className={classes.button}
variant="contained"
onClick={(event) => this.logoff(event)}
>
<FormattedMessage id="konnect.welcome.signoutButton.label" defaultMessage="Sign out"></FormattedMessage>
</Button>
</DialogActions>
</ResponsiveScreen>
);
}
logoff(event) {
event.preventDefault();
this.props.dispatch(executeLogoff()).then((response) => {
const { history } = this.props;
if (response.success) {
history.push('/identifier');
}
});
}
}
Welcomescreen.propTypes = {
classes: PropTypes.object.isRequired,
hello: PropTypes.object,
dispatch: PropTypes.func.isRequired,
history: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { hello } = state.common;
return {
hello
};
};
export default connect(mapStateToProps)(withStyles(styles)(Welcomescreen));
@@ -0,0 +1 @@
export { default } from './Welcomescreen';
+68
View File
@@ -0,0 +1,68 @@
import { injectIntl, defineMessages } from 'react-intl';
export const ERROR_LOGIN_VALIDATE_MISSINGUSERNAME = 'konnect.error.login.validate.missingUsername';
export const ERROR_LOGIN_VALIDATE_MISSINGPASSWORD = 'konnect.error.login.validate.missingPassword';
export const ERROR_LOGIN_FAILED = 'konnect.error.login.failed';
export const ERROR_HTTP_NETWORK_ERROR = 'konnect.error.http.networkError';
export const ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS = 'konnect.error.http.unexpectedResponseStatus';
export const ERROR_HTTP_UNEXPECTED_RESPONSE_STATE = 'konnect.error.http.unexpectedResponseState';
// Translatable error messages.
const translations = defineMessages({
[ERROR_LOGIN_VALIDATE_MISSINGUSERNAME]: {
id: ERROR_LOGIN_VALIDATE_MISSINGUSERNAME,
defaultMessage: 'Please enter a valid username'
},
[ERROR_LOGIN_VALIDATE_MISSINGPASSWORD]: {
id: ERROR_LOGIN_VALIDATE_MISSINGPASSWORD,
defaultMessage: 'Please enter a valid password'
},
[ERROR_LOGIN_FAILED]: {
id: ERROR_LOGIN_FAILED,
defaultMessage: 'Logon failed. Please verify your credentials and try again.'
},
[ERROR_HTTP_NETWORK_ERROR]: {
id: ERROR_HTTP_NETWORK_ERROR,
defaultMessage: 'Network error. Please check your connection and try again.'
},
[ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS]: {
id: ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS,
defaultMessage: 'Unexpected HTTP response: {status}. Please check your connection and try again.'
},
[ERROR_HTTP_UNEXPECTED_RESPONSE_STATE]: {
id: ERROR_HTTP_UNEXPECTED_RESPONSE_STATE,
defaultMessage: 'Unexpected response state: {state}'
}
});
// Error with values.
export class ExtendedError extends Error {
values = undefined;
constructor(message, values) {
super(message);
if (Error.captureStackTrace !== undefined) {
Error.captureStackTrace(this, ExtendedError);
}
this.values = values;
}
}
// Component to translate error text with values.
function ErrorMessageComponent(props) {
const { error, intl } = props;
if (!error) {
return null;
}
const id = error.id ? error.id : error.message;
const messageDescriptor = Object.assign({}, {
id,
defaultMessage: error.id ? error.message : undefined
}, translations[id]);
return intl.formatMessage(messageDescriptor, error.values);
}
export const ErrorMessage = injectIntl(ErrorMessageComponent);
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

+13
View File
@@ -0,0 +1,13 @@
import 'kpop/static/css/base.css';
import 'kpop/static/css/scrollbar.css';
import './app.css';
import * as kpop from 'kpop/es/version';
import * as version from './version';
console.info(`Kopano Identifier build version: ${version.build}`); // eslint-disable-line no-console
console.info(`Kopano Kpop build version: ${kpop.build}`); // eslint-disable-line no-console
// NOTE(longsleep): Load async, this enables code splitting via Webpack.
import(/* webpackChunkName: "identifier-app" */ './app');
+39
View File
@@ -0,0 +1,39 @@
{
"konnect.loading.error.headline": "Verbindung zum Server fehlgeschlagen",
"konnect.login.retryButton.label": "Wiederholen",
"konnect.scopeDescription.aliasBasic": "Zugriff auf Ihre grundlegenden Benutzerinformationen",
"konnect.scopeDescription.offlineAccess": "Dauerhaften Zugriff (läuft nicht ab)",
"konnect.scopeDescription.scope": "Geltungsbereich: {scope}",
"konnect.goodbye.headline": "Bis bald",
"konnect.goodbye.subHeader": "sie sind jetzt von Ihrem Kopano Konto abgemeldet",
"konnect.goodbye.message.close": "Sie können dieses Fenster jetzt schließen.",
"konnect.goodbye.confirm.headline": "Hallo {displayName}",
"konnect.goodbye.confirm.subHeader": "Bitte bestätigen Sie, dass Sie sich abmelden möchten",
"konnect.goodbye.message.confirm": "Klicken Sie auf die Schaltfläche unten um sich aus Ihrem Kopano Konto abzumelden.",
"konnect.goodbye.signoutButton.label": "Abmelden",
"konnect.welcome.signoutButton.label": "Abmelden",
"konnect.chooseaccount.headline": "Konto auswählen",
"konnect.chooseaccount.subHeader": "um sich bei Kopano anzumelden",
"konnect.chooseaccount.useOther.persona.label": "?",
"konnect.chooseaccount.useOther.label": "Anderes Konto",
"konnect.consent.headline": "Hi {displayName}",
"konnect.consent.message": "{clientDisplayName} möchte",
"konnect.consent.tooltip.client": "Wenn Sie \"Einverstanden\" klicken werden Sie zu {redirectURI} weitergeleitet",
"konnect.consent.question": "{clientDisplayName} den Zugriff gestatten?",
"konnect.consent.consequence": "Wenn Sie Einverstanden klicken, erhält die App Zugriff auf Ihre Informationen.",
"konnect.consent.cancelButton.label": "Abbrechen",
"konnect.consent.allowButton.label": "Einverstanden",
"konnect.login.headline": "Anmelden",
"konnect.login.subHeader": "mit Ihrem Kopano Konto",
"konnect.login.usernameField.label": "Benutzername",
"konnect.login.passwordField.label": "Passwort",
"konnect.login.nextButton.label": "Weiter",
"konnect.welcome.headline": "Willkommen {displayName}",
"konnect.welcome.message": "Sie sind angemeldet - super!",
"konnect.error.login.validate.missingUsername": "Geben Sie einen Benutzername ein",
"konnect.error.login.validate.missingPassword": "Geben Sie ein Passwort ein",
"konnect.error.login.failed": "Anmeldung fehlgeschlagen. Bitte überprüfen Sie Ihre Eingabe und versuchen Sie es noch einmal.",
"konnet.error.http.networkError": "Netzwerkfehler. Bitte prüfen Sie Ihre Verbindung und versuchen Sie es noch einmal.",
"konnect.error.http.unexpectedResponseStatus": "Unerwartete HTTP-Antwort: {status}. Bitte prüfen Sie Ihre Verbindung und versuchen Sie es noch einmal.",
"konnect.error.http.unexpectedResponseState": "Unerwarteter Antwort-Status: {state}"
}
+39
View File
@@ -0,0 +1,39 @@
{
"konnect.loading.error.headline": "",
"konnect.login.retryButton.label": "",
"konnect.scopeDescription.aliasBasic": "",
"konnect.scopeDescription.offlineAccess": "",
"konnect.scopeDescription.scope": "",
"konnect.goodbye.headline": "",
"konnect.goodbye.subHeader": "",
"konnect.goodbye.message.close": "",
"konnect.goodbye.confirm.headline": "",
"konnect.goodbye.confirm.subHeader": "",
"konnect.goodbye.message.confirm": "",
"konnect.goodbye.signoutButton.label": "",
"konnect.welcome.signoutButton.label": "",
"konnect.chooseaccount.headline": "",
"konnect.chooseaccount.subHeader": "",
"konnect.chooseaccount.useOther.persona.label": "",
"konnect.chooseaccount.useOther.label": "",
"konnect.consent.headline": "",
"konnect.consent.message": "",
"konnect.consent.tooltip.client": "",
"konnect.consent.question": "",
"konnect.consent.consequence": "",
"konnect.consent.cancelButton.label": "",
"konnect.consent.allowButton.label": "",
"konnect.login.headline": "",
"konnect.login.subHeader": "",
"konnect.login.usernameField.label": "",
"konnect.login.passwordField.label": "",
"konnect.login.nextButton.label": "",
"konnect.welcome.headline": "",
"konnect.welcome.message": "",
"konnect.error.login.validate.missingUsername": "",
"konnect.error.login.validate.missingPassword": "",
"konnect.error.login.failed": "",
"konnet.error.http.networkError": "",
"konnect.error.http.unexpectedResponseStatus": "",
"konnect.error.http.unexpectedResponseState": ""
}
+39
View File
@@ -0,0 +1,39 @@
{
"konnect.loading.error.headline": "La connexion au serveur a échoué",
"konnect.login.retryButton.label": "Réessayer",
"konnect.scopeDescription.aliasBasic": "Consulter les informations de base de votre compte",
"konnect.scopeDescription.offlineAccess": "Conserver les autorisations d'accès à l'avenir",
"konnect.scopeDescription.scope": "Portée : {scope}",
"konnect.goodbye.headline": "Au revoir",
"konnect.goodbye.subHeader": "vous avez été déconnecté de Kopano",
"konnect.goodbye.message.close": "Vous pouvez fermer cette fenêtre à présent.",
"konnect.goodbye.confirm.headline": "Bonjour {displayName}",
"konnect.goodbye.confirm.subHeader": "Confirmer votre déconnexion",
"konnect.goodbye.message.confirm": "Cliquer le bouton ci-dessous, pour quitter Kopano.",
"konnect.goodbye.signoutButton.label": "Quitter",
"konnect.welcome.signoutButton.label": "Quitter",
"konnect.chooseaccount.headline": "Choisir un compte",
"konnect.chooseaccount.subHeader": "pour vous authentifier dans Kopano",
"konnect.chooseaccount.useOther.persona.label": "?",
"konnect.chooseaccount.useOther.label": "Utiliser un autre compte",
"konnect.consent.headline": "Bonjour {displayName}",
"konnect.consent.message": "{clientDisplayName} souhaite",
"konnect.consent.tooltip.client": "En cliquant \"Autoriser\" vous serez redirigé vers : {redirectURI}",
"konnect.consent.question": "Autoriser {clientDisplayName} à faire cela ?",
"konnect.consent.consequence": "En cliquant, vous autoriser l'app à accéder à vos informations.",
"konnect.consent.cancelButton.label": "Annuler",
"konnect.consent.allowButton.label": "Autoriser",
"konnect.login.headline": "Identification",
"konnect.login.subHeader": "avec vos identifiants Kopano",
"konnect.login.usernameField.label": "Utilisateur",
"konnect.login.passwordField.label": "Mot de passe",
"konnect.login.nextButton.label": "Suivant",
"konnect.welcome.headline": "Bienvenue {displayName}",
"konnect.welcome.message": "Magnifique - Vous êtes connecté !",
"konnect.error.login.validate.missingUsername": "Saisir un identifiant",
"konnect.error.login.validate.missingPassword": "Saisir un mot de passe",
"konnect.error.login.failed": "Echec de connexion. Vérifier vos identifiants et essayer à nouveau.",
"konnet.error.http.networkError": "Erreur réseau. Vérifier votre connexion, et réessayer.",
"konnect.error.http.unexpectedResponseStatus": "Erreur HTTP inattendue : {status}. Vérifier votre connexion et réessayer.",
"konnect.error.http.unexpectedResponseState": "Erreur d'état inattendue : {state}"
}
+39
View File
@@ -0,0 +1,39 @@
{
"konnect.loading.error.headline": "सर्वर से कनेक्ट करने में विफल",
"konnect.login.retryButton.label": "पुन: प्रयास करें",
"konnect.scopeDescription.aliasBasic": "अपनी मूल खाता जानकारी देखे",
"konnect.scopeDescription.offlineAccess": "अनुमत पहुंच को लगातार और हमेशा बनाए रखें",
"konnect.scopeDescription.scope": "क्षेत्र: {scope}",
"konnect.goodbye.headline": "अलविदा",
"konnect.goodbye.subHeader": "आपको अपने Kopano खाते से साइन आउट कर दिया गया है",
"konnect.goodbye.message.close": "अब आप इस विंडो को बंद कर सकते हैं.",
"konnect.goodbye.confirm.headline": "नमस्ते {displayName}",
"konnect.goodbye.confirm.subHeader": "कृपया साइन आउट की पुष्टि करें",
"konnect.goodbye.message.confirm": "अपने Kopano खाते से साइन आउट करने के लिए नीचे दिए गए बटन को दबाएं.",
"konnect.goodbye.signoutButton.label": "साइन आउट",
"konnect.welcome.signoutButton.label": "साइन आउट",
"konnect.chooseaccount.headline": "खाता चुनें",
"konnect.chooseaccount.subHeader": "Kopano में साइन इन करने के लिए",
"konnect.chooseaccount.useOther.persona.label": "?",
"konnect.chooseaccount.useOther.label": "दूसरे खाते का उपयोग करें",
"konnect.consent.headline": "नमस्ते {displayName}",
"konnect.consent.message": "{clientDisplayName} चाहते है की",
"konnect.consent.tooltip.client": "\"अनुमति\" पर क्लिक करने से आपको {redirecturI} पे पुनर्निर्देशित किया जायेगा",
"konnect.consent.question": "क्या {clientDisplayName} को ये करने की अनुमति देना चाहते है?",
"konnect.consent.consequence": "अनुमति पर क्लिक करके, आप इस एप्लिकेशन को आपकी जानकारी का उपयोग करने की अनुमति देते हैं.",
"konnect.consent.cancelButton.label": "रद्द करें",
"konnect.consent.allowButton.label": "अनुमति दीजिये",
"konnect.login.headline": "साइन इन",
"konnect.login.subHeader": "अपने Kopano खाते के साथ",
"konnect.login.usernameField.label": "उपयोगकर्ता नाम",
"konnect.login.passwordField.label": "पासवर्ड",
"konnect.login.nextButton.label": "अगला",
"konnect.welcome.headline": "स्वागत हे {displayName}",
"konnect.welcome.message": "आप साइंड इन हैं - अद्भुत!",
"konnect.error.login.validate.missingUsername": "उपयोगकर्ता नाम डालिये",
"konnect.error.login.validate.missingPassword": "पासवर्ड डालिए",
"konnect.error.login.failed": "लोगऑन नाकाम रहा. कृपया अपने क्रेडेंशियल्स जांचे और पुनः प्रयास करें.",
"konnet.error.http.networkError": "नेटवर्क त्रुटि। कृपया अपने संपर्क की जांच करे और फिर से प्रयास करें.",
"konnect.error.http.unexpectedResponseStatus": "अनपेक्षित HTTP प्रतिक्रिया: {status}. कृपया अपने संपर्क की जांच करे और फिर से प्रयास करें.",
"konnect.error.http.unexpectedResponseState": "अनपेक्षित प्रतिक्रिया अवस्था: {state}"
}
+39
View File
@@ -0,0 +1,39 @@
{
"konnect.loading.error.headline": "",
"konnect.login.retryButton.label": "",
"konnect.scopeDescription.aliasBasic": "",
"konnect.scopeDescription.offlineAccess": "",
"konnect.scopeDescription.scope": "",
"konnect.goodbye.headline": "",
"konnect.goodbye.subHeader": "",
"konnect.goodbye.message.close": "",
"konnect.goodbye.confirm.headline": "",
"konnect.goodbye.confirm.subHeader": "",
"konnect.goodbye.message.confirm": "",
"konnect.goodbye.signoutButton.label": "",
"konnect.welcome.signoutButton.label": "",
"konnect.chooseaccount.headline": "",
"konnect.chooseaccount.subHeader": "",
"konnect.chooseaccount.useOther.persona.label": "",
"konnect.chooseaccount.useOther.label": "",
"konnect.consent.headline": "",
"konnect.consent.message": "",
"konnect.consent.tooltip.client": "",
"konnect.consent.question": "",
"konnect.consent.consequence": "",
"konnect.consent.cancelButton.label": "",
"konnect.consent.allowButton.label": "",
"konnect.login.headline": "",
"konnect.login.subHeader": "",
"konnect.login.usernameField.label": "",
"konnect.login.passwordField.label": "",
"konnect.login.nextButton.label": "",
"konnect.welcome.headline": "",
"konnect.welcome.message": "",
"konnect.error.login.validate.missingUsername": "",
"konnect.error.login.validate.missingPassword": "",
"konnect.error.login.failed": "",
"konnet.error.http.networkError": "",
"konnect.error.http.unexpectedResponseStatus": "",
"konnect.error.http.unexpectedResponseState": ""
}
+39
View File
@@ -0,0 +1,39 @@
{
"konnect.loading.error.headline": "",
"konnect.login.retryButton.label": "",
"konnect.scopeDescription.aliasBasic": "",
"konnect.scopeDescription.offlineAccess": "",
"konnect.scopeDescription.scope": "",
"konnect.goodbye.headline": "",
"konnect.goodbye.subHeader": "",
"konnect.goodbye.message.close": "",
"konnect.goodbye.confirm.headline": "",
"konnect.goodbye.confirm.subHeader": "",
"konnect.goodbye.message.confirm": "",
"konnect.goodbye.signoutButton.label": "",
"konnect.welcome.signoutButton.label": "",
"konnect.chooseaccount.headline": "",
"konnect.chooseaccount.subHeader": "",
"konnect.chooseaccount.useOther.persona.label": "",
"konnect.chooseaccount.useOther.label": "",
"konnect.consent.headline": "",
"konnect.consent.message": "",
"konnect.consent.tooltip.client": "",
"konnect.consent.question": "",
"konnect.consent.consequence": "",
"konnect.consent.cancelButton.label": "",
"konnect.consent.allowButton.label": "",
"konnect.login.headline": "",
"konnect.login.subHeader": "",
"konnect.login.usernameField.label": "",
"konnect.login.passwordField.label": "",
"konnect.login.nextButton.label": "",
"konnect.welcome.headline": "",
"konnect.welcome.message": "",
"konnect.error.login.validate.missingUsername": "",
"konnect.error.login.validate.missingPassword": "",
"konnect.error.login.failed": "",
"konnet.error.http.networkError": "",
"konnect.error.http.unexpectedResponseStatus": "",
"konnect.error.http.unexpectedResponseState": ""
}

Some files were not shown because too many files have changed in this diff Show More