Merge remote-tracking branch 'upstream/develop' into feature/theming2

* upstream/develop: (60 commits)
  whoops
  whoops
  DM timeline: stream new statuses
  update-japanese-translation
  Add actual user search.
  incorporate most translation changes from MR 368
  update french translation
  Always show dm panel.
  Add direct message tab.
  api service url
  remove deploy stage
  remove deploy stage
  updated and completed German translation
  On logout switch to public timeline.
  minor modification of Chinese translation
  update Chinese translation
  Add Chinese language
  Fix posting.
  Put oauth text into description.
  Display OAuth login on login form button.
  ...
This commit is contained in:
Henry Jameson 2018-11-26 05:21:58 +03:00
commit a806d43f05
56 changed files with 2963 additions and 383 deletions

View file

@ -3,32 +3,10 @@
# https://hub.docker.com/r/library/node/tags/ # https://hub.docker.com/r/library/node/tags/
image: node:7 image: node:7
before_script:
# Install ssh-agent if not already installed, it is required by Docker.
# (change apt-get to yum if you use a CentOS-based image)
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
# Run ssh-agent (inside the build environment)
- eval $(ssh-agent -s)
# For Docker builds disable host key checking. Be aware that by adding that
# you are suspectible to man-in-the-middle attacks.
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
# This folder is cached between builds
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
#cache:
# paths:
# - node_modules/
stages: stages:
- lint - lint
- build - build
- test - test
- deploy
lint: lint:
stage: lint stage: lint
@ -50,14 +28,3 @@ build:
artifacts: artifacts:
paths: paths:
- dist/ - dist/
deploy:
stage: deploy
environment: dev
only:
- develop
script:
- yarn
- npm run build
- ssh-add <(echo "$SSH_PRIVATE_KEY")
- scp -r dist/* pleroma@tenshi.heldscal.la:~/pleroma

View file

@ -32,3 +32,9 @@ npm run unit
# Configuration # Configuration
Edit config.json for configuration. scopeOptionsEnabled gives you input fields for CWs and the scope settings. Edit config.json for configuration. scopeOptionsEnabled gives you input fields for CWs and the scope settings.
## Options
### Login methods
```loginMethod``` can be set to either ```password``` (the default) or ```token```, which will use the full oauth redirection flow, which is useful for SSO situations.

View file

@ -78,6 +78,7 @@ export default {
window.scrollTo(0, 0) window.scrollTo(0, 0)
}, },
logout () { logout () {
this.$router.replace('/main/public')
this.$store.dispatch('logout') this.$store.dispatch('logout')
} }
} }

184
src/boot/after_store.js Normal file
View file

@ -0,0 +1,184 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from '../App.vue'
import PublicTimeline from '../components/public_timeline/public_timeline.vue'
import PublicAndExternalTimeline from '../components/public_and_external_timeline/public_and_external_timeline.vue'
import FriendsTimeline from '../components/friends_timeline/friends_timeline.vue'
import TagTimeline from '../components/tag_timeline/tag_timeline.vue'
import ConversationPage from '../components/conversation-page/conversation-page.vue'
import Mentions from '../components/mentions/mentions.vue'
import DMs from '../components/dm_timeline/dm_timeline.vue'
import UserProfile from '../components/user_profile/user_profile.vue'
import Settings from '../components/settings/settings.vue'
import Registration from '../components/registration/registration.vue'
import UserSettings from '../components/user_settings/user_settings.vue'
import FollowRequests from '../components/follow_requests/follow_requests.vue'
import OAuthCallback from '../components/oauth_callback/oauth_callback.vue'
import UserSearch from '../components/user_search/user_search.vue'
const afterStoreSetup = ({store, i18n}) => {
window.fetch('/api/statusnet/config.json')
.then((res) => res.json())
.then((data) => {
const {name, closed: registrationClosed, textlimit, server} = data.site
store.dispatch('setInstanceOption', { name: 'name', value: name })
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
store.dispatch('setInstanceOption', { name: 'textlimit', value: parseInt(textlimit) })
store.dispatch('setInstanceOption', { name: 'server', value: server })
var apiConfig = data.site.pleromafe
window.fetch('/static/config.json')
.then((res) => res.json())
.catch((err) => {
console.warn('Failed to load static/config.json, continuing without it.')
console.warn(err)
return {}
})
.then((staticConfig) => {
// This takes static config and overrides properties that are present in apiConfig
var config = Object.assign({}, staticConfig, apiConfig)
var theme = (config.theme)
var background = (config.background)
var hidePostStats = (config.hidePostStats)
var hideUserStats = (config.hideUserStats)
var logo = (config.logo)
var logoMask = (typeof config.logoMask === 'undefined' ? true : config.logoMask)
var logoMargin = (typeof config.logoMargin === 'undefined' ? 0 : config.logoMargin)
var redirectRootNoLogin = (config.redirectRootNoLogin)
var redirectRootLogin = (config.redirectRootLogin)
var chatDisabled = (config.chatDisabled)
var showInstanceSpecificPanel = (config.showInstanceSpecificPanel)
var scopeOptionsEnabled = (config.scopeOptionsEnabled)
var formattingOptionsEnabled = (config.formattingOptionsEnabled)
var collapseMessageWithSubject = (config.collapseMessageWithSubject)
var loginMethod = (config.loginMethod)
var scopeCopy = (config.scopeCopy)
var subjectLineBehavior = (config.subjectLineBehavior)
store.dispatch('setInstanceOption', { name: 'theme', value: theme })
store.dispatch('setInstanceOption', { name: 'background', value: background })
store.dispatch('setInstanceOption', { name: 'hidePostStats', value: hidePostStats })
store.dispatch('setInstanceOption', { name: 'hideUserStats', value: hideUserStats })
store.dispatch('setInstanceOption', { name: 'logo', value: logo })
store.dispatch('setInstanceOption', { name: 'logoMask', value: logoMask })
store.dispatch('setInstanceOption', { name: 'logoMargin', value: logoMargin })
store.dispatch('setInstanceOption', { name: 'redirectRootNoLogin', value: redirectRootNoLogin })
store.dispatch('setInstanceOption', { name: 'redirectRootLogin', value: redirectRootLogin })
store.dispatch('setInstanceOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
store.dispatch('setInstanceOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
store.dispatch('setInstanceOption', { name: 'formattingOptionsEnabled', value: formattingOptionsEnabled })
store.dispatch('setInstanceOption', { name: 'collapseMessageWithSubject', value: collapseMessageWithSubject })
store.dispatch('setInstanceOption', { name: 'loginMethod', value: loginMethod })
store.dispatch('setInstanceOption', { name: 'scopeCopy', value: scopeCopy })
store.dispatch('setInstanceOption', { name: 'subjectLineBehavior', value: subjectLineBehavior })
if (chatDisabled) {
store.dispatch('disableChat')
}
const routes = [
{ name: 'root',
path: '/',
redirect: to => {
return (store.state.users.currentUser
? store.state.instance.redirectRootLogin
: store.state.instance.redirectRootNoLogin) || '/main/all'
}},
{ path: '/main/all', component: PublicAndExternalTimeline },
{ path: '/main/public', component: PublicTimeline },
{ path: '/main/friends', component: FriendsTimeline },
{ path: '/tag/:tag', component: TagTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'dms', path: '/:username/dms', component: DMs },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
{ name: 'registration', path: '/registration/:token', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
{ name: 'user-settings', path: '/user-settings', component: UserSettings },
{ name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },
{ name: 'user-search', path: '/user-search', component: UserSearch, props: (route) => ({ query: route.query.query }) }
]
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior: (to, from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) {
return false
}
return savedPosition || { x: 0, y: 0 }
}
})
/* eslint-disable no-new */
new Vue({
router,
store,
i18n,
el: '#app',
render: h => h(App)
})
})
})
window.fetch('/static/terms-of-service.html')
.then((res) => res.text())
.then((html) => {
store.dispatch('setInstanceOption', { name: 'tos', value: html })
})
window.fetch('/api/pleroma/emoji.json')
.then(
(res) => res.json()
.then(
(values) => {
const emoji = Object.keys(values).map((key) => {
return { shortcode: key, image_url: values[key] }
})
store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji })
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: true })
},
(failure) => {
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: false })
}
),
(error) => console.log(error)
)
window.fetch('/static/emoji.json')
.then((res) => res.json())
.then((values) => {
const emoji = Object.keys(values).map((key) => {
return { shortcode: key, image_url: false, 'utf': values[key] }
})
store.dispatch('setInstanceOption', { name: 'emoji', value: emoji })
})
window.fetch('/instance/panel.html')
.then((res) => res.text())
.then((html) => {
store.dispatch('setInstanceOption', { name: 'instanceSpecificPanelContent', value: html })
})
window.fetch('/nodeinfo/2.0.json')
.then((res) => res.json())
.then((data) => {
const metadata = data.metadata
const features = metadata.features
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') })
store.dispatch('setInstanceOption', { name: 'chatAvailable', value: features.includes('chat') })
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
const suggestions = metadata.suggestions
store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web })
})
}
export default afterStoreSetup

View file

@ -0,0 +1,14 @@
import Timeline from '../timeline/timeline.vue'
const DMs = {
computed: {
timeline () {
return this.$store.state.statuses.timelines.dms
}
},
components: {
Timeline
}
}
export default DMs

View file

@ -0,0 +1,5 @@
<template>
<Timeline :title="$t('nav.dms')" v-bind:timeline="timeline" v-bind:timeline-name="'dms'"/>
</template>
<script src="./dm_timeline.js"></script>

View file

@ -2,6 +2,9 @@ const FavoriteButton = {
props: ['status', 'loggedIn'], props: ['status', 'loggedIn'],
data () { data () {
return { return {
hidePostStatsLocal: typeof this.$store.state.config.hidePostStats === 'undefined'
? this.$store.state.instance.hidePostStats
: this.$store.state.config.hidePostStats,
animated: false animated: false
} }
}, },

View file

@ -1,11 +1,11 @@
<template> <template>
<div v-if="loggedIn"> <div v-if="loggedIn">
<i :class='classes' class='favorite-button fav-active' @click.prevent='favorite()'/> <i :class='classes' class='favorite-button fav-active' @click.prevent='favorite()'/>
<span v-if='status.fave_num > 0'>{{status.fave_num}}</span> <span v-if='!hidePostStatsLocal && status.fave_num > 0'>{{status.fave_num}}</span>
</div> </div>
<div v-else> <div v-else>
<i :class='classes' class='favorite-button'/> <i :class='classes' class='favorite-button'/>
<span v-if='status.fave_num > 0'>{{status.fave_num}}</span> <span v-if='!hidePostStatsLocal && status.fave_num > 0'>{{status.fave_num}}</span>
</div> </div>
</template> </template>

View file

@ -1,22 +1,40 @@
import oauthApi from '../../services/new_api/oauth.js'
const LoginForm = { const LoginForm = {
data: () => ({ data: () => ({
user: {}, user: {},
authError: false authError: false
}), }),
computed: { computed: {
loginMethod () { return this.$store.state.instance.loginMethod },
loggingIn () { return this.$store.state.users.loggingIn }, loggingIn () { return this.$store.state.users.loggingIn },
registrationOpen () { return this.$store.state.instance.registrationOpen } registrationOpen () { return this.$store.state.instance.registrationOpen }
}, },
methods: { methods: {
oAuthLogin () {
oauthApi.login({
oauth: this.$store.state.oauth,
instance: this.$store.state.instance.server,
commit: this.$store.commit
})
},
submit () { submit () {
this.$store.dispatch('loginUser', this.user).then( const data = {
() => {}, oauth: this.$store.state.oauth,
(error) => { instance: this.$store.state.instance.server
this.authError = error }
this.user.username = '' oauthApi.getOrCreateApp(data).then((app) => {
this.user.password = '' oauthApi.getTokenWithCredentials(
} {
) app,
instance: data.instance,
username: this.user.username,
password: this.user.password})
.then((result) => {
this.$store.commit('setToken', result.access_token)
this.$store.dispatch('loginUser', result.access_token)
this.$router.push('/main/friends')
})
})
} }
} }
} }

View file

@ -5,7 +5,7 @@
{{$t('login.login')}} {{$t('login.login')}}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form v-on:submit.prevent='submit(user)' class='login-form'> <form v-if="loginMethod == 'password'" v-on:submit.prevent='submit(user)' class='login-form'>
<div class='form-group'> <div class='form-group'>
<label for='username'>{{$t('login.username')}}</label> <label for='username'>{{$t('login.username')}}</label>
<input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' v-bind:placeholder="$t('login.placeholder')"> <input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' v-bind:placeholder="$t('login.placeholder')">
@ -20,8 +20,17 @@
<button :disabled="loggingIn" type='submit' class='btn btn-default'>{{$t('login.login')}}</button> <button :disabled="loggingIn" type='submit' class='btn btn-default'>{{$t('login.login')}}</button>
</div> </div>
</div> </div>
<div v-if="authError" class='form-group'> </form>
<div class='alert error'>{{authError}}</div>
<form v-if="loginMethod == 'token'" v-on:submit.prevent='oAuthLogin' class="login-form">
<div class="form-group">
<p>{{$t('login.description')}}</p>
</div>
<div class='form-group'>
<div class='login-bottom'>
<div><router-link :to="{name: 'registration'}" v-if='registrationOpen' class='register'>{{$t('login.register')}}</router-link></div>
<button :disabled="loggingIn" type='submit' class='btn btn-default'>{{$t('login.login')}}</button>
</div>
</div> </div>
</form> </form>
</div> </div>

View file

@ -12,6 +12,11 @@
{{ $t("nav.mentions") }} {{ $t("nav.mentions") }}
</router-link> </router-link>
</li> </li>
<li v-if='currentUser'>
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
{{ $t("nav.dms") }}
</router-link>
</li>
<li v-if='currentUser && currentUser.locked'> <li v-if='currentUser && currentUser.locked'>
<router-link to='/friend-requests'> <router-link to='/friend-requests'>
{{ $t("nav.friend_requests") }} {{ $t("nav.friend_requests") }}

View file

@ -0,0 +1,20 @@
import oauth from '../../services/new_api/oauth.js'
const oac = {
props: ['code'],
mounted () {
if (this.code) {
oauth.getToken({
app: this.$store.state.oauth,
instance: this.$store.state.instance.server,
code: this.code
}).then((result) => {
this.$store.commit('setToken', result.access_token)
this.$store.dispatch('loginUser', result.access_token)
this.$router.push('/main/friends')
})
}
}
}
export default oac

View file

@ -0,0 +1,5 @@
<template>
<h1>...</h1>
</template>
<script src="./oauth_callback.js"></script>

View file

@ -24,7 +24,7 @@ const PostStatusForm = {
'replyTo', 'replyTo',
'repliedUser', 'repliedUser',
'attentions', 'attentions',
'messageScope', 'copyMessageScope',
'subject' 'subject'
], ],
components: { components: {
@ -46,6 +46,10 @@ const PostStatusForm = {
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser) statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
} }
const scope = (this.copyMessageScope && this.$store.state.config.copyScope || this.copyMessageScope === 'direct')
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
return { return {
dropFiles: [], dropFiles: [],
submitDisabled: false, submitDisabled: false,
@ -53,12 +57,12 @@ const PostStatusForm = {
posting: false, posting: false,
highlighted: 0, highlighted: 0,
newStatus: { newStatus: {
spoilerText: this.subject, spoilerText: this.subject || '',
status: statusText, status: statusText,
contentType: 'text/plain', contentType: 'text/plain',
nsfw: false, nsfw: false,
files: [], files: [],
visibility: this.messageScope || this.$store.state.users.currentUser.default_scope visibility: scope
}, },
caret: 0 caret: 0
} }
@ -128,6 +132,9 @@ const PostStatusForm = {
statusLength () { statusLength () {
return this.newStatus.status.length return this.newStatus.status.length
}, },
spoilerTextLength () {
return this.newStatus.spoilerText.length
},
statusLengthLimit () { statusLengthLimit () {
return this.$store.state.instance.textlimit return this.$store.state.instance.textlimit
}, },
@ -135,10 +142,10 @@ const PostStatusForm = {
return this.statusLengthLimit > 0 return this.statusLengthLimit > 0
}, },
charactersLeft () { charactersLeft () {
return this.statusLengthLimit - this.statusLength return this.statusLengthLimit - (this.statusLength + this.spoilerTextLength)
}, },
isOverLengthLimit () { isOverLengthLimit () {
return this.hasStatusLengthLimit && (this.statusLength > this.statusLengthLimit) return this.hasStatusLengthLimit && (this.charactersLeft < 0)
}, },
scopeOptionsEnabled () { scopeOptionsEnabled () {
return this.$store.state.instance.scopeOptionsEnabled return this.$store.state.instance.scopeOptionsEnabled
@ -223,6 +230,7 @@ const PostStatusForm = {
if (!data.error) { if (!data.error) {
this.newStatus = { this.newStatus = {
status: '', status: '',
spoilerText: '',
files: [], files: [],
visibility: newStatus.visibility, visibility: newStatus.visibility,
contentType: newStatus.contentType contentType: newStatus.contentType

View file

@ -1,3 +1,5 @@
import oauthApi from '../../services/new_api/oauth.js'
const registration = { const registration = {
data: () => ({ data: () => ({
user: {}, user: {},
@ -25,9 +27,23 @@ const registration = {
this.$store.state.api.backendInteractor.register(this.user).then( this.$store.state.api.backendInteractor.register(this.user).then(
(response) => { (response) => {
if (response.ok) { if (response.ok) {
this.$store.dispatch('loginUser', this.user) const data = {
this.$router.push('/main/all') oauth: this.$store.state.oauth,
this.registering = false instance: this.$store.state.instance.server
}
oauthApi.getOrCreateApp(data).then((app) => {
oauthApi.getTokenWithCredentials(
{
app,
instance: data.instance,
username: this.user.username,
password: this.user.password})
.then((result) => {
this.$store.commit('setToken', result.access_token)
this.$store.dispatch('loginUser', result.access_token)
this.$router.push('/main/friends')
})
})
} else { } else {
this.registering = false this.registering = false
response.json().then((data) => { response.json().then((data) => {

View file

@ -2,6 +2,9 @@ const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'], props: ['status', 'loggedIn', 'visibility'],
data () { data () {
return { return {
hidePostStatsLocal: typeof this.$store.state.config.hidePostStats === 'undefined'
? this.$store.state.instance.hidePostStats
: this.$store.state.config.hidePostStats,
animated: false animated: false
} }
}, },

View file

@ -2,7 +2,7 @@
<div v-if="loggedIn"> <div v-if="loggedIn">
<template v-if="visibility !== 'private' && visibility !== 'direct'"> <template v-if="visibility !== 'private' && visibility !== 'direct'">
<i :class='classes' class='icon-retweet rt-active' v-on:click.prevent='retweet()'></i> <i :class='classes' class='icon-retweet rt-active' v-on:click.prevent='retweet()'></i>
<span v-if='status.repeat_num > 0'>{{status.repeat_num}}</span> <span v-if='!hidePostStatsLocal && status.repeat_num > 0'>{{status.repeat_num}}</span>
</template> </template>
<template v-else> <template v-else>
<i :class='classes' class='icon-lock' :title="$t('timeline.no_retweet_hint')"></i> <i :class='classes' class='icon-lock' :title="$t('timeline.no_retweet_hint')"></i>
@ -10,7 +10,7 @@
</div> </div>
<div v-else-if="!loggedIn"> <div v-else-if="!loggedIn">
<i :class='classes' class='icon-retweet'></i> <i :class='classes' class='icon-retweet'></i>
<span v-if='status.repeat_num > 0'>{{status.repeat_num}}</span> <span v-if='!hidePostStatsLocal && status.repeat_num > 0'>{{status.repeat_num}}</span>
</div> </div>
</template> </template>

View file

@ -13,6 +13,14 @@ const settings = {
hideAttachmentsLocal: user.hideAttachments, hideAttachmentsLocal: user.hideAttachments,
hideAttachmentsInConvLocal: user.hideAttachmentsInConv, hideAttachmentsInConvLocal: user.hideAttachmentsInConv,
hideNsfwLocal: user.hideNsfw, hideNsfwLocal: user.hideNsfw,
hidePostStatsLocal: typeof user.hidePostStats === 'undefined'
? instance.hidePostStats
: user.hidePostStats,
hidePostStatsDefault: this.$t('settings.values.' + instance.hidePostStats),
hideUserStatsLocal: typeof user.hideUserStats === 'undefined'
? instance.hideUserStats
: user.hideUserStats,
hideUserStatsDefault: this.$t('settings.values.' + instance.hideUserStats),
notificationVisibilityLocal: user.notificationVisibility, notificationVisibilityLocal: user.notificationVisibility,
replyVisibilityLocal: user.replyVisibility, replyVisibilityLocal: user.replyVisibility,
loopVideoLocal: user.loopVideo, loopVideoLocal: user.loopVideo,
@ -26,6 +34,12 @@ const settings = {
? instance.collapseMessageWithSubject ? instance.collapseMessageWithSubject
: user.collapseMessageWithSubject, : user.collapseMessageWithSubject,
collapseMessageWithSubjectDefault: this.$t('settings.values.' + instance.collapseMessageWithSubject), collapseMessageWithSubjectDefault: this.$t('settings.values.' + instance.collapseMessageWithSubject),
subjectLineBehaviorLocal: typeof user.subjectLineBehavior === 'undefined'
? instance.subjectLineBehavior
: user.subjectLineBehavior,
subjectLineBehaviorDefault: instance.subjectLineBehavior,
scopeCopyLocal: user.scopeCopy,
scopeCopyDefault: this.$t('settings.values.' + instance.scopeCopy),
stopGifs: user.stopGifs, stopGifs: user.stopGifs,
loopSilentAvailable: loopSilentAvailable:
// Firefox // Firefox
@ -56,6 +70,12 @@ const settings = {
hideAttachmentsInConvLocal (value) { hideAttachmentsInConvLocal (value) {
this.$store.dispatch('setOption', { name: 'hideAttachmentsInConv', value }) this.$store.dispatch('setOption', { name: 'hideAttachmentsInConv', value })
}, },
hidePostStatsLocal (value) {
this.$store.dispatch('setOption', { name: 'hidePostStats', value })
},
hideUserStatsLocal (value) {
this.$store.dispatch('setOption', { name: 'hideUserStats', value })
},
hideNsfwLocal (value) { hideNsfwLocal (value) {
this.$store.dispatch('setOption', { name: 'hideNsfw', value }) this.$store.dispatch('setOption', { name: 'hideNsfw', value })
}, },
@ -99,6 +119,12 @@ const settings = {
collapseMessageWithSubjectLocal (value) { collapseMessageWithSubjectLocal (value) {
this.$store.dispatch('setOption', { name: 'collapseMessageWithSubject', value }) this.$store.dispatch('setOption', { name: 'collapseMessageWithSubject', value })
}, },
scopeCopyLocal (value) {
this.$store.dispatch('setOption', { name: 'scopeCopy', value })
},
subjectLineBehaviorLocal (value) {
this.$store.dispatch('setOption', { name: 'subjectLineBehavior', value })
},
stopGifs (value) { stopGifs (value) {
this.$store.dispatch('setOption', { name: 'stopGifs', value }) this.$store.dispatch('setOption', { name: 'stopGifs', value })
} }

View file

@ -54,6 +54,41 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting-item">
<h2>{{$t('settings.composing')}}</h2>
<ul class="setting-list">
<li>
<input type="checkbox" id="scopeCopy" v-model="scopeCopyLocal">
<label for="scopeCopy">
{{$t('settings.scope_copy')}} {{$t('settings.instance_default', { value: scopeCopyDefault })}}
</label>
</li>
<li>
<div>
{{$t('settings.subject_line_behavior')}}
<label for="subjectLineBehavior" class="select">
<select id="subjectLineBehavior" v-model="subjectLineBehaviorLocal">
<option value="email">
{{$t('settings.subject_line_email')}}
{{subjectLineBehaviorDefault == 'email' ? $t('settings.instance_default_simple') : ''}}
</option>
<option value="masto">
{{$t('settings.subject_line_mastodon')}}
{{subjectLineBehaviorDefault == 'mastodon' ? $t('settings.instance_default_simple') : ''}}
</option>
<option value="noop">
{{$t('settings.subject_line_noop')}}
{{subjectLineBehaviorDefault == 'noop' ? $t('settings.instance_default_simple') : ''}}
</option>
</select>
<i class="icon-down-open"/>
</label>
</div>
</li>
</ul>
</div>
<div class="setting-item"> <div class="setting-item">
<h2>{{$t('settings.attachments')}}</h2> <h2>{{$t('settings.attachments')}}</h2>
<ul class="setting-list"> <ul class="setting-list">
@ -139,6 +174,18 @@
<i class="icon-down-open"/> <i class="icon-down-open"/>
</label> </label>
</div> </div>
<div>
<input type="checkbox" id="hidePostStats" v-model="hidePostStatsLocal">
<label for="hidePostStats">
{{$t('settings.hide_post_stats')}} {{$t('settings.instance_default', { value: hidePostStatsDefault })}}
</label>
</div>
<div>
<input type="checkbox" id="hideUserStats" v-model="hideUserStatsLocal">
<label for="hideUserStats">
{{$t('settings.hide_user_stats')}} {{$t('settings.instance_default', { value: hideUserStatsDefault })}}
</label>
</div>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<p>{{$t('settings.filtering_explanation')}}</p> <p>{{$t('settings.filtering_explanation')}}</p>

View file

@ -31,10 +31,17 @@ const Status = {
preview: null, preview: null,
showPreview: false, showPreview: false,
showingTall: false, showingTall: false,
expandingSubject: !this.$store.state.config.collapseMessageWithSubject expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined'
? !this.$store.state.instance.collapseMessageWithSubject
: !this.$store.state.config.collapseMessageWithSubject
} }
}, },
computed: { computed: {
localCollapseSubjectDefault () {
return typeof this.$store.state.config.collapseMessageWithSubject === 'undefined'
? this.$store.state.instance.collapseMessageWithSubject
: this.$store.state.config.collapseMessageWithSubject
},
muteWords () { muteWords () {
return this.$store.state.config.muteWords return this.$store.state.config.muteWords
}, },
@ -147,13 +154,13 @@ const Status = {
return this.status.attentions.length > 0 return this.status.attentions.length > 0
}, },
hideSubjectStatus () { hideSubjectStatus () {
if (this.tallStatus && !this.$store.state.config.collapseMessageWithSubject) { if (this.tallStatus && !this.localCollapseSubjectDefault) {
return false return false
} }
return !this.expandingSubject && this.status.summary return !this.expandingSubject && this.status.summary
}, },
hideTallStatus () { hideTallStatus () {
if (this.status.summary && this.$store.state.config.collapseMessageWithSubject) { if (this.status.summary && this.localCollapseSubjectDefault) {
return false return false
} }
if (this.showingTall) { if (this.showingTall) {
@ -168,16 +175,22 @@ const Status = {
if (!this.status.nsfw) { if (!this.status.nsfw) {
return false return false
} }
if (this.status.summary && this.$store.state.config.collapseMessageWithSubject) { if (this.status.summary && this.localCollapseSubjectDefault) {
return false return false
} }
return true return true
}, },
replySubject () { replySubject () {
if (this.status.summary && !this.status.summary.match(/^re[: ]/i)) { if (!this.status.summary) return ''
const behavior = this.$store.state.config.subjectLineBehavior
const startsWithRe = this.status.summary.match(/^re[: ]/i)
if (behavior !== 'noop' && startsWithRe || behavior === 'masto') {
return this.status.summary
} else if (behavior === 'email') {
return 're: '.concat(this.status.summary) return 're: '.concat(this.status.summary)
} else if (behavior === 'noop') {
return ''
} }
return this.status.summary
}, },
attachmentSize () { attachmentSize () {
if ((this.$store.state.config.hideAttachments && !this.inConversation) || if ((this.$store.state.config.hideAttachments && !this.inConversation) ||

View file

@ -106,7 +106,7 @@
</div> </div>
<div class="container" v-if="replying"> <div class="container" v-if="replying">
<div class="reply-left"/> <div class="reply-left"/>
<post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" :message-scope="status.visibility" :subject="replySubject" v-on:posted="toggleReplying"/> <post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" :copy-message-scope="status.visibility" :subject="replySubject" v-on:posted="toggleReplying"/>
</div> </div>
</template> </template>
</div> </div>

View file

@ -3,6 +3,13 @@ import { hex2rgb } from '../../services/color_convert/color_convert.js'
export default { export default {
props: [ 'user', 'switcher', 'selected', 'hideBio' ], props: [ 'user', 'switcher', 'selected', 'hideBio' ],
data () {
return {
hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined'
? this.$store.state.instance.hideUserStats
: this.$store.state.config.hideUserStats
}
},
computed: { computed: {
headingStyle () { headingStyle () {
const color = this.$store.state.config.customTheme.colors.bg const color = this.$store.state.config.customTheme.colors.bg

View file

@ -17,7 +17,7 @@
<div :title="user.name" class='user-name' v-else>{{user.name}}</div> <div :title="user.name" class='user-name' v-else>{{user.name}}</div>
<router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }"> <router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }">
<span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span> <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
<span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> <span v-if="!hideUserStatsLocal" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span>
</router-link> </router-link>
</div> </div>
</div> </div>
@ -91,23 +91,24 @@
</div> </div>
</div> </div>
<div class="panel-body profile-panel-body"> <div class="panel-body profile-panel-body">
<div class="user-counts" :class="{clickable: switcher}"> <div v-if="!hideUserStatsLocal || switcher" class="user-counts" :class="{clickable: switcher}">
<div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}"> <div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}">
<h5>{{ $t('user_card.statuses') }}</h5> <h5>{{ $t('user_card.statuses') }}</h5>
<span>{{user.statuses_count}} <br></span> <span v-if="!hideUserStatsLocal">{{user.statuses_count}} <br></span>
</div> </div>
<div class="user-count" v-on:click.prevent="setProfileView('friends')" :class="{selected: selected === 'friends'}"> <div class="user-count" v-on:click.prevent="setProfileView('friends')" :class="{selected: selected === 'friends'}">
<h5>{{ $t('user_card.followees') }}</h5> <h5>{{ $t('user_card.followees') }}</h5>
<span>{{user.friends_count}}</span> <span v-if="!hideUserStatsLocal">{{user.friends_count}}</span>
</div> </div>
<div class="user-count" v-on:click.prevent="setProfileView('followers')" :class="{selected: selected === 'followers'}"> <div class="user-count" v-on:click.prevent="setProfileView('followers')" :class="{selected: selected === 'followers'}">
<h5>{{ $t('user_card.followers') }}</h5> <h5>{{ $t('user_card.followers') }}</h5>
<span>{{user.followers_count}}</span> <span v-if="!hideUserStatsLocal">{{user.followers_count}}</span>
</div> </div>
</div> </div>
<p v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
<p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
</div> </div>
<p v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
<p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
</div>
</div> </div>
</template> </template>

View file

@ -7,25 +7,10 @@ const UserFinder = {
}), }),
methods: { methods: {
findUser (username) { findUser (username) {
username = username[0] === '@' ? username.slice(1) : username this.$router.push({ name: 'user-search', query: { query: username } })
this.loading = true
this.$store.state.api.backendInteractor.externalProfile(username)
.then((user) => {
this.loading = false
this.hidden = true
if (!user.error) {
this.$store.commit('addNewUsers', [user])
this.$router.push({name: 'user-profile', params: {id: user.id}})
} else {
this.error = true
}
})
}, },
toggleHidden () { toggleHidden () {
this.hidden = !this.hidden this.hidden = !this.hidden
},
dismissError () {
this.error = false
} }
} }
} }

View file

@ -1,9 +1,5 @@
<template> <template>
<span class="user-finder-container"> <span class="user-finder-container">
<span class="alert error" v-if="error">
<i class="icon-cancel user-finder-icon" @click="dismissError"/>
{{$t('finder.error_fetching_user')}}
</span>
<i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" /> <i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" />
<a href="#" v-if="hidden"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden"/></a> <a href="#" v-if="hidden"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden"/></a>
<span v-else> <span v-else>

View file

@ -0,0 +1,33 @@
import UserCard from '../user_card/user_card.vue'
import userSearchApi from '../../services/new_api/user_search.js'
const userSearch = {
components: {
UserCard
},
props: [
'query'
],
data () {
return {
users: []
}
},
mounted () {
this.search(this.query)
},
watch: {
query (newV) {
this.search(newV)
}
},
methods: {
search (query) {
userSearchApi.search({query, store: this.$store})
.then((res) => {
this.users = res
})
}
}
}
export default userSearch

View file

@ -0,0 +1,12 @@
<template>
<div class="user-seach panel panel-default">
<div class="panel-heading">
{{$t('nav.user_search')}}
</div>
<div class="panel-body">
<user-card v-for="user in users" :key="user.id" :user="user" :showFollows="true"></user-card>
</div>
</div>
</template>
<script src="./user_search.js"></script>

201
src/i18n/ar.json Normal file
View file

@ -0,0 +1,201 @@
{
"chat": {
"title": "الدردشة"
},
"features_panel": {
"chat": "الدردشة",
"gopher": "غوفر",
"media_proxy": "بروكسي الوسائط",
"scope_options": "",
"text_limit": "الحد الأقصى للنص",
"title": "الميّزات",
"who_to_follow": "للمتابعة"
},
"finder": {
"error_fetching_user": "خطأ أثناء جلب صفحة المستخدم",
"find_user": "البحث عن مستخدِم"
},
"general": {
"apply": "تطبيق",
"submit": "إرسال"
},
"login": {
"login": "تسجيل الدخول",
"logout": "الخروج",
"password": "الكلمة السرية",
"placeholder": "مثال lain",
"register": "انشاء حساب",
"username": "إسم المستخدم"
},
"nav": {
"chat": "الدردشة المحلية",
"friend_requests": "طلبات المتابَعة",
"mentions": "الإشارات",
"public_tl": "الخيط الزمني العام",
"timeline": "الخيط الزمني",
"twkn": "كافة الشبكة المعروفة"
},
"notifications": {
"broken_favorite": "منشور مجهول، جارٍ البحث عنه…",
"favorited_you": "أعجِب بمنشورك",
"followed_you": "يُتابعك",
"load_older": "تحميل الإشعارات الأقدم",
"notifications": "الإخطارات",
"read": "مقروء!",
"repeated_you": "شارَك منشورك"
},
"post_status": {
"account_not_locked_warning": "",
"account_not_locked_warning_link": "مقفل",
"attachments_sensitive": "اعتبر المرفقات كلها كمحتوى حساس",
"content_type": {
"plain_text": "نص صافٍ"
},
"content_warning": "الموضوع (اختياري)",
"default": "وصلت للتوّ إلى لوس أنجلس.",
"direct_warning": "",
"posting": "النشر",
"scope": {
"direct": "",
"private": "",
"public": "علني - يُنشر على الخيوط الزمنية العمومية",
"unlisted": "غير مُدرَج - لا يُنشَر على الخيوط الزمنية العمومية"
}
},
"registration": {
"bio": "السيرة الذاتية",
"email": "عنوان البريد الإلكتروني",
"fullname": "الإسم المعروض",
"password_confirm": "تأكيد الكلمة السرية",
"registration": "التسجيل",
"token": "رمز الدعوة"
},
"settings": {
"attachmentRadius": "المُرفَقات",
"attachments": "المُرفَقات",
"autoload": "",
"avatar": "الصورة الرمزية",
"avatarAltRadius": "الصور الرمزية (الإشعارات)",
"avatarRadius": "الصور الرمزية",
"background": "الخلفية",
"bio": "السيرة الذاتية",
"btnRadius": "الأزرار",
"cBlue": "أزرق (الرد، المتابَعة)",
"cGreen": "أخضر (إعادة النشر)",
"cOrange": "برتقالي (مفضلة)",
"cRed": "أحمر (إلغاء)",
"change_password": "تغيير كلمة السر",
"change_password_error": "وقع هناك خلل أثناء تعديل كلمتك السرية.",
"changed_password": "تم تغيير كلمة المرور بنجاح!",
"collapse_subject": "",
"confirm_new_password": "تأكيد كلمة السر الجديدة",
"current_avatar": "صورتك الرمزية الحالية",
"current_password": "كلمة السر الحالية",
"current_profile_banner": "الرأسية الحالية لصفحتك الشخصية",
"data_import_export_tab": "تصدير واستيراد البيانات",
"default_vis": "أسلوب العرض الافتراضي",
"delete_account": "حذف الحساب",
"delete_account_description": "حذف حسابك و كافة منشوراتك نهائيًا.",
"delete_account_error": "",
"delete_account_instructions": "يُرجى إدخال كلمتك السرية أدناه لتأكيد عملية حذف الحساب.",
"export_theme": "حفظ النموذج",
"filtering": "التصفية",
"filtering_explanation": "سيتم إخفاء كافة المنشورات التي تحتوي على هذه الكلمات، كلمة واحدة في كل سطر",
"follow_export": "تصدير الاشتراكات",
"follow_export_button": "تصدير الاشتراكات كملف csv",
"follow_export_processing": "التصدير جارٍ، سوف يُطلَب منك تنزيل ملفك بعد حين",
"follow_import": "استيراد الاشتراكات",
"follow_import_error": "خطأ أثناء استيراد المتابِعين",
"follows_imported": "",
"foreground": "الأمامية",
"general": "الإعدادات العامة",
"hide_attachments_in_convo": "إخفاء المرفقات على المحادثات",
"hide_attachments_in_tl": "إخفاء المرفقات على الخيط الزمني",
"hide_post_stats": "",
"hide_user_stats": "",
"import_followers_from_a_csv_file": "",
"import_theme": "تحميل نموذج",
"inputRadius": "",
"instance_default": "",
"interfaceLanguage": "لغة الواجهة",
"invalid_theme_imported": "",
"limited_availability": "غير متوفر على متصفحك",
"links": "الروابط",
"lock_account_description": "",
"loop_video": "",
"loop_video_silent_only": "",
"name": "الاسم",
"name_bio": "الاسم والسيرة الذاتية",
"new_password": "كلمة السر الجديدة",
"no_rich_text_description": "",
"notification_visibility": "نوع الإشعارات التي تريد عرضها",
"notification_visibility_follows": "يتابع",
"notification_visibility_likes": "الإعجابات",
"notification_visibility_mentions": "الإشارات",
"notification_visibility_repeats": "",
"nsfw_clickthrough": "",
"panelRadius": "",
"pause_on_unfocused": "",
"presets": "النماذج",
"profile_background": "خلفية الصفحة الشخصية",
"profile_banner": "رأسية الصفحة الشخصية",
"profile_tab": "الملف الشخصي",
"radii_help": "",
"replies_in_timeline": "الردود على الخيط الزمني",
"reply_link_preview": "",
"reply_visibility_all": "عرض كافة الردود",
"reply_visibility_following": "",
"reply_visibility_self": "",
"saving_err": "خطأ أثناء حفظ الإعدادات",
"saving_ok": "تم حفظ الإعدادات",
"security_tab": "الأمان",
"set_new_avatar": "اختيار صورة رمزية جديدة",
"set_new_profile_background": "اختيار خلفية جديدة للملف الشخصي",
"set_new_profile_banner": "اختيار رأسية جديدة للصفحة الشخصية",
"settings": "الإعدادات",
"stop_gifs": "",
"streaming": "",
"text": "النص",
"theme": "المظهر",
"theme_help": "",
"tooltipRadius": "",
"user_settings": "إعدادات المستخدم",
"values": {
"false": "لا",
"true": "نعم"
}
},
"timeline": {
"collapse": "",
"conversation": "محادثة",
"error_fetching": "خطأ أثناء جلب التحديثات",
"load_older": "تحميل المنشورات القديمة",
"no_retweet_hint": "",
"repeated": "",
"show_new": "عرض الجديد",
"up_to_date": "تم تحديثه"
},
"user_card": {
"approve": "قبول",
"block": "حظر",
"blocked": "تم حظره!",
"deny": "رفض",
"follow": "اتبع",
"followees": "",
"followers": "مُتابِعون",
"following": "",
"follows_you": "يتابعك!",
"mute": "كتم",
"muted": "تم كتمه",
"per_day": "في اليوم",
"remote_follow": "مُتابَعة عن بُعد",
"statuses": "المنشورات"
},
"user_profile": {
"timeline_title": "الخيط الزمني للمستخدم"
},
"who_to_follow": {
"more": "المزيد",
"who_to_follow": "للمتابعة"
}
}

199
src/i18n/ca.json Normal file
View file

@ -0,0 +1,199 @@
{
"chat": {
"title": "Xat"
},
"features_panel": {
"chat": "Xat",
"gopher": "Gopher",
"media_proxy": "Proxy per multimèdia",
"scope_options": "Opcions d'abast i visibilitat",
"text_limit": "Límit de text",
"title": "Funcionalitats",
"who_to_follow": "A qui seguir"
},
"finder": {
"error_fetching_user": "No s'ha pogut carregar l'usuari/a",
"find_user": "Find user"
},
"general": {
"apply": "Aplica",
"submit": "Desa"
},
"login": {
"login": "Inicia sessió",
"logout": "Tanca la sessió",
"password": "Contrasenya",
"placeholder": "p.ex.: Maria",
"register": "Registra't",
"username": "Nom d'usuari/a"
},
"nav": {
"chat": "Xat local públic",
"friend_requests": "Soŀlicituds de connexió",
"mentions": "Mencions",
"public_tl": "Flux públic del node",
"timeline": "Flux personal",
"twkn": "Flux de la xarxa coneguda"
},
"notifications": {
"broken_favorite": "No es coneix aquest estat. S'està cercant.",
"favorited_you": "ha marcat un estat teu",
"followed_you": "ha començat a seguir-te",
"load_older": "Carrega més notificacions",
"notifications": "Notificacions",
"read": "Read!",
"repeated_you": "ha repetit el teu estat"
},
"post_status": {
"account_not_locked_warning": "El teu compte no està {0}. Qualsevol persona pot seguir-te per llegir les teves entrades reservades només a seguidores.",
"account_not_locked_warning_link": "bloquejat",
"attachments_sensitive": "Marca l'adjunt com a delicat",
"content_type": {
"plain_text": "Text pla"
},
"content_warning": "Assumpte (opcional)",
"default": "Em sento…",
"direct_warning": "Aquesta entrada només serà visible per les usuràries que etiquetis",
"posting": "Publicació",
"scope": {
"direct": "Directa - Publica només per les usuàries etiquetades",
"private": "Només seguidors/es - Publica només per comptes que et segueixin",
"public": "Pública - Publica als fluxos públics",
"unlisted": "Silenciosa - No la mostris en fluxos públics"
}
},
"registration": {
"bio": "Presentació",
"email": "Correu",
"fullname": "Nom per mostrar",
"password_confirm": "Confirma la contrasenya",
"registration": "Registra't",
"token": "Codi d'invitació"
},
"settings": {
"attachmentRadius": "Adjunts",
"attachments": "Adjunts",
"autoload": "Recarrega automàticament en arribar a sota de tot.",
"avatar": "Avatar",
"avatarAltRadius": "Avatars en les notificacions",
"avatarRadius": "Avatars",
"background": "Fons de pantalla",
"bio": "Presentació",
"btnRadius": "Botons",
"cBlue": "Blau (respon, segueix)",
"cGreen": "Verd (republica)",
"cOrange": "Taronja (marca com a preferit)",
"cRed": "Vermell (canceŀla)",
"change_password": "Canvia la contrasenya",
"change_password_error": "No s'ha pogut canviar la contrasenya",
"changed_password": "S'ha canviat la contrasenya",
"collapse_subject": "Replega les entrades amb títol",
"confirm_new_password": "Confirma la nova contrasenya",
"current_avatar": "L'avatar actual",
"current_password": "La contrasenya actual",
"current_profile_banner": "El fons de perfil actual",
"data_import_export_tab": "Importa o exporta dades",
"default_vis": "Abast per defecte de les entrades",
"delete_account": "Esborra el compte",
"delete_account_description": "Esborra permanentment el teu compte i tots els missatges",
"delete_account_error": "No s'ha pogut esborrar el compte. Si continua el problema, contacta amb l'administració del node",
"delete_account_instructions": "Confirma que vols esborrar el compte escrivint la teva contrasenya aquí sota",
"export_theme": "Desa el tema",
"filtering": "Filtres",
"filtering_explanation": "Es silenciaran totes les entrades que continguin aquestes paraules. Separa-les per línies",
"follow_export": "Exporta la llista de contactes",
"follow_export_button": "Exporta tots els comptes que segueixes a un fitxer CSV",
"follow_export_processing": "S'està processant la petició. Aviat podràs descarregar el fitxer",
"follow_import": "Importa els contactes",
"follow_import_error": "No s'ha pogut importar els contactes",
"follows_imported": "S'han importat els contactes. Trigaran una estoneta en ser processats.",
"foreground": "Primer pla",
"general": "General",
"hide_attachments_in_convo": "Amaga els adjunts en les converses",
"hide_attachments_in_tl": "Amaga els adjunts en el flux d'entrades",
"import_followers_from_a_csv_file": "Importa els contactes des d'un fitxer CSV",
"import_theme": "Carrega un tema",
"inputRadius": "Caixes d'entrada de text",
"instance_default": "(default: {value})",
"interfaceLanguage": "Llengua de la interfície",
"invalid_theme_imported": "No s'ha entès l'arxiu carregat perquè no és un tema vàlid de Pleroma. No s'ha fet cap canvi als temes actuals.",
"limited_availability": "No està disponible en aquest navegador",
"links": "Enllaços",
"lock_account_description": "Restringeix el teu compte només a seguidores aprovades.",
"loop_video": "Reprodueix els vídeos en bucle",
"loop_video_silent_only": "Reprodueix en bucles només els vídeos sense so (com els \"GIF\" de Mastodon)",
"name": "Nom",
"name_bio": "Nom i presentació",
"new_password": "Contrasenya nova",
"notification_visibility": "Notifica'm quan algú",
"notification_visibility_follows": "Comença a seguir-me",
"notification_visibility_likes": "Marca com a preferida una entrada meva",
"notification_visibility_mentions": "Em menciona",
"notification_visibility_repeats": "Republica una entrada meva",
"no_rich_text_description": "Neteja el formatat de text de totes les entrades",
"nsfw_clickthrough": "Amaga el contingut NSFW darrer d'una imatge clicable",
"panelRadius": "Panells",
"pause_on_unfocused": "Pausa la reproducció en continu quan la pestanya perdi el focus",
"presets": "Temes",
"profile_background": "Fons de pantalla",
"profile_banner": "Fons de perfil",
"profile_tab": "Perfil",
"radii_help": "Configura l'arrodoniment de les vores (en píxels)",
"replies_in_timeline": "Replies in timeline",
"reply_link_preview": "Mostra el missatge citat en passar el ratolí per sobre de l'enllaç de resposta",
"reply_visibility_all": "Mostra totes les respostes",
"reply_visibility_following": "Mostra només les respostes a entrades meves o d'usuàries que jo segueixo",
"reply_visibility_self": "Mostra només les respostes a entrades meves",
"saving_err": "No s'ha pogut desar la configuració",
"saving_ok": "S'ha desat la configuració",
"security_tab": "Seguretat",
"set_new_avatar": "Canvia l'avatar",
"set_new_profile_background": "Canvia el fons de pantalla",
"set_new_profile_banner": "Canvia el fons del perfil",
"settings": "Configuració",
"stop_gifs": "Anima els GIF només en passar-hi el ratolí per sobre",
"streaming": "Carrega automàticament entrades noves quan estigui a dalt de tot",
"text": "Text",
"theme": "Tema",
"theme_help": "Personalitza els colors del tema. Escriu-los en format RGB hexadecimal (#rrggbb)",
"tooltipRadius": "Missatges sobreposats",
"user_settings": "Configuració personal",
"values": {
"false": "no",
"true": "sí"
}
},
"timeline": {
"collapse": "Replega",
"conversation": "Conversa",
"error_fetching": "S'ha produït un error en carregar les entrades",
"load_older": "Carrega entrades anteriors",
"no_retweet_hint": "L'entrada és només per a seguidores o és \"directa\", i per tant no es pot republicar",
"repeated": "republicat",
"show_new": "Mostra els nous",
"up_to_date": "Actualitzat"
},
"user_card": {
"approve": "Aprova",
"block": "Bloqueja",
"blocked": "Bloquejat!",
"deny": "Denega",
"follow": "Segueix",
"followees": "Segueixo",
"followers": "Seguidors/es",
"following": "Seguint!",
"follows_you": "Et segueix!",
"mute": "Silencia",
"muted": "Silenciat",
"per_day": "per dia",
"remote_follow": "Seguiment remot",
"statuses": "Estats"
},
"user_profile": {
"timeline_title": "Flux personal"
},
"who_to_follow": {
"more": "More",
"who_to_follow": "A qui seguir"
}
}

View file

@ -2,6 +2,15 @@
"chat": { "chat": {
"title": "Chat" "title": "Chat"
}, },
"features_panel": {
"chat": "Chat",
"gopher": "Gopher",
"media_proxy": "Media Proxy",
"scope_options": "Scope options",
"text_limit": "Textlimit",
"title": "Features",
"who_to_follow": "Who to follow"
},
"finder": { "finder": {
"error_fetching_user": "Fehler beim Suchen des Benutzers", "error_fetching_user": "Fehler beim Suchen des Benutzers",
"find_user": "Finde Benutzer" "find_user": "Finde Benutzer"
@ -12,6 +21,7 @@
}, },
"login": { "login": {
"login": "Anmelden", "login": "Anmelden",
"description": "Mit OAuth anmelden",
"logout": "Abmelden", "logout": "Abmelden",
"password": "Passwort", "password": "Passwort",
"placeholder": "z.B. lain", "placeholder": "z.B. lain",
@ -24,11 +34,13 @@
"mentions": "Erwähnungen", "mentions": "Erwähnungen",
"public_tl": "Lokale Zeitleiste", "public_tl": "Lokale Zeitleiste",
"timeline": "Zeitleiste", "timeline": "Zeitleiste",
"twkn": "Das gesamte Netzwerk" "twkn": "Das gesamte bekannte Netzwerk"
}, },
"notifications": { "notifications": {
"broken_favorite": "Unbekannte Nachricht, suche danach...",
"favorited_you": "favorisierte deine Nachricht", "favorited_you": "favorisierte deine Nachricht",
"followed_you": "folgt dir", "followed_you": "folgt dir",
"load_older": "Ältere Benachrichtigungen laden",
"notifications": "Benachrichtigungen", "notifications": "Benachrichtigungen",
"read": "Gelesen!", "read": "Gelesen!",
"repeated_you": "wiederholte deine Nachricht" "repeated_you": "wiederholte deine Nachricht"
@ -36,6 +48,11 @@
"post_status": { "post_status": {
"account_not_locked_warning": "Dein Profil ist nicht {0}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.", "account_not_locked_warning": "Dein Profil ist nicht {0}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.",
"account_not_locked_warning_link": "gesperrt", "account_not_locked_warning_link": "gesperrt",
"attachments_sensitive": "Anhänge als heikel markieren",
"content_type": {
"plain_text": "Nur Text"
},
"content_warning": "Betreff (optional)",
"default": "Sitze gerade im Hofbräuhaus.", "default": "Sitze gerade im Hofbräuhaus.",
"direct_warning": "Dieser Beitrag wird nur für die erwähnten Nutzer sichtbar sein.", "direct_warning": "Dieser Beitrag wird nur für die erwähnten Nutzer sichtbar sein.",
"posting": "Veröffentlichen", "posting": "Veröffentlichen",
@ -71,42 +88,68 @@
"change_password": "Passwort ändern", "change_password": "Passwort ändern",
"change_password_error": "Es gab ein Problem bei der Änderung des Passworts.", "change_password_error": "Es gab ein Problem bei der Änderung des Passworts.",
"changed_password": "Passwort erfolgreich geändert!", "changed_password": "Passwort erfolgreich geändert!",
"collapse_subject": "Beiträge mit Betreff einklappen",
"confirm_new_password": "Neues Passwort bestätigen", "confirm_new_password": "Neues Passwort bestätigen",
"current_avatar": "Dein derzeitiger Avatar", "current_avatar": "Dein derzeitiger Avatar",
"current_password": "Aktuelles Passwort", "current_password": "Aktuelles Passwort",
"current_profile_banner": "Der derzeitige Banner deines Profils", "current_profile_banner": "Der derzeitige Banner deines Profils",
"data_import_export_tab": "Datenimport/-export",
"default_vis": "Standard-Sichtbarkeitsumfang",
"delete_account": "Account löschen", "delete_account": "Account löschen",
"delete_account_description": "Lösche deinen Account und alle deine Nachrichten unwiderruflich.", "delete_account_description": "Lösche deinen Account und alle deine Nachrichten unwiderruflich.",
"delete_account_error": "Es ist ein Fehler beim löschen deines Accounts aufgetreten. Tritt dies weiterhin auf, wende dich an den Administrator der Instanz.", "delete_account_error": "Es ist ein Fehler beim Löschen deines Accounts aufgetreten. Tritt dies weiterhin auf, wende dich an den Administrator der Instanz.",
"delete_account_instructions": "Tippe dein Passwort unten in das Feld ein, um die Löschung deines Accounts zu bestätigen.", "delete_account_instructions": "Tippe dein Passwort unten in das Feld ein, um die Löschung deines Accounts zu bestätigen.",
"export_theme": "Farbschema speichern", "export_theme": "Farbschema speichern",
"filtering": "Filter", "filtering": "Filtern",
"filtering_explanation": "Alle Beiträge die diese Wörter enthalten werden ausgeblendet. Ein Wort pro Zeile.", "filtering_explanation": "Alle Beiträge die diese Wörter enthalten werden ausgeblendet. Ein Wort pro Zeile.",
"follow_export": "Follower exportieren", "follow_export": "Follower exportieren",
"follow_export_button": "Liste (.csv) erstellen", "follow_export_button": "Exportiere deine Follows in eine csv-Datei",
"follow_export_processing": "In Bearbeitung. Die Liste steht gleich zum herunterladen bereit.", "follow_export_processing": "In Bearbeitung. Die Liste steht gleich zum herunterladen bereit.",
"follow_import": "Followers importieren", "follow_import": "Followers importieren",
"follow_import_error": "Fehler beim importieren der Follower", "follow_import_error": "Fehler beim importieren der Follower",
"follows_imported": "Followers importiert! Die Bearbeitung kann eine Zeit lang dauern.", "follows_imported": "Followers importiert! Die Bearbeitung kann eine Zeit lang dauern.",
"foreground": "Vordergrund", "foreground": "Vordergrund",
"general": "Allgemein",
"hide_attachments_in_convo": "Anhänge in Unterhaltungen ausblenden", "hide_attachments_in_convo": "Anhänge in Unterhaltungen ausblenden",
"hide_attachments_in_tl": "Anhänge in der Zeitleiste ausblenden", "hide_attachments_in_tl": "Anhänge in der Zeitleiste ausblenden",
"hide_post_stats": "Beitragsstatistiken verbergen (z.B. die Anzahl der Favoriten)",
"hide_user_stats": "Benutzerstatistiken verbergen (z.B. die Anzahl der Follower)",
"import_followers_from_a_csv_file": "Importiere Follower, denen du folgen möchtest, aus einer CSV-Datei", "import_followers_from_a_csv_file": "Importiere Follower, denen du folgen möchtest, aus einer CSV-Datei",
"import_theme": "Farbschema laden", "import_theme": "Farbschema laden",
"inputRadius": "Eingabefelder", "inputRadius": "Eingabefelder",
"instance_default": "(Standard: {value})",
"interfaceLanguage": "Sprache der Oberfläche",
"invalid_theme_imported": "Die ausgewählte Datei ist kein unterstütztes Pleroma-Theme. Keine Änderungen wurden vorgenommen.", "invalid_theme_imported": "Die ausgewählte Datei ist kein unterstütztes Pleroma-Theme. Keine Änderungen wurden vorgenommen.",
"limited_availability": "In deinem Browser nicht verfügbar",
"links": "Links", "links": "Links",
"lock_account_description": "Sperre deinen Account, um neue Follower zu genehmigen oder abzulehnen", "lock_account_description": "Sperre deinen Account, um neue Follower zu genehmigen oder abzulehnen",
"loop_video": "Videos wiederholen",
"loop_video_silent_only": "Nur Videos ohne Ton wiederholen (z.B. Mastodons \"gifs\")",
"name": "Name", "name": "Name",
"name_bio": "Name & Bio", "name_bio": "Name & Bio",
"new_password": "Neues Passwort", "new_password": "Neues Passwort",
"notification_visibility": "Benachrichtigungstypen, die angezeigt werden sollen",
"notification_visibility_follows": "Follows",
"notification_visibility_likes": "Favoriten",
"notification_visibility_mentions": "Erwähnungen",
"notification_visibility_repeats": "Wiederholungen",
"no_rich_text_description": "Rich-Text Formatierungen von allen Beiträgen entfernen",
"nsfw_clickthrough": "Aktiviere ausblendbares Overlay für Anhänge, die als NSFW markiert sind", "nsfw_clickthrough": "Aktiviere ausblendbares Overlay für Anhänge, die als NSFW markiert sind",
"panelRadius": "Panel", "panelRadius": "Panel",
"pause_on_unfocused": "Streaming pausieren, wenn das Tab nicht fokussiert ist",
"presets": "Voreinstellungen", "presets": "Voreinstellungen",
"profile_background": "Profil Hintergrund", "profile_background": "Profilhintergrund",
"profile_banner": "Profil Banner", "profile_banner": "Profilbanner",
"profile_tab": "Profil",
"radii_help": "Kantenrundung (in Pixel) der Oberfläche anpassen", "radii_help": "Kantenrundung (in Pixel) der Oberfläche anpassen",
"reply_link_preview": "Aktiviere reply-link Vorschau bei Maus-Hover", "replies_in_timeline": "Antworten in der Zeitleiste",
"reply_link_preview": "Antwortlink-Vorschau beim Überfahren mit der Maus aktivieren",
"reply_visibility_all": "Alle Antworten zeigen",
"reply_visibility_following": "Zeige nur Antworten an mich oder an Benutzer, denen ich folge",
"reply_visibility_self": "Nur Antworten an mich anzeigen",
"saving_err": "Fehler beim Speichern der Einstellungen",
"saving_ok": "Einstellungen gespeichert",
"security_tab": "Sicherheit",
"set_new_avatar": "Setze einen neuen Avatar", "set_new_avatar": "Setze einen neuen Avatar",
"set_new_profile_background": "Setze einen neuen Hintergrund für dein Profil", "set_new_profile_background": "Setze einen neuen Hintergrund für dein Profil",
"set_new_profile_banner": "Setze einen neuen Banner für dein Profil", "set_new_profile_banner": "Setze einen neuen Banner für dein Profil",
@ -115,15 +158,20 @@
"streaming": "Aktiviere automatisches Laden (Streaming) von neuen Beiträgen", "streaming": "Aktiviere automatisches Laden (Streaming) von neuen Beiträgen",
"text": "Text", "text": "Text",
"theme": "Farbschema", "theme": "Farbschema",
"theme_help": "Benutze HTML Farbcodes (#rrggbb) um dein Farbschema anzupassen", "theme_help": "Benutze HTML-Farbcodes (#rrggbb) um dein Farbschema anzupassen",
"tooltipRadius": "Tooltips/Warnungen", "tooltipRadius": "Tooltips/Warnungen",
"user_settings": "Benutzereinstellungen" "user_settings": "Benutzereinstellungen",
"values": {
"false": "nein",
"true": "Ja"
}
}, },
"timeline": { "timeline": {
"collapse": "Einklappen", "collapse": "Einklappen",
"conversation": "Unterhaltung", "conversation": "Unterhaltung",
"error_fetching": "Fehler beim Laden", "error_fetching": "Fehler beim Laden",
"load_older": "Lade ältere Beiträge", "load_older": "Lade ältere Beiträge",
"no_retweet_hint": "Der Beitrag ist als nur-für-Follower oder als Direktnachricht markiert und kann nicht wiederholt werden.",
"repeated": "wiederholte", "repeated": "wiederholte",
"show_new": "Zeige Neuere", "show_new": "Zeige Neuere",
"up_to_date": "Aktuell" "up_to_date": "Aktuell"
@ -146,5 +194,9 @@
}, },
"user_profile": { "user_profile": {
"timeline_title": "Beiträge" "timeline_title": "Beiträge"
},
"who_to_follow": {
"more": "Mehr",
"who_to_follow": "Wem soll ich folgen"
} }
} }

View file

@ -21,6 +21,7 @@
}, },
"login": { "login": {
"login": "Log in", "login": "Log in",
"description": "Log in with OAuth",
"logout": "Log out", "logout": "Log out",
"password": "Password", "password": "Password",
"placeholder": "e.g. lain", "placeholder": "e.g. lain",
@ -31,9 +32,11 @@
"chat": "Local Chat", "chat": "Local Chat",
"friend_requests": "Follow Requests", "friend_requests": "Follow Requests",
"mentions": "Mentions", "mentions": "Mentions",
"dms": "Direct Messages",
"public_tl": "Public Timeline", "public_tl": "Public Timeline",
"timeline": "Timeline", "timeline": "Timeline",
"twkn": "The Whole Known Network" "twkn": "The Whole Known Network",
"user_search": "User Search"
}, },
"notifications": { "notifications": {
"broken_favorite": "Unknown status, searching for it...", "broken_favorite": "Unknown status, searching for it...",
@ -88,6 +91,7 @@
"change_password_error": "There was an issue changing your password.", "change_password_error": "There was an issue changing your password.",
"changed_password": "Password changed successfully!", "changed_password": "Password changed successfully!",
"collapse_subject": "Collapse posts with subjects", "collapse_subject": "Collapse posts with subjects",
"composing": "Composing",
"confirm_new_password": "Confirm new password", "confirm_new_password": "Confirm new password",
"current_avatar": "Your current avatar", "current_avatar": "Your current avatar",
"current_password": "Current password", "current_password": "Current password",
@ -111,11 +115,14 @@
"general": "General", "general": "General",
"hide_attachments_in_convo": "Hide attachments in conversations", "hide_attachments_in_convo": "Hide attachments in conversations",
"hide_attachments_in_tl": "Hide attachments in timeline", "hide_attachments_in_tl": "Hide attachments in timeline",
"hide_post_stats": "Hide post statistics (e.g. the number of favorites)",
"hide_user_stats": "Hide user statistics (e.g. the number of followers)",
"import_followers_from_a_csv_file": "Import follows from a csv file", "import_followers_from_a_csv_file": "Import follows from a csv file",
"import_theme": "Load preset", "import_theme": "Load preset",
"inputRadius": "Input fields", "inputRadius": "Input fields",
"checkboxRadius": "Checkboxes", "checkboxRadius": "Checkboxes",
"instance_default": "(default: {value})", "instance_default": "(default: {value})",
"instance_default_simple" : "(default)",
"interfaceLanguage": "Interface language", "interfaceLanguage": "Interface language",
"invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.", "invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
"limited_availability": "Unavailable in your browser", "limited_availability": "Unavailable in your browser",
@ -131,7 +138,7 @@
"notification_visibility_likes": "Likes", "notification_visibility_likes": "Likes",
"notification_visibility_mentions": "Mentions", "notification_visibility_mentions": "Mentions",
"notification_visibility_repeats": "Repeats", "notification_visibility_repeats": "Repeats",
"no_rich_text_description": "Disable rich text support", "no_rich_text_description": "Strip rich text formatting from all posts",
"nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding", "nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding",
"panelRadius": "Panels", "panelRadius": "Panels",
"pause_on_unfocused": "Pause streaming when tab is not focused", "pause_on_unfocused": "Pause streaming when tab is not focused",
@ -148,10 +155,15 @@
"saving_err": "Error saving settings", "saving_err": "Error saving settings",
"saving_ok": "Settings saved", "saving_ok": "Settings saved",
"security_tab": "Security", "security_tab": "Security",
"scope_copy": "Copy scope when replying (DMs are always copied)",
"set_new_avatar": "Set new avatar", "set_new_avatar": "Set new avatar",
"set_new_profile_background": "Set new profile background", "set_new_profile_background": "Set new profile background",
"set_new_profile_banner": "Set new profile banner", "set_new_profile_banner": "Set new profile banner",
"settings": "Settings", "settings": "Settings",
"subject_line_behavior": "Copy subject when replying",
"subject_line_email": "Like email: \"re: subject\"",
"subject_line_mastodon": "Like mastodon: copy as is",
"subject_line_noop": "Do not copy",
"stop_gifs": "Play-on-hover GIFs", "stop_gifs": "Play-on-hover GIFs",
"streaming": "Enable automatic streaming of new posts when scrolled to the top", "streaming": "Enable automatic streaming of new posts when scrolled to the top",
"text": "Text", "text": "Text",

View file

@ -21,6 +21,7 @@
}, },
"login": { "login": {
"login": "Connexion", "login": "Connexion",
"description": "Connexion avec OAuth",
"logout": "Déconnexion", "logout": "Déconnexion",
"password": "Mot de passe", "password": "Mot de passe",
"placeholder": "p.e. lain", "placeholder": "p.e. lain",
@ -30,6 +31,7 @@
"nav": { "nav": {
"chat": "Chat local", "chat": "Chat local",
"friend_requests": "Demandes d'ami", "friend_requests": "Demandes d'ami",
"dms": "Messages adressés",
"mentions": "Notifications", "mentions": "Notifications",
"public_tl": "Statuts locaux", "public_tl": "Statuts locaux",
"timeline": "Journal", "timeline": "Journal",
@ -86,7 +88,7 @@
"cRed": "Rouge (Annuler)", "cRed": "Rouge (Annuler)",
"change_password": "Changez votre mot de passe", "change_password": "Changez votre mot de passe",
"change_password_error": "Il y a eu un problème pour changer votre mot de passe.", "change_password_error": "Il y a eu un problème pour changer votre mot de passe.",
"changed_password": "Mot de passe changé avec succès!", "changed_password": "Mot de passe modifié avec succès !",
"collapse_subject": "Réduire les messages avec des sujets", "collapse_subject": "Réduire les messages avec des sujets",
"confirm_new_password": "Confirmation du nouveau mot de passe", "confirm_new_password": "Confirmation du nouveau mot de passe",
"current_avatar": "Avatar actuel", "current_avatar": "Avatar actuel",
@ -100,21 +102,24 @@
"delete_account_instructions": "Indiquez votre mot de passe ci-dessous pour confirmer la suppression de votre compte.", "delete_account_instructions": "Indiquez votre mot de passe ci-dessous pour confirmer la suppression de votre compte.",
"export_theme": "Enregistrer le thème", "export_theme": "Enregistrer le thème",
"filtering": "Filtre", "filtering": "Filtre",
"filtering_explanation": "Tous les statuts contenant ces mots seront masqués. Un mot par ligne.", "filtering_explanation": "Tous les statuts contenant ces mots seront masqués. Un mot par ligne",
"follow_export": "Exporter les abonnements", "follow_export": "Exporter les abonnements",
"follow_export_button": "Exporter les abonnements en csv", "follow_export_button": "Exporter les abonnements en csv",
"follow_export_processing": "Exportation en cours…", "follow_export_processing": "Exportation en cours…",
"follow_import": "Importer des abonnements", "follow_import": "Importer des abonnements",
"follow_import_error": "Erreur lors de l'importation des abonnements.", "follow_import_error": "Erreur lors de l'importation des abonnements",
"follows_imported": "Abonnements importés ! Le traitement peut prendre un moment.", "follows_imported": "Abonnements importés ! Le traitement peut prendre un moment.",
"foreground": "Premier plan", "foreground": "Premier plan",
"general": "Général", "general": "Général",
"hide_attachments_in_convo": "Masquer les pièces jointes dans les conversations", "hide_attachments_in_convo": "Masquer les pièces jointes dans les conversations",
"hide_attachments_in_tl": "Masquer les pièces jointes dans le journal", "hide_attachments_in_tl": "Masquer les pièces jointes dans le journal",
"hide_post_stats": "Masquer les statistiques de publication (le nombre de favoris)",
"hide_user_stats": "Masquer les statistiques de profil (le nombre d'amis)",
"import_followers_from_a_csv_file": "Importer des abonnements depuis un fichier csv", "import_followers_from_a_csv_file": "Importer des abonnements depuis un fichier csv",
"import_theme": "Charger le thème", "import_theme": "Charger le thème",
"inputRadius": "Champs de texte", "inputRadius": "Champs de texte",
"instance_default": "(default: {value})", "instance_default": "(default: {value})",
"instance_default_simple" : "(default)",
"interfaceLanguage": "Langue de l'interface", "interfaceLanguage": "Langue de l'interface",
"invalid_theme_imported": "Le fichier sélectionné n'est pas un thème Pleroma pris en charge. Aucun changement n'a été apporté à votre thème.", "invalid_theme_imported": "Le fichier sélectionné n'est pas un thème Pleroma pris en charge. Aucun changement n'a été apporté à votre thème.",
"limited_availability": "Non disponible dans votre navigateur", "limited_availability": "Non disponible dans votre navigateur",
@ -155,8 +160,8 @@
"streaming": "Charger automatiquement les nouveaux statuts lorsque vous êtes au haut de la page", "streaming": "Charger automatiquement les nouveaux statuts lorsque vous êtes au haut de la page",
"text": "Texte", "text": "Texte",
"theme": "Thème", "theme": "Thème",
"theme_help": "Spécifiez des codes couleur hexadécimaux (#aabbcc) pour personnaliser les couleurs du thème", "theme_help": "Spécifiez des codes couleur hexadécimaux (#rrvvbb) pour personnaliser les couleurs du thème.",
"tooltipRadius": "Info-bulles/alertes ", "tooltipRadius": "Info-bulles/alertes",
"user_settings": "Paramètres utilisateur", "user_settings": "Paramètres utilisateur",
"values": { "values": {
"false": "non", "false": "non",
@ -176,7 +181,7 @@
"user_card": { "user_card": {
"approve": "Accepter", "approve": "Accepter",
"block": "Bloquer", "block": "Bloquer",
"blocked": "Bloqué", "blocked": "Bloqué !",
"deny": "Rejeter", "deny": "Rejeter",
"follow": "Suivre", "follow": "Suivre",
"followees": "Suivis", "followees": "Suivis",

201
src/i18n/ga.json Normal file
View file

@ -0,0 +1,201 @@
{
"chat": {
"title": "Comhrá"
},
"features_panel": {
"chat": "Comhrá",
"gopher": "Gófar",
"media_proxy": "Seachfhreastalaí meáin",
"scope_options": "Rogha scóip",
"text_limit": "Teorainn Téacs",
"title": "Gnéithe",
"who_to_follow": "Daoine le leanúint"
},
"finder": {
"error_fetching_user": "Earráid a aimsiú d'úsáideoir",
"find_user": "Aimsigh úsáideoir"
},
"general": {
"apply": "Feidhmigh",
"submit": "Deimhnigh"
},
"login": {
"login": "Logáil isteach",
"logout": "Logáil amach",
"password": "Pasfhocal",
"placeholder": "m.sh. Daire",
"register": "Clárú",
"username": "Ainm Úsáideora"
},
"nav": {
"chat": "Comhrá Áitiúil",
"friend_requests": "Iarratas ar Cairdeas",
"mentions": "Tagairt",
"public_tl": "Amlíne Poiblí",
"timeline": "Amlíne",
"twkn": "An Líonra Iomlán"
},
"notifications": {
"broken_favorite": "Post anaithnid. Cuardach dó...",
"favorited_you": "toghadh le do phost",
"followed_you": "lean tú",
"load_older": "Luchtaigh fógraí aosta",
"notifications": "Fógraí",
"read": "Léigh!",
"repeated_you": "athphostáil tú"
},
"post_status": {
"account_not_locked_warning": "Níl do chuntas {0}. Is féidir le duine ar bith a leanúint leat chun do phoist leantacha amháin a fheiceáil.",
"account_not_locked_warning_link": "faoi glas",
"attachments_sensitive": "Marcáil ceangaltán mar íogair",
"content_type": {
"plain_text": "Gnáth-théacs"
},
"content_warning": "Teideal (roghnach)",
"default": "Lá iontach anseo i nGaillimh",
"direct_warning": "Ní bheidh an post seo le feiceáil ach amháin do na húsáideoirí atá luaite.",
"posting": "Post nua",
"scope": {
"direct": "Díreach - Post chuig úsáideoirí luaite amháin",
"private": "Leanúna amháin - Post chuig lucht leanúna amháin",
"public": "Poiblí - Post chuig amlínte poiblí",
"unlisted": "Neamhliostaithe - Ná cuir post chuig amlínte poiblí"
}
},
"registration": {
"bio": "Scéal saoil",
"email": "Ríomhphost",
"fullname": "Ainm taispeána'",
"password_confirm": "Deimhnigh do pasfhocal",
"registration": "Clárú",
"token": "Cód cuireadh"
},
"settings": {
"attachmentRadius": "Ceangaltáin",
"attachments": "Ceangaltáin",
"autoload": "Cumasaigh luchtú uathoibríoch nuair a scrollaítear go bun",
"avatar": "Phictúir phrófíle",
"avatarAltRadius": "Phictúirí phrófíle (Fograí)",
"avatarRadius": "Phictúirí phrófíle",
"background": "Cúlra",
"bio": "Scéal saoil",
"btnRadius": "Cnaipí",
"cBlue": "Gorm (Freagra, lean)",
"cGreen": "Glas (Athphóstail)",
"cOrange": "Oráiste (Cosúil)",
"cRed": "Dearg (Cealaigh)",
"change_password": "Athraigh do pasfhocal",
"change_password_error": "Bhí fadhb ann ag athrú do pasfhocail",
"changed_password": "Athraigh an pasfhocal go rathúil!",
"collapse_subject": "Poist a chosc le teidil",
"confirm_new_password": "Deimhnigh do pasfhocal nua",
"current_avatar": "Phictúir phrófíle",
"current_password": "Pasfhocal reatha",
"current_profile_banner": "Phictúir ceanntáisc",
"data_import_export_tab": "Iompórtáil / Easpórtáil Sonraí",
"default_vis": "Scóip infheicthe réamhshocraithe",
"delete_account": "Scrios cuntas",
"delete_account_description": "Do chuntas agus do chuid teachtaireachtaí go léir a scriosadh go buan.",
"delete_account_error": "Bhí fadhb ann a scriosadh do chuntas. Má leanann sé seo, téigh i dteagmháil le do riarthóir.",
"delete_account_instructions": "Scríobh do phasfhocal san ionchur thíos chun deimhniú a scriosadh.",
"export_theme": "Sábháil Téama",
"filtering": "Scagadh",
"filtering_explanation": "Beidh gach post ina bhfuil na focail seo i bhfolach, ceann in aghaidh an líne",
"follow_export": "Easpórtáil do leanann",
"follow_export_button": "Easpórtáil do leanann chuig comhad csv",
"follow_export_processing": "Próiseáil. Iarrtar ort go luath an comhad a íoslódáil.",
"follow_import": "Iompórtáil do leanann",
"follow_import_error": "Earráid agus do leanann a iompórtáil",
"follows_imported": "Do leanann iompórtáil! Tógfaidh an próiseas iad le tamall.",
"foreground": "Tulra",
"general": "Ginearálta",
"hide_attachments_in_convo": "Folaigh ceangaltáin i comhráite",
"hide_attachments_in_tl": "Folaigh ceangaltáin sa amlíne",
"hide_post_stats": "Folaigh staitisticí na bpost (m.sh. líon na n-athrá)",
"hide_user_stats": "Folaigh na staitisticí úsáideora (m.sh. líon na leantóiri)",
"import_followers_from_a_csv_file": "Iompórtáil leanann ó chomhad csv",
"import_theme": "Luchtaigh Téama",
"inputRadius": "Limistéar iontrála",
"instance_default": "(Réamhshocrú: {value})",
"interfaceLanguage": "Teanga comhéadain",
"invalid_theme_imported": "Ní téama bailí é an comhad dícheangailte. Níor rinneadh aon athruithe.",
"limited_availability": "Níl sé ar fáil i do bhrabhsálaí",
"links": "Naisc",
"lock_account_description": "Srian a chur ar do chuntas le lucht leanúna ceadaithe amháin",
"loop_video": "Lúb físeáin",
"loop_video_silent_only": "Lúb físeáin amháin gan fuaim (i.e. Mastodon's \"gifs\")",
"name": "Ainm",
"name_bio": "Ainm ⁊ Scéal",
"new_password": "Pasfhocal nua'",
"notification_visibility": "Cineálacha fógraí a thaispeáint",
"notification_visibility_follows": "Leana",
"notification_visibility_likes": "Thaithin",
"notification_visibility_mentions": "Tagairt",
"notification_visibility_repeats": "Atphostáil",
"no_rich_text_description": "Bain formáidiú téacs saibhir ó gach post",
"nsfw_clickthrough": "Cumasaigh an ceangaltán NSFW cliceáil ar an gcnaipe",
"panelRadius": "Painéil",
"pause_on_unfocused": "Sruthú ar sos nuair a bhíonn an fócas caillte",
"presets": "Réamhshocruithe",
"profile_background": "Cúlra Próifíl",
"profile_banner": "Phictúir Ceanntáisc",
"profile_tab": "Próifíl",
"radii_help": "Cruinniú imeall comhéadan a chumrú (i bpicteilíní)",
"replies_in_timeline": "Freagraí sa amlíne",
"reply_link_preview": "Cumasaigh réamhamharc nasc freagartha ar chlár na luiche",
"reply_visibility_all": "Taispeáin gach freagra",
"reply_visibility_following": "Taispeáin freagraí amháin atá dírithe ar mise nó ar úsáideoirí atá mé ag leanúint",
"reply_visibility_self": "Taispeáin freagraí amháin atá dírithe ar mise",
"saving_err": "Earráid socruithe a shábháil",
"saving_ok": "Socruithe sábháilte",
"security_tab": "Slándáil",
"set_new_avatar": "Athraigh do phictúir phrófíle",
"set_new_profile_background": "Athraigh do cúlra próifíl",
"set_new_profile_banner": "Athraigh do phictúir ceanntáisc",
"settings": "Socruithe",
"stop_gifs": "Seinn GIFs ar an scáileán",
"streaming": "Cumasaigh post nua a shruthú uathoibríoch nuair a scrollaítear go barr an leathanaigh",
"text": "Téacs",
"theme": "Téama",
"theme_help": "Úsáid cód daith hex (#rrggbb) chun do schéim a saincheapadh",
"tooltipRadius": "Bileoga eolais",
"user_settings": "Socruithe úsáideora",
"values": {
"false": "níl",
"true": "tá"
}
},
"timeline": {
"collapse": "Folaigh",
"conversation": "Cómhra",
"error_fetching": "Earráid a thabhairt cothrom le dáta",
"load_older": "Luchtaigh níos mó",
"no_retweet_hint": "Tá an post seo marcáilte mar lucht leanúna amháin nó díreach agus ní féidir é a athphostáil",
"repeated": "athphostáil",
"show_new": "Taispeáin nua",
"up_to_date": "Nuashonraithe"
},
"user_card": {
"approve": "Údaraigh",
"block": "Cosc",
"blocked": "Cuireadh coisc!",
"deny": "Diúltaigh",
"follow": "Lean",
"followees": "Leantóirí",
"followers": "Á Leanúint",
"following": "Á Leanúint",
"follows_you": "Leanann tú",
"mute": "Cuir i mód ciúin",
"muted": "Mód ciúin",
"per_day": "laethúil",
"remote_follow": "Leaníunt iargúlta",
"statuses": "Poist"
},
"user_profile": {
"timeline_title": "Amlíne úsáideora"
},
"who_to_follow": {
"more": "Feach uile",
"who_to_follow": "Daoine le leanúint"
}
}

View file

@ -1,47 +1,129 @@
{ {
"general": { "general": {
"submit": "Invia" "submit": "Invia",
"apply": "Applica"
}, },
"nav": { "nav": {
"mentions": "Menzioni", "mentions": "Menzioni",
"public_tl": "Sequenza temporale pubblica", "public_tl": "Sequenza temporale pubblica",
"timeline": "Sequenza temporale", "timeline": "Sequenza temporale",
"twkn": "L'intiera rete conosciuta" "twkn": "L'intera rete conosciuta",
"chat": "Chat Locale",
"friend_requests": "Richieste di Seguirti"
}, },
"notifications": { "notifications": {
"followed_you": "ti ha seguito", "followed_you": "ti segue",
"notifications": "Notifiche", "notifications": "Notifiche",
"read": "Leggi!" "read": "Leggi!",
"broken_favorite": "Stato sconosciuto, lo sto cercando...",
"favorited_you": "ha messo mi piace al tuo stato",
"load_older": "Carica notifiche più vecchie",
"repeated_you": "ha condiviso il tuo stato"
}, },
"settings": { "settings": {
"attachments": "Allegati", "attachments": "Allegati",
"autoload": "Abilita caricamento automatico quando si raggiunge il fondo schermo", "autoload": "Abilita caricamento automatico quando si raggiunge fondo pagina",
"avatar": "Avatar", "avatar": "Avatar",
"bio": "Introduzione", "bio": "Introduzione",
"current_avatar": "Il tuo attuale avatar", "current_avatar": "Il tuo avatar attuale",
"current_profile_banner": "Sfondo attuale", "current_profile_banner": "Il tuo banner attuale",
"filtering": "Filtri", "filtering": "Filtri",
"filtering_explanation": "Filtra via le notifiche che contengono le seguenti parole (inserisci rigo per rigo le parole di innesco)", "filtering_explanation": "Tutti i post contenenti queste parole saranno silenziati, uno per linea",
"hide_attachments_in_convo": "Nascondi gli allegati presenti nelle conversazioni", "hide_attachments_in_convo": "Nascondi gli allegati presenti nelle conversazioni",
"hide_attachments_in_tl": "Nascondi gli allegati presenti nella sequenza temporale", "hide_attachments_in_tl": "Nascondi gli allegati presenti nella sequenza temporale",
"name": "Nome", "name": "Nome",
"name_bio": "Nome & Introduzione", "name_bio": "Nome & Introduzione",
"nsfw_clickthrough": "Abilita la trasparenza degli allegati NSFW", "nsfw_clickthrough": "Abilita il click per visualizzare gli allegati segnati come NSFW",
"profile_background": "Sfondo della tua pagina", "profile_background": "Sfondo della tua pagina",
"profile_banner": "Sfondo del tuo profilo", "profile_banner": "Banner del tuo profilo",
"reply_link_preview": "Ability il reply-link preview al passaggio del mouse", "reply_link_preview": "Abilita il link per la risposta al passaggio del mouse",
"set_new_avatar": "Scegli un nuovo avatar", "set_new_avatar": "Scegli un nuovo avatar",
"set_new_profile_background": "Scegli un nuovo sfondo per la tua pagina", "set_new_profile_background": "Scegli un nuovo sfondo per la tua pagina",
"set_new_profile_banner": "Scegli un nuovo sfondo per il tuo profilo", "set_new_profile_banner": "Scegli un nuovo banner per il tuo profilo",
"settings": "Settaggi", "settings": "Impostazioni",
"theme": "Tema", "theme": "Tema",
"user_settings": "Configurazione dell'utente" "user_settings": "Impostazioni Utente",
"attachmentRadius": "Allegati",
"avatarAltRadius": "Avatar (Notifiche)",
"avatarRadius": "Avatar",
"background": "Sfondo",
"btnRadius": "Pulsanti",
"cBlue": "Blu (Rispondere, seguire)",
"cGreen": "Verde (Condividi)",
"cOrange": "Arancio (Mi piace)",
"cRed": "Rosso (Annulla)",
"change_password": "Cambia Password",
"change_password_error": "C'è stato un problema durante il cambiamento della password.",
"changed_password": "Password cambiata correttamente!",
"collapse_subject": "Riduci post che hanno un oggetto",
"confirm_new_password": "Conferma la nuova password",
"current_password": "Password attuale",
"data_import_export_tab": "Importa / Esporta Dati",
"default_vis": "Visibilità predefinita dei post",
"delete_account": "Elimina Account",
"delete_account_description": "Elimina definitivamente il tuo account e tutti i tuoi messaggi.",
"delete_account_error": "C'è stato un problema durante l'eliminazione del tuo account. Se il problema persiste contatta l'amministratore della tua istanza.",
"delete_account_instructions": "Digita la tua password nel campo sottostante per confermare l'eliminazione dell'account.",
"export_theme": "Salva settaggi",
"follow_export": "Esporta la lista di chi segui",
"follow_export_button": "Esporta la lista di chi segui in un file csv",
"follow_export_processing": "Sto elaborando, presto ti sarà chiesto di scaricare il tuo file",
"follow_import": "Importa la lista di chi segui",
"follow_import_error": "Errore nell'importazione della lista di chi segui",
"follows_imported": "Importazione riuscita! L'elaborazione richiederà un po' di tempo.",
"foreground": "In primo piano",
"general": "Generale",
"hide_post_stats": "Nascondi statistiche dei post (es. il numero di mi piace)",
"hide_user_stats": "Nascondi statistiche dell'utente (es. il numero di chi ti segue)",
"import_followers_from_a_csv_file": "Importa una lista di chi segui da un file csv",
"import_theme": "Carica settaggi",
"inputRadius": "Campi di testo",
"instance_default": "(predefinito: {value})",
"interfaceLanguage": "Linguaggio dell'interfaccia",
"invalid_theme_imported": "Il file selezionato non è un file di tema per Pleroma supportato. Il tuo tema non è stato modificato.",
"limited_availability": "Non disponibile nel tuo browser",
"links": "Collegamenti",
"lock_account_description": "Limita il tuo account solo per contatti approvati",
"loop_video": "Riproduci video in ciclo continuo",
"loop_video_silent_only": "Riproduci solo video senza audio in ciclo continuo (es. le gif di Mastodon)",
"new_password": "Nuova password",
"notification_visibility": "Tipi di notifiche da mostrare",
"notification_visibility_follows": "Nuove persone ti seguono",
"notification_visibility_likes": "Mi piace",
"notification_visibility_mentions": "Menzioni",
"notification_visibility_repeats": "Condivisioni",
"no_rich_text_description": "Togli la formattazione del testo da tutti i post",
"panelRadius": "Pannelli",
"pause_on_unfocused": "Metti in pausa l'aggiornamento continuo quando la scheda non è in primo piano",
"presets": "Valori predefiniti",
"profile_tab": "Profilo",
"radii_help": "Imposta l'arrotondamento dei bordi (in pixel)",
"replies_in_timeline": "Risposte nella sequenza temporale",
"reply_visibility_all": "Mostra tutte le risposte",
"reply_visibility_following": "Mostra solo le risposte dirette a me o agli utenti che seguo",
"reply_visibility_self": "Mostra solo risposte dirette a me",
"saving_err": "Errore nel salvataggio delle impostazioni",
"saving_ok": "Impostazioni salvate",
"security_tab": "Sicurezza",
"stop_gifs": "Riproduci GIF al passaggio del cursore del mouse",
"streaming": "Abilita aggiornamento automatico dei nuovi post quando si è in alto alla pagina",
"text": "Testo",
"theme_help": "Usa codici colore esadecimali (#rrggbb) per personalizzare il tuo schema di colori.",
"tooltipRadius": "Descrizioni/avvisi",
"values": {
"false": "no",
"true": "si"
}
}, },
"timeline": { "timeline": {
"error_fetching": "Errori nel prelievo aggiornamenti", "error_fetching": "Errore nel prelievo aggiornamenti",
"load_older": "Carica messaggi più vecchi", "load_older": "Carica messaggi più vecchi",
"show_new": "Mostra nuovi", "show_new": "Mostra nuovi",
"up_to_date": "Aggiornato" "up_to_date": "Aggiornato",
"collapse": "Riduci",
"conversation": "Conversazione",
"no_retweet_hint": "La visibilità del post è impostata solo per chi ti segue o messaggio diretto e non può essere condiviso",
"repeated": "condiviso"
}, },
"user_card": { "user_card": {
"follow": "Segui", "follow": "Segui",
@ -49,9 +131,71 @@
"followers": "Chi ti segue", "followers": "Chi ti segue",
"following": "Lo stai seguendo!", "following": "Lo stai seguendo!",
"follows_you": "Ti segue!", "follows_you": "Ti segue!",
"mute": "Ammutolisci", "mute": "Silenzia",
"muted": "Ammutoliti", "muted": "Silenziato",
"per_day": "al giorno", "per_day": "al giorno",
"statuses": "Messaggi" "statuses": "Messaggi",
"approve": "Approva",
"block": "Blocca",
"blocked": "Bloccato!",
"deny": "Nega",
"remote_follow": "Segui da remoto"
},
"chat": {
"title": "Chat"
},
"features_panel": {
"chat": "Chat",
"gopher": "Gopher",
"media_proxy": "Media proxy",
"scope_options": "Opzioni di visibilità",
"text_limit": "Lunghezza limite",
"title": "Caratteristiche",
"who_to_follow": "Chi seguire"
},
"finder": {
"error_fetching_user": "Errore nel recupero dell'utente",
"find_user": "Trova utente"
},
"login": {
"login": "Accedi",
"logout": "Disconnettiti",
"password": "Password",
"placeholder": "es. lain",
"register": "Registrati",
"username": "Nome utente"
},
"post_status": {
"account_not_locked_warning": "Il tuo account non è {0}. Chiunque può seguirti e vedere i tuoi post riservati a chi ti segue.",
"account_not_locked_warning_link": "bloccato",
"attachments_sensitive": "Segna allegati come sensibili",
"content_type": {
"plain_text": "Testo normale"
},
"content_warning": "Oggetto (facoltativo)",
"default": "Appena atterrato in L.A.",
"direct_warning": "Questo post sarà visibile solo dagli utenti menzionati.",
"posting": "Pubblica",
"scope": {
"direct": "Diretto - Pubblicato solo per gli utenti menzionati",
"private": "Solo per chi ti segue - Visibile solo da chi ti segue",
"public": "Pubblico - Visibile sulla sequenza temporale pubblica",
"unlisted": "Non elencato - Non visibile sulla sequenza temporale pubblica"
}
},
"registration": {
"bio": "Introduzione",
"email": "Email",
"fullname": "Nome visualizzato",
"password_confirm": "Conferma password",
"registration": "Registrazione",
"token": "Codice d'invito"
},
"user_profile": {
"timeline_title": "Sequenza Temporale dell'Utente"
},
"who_to_follow": {
"more": "Più",
"who_to_follow": "Chi seguire"
} }
} }

View file

@ -21,6 +21,7 @@
}, },
"login": { "login": {
"login": "ログイン", "login": "ログイン",
"description": "OAuthでログイン",
"logout": "ログアウト", "logout": "ログアウト",
"password": "パスワード", "password": "パスワード",
"placeholder": "れい: lain", "placeholder": "れい: lain",
@ -31,6 +32,7 @@
"chat": "ローカルチャット", "chat": "ローカルチャット",
"friend_requests": "フォローリクエスト", "friend_requests": "フォローリクエスト",
"mentions": "メンション", "mentions": "メンション",
"dms": "ダイレクトメッセージ",
"public_tl": "パブリックタイムライン", "public_tl": "パブリックタイムライン",
"timeline": "タイムライン", "timeline": "タイムライン",
"twkn": "つながっているすべてのネットワーク" "twkn": "つながっているすべてのネットワーク"
@ -111,6 +113,8 @@
"general": "ぜんぱん", "general": "ぜんぱん",
"hide_attachments_in_convo": "スレッドのファイルをかくす", "hide_attachments_in_convo": "スレッドのファイルをかくす",
"hide_attachments_in_tl": "タイムラインのファイルをかくす", "hide_attachments_in_tl": "タイムラインのファイルをかくす",
"hide_post_stats": "とうこうのとうけいをかくす (れい: おきにいりのかず)",
"hide_user_stats": "ユーザーのとうけいをかくす (れい: フォロワーのかず)",
"import_followers_from_a_csv_file": "CSVファイルからフォローをインポートする", "import_followers_from_a_csv_file": "CSVファイルからフォローをインポートする",
"import_theme": "ロード", "import_theme": "ロード",
"inputRadius": "インプットフィールド", "inputRadius": "インプットフィールド",

View file

@ -1,5 +1,6 @@
// When contributing, please sort JSON before committing so it would be easier to see what's missing and what's being added compared to English and other languages. It's not obligatory, but just an advice. // When contributing, please sort JSON before committing so it would be easier to see what's missing and what's being added compared to English and other languages. It's not obligatory, but just an advice.
// To sort json use jq https://stedolan.github.io/jq and invoke it like `jq -S . xx.json > xx.sorted.json`, AFAIK, there's no inplace edit option like in sed // To sort json use jq https://stedolan.github.io/jq and invoke it like `jq -S . xx.json > xx.sorted.json`, AFAIK, there's no inplace edit option like in sed
// Also, when adding a new language to "messages" variable, please do it alphabetically by language code so that users can search or check their custom language easily.
// For anyone contributing to old huge messages.js and in need to quickly convert it to JSON // For anyone contributing to old huge messages.js and in need to quickly convert it to JSON
// sed command for converting currently formatted JS to JSON: // sed command for converting currently formatted JS to JSON:
@ -7,23 +8,27 @@
// There's only problem that apostrophe character ' gets replaced by \\ so you have to fix it manually, sorry. // There's only problem that apostrophe character ' gets replaced by \\ so you have to fix it manually, sorry.
const messages = { const messages = {
ar: require('./ar.json'),
ca: require('./ca.json'),
de: require('./de.json'), de: require('./de.json'),
fi: require('./fi.json'),
en: require('./en.json'), en: require('./en.json'),
eo: require('./eo.json'), eo: require('./eo.json'),
es: require('./es.json'),
et: require('./et.json'), et: require('./et.json'),
hu: require('./hu.json'), fi: require('./fi.json'),
ro: require('./ro.json'),
ja: require('./ja.json'),
fr: require('./fr.json'), fr: require('./fr.json'),
ga: require('./ga.json'),
he: require('./he.json'),
hu: require('./hu.json'),
it: require('./it.json'), it: require('./it.json'),
ja: require('./ja.json'),
nb: require('./nb.json'),
oc: require('./oc.json'), oc: require('./oc.json'),
pl: require('./pl.json'), pl: require('./pl.json'),
es: require('./es.json'),
pt: require('./pt.json'), pt: require('./pt.json'),
ro: require('./ro.json'),
ru: require('./ru.json'), ru: require('./ru.json'),
nb: require('./nb.json'), zh: require('./zh.json')
he: require('./he.json')
} }
export default messages export default messages

View file

@ -1,6 +1,15 @@
{ {
"chat": { "chat": {
"title": "Chat" "title": "Nettprat"
},
"features_panel": {
"chat": "Nettprat",
"gopher": "Gopher",
"media_proxy": "Media proxy",
"scope_options": "Velg mottakere",
"text_limit": "Tekst-grense",
"title": "Egenskaper",
"who_to_follow": "Hvem å følge"
}, },
"finder": { "finder": {
"error_fetching_user": "Feil ved henting av bruker", "error_fetching_user": "Feil ved henting av bruker",
@ -8,7 +17,7 @@
}, },
"general": { "general": {
"apply": "Bruk", "apply": "Bruk",
"submit": "Legg ut" "submit": "Send"
}, },
"login": { "login": {
"login": "Logg inn", "login": "Logg inn",
@ -19,29 +28,47 @@
"username": "Brukernavn" "username": "Brukernavn"
}, },
"nav": { "nav": {
"chat": "Lokal Chat", "chat": "Lokal nettprat",
"friend_requests": "Følgeforespørsler",
"mentions": "Nevnt", "mentions": "Nevnt",
"public_tl": "Offentlig Tidslinje", "public_tl": "Offentlig Tidslinje",
"timeline": "Tidslinje", "timeline": "Tidslinje",
"twkn": "Det hele kjente nettverket" "twkn": "Det hele kjente nettverket"
}, },
"notifications": { "notifications": {
"broken_favorite": "Ukjent status, leter etter den...",
"favorited_you": "likte din status", "favorited_you": "likte din status",
"followed_you": "fulgte deg", "followed_you": "fulgte deg",
"load_older": "Last eldre varsler",
"notifications": "Varslinger", "notifications": "Varslinger",
"read": "Les!", "read": "Les!",
"repeated_you": "Gjentok din status" "repeated_you": "Gjentok din status"
}, },
"post_status": { "post_status": {
"account_not_locked_warning": "Kontoen din er ikke {0}. Hvem som helst kan følge deg for å se dine statuser til følgere",
"account_not_locked_warning_link": "låst",
"attachments_sensitive": "Merk vedlegg som sensitive",
"content_type": {
"plain_text": "Klar tekst"
},
"content_warning": "Tema (valgfritt)",
"default": "Landet akkurat i L.A.", "default": "Landet akkurat i L.A.",
"posting": "Publiserer" "direct_warning": "Denne statusen vil kun bli sett av nevnte brukere",
"posting": "Publiserer",
"scope": {
"direct": "Direkte, publiser bare til nevnte brukere",
"private": "Bare følgere, publiser bare til brukere som følger deg",
"public": "Offentlig, publiser til offentlige tidslinjer",
"unlisted": "Uoppført, ikke publiser til offentlige tidslinjer"
}
}, },
"registration": { "registration": {
"bio": "Biografi", "bio": "Biografi",
"email": "Epost-adresse", "email": "Epost-adresse",
"fullname": "Visningsnavn", "fullname": "Visningsnavn",
"password_confirm": "Bekreft passord", "password_confirm": "Bekreft passord",
"registration": "Registrering" "registration": "Registrering",
"token": "Invitasjons-bevis"
}, },
"settings": { "settings": {
"attachmentRadius": "Vedlegg", "attachmentRadius": "Vedlegg",
@ -57,27 +84,69 @@
"cGreen": "Grønn (Gjenta)", "cGreen": "Grønn (Gjenta)",
"cOrange": "Oransje (Lik)", "cOrange": "Oransje (Lik)",
"cRed": "Rød (Avbryt)", "cRed": "Rød (Avbryt)",
"change_password": "Endre passord",
"change_password_error": "Feil ved endring av passord",
"changed_password": "Passord endret",
"collapse_subject": "Sammenfold statuser med tema",
"confirm_new_password": "Bekreft nytt passord",
"current_avatar": "Ditt nåværende profilbilde", "current_avatar": "Ditt nåværende profilbilde",
"current_password": "Nåværende passord",
"current_profile_banner": "Din nåværende profil-banner", "current_profile_banner": "Din nåværende profil-banner",
"data_import_export_tab": "Data import / eksport",
"default_vis": "Standard visnings-omfang",
"delete_account": "Slett konto",
"delete_account_description": "Slett din konto og alle dine statuser",
"delete_account_error": "Det oppsto et problem ved sletting av kontoen din, hvis dette problemet forblir kontakt din administrator",
"delete_account_instructions": "Skriv inn ditt passord i feltet nedenfor for å bekrefte sletting av konto",
"export_theme": "Lagre tema",
"filtering": "Filtrering", "filtering": "Filtrering",
"filtering_explanation": "Alle statuser som inneholder disse ordene vil bli dempet, en kombinasjon av tegn per linje", "filtering_explanation": "Alle statuser som inneholder disse ordene vil bli dempet, en kombinasjon av tegn per linje",
"follow_export": "Eksporter følginger",
"follow_export_button": "Eksporter følgingene dine til en .csv fil",
"follow_export_processing": "Jobber, du vil snart bli spurt om å laste ned filen din.",
"follow_import": "Importer følginger", "follow_import": "Importer følginger",
"follow_import_error": "Feil ved importering av følginger.", "follow_import_error": "Feil ved importering av følginger.",
"follows_imported": "Følginger imported! Det vil ta litt tid å behandle de.", "follows_imported": "Følginger importert! Behandling vil ta litt tid.",
"foreground": "Framgrunn", "foreground": "Forgrunn",
"general": "Generell",
"hide_attachments_in_convo": "Gjem vedlegg i samtaler", "hide_attachments_in_convo": "Gjem vedlegg i samtaler",
"hide_attachments_in_tl": "Gjem vedlegg på tidslinje", "hide_attachments_in_tl": "Gjem vedlegg på tidslinje",
"import_followers_from_a_csv_file": "Importer følginger fra en csv fil", "import_followers_from_a_csv_file": "Importer følginger fra en csv fil",
"import_theme": "Last tema",
"inputRadius": "Input felt",
"instance_default": "(standard: {value})",
"interfaceLanguage": "Grensesnitt-språk",
"invalid_theme_imported": "Den valgte filen er ikke ett støttet Pleroma-tema, ingen endringer til ditt tema ble gjort",
"limited_availability": "Ikke tilgjengelig i din nettleser",
"links": "Linker", "links": "Linker",
"lock_account_description": "Begrens din konto til bare godkjente følgere",
"loop_video": "Gjenta videoer",
"loop_video_silent_only": "Gjenta bare videoer uten lyd, (for eksempel Mastodon sine \"gifs\")",
"name": "Navn", "name": "Navn",
"name_bio": "Navn & Biografi", "name_bio": "Navn & Biografi",
"new_password": "Nytt passord",
"notification_visibility": "Typer varsler som skal vises",
"notification_visibility_follows": "Følginger",
"notification_visibility_likes": "Likes",
"notification_visibility_mentions": "Nevnt",
"notification_visibility_repeats": "Gjentakelser",
"no_rich_text_description": "Fjern all formatering fra statuser",
"nsfw_clickthrough": "Krev trykk for å vise statuser som kan være upassende", "nsfw_clickthrough": "Krev trykk for å vise statuser som kan være upassende",
"panelRadius": "Panel", "panelRadius": "Panel",
"presets": "Forhåndsdefinerte fargekoder", "pause_on_unfocused": "Stopp henting av poster når vinduet ikke er i fokus",
"presets": "Forhåndsdefinerte tema",
"profile_background": "Profil-bakgrunn", "profile_background": "Profil-bakgrunn",
"profile_banner": "Profil-banner", "profile_banner": "Profil-banner",
"profile_tab": "Profil",
"radii_help": "Bestem hvor runde hjørnene i brukergrensesnittet skal være (i piksler)", "radii_help": "Bestem hvor runde hjørnene i brukergrensesnittet skal være (i piksler)",
"replies_in_timeline": "Svar på tidslinje",
"reply_link_preview": "Vis en forhåndsvisning når du holder musen over svar til en status", "reply_link_preview": "Vis en forhåndsvisning når du holder musen over svar til en status",
"reply_visibility_all": "Vis alle svar",
"reply_visibility_following": "Vis bare svar som er til meg eller folk jeg følger",
"reply_visibility_self": "Vis bare svar som er til meg",
"saving_err": "Feil ved lagring av innstillinger",
"saving_ok": "Innstillinger lagret",
"security_tab": "Sikkerhet",
"set_new_avatar": "Rediger profilbilde", "set_new_avatar": "Rediger profilbilde",
"set_new_profile_background": "Rediger profil-bakgrunn", "set_new_profile_background": "Rediger profil-bakgrunn",
"set_new_profile_banner": "Sett ny profil-banner", "set_new_profile_banner": "Sett ny profil-banner",
@ -88,20 +157,27 @@
"theme": "Tema", "theme": "Tema",
"theme_help": "Bruk heksadesimale fargekoder (#rrggbb) til å endre farge-temaet ditt.", "theme_help": "Bruk heksadesimale fargekoder (#rrggbb) til å endre farge-temaet ditt.",
"tooltipRadius": "Verktøytips/advarsler", "tooltipRadius": "Verktøytips/advarsler",
"user_settings": "Brukerinstillinger" "user_settings": "Brukerinstillinger",
"values": {
"false": "nei",
"true": "ja"
}
}, },
"timeline": { "timeline": {
"collapse": "Sammenfold", "collapse": "Sammenfold",
"conversation": "Samtale", "conversation": "Samtale",
"error_fetching": "Feil ved henting av oppdateringer", "error_fetching": "Feil ved henting av oppdateringer",
"load_older": "Last eldre statuser", "load_older": "Last eldre statuser",
"no_retweet_hint": "Status er markert som bare til følgere eller direkte og kan ikke gjentas",
"repeated": "gjentok", "repeated": "gjentok",
"show_new": "Vis nye", "show_new": "Vis nye",
"up_to_date": "Oppdatert" "up_to_date": "Oppdatert"
}, },
"user_card": { "user_card": {
"approve": "Godkjenn",
"block": "Blokker", "block": "Blokker",
"blocked": "Blokkert!", "blocked": "Blokkert!",
"deny": "Avslå",
"follow": "Følg", "follow": "Følg",
"followees": "Følger", "followees": "Følger",
"followers": "Følgere", "followers": "Følgere",
@ -115,5 +191,9 @@
}, },
"user_profile": { "user_profile": {
"timeline_title": "Bruker-tidslinje" "timeline_title": "Bruker-tidslinje"
},
"who_to_follow": {
"more": "Mer",
"who_to_follow": "Hvem å følge"
} }
} }

View file

@ -23,26 +23,43 @@
"mentions": "Notificacions", "mentions": "Notificacions",
"public_tl": "Estatuts locals", "public_tl": "Estatuts locals",
"timeline": "Flux dactualitat", "timeline": "Flux dactualitat",
"twkn": "Lo malhum conegut" "twkn": "Lo malhum conegut",
"friend_requests": "Demandas d'abonament"
}, },
"notifications": { "notifications": {
"favorited_you": "a aimat vòstre estatut", "favorited_you": "a aimat vòstre estatut",
"followed_you": "vos a seguit", "followed_you": "vos a seguit",
"notifications": "Notficacions", "notifications": "Notficacions",
"read": "Legit!", "read": "Legit !",
"repeated_you": "a repetit your vòstre estatut" "repeated_you": "a repetit vòstre estatut",
"broken_favorite": "Estatut desconegut, sèm a lo cercar...",
"load_older": "Cargar las notificaciones mai ancianas"
}, },
"post_status": { "post_status": {
"content_warning": "Avís de contengut (opcional)", "content_warning": "Avís de contengut (opcional)",
"default": "Escrivètz aquí vòstre estatut.", "default": "Escrivètz aquí vòstre estatut.",
"posting": "Mandadís" "posting": "Mandadís",
"account_not_locked_warning": "Vòstre compte es pas {0}. Qual que siá pòt vos seguir per veire vòstras publicacions destinadas pas qu'a vòstres seguidors.",
"account_not_locked_warning_link": "clavat",
"attachments_sensitive": "Marcar las pèças juntas coma sensiblas",
"content_type": {
"plain_text": "Tèxte brut"
},
"direct_warning": "Aquesta publicacion serà pas que visibla pels utilizaires mencionats.",
"scope": {
"direct": "Dirècte - Publicar pels utilizaires mencionats solament",
"private": "Seguidors solament - Publicar pels sols seguidors",
"public": "Public - Publicar pel flux dactualitat public",
"unlisted": "Pas listat - Publicar pas pel flux public"
}
}, },
"registration": { "registration": {
"bio": "Biografia", "bio": "Biografia",
"email": "Adreça de corrièl", "email": "Adreça de corrièl",
"fullname": "Nom complèt", "fullname": "Nom complèt",
"password_confirm": "Confirmar lo senhal", "password_confirm": "Confirmar lo senhal",
"registration": "Inscripcion" "registration": "Inscripcion",
"token": "Geton de convidat"
}, },
"settings": { "settings": {
"attachmentRadius": "Pèças juntas", "attachmentRadius": "Pèças juntas",
@ -60,7 +77,7 @@
"cRed": "Roge (Anullar)", "cRed": "Roge (Anullar)",
"change_password": "Cambiar lo senhal", "change_password": "Cambiar lo senhal",
"change_password_error": "Una error ses producha en cambiant lo senhal.", "change_password_error": "Una error ses producha en cambiant lo senhal.",
"changed_password": "Senhal corrèctament cambiat", "changed_password": "Senhal corrèctament cambiat !",
"confirm_new_password": "Confirmatz lo nòu senhal", "confirm_new_password": "Confirmatz lo nòu senhal",
"current_avatar": "Vòstre avatar actual", "current_avatar": "Vòstre avatar actual",
"current_password": "Senhal actual", "current_password": "Senhal actual",
@ -70,7 +87,7 @@
"delete_account_error": "Una error ses producha en suprimir lo compte. Saquò ten darribar mercés de contactar vòstre administrador dinstància.", "delete_account_error": "Una error ses producha en suprimir lo compte. Saquò ten darribar mercés de contactar vòstre administrador dinstància.",
"delete_account_instructions": "Picatz vòstre senhal dins lo camp tèxte çai-jos per confirmar la supression del compte.", "delete_account_instructions": "Picatz vòstre senhal dins lo camp tèxte çai-jos per confirmar la supression del compte.",
"filtering": "Filtre", "filtering": "Filtre",
"filtering_explanation": "Totes los estatuts amb aqueles mots seràn en silenci, un mot per linha.", "filtering_explanation": "Totes los estatuts amb aqueles mots seràn en silenci, un mot per linha",
"follow_export": "Exportar los abonaments", "follow_export": "Exportar los abonaments",
"follow_export_button": "Exportar vòstres abonaments dins un fichièr csv", "follow_export_button": "Exportar vòstres abonaments dins un fichièr csv",
"follow_export_processing": "Tractament, vos demandarem lèu de telecargar lo fichièr", "follow_export_processing": "Tractament, vos demandarem lèu de telecargar lo fichièr",
@ -103,7 +120,41 @@
"theme": "Tèma", "theme": "Tèma",
"theme_help": "Emplegatz los còdis de color hex (#rrggbb) per personalizar vòstre tèma de color.", "theme_help": "Emplegatz los còdis de color hex (#rrggbb) per personalizar vòstre tèma de color.",
"tooltipRadius": "Astúcias/Alèrta", "tooltipRadius": "Astúcias/Alèrta",
"user_settings": "Paramètres utilizaire" "user_settings": "Paramètres utilizaire",
"collapse_subject": "Replegar las publicacions amb de subjèctes",
"data_import_export_tab": "Importar / Exportar las donadas",
"default_vis": "Nivèl de visibilitat per defaut",
"export_theme": "Enregistrar la preconfiguracion",
"general": "General",
"hide_post_stats": "Amagar los estatistics de publicacion (ex. lo ombre de favorits)",
"hide_user_stats": "Amagar las estatisticas de lutilizaire (ex. lo nombre de seguidors)",
"import_theme": "Cargar un tèma",
"instance_default": "(defaut : {value})",
"interfaceLanguage": "Lenga de linterfàcia",
"invalid_theme_imported": "Lo fichièr seleccionat es pas un tèma Pleroma valid. Cap de cambiament es estat fach a vòstre tèma.",
"limited_availability": "Pas disponible per vòstre navigador",
"lock_account_description": "Limitar vòstre compte als seguidors acceptats solament",
"loop_video": "Bocla vidèo",
"loop_video_silent_only": "Legir en bocla solament las vidèos sens son (coma los « Gifs » de Mastodon)",
"notification_visibility": "Tipes de notificacion de mostrar",
"notification_visibility_follows": "Abonaments",
"notification_visibility_likes": "Aiman",
"notification_visibility_mentions": "Mencions",
"notification_visibility_repeats": "Repeticions",
"no_rich_text_description": "Netejar lo format tèxte de totas las publicacions",
"pause_on_unfocused": "Pausar la difusion quand longlet es pas seleccionat",
"profile_tab": "Perfil",
"replies_in_timeline": "Responsas del flux",
"reply_visibility_all": "Mostrar totas las responsas",
"reply_visibility_following": "Mostrar pas que las responsas que me son destinada a ieu o un utilizaire que seguissi",
"reply_visibility_self": "Mostrar pas que las responsas que me son destinadas",
"saving_err": "Error en enregistrant los paramètres",
"saving_ok": "Paramètres enregistrats",
"security_tab": "Seguretat",
"values": {
"false": "non",
"true": "òc"
}
}, },
"timeline": { "timeline": {
"collapse": "Tampar", "collapse": "Tampar",
@ -112,23 +163,39 @@
"load_older": "Ne veire mai", "load_older": "Ne veire mai",
"repeated": "repetit", "repeated": "repetit",
"show_new": "Ne veire mai", "show_new": "Ne veire mai",
"up_to_date": "A jorn" "up_to_date": "A jorn",
"no_retweet_hint": "La publicacion marcada coma pels seguidors solament o dirècte pòt pas èsser repetida"
}, },
"user_card": { "user_card": {
"block": "Blocar", "block": "Blocar",
"blocked": "Blocat", "blocked": "Blocat !",
"follow": "Seguir", "follow": "Seguir",
"followees": "Abonaments", "followees": "Abonaments",
"followers": "Seguidors", "followers": "Seguidors",
"following": "Seguit!", "following": "Seguit !",
"follows_you": "Vos sèc!", "follows_you": "Vos sèc !",
"mute": "Amagar", "mute": "Amagar",
"muted": "Amagat", "muted": "Amagat",
"per_day": "per jorn", "per_day": "per jorn",
"remote_follow": "Seguir a distància", "remote_follow": "Seguir a distància",
"statuses": "Estatuts" "statuses": "Estatuts",
"approve": "Validar",
"deny": "Refusar"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Flux utilizaire" "timeline_title": "Flux utilizaire"
},
"features_panel": {
"chat": "Discutida",
"gopher": "Gopher",
"media_proxy": "Servidor mandatari dels mèdias",
"scope_options": "Opcions d'encastres",
"text_limit": "Limit de tèxte",
"title": "Foncionalitats",
"who_to_follow": "Qui seguir"
},
"who_to_follow": {
"more": "Mai",
"who_to_follow": "Qui seguir"
} }
} }

View file

@ -114,6 +114,7 @@
"notification_visibility_likes": "Лайки", "notification_visibility_likes": "Лайки",
"notification_visibility_mentions": "Упоминания", "notification_visibility_mentions": "Упоминания",
"notification_visibility_repeats": "Повторы", "notification_visibility_repeats": "Повторы",
"no_rich_text_description": "Убрать форматирование из всех постов",
"nsfw_clickthrough": "Включить скрытие NSFW вложений", "nsfw_clickthrough": "Включить скрытие NSFW вложений",
"panelRadius": "Панели", "panelRadius": "Панели",
"pause_on_unfocused": "Приостановить загрузку когда вкладка не в фокусе", "pause_on_unfocused": "Приостановить загрузку когда вкладка не в фокусе",

201
src/i18n/zh.json Normal file
View file

@ -0,0 +1,201 @@
{
"chat": {
"title": "聊天"
},
"features_panel": {
"chat": "聊天",
"gopher": "Gopher",
"media_proxy": "媒体代理",
"scope_options": "可见范围设置",
"text_limit": "文本长度限制",
"title": "功能",
"who_to_follow": "推荐关注"
},
"finder": {
"error_fetching_user": "获取用户时发生错误",
"find_user": "寻找用户"
},
"general": {
"apply": "应用",
"submit": "提交"
},
"login": {
"login": "登录",
"logout": "登出",
"password": "密码",
"placeholder": "例如lain",
"register": "注册",
"username": "用户名"
},
"nav": {
"chat": "本地聊天",
"friend_requests": "关注请求",
"mentions": "提及",
"public_tl": "公共时间线",
"timeline": "时间线",
"twkn": "所有已知网络"
},
"notifications": {
"broken_favorite": "未知的状态,正在搜索中...",
"favorited_you": "收藏了你的状态",
"followed_you": "关注了你",
"load_older": "加载更早的通知",
"notifications": "通知",
"read": "阅读!",
"repeated_you": "转发了你的状态"
},
"post_status": {
"account_not_locked_warning": "你的帐号没有 {0}。任何人都可以关注你并浏览你的上锁内容。",
"account_not_locked_warning_link": "上锁",
"attachments_sensitive": "标记附件为敏感内容",
"content_type": {
"plain_text": "纯文本"
},
"content_warning": "主题(可选)",
"default": "刚刚抵达上海",
"direct_warning": "本条内容只有被提及的用户能够看到。",
"posting": "发送",
"scope": {
"direct": "私信 - 只发送给被提及的用户",
"private": "仅关注者 - 只有关注了你的人能看到",
"public": "公共 - 发送到公共时间轴",
"unlisted": "不公开 - 所有人可见,但不会发送到公共时间轴"
}
},
"registration": {
"bio": "简介",
"email": "电子邮箱",
"fullname": "全名",
"password_confirm": "确认密码",
"registration": "注册",
"token": "邀请码"
},
"settings": {
"attachmentRadius": "附件",
"attachments": "附件",
"autoload": "启用滚动到底部时的自动加载",
"avatar": "头像",
"avatarAltRadius": "头像(通知)",
"avatarRadius": "头像",
"background": "背景",
"bio": "简介",
"btnRadius": "按钮",
"cBlue": "蓝色(回复,关注)",
"cGreen": "绿色(转发)",
"cOrange": "橙色(收藏)",
"cRed": "红色(取消)",
"change_password": "修改密码",
"change_password_error": "修改密码的时候出了点问题。",
"changed_password": "成功修改了密码!",
"collapse_subject": "折叠带主题的内容",
"confirm_new_password": "确认新密码",
"current_avatar": "当前头像",
"current_password": "当前密码",
"current_profile_banner": "您当前的横幅图片",
"data_import_export_tab": "数据导入/导出",
"default_vis": "默认可见范围",
"delete_account": "删除账户",
"delete_account_description": "永久删除你的帐号和所有消息。",
"delete_account_error": "删除账户时发生错误,如果一直删除不了,请联系实例管理员。",
"delete_account_instructions": "在下面输入你的密码来确认删除账户",
"export_theme": "导出预置主题",
"filtering": "过滤器",
"filtering_explanation": "所有包含以下词汇的内容都会被隐藏,一行一个",
"follow_export": "导出关注",
"follow_export_button": "将关注导出成 csv 文件",
"follow_export_processing": "正在处理,过一会儿就可以下载你的文件了",
"follow_import": "导入关注",
"follow_import_error": "导入关注时错误",
"follows_imported": "关注已导入!尚需要一些时间来处理。",
"foreground": "前景",
"general": "通用",
"hide_attachments_in_convo": "在对话中隐藏附件",
"hide_attachments_in_tl": "在时间线上隐藏附件",
"hide_post_stats": "隐藏推文相关的统计数据(例如:收藏的次数)",
"hide_user_stats": "隐藏用户的统计数据(例如:关注者的数量)",
"import_followers_from_a_csv_file": "从 csv 文件中导入关注",
"import_theme": "导入预置主题",
"inputRadius": "输入框",
"instance_default": "(默认:{value})",
"interfaceLanguage": "界面语言",
"invalid_theme_imported": "您所选择的主题文件不被 Pleroma 支持,因此主题未被修改。",
"limited_availability": "在您的浏览器中无法使用",
"links": "链接",
"lock_account_description": "你需要手动审核关注请求",
"loop_video": "循环视频",
"loop_video_silent_only": "只循环没有声音的视频例如Mastodon 里的“GIF”",
"name": "名字",
"name_bio": "名字及简介",
"new_password": "新密码",
"notification_visibility": "要显示的通知类型",
"notification_visibility_follows": "关注",
"notification_visibility_likes": "点赞",
"notification_visibility_mentions": "提及",
"notification_visibility_repeats": "转发",
"no_rich_text_description": "不显示富文本格式",
"nsfw_clickthrough": "将不和谐附件隐藏,点击才能打开",
"panelRadius": "面板",
"pause_on_unfocused": "在离开页面时暂停时间线推送",
"presets": "预置",
"profile_background": "个人资料背景图",
"profile_banner": "横幅图片",
"profile_tab": "个人资料",
"radii_help": "设置界面边缘的圆角 (单位:像素)",
"replies_in_timeline": "时间线中的回复",
"reply_link_preview": "启用鼠标悬停时预览回复链接",
"reply_visibility_all": "显示所有回复",
"reply_visibility_following": "只显示发送给我的回复/发送给我关注的用户的回复",
"reply_visibility_self": "只显示发送给我的回复",
"saving_err": "保存设置时发生错误",
"saving_ok": "设置已保存",
"security_tab": "安全",
"set_new_avatar": "设置新头像",
"set_new_profile_background": "设置新的个人资料背景",
"set_new_profile_banner": "设置新的横幅图片",
"settings": "设置",
"stop_gifs": "鼠标悬停时播放GIF",
"streaming": "开启滚动到顶部时的自动推送",
"text": "文本",
"theme": "主题",
"theme_help": "使用十六进制代码(#rrggbb来设置主题颜色。",
"tooltipRadius": "提醒",
"user_settings": "用户设置",
"values": {
"false": "否",
"true": "是"
}
},
"timeline": {
"collapse": "折叠",
"conversation": "对话",
"error_fetching": "获取更新时发生错误",
"load_older": "加载更早的状态",
"no_retweet_hint": "这条内容仅关注者可见,或者是私信,因此不能转发。",
"repeated": "已转发",
"show_new": "显示新内容",
"up_to_date": "已是最新"
},
"user_card": {
"approve": "允许",
"block": "屏蔽",
"blocked": "已屏蔽!",
"deny": "拒绝",
"follow": "关注",
"followees": "正在关注",
"followers": "关注者",
"following": "正在关注!",
"follows_you": "关注了你!",
"mute": "隐藏",
"muted": "已隐藏",
"per_day": "每天",
"remote_follow": "跨站关注",
"statuses": "状态"
},
"user_profile": {
"timeline_title": "用户时间线"
},
"who_to_follow": {
"more": "更多",
"who_to_follow": "推荐关注"
}
}

View file

@ -17,7 +17,9 @@ const saveImmedeatelyActions = [
'clearCurrentUser', 'clearCurrentUser',
'setCurrentUser', 'setCurrentUser',
'setHighlight', 'setHighlight',
'setOption' 'setOption',
'setClientData',
'setToken'
] ]
const defaultStorage = (() => { const defaultStorage = (() => {
@ -43,8 +45,8 @@ export default function createPersistedState ({
storage = defaultStorage, storage = defaultStorage,
subscriber = store => handler => store.subscribe(handler) subscriber = store => handler => store.subscribe(handler)
} = {}) { } = {}) {
return store => { return getState(key, storage).then((savedState) => {
getState(key, storage).then((savedState) => { return store => {
try { try {
if (typeof savedState === 'object') { if (typeof savedState === 'object') {
// build user cache // build user cache
@ -67,8 +69,8 @@ export default function createPersistedState ({
value: store.state.config.customTheme value: store.state.config.customTheme
}) })
} }
if (store.state.users.lastLoginName) { if (store.state.oauth.token) {
store.dispatch('loginUser', {username: store.state.users.lastLoginName, password: 'xxx'}) store.dispatch('loginUser', store.state.oauth.token)
} }
loaded = true loaded = true
} catch (e) { } catch (e) {
@ -76,28 +78,27 @@ export default function createPersistedState ({
console.error(e) console.error(e)
loaded = true loaded = true
} }
}) subscriber(store)((mutation, state) => {
try {
subscriber(store)((mutation, state) => { if (saveImmedeatelyActions.includes(mutation.type)) {
try { setState(key, reducer(state, paths), storage)
if (saveImmedeatelyActions.includes(mutation.type)) { .then(success => {
setState(key, reducer(state, paths), storage) if (typeof success !== 'undefined') {
.then(success => { if (mutation.type === 'setOption') {
if (typeof success !== 'undefined') { store.dispatch('settingsSaved', { success })
if (mutation.type === 'setOption') { }
store.dispatch('settingsSaved', { success })
} }
} }, error => {
}, error => { if (mutation.type === 'setOption') {
if (mutation.type === 'setOption') { store.dispatch('settingsSaved', { error })
store.dispatch('settingsSaved', { error }) }
} })
}) }
} catch (e) {
console.log("Couldn't persist state:")
console.log(e)
} }
} catch (e) { })
console.log("Couldn't persist state:") }
console.log(e) })
}
})
}
} }

View file

@ -1,18 +1,6 @@
import Vue from 'vue' import Vue from 'vue'
import VueRouter from 'vue-router' import VueRouter from 'vue-router'
import Vuex from 'vuex' import Vuex from 'vuex'
import App from './App.vue'
import PublicTimeline from './components/public_timeline/public_timeline.vue'
import PublicAndExternalTimeline from './components/public_and_external_timeline/public_and_external_timeline.vue'
import FriendsTimeline from './components/friends_timeline/friends_timeline.vue'
import TagTimeline from './components/tag_timeline/tag_timeline.vue'
import ConversationPage from './components/conversation-page/conversation-page.vue'
import Mentions from './components/mentions/mentions.vue'
import UserProfile from './components/user_profile/user_profile.vue'
import Settings from './components/settings/settings.vue'
import Registration from './components/registration/registration.vue'
import UserSettings from './components/user_settings/user_settings.vue'
import FollowRequests from './components/follow_requests/follow_requests.vue'
import interfaceModule from './modules/interface.js' import interfaceModule from './modules/interface.js'
import instanceModule from './modules/instance.js' import instanceModule from './modules/instance.js'
@ -21,6 +9,7 @@ import usersModule from './modules/users.js'
import apiModule from './modules/api.js' import apiModule from './modules/api.js'
import configModule from './modules/config.js' import configModule from './modules/config.js'
import chatModule from './modules/chat.js' import chatModule from './modules/chat.js'
import oauthModule from './modules/oauth.js'
import VueTimeago from 'vue-timeago' import VueTimeago from 'vue-timeago'
import VueI18n from 'vue-i18n' import VueI18n from 'vue-i18n'
@ -31,6 +20,8 @@ import messages from './i18n/messages.js'
import VueChatScroll from 'vue-chat-scroll' import VueChatScroll from 'vue-chat-scroll'
import afterStoreSetup from './boot/after_store.js'
const currentLocale = (window.navigator.language || 'en').split('-')[0] const currentLocale = (window.navigator.language || 'en').split('-')[0]
Vue.use(Vuex) Vue.use(Vuex)
@ -45,29 +36,6 @@ Vue.use(VueTimeago, {
Vue.use(VueI18n) Vue.use(VueI18n)
Vue.use(VueChatScroll) Vue.use(VueChatScroll)
const persistedStateOptions = {
paths: [
'config',
'users.lastLoginName',
'statuses.notifications.maxSavedId'
]
}
const store = new Vuex.Store({
modules: {
interface: interfaceModule,
instance: instanceModule,
statuses: statusesModule,
users: usersModule,
api: apiModule,
config: configModule,
chat: chatModule
},
plugins: [createPersistedState(persistedStateOptions)],
strict: false // Socket modifies itself, let's ignore this for now.
// strict: process.env.NODE_ENV !== 'production'
})
const i18n = new VueI18n({ const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary // By default, use the browser locale, we will update it if neccessary
locale: currentLocale, locale: currentLocale,
@ -75,149 +43,30 @@ const i18n = new VueI18n({
messages messages
}) })
window.fetch('/api/statusnet/config.json') const persistedStateOptions = {
.then((res) => res.json()) paths: [
.then((data) => { 'config',
const {name, closed: registrationClosed, textlimit, server} = data.site 'users.lastLoginName',
'statuses.notifications.maxSavedId',
store.dispatch('setInstanceOption', { name: 'name', value: name }) 'oauth'
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: (registrationClosed === '0') }) ]
store.dispatch('setInstanceOption', { name: 'textlimit', value: parseInt(textlimit) }) }
store.dispatch('setInstanceOption', { name: 'server', value: server }) createPersistedState(persistedStateOptions).then((persistedState) => {
const store = new Vuex.Store({
var apiConfig = data.site.pleromafe modules: {
interface: interfaceModule,
window.fetch('/static/config.json') instance: instanceModule,
.then((res) => res.json()) statuses: statusesModule,
.catch((err) => { users: usersModule,
console.warn('Failed to load static/config.json, continuing without it.') api: apiModule,
console.warn(err) config: configModule,
return {} chat: chatModule,
}) oauth: oauthModule
.then((staticConfig) => { },
// This takes static config and overrides properties that are present in apiConfig plugins: [persistedState],
var config = Object.assign({}, staticConfig, apiConfig) strict: false // Socket modifies itself, let's ignore this for now.
// strict: process.env.NODE_ENV !== 'production'
var theme = (config.theme)
var background = (config.background)
var logo = (config.logo)
var logoMask = (typeof config.logoMask === 'undefined' ? true : config.logoMask)
var logoMargin = (typeof config.logoMargin === 'undefined' ? 0 : config.logoMargin)
var redirectRootNoLogin = (config.redirectRootNoLogin)
var redirectRootLogin = (config.redirectRootLogin)
var chatDisabled = (config.chatDisabled)
var showInstanceSpecificPanel = (config.showInstanceSpecificPanel)
var scopeOptionsEnabled = (config.scopeOptionsEnabled)
var formattingOptionsEnabled = (config.formattingOptionsEnabled)
var collapseMessageWithSubject = (config.collapseMessageWithSubject)
store.dispatch('setInstanceOption', { name: 'theme', value: theme })
store.dispatch('setInstanceOption', { name: 'background', value: background })
store.dispatch('setInstanceOption', { name: 'logo', value: logo })
store.dispatch('setInstanceOption', { name: 'logoMask', value: logoMask })
store.dispatch('setInstanceOption', { name: 'logoMargin', value: logoMargin })
store.dispatch('setInstanceOption', { name: 'redirectRootNoLogin', value: redirectRootNoLogin })
store.dispatch('setInstanceOption', { name: 'redirectRootLogin', value: redirectRootLogin })
store.dispatch('setInstanceOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
store.dispatch('setInstanceOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
store.dispatch('setInstanceOption', { name: 'formattingOptionsEnabled', value: formattingOptionsEnabled })
store.dispatch('setInstanceOption', { name: 'collapseMessageWithSubject', value: collapseMessageWithSubject })
if (chatDisabled) {
store.dispatch('disableChat')
}
const routes = [
{ name: 'root',
path: '/',
redirect: to => {
return (store.state.users.currentUser
? store.state.instance.redirectRootLogin
: store.state.instance.redirectRootNoLogin) || '/main/all'
}},
{ path: '/main/all', component: PublicAndExternalTimeline },
{ path: '/main/public', component: PublicTimeline },
{ path: '/main/friends', component: FriendsTimeline },
{ path: '/tag/:tag', component: TagTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
{ name: 'registration', path: '/registration/:token', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
]
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior: (to, from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) {
return false
}
return savedPosition || { x: 0, y: 0 }
}
})
/* eslint-disable no-new */
new Vue({
router,
store,
i18n,
el: '#app',
render: h => h(App)
})
})
}) })
window.fetch('/static/terms-of-service.html') afterStoreSetup({store, i18n})
.then((res) => res.text()) })
.then((html) => {
store.dispatch('setInstanceOption', { name: 'tos', value: html })
})
window.fetch('/api/pleroma/emoji.json')
.then(
(res) => res.json()
.then(
(values) => {
const emoji = Object.keys(values).map((key) => {
return { shortcode: key, image_url: values[key] }
})
store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji })
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: true })
},
(failure) => {
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: false })
}
),
(error) => console.log(error)
)
window.fetch('/static/emoji.json')
.then((res) => res.json())
.then((values) => {
const emoji = Object.keys(values).map((key) => {
return { shortcode: key, image_url: false, 'utf': values[key] }
})
store.dispatch('setInstanceOption', { name: 'emoji', value: emoji })
})
window.fetch('/instance/panel.html')
.then((res) => res.text())
.then((html) => {
store.dispatch('setInstanceOption', { name: 'instanceSpecificPanelContent', value: html })
})
window.fetch('/nodeinfo/2.0.json')
.then((res) => res.json())
.then((data) => {
const metadata = data.metadata
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: data.metadata.mediaProxy })
store.dispatch('setInstanceOption', { name: 'chatAvailable', value: data.metadata.chat })
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: data.metadata.gopher })
const suggestions = metadata.suggestions
store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web })
})

View file

@ -5,7 +5,7 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0]
const defaultState = { const defaultState = {
colors: {}, colors: {},
collapseMessageWithSubject: false, collapseMessageWithSubject: undefined, // instance default
hideAttachments: false, hideAttachments: false,
hideAttachmentsInConv: false, hideAttachmentsInConv: false,
hideNsfw: true, hideNsfw: true,
@ -25,7 +25,9 @@ const defaultState = {
}, },
muteWords: [], muteWords: [],
highlight: {}, highlight: {},
interfaceLanguage: browserLocale interfaceLanguage: browserLocale,
scopeCopy: undefined, // instance default
subjectLineBehavior: undefined // instance default
} }
const config = { const config = {

View file

@ -18,7 +18,12 @@ const defaultState = {
scopeOptionsEnabled: true, scopeOptionsEnabled: true,
formattingOptionsEnabled: false, formattingOptionsEnabled: false,
collapseMessageWithSubject: false, collapseMessageWithSubject: false,
hidePostStats: false,
hideUserStats: false,
disableChat: false, disableChat: false,
scopeCopy: true,
subjectLineBehavior: 'email',
loginMethod: 'password',
// Nasty stuff // Nasty stuff
pleromaBackend: true, pleromaBackend: true,

18
src/modules/oauth.js Normal file
View file

@ -0,0 +1,18 @@
const oauth = {
state: {
client_id: false,
client_secret: false,
token: false
},
mutations: {
setClientData (state, data) {
state.client_id = data.client_id
state.client_secret = data.client_secret
},
setToken (state, token) {
state.token = token
}
}
}
export default oauth

View file

@ -41,7 +41,8 @@ export const defaultState = {
own: emptyTl(), own: emptyTl(),
publicAndExternal: emptyTl(), publicAndExternal: emptyTl(),
friends: emptyTl(), friends: emptyTl(),
tag: emptyTl() tag: emptyTl(),
dms: emptyTl()
} }
} }
@ -171,6 +172,14 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
sortTimeline(mentions) sortTimeline(mentions)
} }
} }
if (status.visibility === 'direct') {
const dms = state.timelines.dms
mergeOrAdd(dms.statuses, dms.statusesObject, status)
dms.newStatusCount += 1
sortTimeline(dms)
}
} }
// Decide if we should treat the status as new for this timeline. // Decide if we should treat the status as new for this timeline.

View file

@ -82,24 +82,26 @@ const users = {
}, },
logout (store) { logout (store) {
store.commit('clearCurrentUser') store.commit('clearCurrentUser')
store.commit('setToken', false)
store.dispatch('stopFetching', 'friends') store.dispatch('stopFetching', 'friends')
store.commit('setBackendInteractor', backendInteractorService()) store.commit('setBackendInteractor', backendInteractorService())
}, },
loginUser (store, userCredentials) { loginUser (store, accessToken) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const commit = store.commit const commit = store.commit
commit('beginLogin') commit('beginLogin')
store.rootState.api.backendInteractor.verifyCredentials(userCredentials) store.rootState.api.backendInteractor.verifyCredentials(accessToken)
.then((response) => { .then((response) => {
if (response.ok) { if (response.ok) {
response.json() response.json()
.then((user) => { .then((user) => {
user.credentials = userCredentials // user.credentials = userCredentials
user.credentials = accessToken
commit('setCurrentUser', user) commit('setCurrentUser', user)
commit('addNewUsers', [user]) commit('addNewUsers', [user])
// Set our new backend interactor // Set our new backend interactor
commit('setBackendInteractor', backendInteractorService(userCredentials)) commit('setBackendInteractor', backendInteractorService(accessToken))
if (user.token) { if (user.token) {
store.dispatch('initializeSocket', user.token) store.dispatch('initializeSocket', user.token)

View file

@ -15,6 +15,7 @@ const STATUS_URL = '/api/statuses/show'
const MEDIA_UPLOAD_URL = '/api/statusnet/media/upload' const MEDIA_UPLOAD_URL = '/api/statusnet/media/upload'
const CONVERSATION_URL = '/api/statusnet/conversation' const CONVERSATION_URL = '/api/statusnet/conversation'
const MENTIONS_URL = '/api/statuses/mentions.json' const MENTIONS_URL = '/api/statuses/mentions.json'
const DM_TIMELINE_URL = '/api/statuses/dm_timeline.json'
const FOLLOWERS_URL = '/api/statuses/followers.json' const FOLLOWERS_URL = '/api/statuses/followers.json'
const FRIENDS_URL = '/api/statuses/friends.json' const FRIENDS_URL = '/api/statuses/friends.json'
const FOLLOWING_URL = '/api/friendships/create.json' const FOLLOWING_URL = '/api/friendships/create.json'
@ -52,16 +53,6 @@ let fetch = (url, options) => {
return oldfetch(fullUrl, options) return oldfetch(fullUrl, options)
} }
// from https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
let utoa = (str) => {
// first we use encodeURIComponent to get percent-encoded UTF-8,
// then we convert the percent encodings into raw bytes which
// can be fed into btoa.
return btoa(encodeURIComponent(str)
.replace(/%([0-9A-F]{2})/g,
(match, p1) => { return String.fromCharCode('0x' + p1) }))
}
// Params // Params
// cropH // cropH
// cropW // cropW
@ -175,9 +166,9 @@ const register = (params) => {
}) })
} }
const authHeaders = (user) => { const authHeaders = (accessToken) => {
if (user && user.username && user.password) { if (accessToken) {
return { 'Authorization': `Basic ${utoa(`${user.username}:${user.password}`)}` } return { 'Authorization': `Bearer ${accessToken}` }
} else { } else {
return { } return { }
} }
@ -302,6 +293,7 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
public: PUBLIC_TIMELINE_URL, public: PUBLIC_TIMELINE_URL,
friends: FRIENDS_TIMELINE_URL, friends: FRIENDS_TIMELINE_URL,
mentions: MENTIONS_URL, mentions: MENTIONS_URL,
dms: DM_TIMELINE_URL,
notifications: QVITTER_USER_NOTIFICATIONS_URL, notifications: QVITTER_USER_NOTIFICATIONS_URL,
'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL, 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL,
user: QVITTER_USER_TIMELINE_URL, user: QVITTER_USER_TIMELINE_URL,

View file

@ -0,0 +1,82 @@
import {reduce} from 'lodash'
const getOrCreateApp = ({oauth, instance}) => {
const url = `${instance}/api/v1/apps`
const form = new window.FormData()
form.append('client_name', `PleromaFE_${Math.random()}`)
form.append('redirect_uris', `${window.location.origin}/oauth-callback`)
form.append('scopes', 'read write follow')
return window.fetch(url, {
method: 'POST',
body: form
}).then((data) => data.json())
}
const login = (args) => {
getOrCreateApp(args).then((app) => {
args.commit('setClientData', app)
const data = {
response_type: 'code',
client_id: app.client_id,
redirect_uri: app.redirect_uri,
scope: 'read write follow'
}
const dataString = reduce(data, (acc, v, k) => {
const encoded = `${k}=${encodeURIComponent(v)}`
if (!acc) {
return encoded
} else {
return `${acc}&${encoded}`
}
}, false)
// Do the redirect...
const url = `${args.instance}/oauth/authorize?${dataString}`
window.location.href = url
})
}
const getTokenWithCredentials = ({app, instance, username, password}) => {
const url = `${instance}/oauth/token`
const form = new window.FormData()
form.append('client_id', app.client_id)
form.append('client_secret', app.client_secret)
form.append('grant_type', 'password')
form.append('username', username)
form.append('password', password)
return window.fetch(url, {
method: 'POST',
body: form
}).then((data) => data.json())
}
const getToken = ({app, instance, code}) => {
const url = `${instance}/oauth/token`
const form = new window.FormData()
form.append('client_id', app.client_id)
form.append('client_secret', app.client_secret)
form.append('grant_type', 'authorization_code')
form.append('code', code)
form.append('redirect_uri', `${window.location.origin}/oauth-callback`)
return window.fetch(url, {
method: 'POST',
body: form
}).then((data) => data.json())
}
const oauth = {
login,
getToken,
getTokenWithCredentials,
getOrCreateApp
}
export default oauth

View file

@ -0,0 +1,16 @@
import utils from './utils.js'
const search = ({query, store}) => {
return utils.request({
store,
url: '/api/pleroma/search_user',
params: {
query
}
}).then((data) => data.json())
}
const UserSearch = {
search
}
export default UserSearch

View file

@ -0,0 +1,36 @@
const queryParams = (params) => {
return Object.keys(params)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.join('&')
}
const headers = (store) => {
const accessToken = store.state.oauth.token
if (accessToken) {
return {'Authorization': `Bearer ${accessToken}`}
} else {
return {}
}
}
const request = ({method = 'GET', url, params, store}) => {
const instance = store.state.instance.server
let fullUrl = `${instance}${url}`
if (method === 'GET' && params) {
fullUrl = fullUrl + `?${queryParams(params)}`
}
return window.fetch(fullUrl, {
method,
headers: headers(store),
credentials: 'same-origin'
})
}
const utils = {
queryParams,
request
}
export default utils

View file

@ -10,5 +10,10 @@
"showInstanceSpecificPanel": false, "showInstanceSpecificPanel": false,
"scopeOptionsEnabled": false, "scopeOptionsEnabled": false,
"formattingOptionsEnabled": false, "formattingOptionsEnabled": false,
"collapseMessageWithSubject": false "collapseMessageWithSubject": false,
"scopeCopy": false,
"subjectLineBehavior": "email",
"hidePostStats": false,
"hideUserStats": false,
"loginMethod": "password"
} }

10
static/timeago-ca.json Normal file
View file

@ -0,0 +1,10 @@
[
"ara mateix",
["fa %s s", "fa %s s"],
["fa %s min", "fa %s min"],
["fa %s h", "fa %s h"],
["fa %s dia", "fa %s dies"],
["fa %s setm.", "fa %s setm."],
["fa %s mes", "fa %s mesos"],
["fa %s any", "fa %s anys"]
]

10
static/timeago-ga.json Normal file
View file

@ -0,0 +1,10 @@
[
"Anois",
["%s s", "%s s"],
["%s n", "%s nóimeád"],
["%s u", "%s uair"],
["%s l", "%s lá"],
["%s se", "%s seachtaine"],
["%s m", "%s mí"],
["%s b", "%s bliainta"]
]

10
static/timeago-oc.json Normal file
View file

@ -0,0 +1,10 @@
[
"ara meteis",
["fa %s s", "fa %s s"],
["fa %s min", "fa %s min"],
["fa %s h", "fa %s h"],
["fa %s jorn", "fa %s jorns"],
["fa %s setm.", "fa %s setm."],
["fa %s mes", "fa %s meses"],
["fa %s an", "fa %s ans"]
]

977
yarn.lock

File diff suppressed because it is too large Load diff