possibility to set language for post
This commit is contained in:
parent
a7eaec3391
commit
4d576b00fa
|
@ -60,5 +60,6 @@ export default [
|
|||
{ id: 'fa-crosshairs', src: 'src/thirdparty/font-awesome-svg-png/white/svg/crosshairs.svg' },
|
||||
{ id: 'fa-magic', src: 'src/thirdparty/font-awesome-svg-png/white/svg/magic.svg' },
|
||||
{ id: 'fa-hashtag', src: 'src/thirdparty/font-awesome-svg-png/white/svg/hashtag.svg' },
|
||||
{ id: 'fa-bookmark', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bookmark.svg' }
|
||||
{ id: 'fa-bookmark', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bookmark.svg' },
|
||||
{ id: 'fa-language', src: 'src/thirdparty/font-awesome-svg-png/white/svg/language.svg' }
|
||||
]
|
||||
|
|
|
@ -330,7 +330,7 @@ export default {
|
|||
aboutAppDescription: `
|
||||
<p>
|
||||
Semaphore is
|
||||
<a rel="noopener" target="_blank" href="https://github.com/NickColley/semaphore">free and open-source software</a>
|
||||
<a rel="noopener" target="_blank" href="https://github.com/NickColley/semaphore">free and open-source software</a>
|
||||
maintained by <a rel="noopener" target="_blank" href="https://nickcolley.co.uk">Nick Colley</a>
|
||||
and distributed under the
|
||||
<a rel="noopener" target="_blank"
|
||||
|
@ -696,5 +696,15 @@ export default {
|
|||
statusesList: 'Statuses: list',
|
||||
notificationsOnInstance: 'Notifications on {instance}',
|
||||
// Details
|
||||
statusEdited: 'Edited'
|
||||
statusEdited: 'Edited',
|
||||
// Settings > Languages
|
||||
languages: 'Languages',
|
||||
addLanguage: 'Add language',
|
||||
add: 'Add',
|
||||
languageCode: 'Language code',
|
||||
enterLanguageCode: 'Enter language code',
|
||||
getLanguageCode: 'Language should be code from ISO-639 base. To check the right code for the language visti IANA language sub-tag registry.',
|
||||
ianaLanguageRegistry: 'IANA registry',
|
||||
setLanguageLabel: 'Set language (current {label})',
|
||||
setLanguage: 'Set language'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { store } from '../_store/store.js'
|
||||
import { goto } from '../../../__sapper__/client.js'
|
||||
|
||||
export function addLanguage () {
|
||||
const { languages, newLanguage } = store.get()
|
||||
languages.push(newLanguage.toLowerCase().trim())
|
||||
store.set({ languages })
|
||||
store.save()
|
||||
goto('/settings/languages')
|
||||
}
|
||||
|
||||
export function resetNewLanguage() {
|
||||
const newLanguage = ''
|
||||
store.set({ newLanguage })
|
||||
store.save()
|
||||
}
|
|
@ -27,7 +27,7 @@ export async function insertHandleForReply (statusId) {
|
|||
|
||||
export async function postStatus (realm, text, inReplyToId, mediaIds,
|
||||
sensitive, spoilerText, visibility,
|
||||
mediaDescriptions, inReplyToUuid, poll, mediaFocalPoints) {
|
||||
mediaDescriptions, inReplyToUuid, poll, mediaFocalPoints, language) {
|
||||
const { currentInstance, accessToken, online } = store.get()
|
||||
|
||||
if (!online) {
|
||||
|
@ -56,7 +56,7 @@ export async function postStatus (realm, text, inReplyToId, mediaIds,
|
|||
}
|
||||
}))
|
||||
const status = await postStatusToServer(currentInstance, accessToken, text,
|
||||
inReplyToId, mediaIds, sensitive, spoilerText, visibility, poll, mediaFocalPoints)
|
||||
inReplyToId, mediaIds, sensitive, spoilerText, visibility, poll, language, mediaFocalPoints)
|
||||
addStatusOrNotification(currentInstance, 'home', status)
|
||||
store.clearComposeData(realm)
|
||||
emit('postedStatus', realm, inReplyToUuid)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import { store } from '../_store/store.js'
|
||||
|
||||
export function setLanguage (realm, language) {
|
||||
store.setComposeData(realm, { language })
|
||||
}
|
|
@ -3,13 +3,14 @@ import { DEFAULT_TIMEOUT, get, post, put, WRITE_TIMEOUT } from '../_utils/ajax.j
|
|||
|
||||
// post is create, put is edit
|
||||
async function postOrPutStatus (url, accessToken, method, text, inReplyToId, mediaIds,
|
||||
sensitive, spoilerText, visibility, poll) {
|
||||
sensitive, spoilerText, visibility, poll, language) {
|
||||
const body = {
|
||||
status: text,
|
||||
media_ids: mediaIds,
|
||||
sensitive,
|
||||
spoiler_text: spoilerText,
|
||||
poll,
|
||||
language,
|
||||
...(method === 'post' && {
|
||||
// you can't change these properties when editing
|
||||
in_reply_to_id: inReplyToId,
|
||||
|
@ -31,17 +32,17 @@ async function postOrPutStatus (url, accessToken, method, text, inReplyToId, med
|
|||
}
|
||||
|
||||
export async function postStatus (instanceName, accessToken, text, inReplyToId, mediaIds,
|
||||
sensitive, spoilerText, visibility, poll) {
|
||||
sensitive, spoilerText, visibility, poll, language) {
|
||||
const url = `${basename(instanceName)}/api/v1/statuses`
|
||||
return postOrPutStatus(url, accessToken, 'post', text, inReplyToId, mediaIds,
|
||||
sensitive, spoilerText, visibility, poll)
|
||||
sensitive, spoilerText, visibility, poll, language)
|
||||
}
|
||||
|
||||
export async function putStatus (instanceName, accessToken, id, text, inReplyToId, mediaIds,
|
||||
sensitive, spoilerText, visibility, poll) {
|
||||
sensitive, spoilerText, visibility, poll, language) {
|
||||
const url = `${basename(instanceName)}/api/v1/statuses/${id}`
|
||||
return postOrPutStatus(url, accessToken, 'put', text, inReplyToId, mediaIds,
|
||||
sensitive, spoilerText, visibility, poll)
|
||||
sensitive, spoilerText, visibility, poll, language)
|
||||
}
|
||||
|
||||
export async function getStatusContext (instanceName, accessToken, statusId) {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<ComposePoll {realm} {poll} />
|
||||
</div>
|
||||
{/if}
|
||||
<ComposeToolbar {realm} {postPrivacy} {media} {contentWarningShown} {text} {poll} />
|
||||
<ComposeToolbar {realm} {postPrivacy} {media} {language} {contentWarningShown} {text} {poll} />
|
||||
<ComposeLengthIndicator {length} {overLimit} />
|
||||
<ComposeMedia {realm} {media} />
|
||||
<ComposeMediaSensitive {realm} {media} {sensitive} {contentWarning} {contentWarningShown} />
|
||||
|
@ -173,6 +173,9 @@
|
|||
poll: ({ composeData }) => composeData.poll,
|
||||
inReplyToId: ({ composeData }) => composeData.inReplyToId,
|
||||
postPrivacy: ({ postPrivacyKey }) => POST_PRIVACY_OPTIONS.find(_ => _.key === postPrivacyKey),
|
||||
language: ({ composeData, $languages }) => {
|
||||
return composeData.language ? composeData.language : ($languages.length ? $languages[0] : 'en')
|
||||
},
|
||||
defaultPostPrivacyKey: ({ $currentVerifyCredentials }) => (
|
||||
($currentVerifyCredentials && $currentVerifyCredentials.source.privacy) || 'public'
|
||||
),
|
||||
|
@ -219,7 +222,8 @@
|
|||
inReplyToUuid, // typical replies, using Semaphore-specific uuid
|
||||
inReplyToId, // delete-and-redraft replies, using standard id
|
||||
poll,
|
||||
sensitive
|
||||
sensitive,
|
||||
language
|
||||
} = this.get()
|
||||
const mediaIds = media.map(_ => _.data.id)
|
||||
const mediaDescriptions = media.map(_ => _.description)
|
||||
|
@ -248,7 +252,7 @@
|
|||
/* no await */ postStatus(realm, text, inReplyTo, mediaIds,
|
||||
sensitive, contentWarning, postPrivacyKey,
|
||||
mediaDescriptions, inReplyToUuid, pollToPost,
|
||||
mediaFocalPoints)
|
||||
mediaFocalPoints, language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,12 @@
|
|||
pressable={true}
|
||||
pressed={contentWarningShown}
|
||||
/>
|
||||
<IconButton
|
||||
className="compose-toolbar-button"
|
||||
label={setLanguageLabel}
|
||||
href="#fa-language"
|
||||
on:click="onSetLanguageClick()"
|
||||
/>
|
||||
</div>
|
||||
<input ref:input
|
||||
on:change="onFileChange(event)"
|
||||
|
@ -74,6 +80,7 @@
|
|||
import { store } from '../../_store/store.js'
|
||||
import { importShowEmojiDialog } from '../dialog/asyncDialogs/importShowEmojiDialog.js'
|
||||
import { importShowPostPrivacyDialog } from '../dialog/asyncDialogs/importShowPostPrivacyDialog.js'
|
||||
import { importShowSetLanguageDialog } from '../dialog/asyncDialogs/importShowSetLanguageDialog.js'
|
||||
import { doMediaUpload } from '../../_actions/media.js'
|
||||
import { toggleContentWarningShown } from '../../_actions/contentWarnings.js'
|
||||
import { mediaAccept } from '../../_static/media.js'
|
||||
|
@ -91,6 +98,9 @@
|
|||
computed: {
|
||||
postPrivacyLabel: ({ postPrivacy }) => (
|
||||
formatIntl('intl.postPrivacyLabel', { label: postPrivacy.label })
|
||||
),
|
||||
setLanguageLabel: ({ language }) => (
|
||||
formatIntl('intl.setLanguageLabel', { label: language })
|
||||
)
|
||||
},
|
||||
store: () => store,
|
||||
|
@ -119,6 +129,11 @@
|
|||
const showPostPrivacyDialog = await importShowPostPrivacyDialog()
|
||||
showPostPrivacyDialog(realm)
|
||||
},
|
||||
async onSetLanguageClick () {
|
||||
const { realm } = this.get()
|
||||
const showSetLanguageDialog = await importShowSetLanguageDialog()
|
||||
showSetLanguageDialog(realm)
|
||||
},
|
||||
onContentWarningClick () {
|
||||
const { realm } = this.get()
|
||||
toggleContentWarningShown(realm)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const importShowSetLanguageDialog = () => import(
|
||||
'../creators/showSetLanguageDialog.js'
|
||||
).then(mod => mod.default)
|
|
@ -0,0 +1,50 @@
|
|||
<ModalDialog
|
||||
{id}
|
||||
{label}
|
||||
{title}
|
||||
shrinkWidthToFit={true}
|
||||
background="var(--main-bg)"
|
||||
>
|
||||
<GenericDialogList selectable={true} {items} on:click="onClick(event)" />
|
||||
</ModalDialog>
|
||||
<script>
|
||||
import ModalDialog from './ModalDialog.html'
|
||||
import { store } from '../../../_store/store.js'
|
||||
import { setLanguage } from '../../../_actions/language.js'
|
||||
import GenericDialogList from './GenericDialogList.html'
|
||||
import { show } from '../helpers/showDialog.js'
|
||||
import { close } from '../helpers/closeDialog.js'
|
||||
import { oncreate } from '../helpers/onCreateDialog.js'
|
||||
|
||||
export default {
|
||||
oncreate,
|
||||
components: {
|
||||
ModalDialog,
|
||||
GenericDialogList
|
||||
},
|
||||
store: () => store,
|
||||
methods: {
|
||||
show,
|
||||
close,
|
||||
onClick (item) {
|
||||
const { realm } = this.get()
|
||||
setLanguage(realm, item.key)
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
composeData: ({ $currentComposeData, realm }) => $currentComposeData[realm] || {},
|
||||
language: ({ composeData, $languages }) => {
|
||||
return composeData.language ? composeData.language : ($languages.length ? $languages[0] : 'en')
|
||||
},
|
||||
items: ({ language, $languages }) => {
|
||||
return $languages.map(option => ({
|
||||
key: option,
|
||||
label: option.toUpperCase(),
|
||||
icon: 'fa-language',
|
||||
selected: language === option
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,10 @@
|
|||
import SetLanguageDialog from '../components/SetLanguageDialog.html'
|
||||
import { showDialog } from './showDialog.js'
|
||||
|
||||
export default function showSetLanguageDialog (realm) {
|
||||
return showDialog(SetLanguageDialog, {
|
||||
label: 'intl.setLanguage',
|
||||
title: 'intl.setLanguage',
|
||||
realm
|
||||
})
|
||||
}
|
|
@ -51,6 +51,8 @@
|
|||
settings: 'intl.settings',
|
||||
'settings/about': 'intl.aboutApp',
|
||||
'settings/general': 'intl.general',
|
||||
'settings/languages': 'intl.languages',
|
||||
'settings/languages/add': 'intl.addLanguage',
|
||||
'settings/instances': 'intl.instances',
|
||||
'settings/instances/add': $isUserLoggedIn ? 'intl.addInstance' : 'intl.logIn'
|
||||
}),
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
</span>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if language}
|
||||
<span class="status-application status-application-span language-tag">
|
||||
{language}
|
||||
</span>
|
||||
{/if}
|
||||
<a class="status-favs-reblogs status-reblogs"
|
||||
rel="prefetch"
|
||||
href="/statuses/{originalStatusId}/reblogs"
|
||||
|
@ -131,6 +136,10 @@
|
|||
|
||||
}
|
||||
|
||||
.language-tag {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script>
|
||||
import ExternalLink from '../ExternalLink.html'
|
||||
|
@ -181,6 +190,7 @@
|
|||
}
|
||||
return originalStatus.favourites_count || 0
|
||||
},
|
||||
language: ({ originalStatus }) => originalStatus.language,
|
||||
displayAbsoluteFormattedDate: ({ createdAtDateTS, $isMobileSize }) => (
|
||||
($isMobileSize ? shortAbsoluteDateFormatter : absoluteDateFormatter)().format(createdAtDateTS)
|
||||
),
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
<SettingsListRow>
|
||||
<SettingsListButton href="/settings/instances" label="{intl.instances}"/>
|
||||
</SettingsListRow>
|
||||
<SettingsListRow>
|
||||
<SettingsListButton href="/settings/languages" label="{intl.languages}"/>
|
||||
</SettingsListRow>
|
||||
<SettingsListRow>
|
||||
<SettingsListButton href="/settings/wellness" label="{intl.wellness}"/>
|
||||
</SettingsListRow>
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
<SettingsLayout page='settings/languages/add' label={intl.addLanguage}>
|
||||
<h1 id="add-an-language-h1">{intl.addLanguage}</h1>
|
||||
|
||||
<div class="add-new-language">
|
||||
<form on:submit='onSubmitLanguage(event)' aria-labelledby="add-an-language-h1">
|
||||
|
||||
{#if !hasIndexedDB || !hasLocalStorage}
|
||||
<div class="form-error form-error-user-error" role="alert">
|
||||
{intl.storageError}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<noscript>
|
||||
<div class="form-error" role="alert">
|
||||
{intl.javaScriptError}
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<label for="languageInput">{intl.languageCode}</label>
|
||||
<input type="text" autocapitalize="none" spellcheck="false" id="languageInput"
|
||||
bind:value='$newLanguage' placeholder="{intl.enterLanguageCode}" required
|
||||
>
|
||||
<button class="primary" type="submit" id="submitButton"
|
||||
disabled={!$newLanguage}>
|
||||
{intl.add}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
{intl.getLanguageCode}
|
||||
<a rel="noopener" target="_blank" href="https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry">{intl.ianaLanguageRegistry}</a>
|
||||
</p>
|
||||
</SettingsLayout>
|
||||
<style>
|
||||
.add-new-language {
|
||||
background: var(--form-bg);
|
||||
padding: 5px 10px 15px;
|
||||
margin: 20px auto;
|
||||
border: 1px solid var(--form-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.form-error {
|
||||
border: 2px solid var(--warn-color);
|
||||
border-radius: 2px;
|
||||
padding: 10px;
|
||||
font-size: 1.3em;
|
||||
margin: 5px;
|
||||
background-color: var(--main-bg);
|
||||
}
|
||||
input {
|
||||
min-width: 70%;
|
||||
max-width: 100%;
|
||||
background-color: var(--input-bg);
|
||||
}
|
||||
|
||||
label, input, button, :global(.add-new-language-aside) {
|
||||
display: block;
|
||||
margin: 20px 5px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
input {
|
||||
min-width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<script>
|
||||
import SettingsLayout from '../../../_components/settings/SettingsLayout.html'
|
||||
import { store } from '../../../_store/store.js'
|
||||
import { addLanguage, resetNewLanguage } from '../../../_actions/addLanguage.js'
|
||||
|
||||
export default {
|
||||
async oncreate () {
|
||||
this.set({
|
||||
hasIndexedDB: await testHasIndexedDB(),
|
||||
hasLocalStorage: testHasLocalStorage()
|
||||
})
|
||||
resetNewLanguage()
|
||||
},
|
||||
components: {
|
||||
SettingsLayout
|
||||
},
|
||||
store: () => store,
|
||||
data: () => ({
|
||||
hasIndexedDB: true,
|
||||
hasLocalStorage: true
|
||||
}),
|
||||
methods: {
|
||||
onSubmitLanguage (event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
addLanguage()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,40 @@
|
|||
<SettingsLayout page='settings/languages' label="{intl.languages}">
|
||||
<h1>{intl.languages}</h1>
|
||||
|
||||
<SettingsList>
|
||||
{#each $languages as language}
|
||||
<SettingsListRow>
|
||||
<span class="language-list-item">
|
||||
{language}
|
||||
</span>
|
||||
</SettingsListRow>
|
||||
{/each}
|
||||
</SettingsList>
|
||||
|
||||
<p>
|
||||
<a rel="prefetch" href="/settings/languages/add" id="add-link-1">{intl.addLanguage}</a>
|
||||
</p>
|
||||
</SettingsLayout>
|
||||
<style>
|
||||
.language-list-item {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import { store } from '../../../_store/store.js'
|
||||
import SettingsLayout from '../../../_components/settings/SettingsLayout.html'
|
||||
import SettingsList from '../../../_components/settings/SettingsList.html'
|
||||
import SettingsListRow from '../../../_components/settings/SettingsListRow.html'
|
||||
import { formatIntl } from '../../../_utils/formatIntl.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsLayout,
|
||||
SettingsList,
|
||||
SettingsListRow
|
||||
},
|
||||
store: () => store
|
||||
}
|
||||
</script>
|
|
@ -44,7 +44,9 @@ const persistedState = {
|
|||
reduceMotion:
|
||||
!process.browser ||
|
||||
matchMedia('(prefers-reduced-motion: reduce)').matches,
|
||||
underlineLinks: false
|
||||
underlineLinks: false,
|
||||
languages: ['en'],
|
||||
newLanguage: ''
|
||||
}
|
||||
|
||||
const nonPersistedState = {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<Title name="{intl.addLanguage}" settingsPage={true} />
|
||||
|
||||
<LazyPage {pageComponent} {params} />
|
||||
|
||||
<script>
|
||||
import Title from '../../_components/Title.html'
|
||||
import LazyPage from '../../_components/LazyPage.html'
|
||||
import pageComponent from '../../_pages/settings/languages/add.html'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
Title,
|
||||
LazyPage
|
||||
},
|
||||
data: () => ({
|
||||
pageComponent
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Title name="{intl.languages}" settingsPage={true} />
|
||||
|
||||
<LazyPage {pageComponent} {params} />
|
||||
|
||||
<script>
|
||||
import Title from '../../_components/Title.html'
|
||||
import LazyPage from '../../_components/LazyPage.html'
|
||||
import pageComponent from '../../_pages/settings/languages/index.html'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
Title,
|
||||
LazyPage
|
||||
},
|
||||
data: () => ({
|
||||
pageComponent
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue